vigiles 22.0.0 → 24.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/adapters/claude-code/run-scripts.js +26 -2
- package/dist/cli-flag-check.js +2 -1
- package/dist/cli.d.ts +121 -0
- package/dist/cli.js +375 -32
- 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/core/rule-meta.d.ts +1 -1
- package/dist/core/rule-meta.js +16 -0
- package/dist/core/types.d.ts +44 -0
- package/dist/core/validate.js +18 -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/harness-resolve-hooks.d.mts +13 -0
- package/dist/harness-resolve-hooks.mjs +50 -0
- 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/test-coverage-files.js +17 -8
- package/dist/test-coverage.js +29 -16
- package/package.json +1 -1
|
@@ -202,26 +202,28 @@ function isColocated(surface, testPath) {
|
|
|
202
202
|
return (0, coverage_evidence_js_1.isColocatedTest)(surface, testPath);
|
|
203
203
|
}
|
|
204
204
|
/** Mirror of test-coverage.ts `coverageOf` — strongest evidence across tests. */
|
|
205
|
-
function coverageOf(surface, tests) {
|
|
205
|
+
function coverageOf(surface, tests, globs) {
|
|
206
206
|
let best = null;
|
|
207
207
|
for (const t of tests) {
|
|
208
208
|
if (t.path === surface.path)
|
|
209
209
|
continue;
|
|
210
|
-
const ev = (0, coverage_evidence_js_1.evidenceFor)(surface, t, isColocated(surface, t.path));
|
|
210
|
+
const ev = (0, coverage_evidence_js_1.evidenceFor)(surface, t, isColocated(surface, t.path), (0, coverage_evidence_js_1.matchesSurfaceGlob)(surface, t.path, globs));
|
|
211
211
|
if (!ev)
|
|
212
212
|
continue;
|
|
213
|
-
|
|
213
|
+
// Rank, do not first-win: with a colocated harness AND a configured
|
|
214
|
+
// suite the reported provenance must not depend on glob order.
|
|
215
|
+
if (!best || (0, coverage_evidence_js_1.strongerEvidence)(ev, best.evidence))
|
|
214
216
|
best = { surface, evidence: ev, by: t.path };
|
|
215
217
|
}
|
|
216
218
|
return best;
|
|
217
219
|
}
|
|
218
220
|
/** Mirror of test-coverage.ts `tierOf` — one tier's covered/untested split. */
|
|
219
|
-
function tierOf(considered, tests) {
|
|
221
|
+
function tierOf(considered, tests, globs) {
|
|
220
222
|
const covered = [];
|
|
221
223
|
const untested = [];
|
|
222
224
|
const decisions = [];
|
|
223
225
|
for (const s of considered) {
|
|
224
|
-
const decision = coverageOf(s, tests);
|
|
226
|
+
const decision = coverageOf(s, tests, globs);
|
|
225
227
|
if (decision) {
|
|
226
228
|
covered.push(s);
|
|
227
229
|
decisions.push(decision);
|
|
@@ -252,12 +254,19 @@ repoName) {
|
|
|
252
254
|
];
|
|
253
255
|
const considered = surfaces.filter((s) => !s.ignored);
|
|
254
256
|
const tests = discoverTests(files);
|
|
255
|
-
|
|
257
|
+
// NO configured `{surface}` globs here, and that is a property of this twin
|
|
258
|
+
// rather than a gap: the browser engine reads a file MAP, not a repo, so there
|
|
259
|
+
// is no `.vigilesrc.json` for a user to have configured. Passing an empty list
|
|
260
|
+
// makes `matchesSurfaceGlob` false for everything, so this path behaves exactly
|
|
261
|
+
// as it did before the tier existed. Said out loud because a silent asymmetry
|
|
262
|
+
// between the twins is how they drift.
|
|
263
|
+
const noConfiguredGlobs = [];
|
|
264
|
+
const union = tierOf(considered, tests, noConfiguredGlobs);
|
|
256
265
|
return {
|
|
257
266
|
untested: [...union.untested],
|
|
258
267
|
decisions: union.decisions,
|
|
259
|
-
harness: tierOf(considered, tests.filter((t) => !(0, coverage_evidence_js_1.isEvalScript)((0, posix_path_js_1.basename)(t.path)))),
|
|
260
|
-
evals: tierOf(considered, tests.filter((t) => (0, coverage_evidence_js_1.isEvalScript)((0, posix_path_js_1.basename)(t.path)))),
|
|
268
|
+
harness: tierOf(considered, tests.filter((t) => !(0, coverage_evidence_js_1.isEvalScript)((0, posix_path_js_1.basename)(t.path))), noConfiguredGlobs),
|
|
269
|
+
evals: tierOf(considered, tests.filter((t) => (0, coverage_evidence_js_1.isEvalScript)((0, posix_path_js_1.basename)(t.path))), noConfiguredGlobs),
|
|
261
270
|
};
|
|
262
271
|
}
|
|
263
272
|
//# sourceMappingURL=test-coverage-files.js.map
|
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": "24.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",
|