vigiles 30.0.2 → 31.0.1
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/dist/adapter-conformance.js +9 -15
- package/dist/adapters/claude-code/run-scripts.d.ts +5 -3
- package/dist/adapters/claude-code/run-scripts.js +5 -3
- package/dist/claude-code.js +5 -0
- package/dist/cli-main.d.ts +8 -0
- package/dist/cli-main.js +315 -212
- package/dist/codex.js +5 -0
- package/dist/core/compile.d.ts +5 -5
- package/dist/core/compile.js +28 -25
- package/dist/core/config-schema.d.ts +32 -32
- package/dist/core/coverage.d.ts +4 -3
- package/dist/core/coverage.js +4 -3
- package/dist/core/doc-refs.d.ts +3 -1
- package/dist/core/doc-refs.js +2 -1
- package/dist/core/frame.d.ts +90 -0
- package/dist/core/frame.js +58 -0
- package/dist/core/glob-ignore.d.ts +28 -0
- package/dist/core/glob-ignore.js +42 -0
- package/dist/core/orphans.d.ts +5 -3
- package/dist/core/orphans.js +5 -4
- package/dist/core/refs.d.ts +2 -2
- package/dist/core/refs.js +9 -12
- package/dist/core/spec.js +5 -0
- package/dist/core/symbols.d.ts +25 -19
- package/dist/core/symbols.js +51 -74
- package/dist/core/tree-sitter-wasm.d.ts +24 -0
- package/dist/core/tree-sitter-wasm.js +128 -0
- package/dist/eval-surface.js +5 -0
- package/dist/exclude.d.ts +3 -5
- package/dist/exclude.js +3 -3
- package/dist/hook-install.js +23 -10
- package/dist/hook.js +5 -0
- package/dist/jest.js +5 -0
- package/dist/linting.d.ts +11 -30
- package/dist/linting.js +22 -35
- package/dist/scan.d.ts +3 -3
- package/dist/scan.js +8 -7
- package/dist/test-coverage.d.ts +20 -3
- package/dist/test-coverage.js +40 -14
- package/dist/test.js +5 -0
- package/dist/vitest.mjs +5 -0
- package/package.json +4 -7
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ID_KINDS = exports.SCOPE_KINDS = void 0;
|
|
4
|
+
exports.loadWasmGrammar = loadWasmGrammar;
|
|
5
|
+
exports.wasmDefinedSymbols = wasmDefinedSymbols;
|
|
6
|
+
/**
|
|
7
|
+
* vigiles — the Python / Ruby / Rust parsers, as WebAssembly, on the main thread.
|
|
8
|
+
*
|
|
9
|
+
* WHY WASM (#257). These three used to be `@ast-grep/lang-*` native grammars, the only packages
|
|
10
|
+
* in our tree with a `postinstall`; since pnpm 10 an unapproved dependency build script fails a
|
|
11
|
+
* consumer's install (`ERR_PNPM_IGNORED_BUILDS`). `@vscode/tree-sitter-wasm` (Microsoft, MIT)
|
|
12
|
+
* ships prebuilt `.wasm` grammars plus the web-tree-sitter runtime with no dependencies and no
|
|
13
|
+
* install scripts: a plain dependency, nothing for the consumer to approve or add.
|
|
14
|
+
*
|
|
15
|
+
* WHY ASYNC, AND WHY NO WORKER. WebAssembly instantiation is async (`Parser.init()`,
|
|
16
|
+
* `Language.load()`). The first cut kept the symbol check synchronous behind a worker thread
|
|
17
|
+
* and `Atomics.wait`, because `compileClaude` & co. were public and synchronous. They are no
|
|
18
|
+
* longer public (same major), so the check is async end to end and this module simply awaits.
|
|
19
|
+
*
|
|
20
|
+
* LAZY. Nothing loads at import: the runtime is `import()`ed on the first `.py` / `.rb` / `.rs`
|
|
21
|
+
* reference, and each grammar is loaded once per process.
|
|
22
|
+
*/
|
|
23
|
+
const promises_1 = require("node:fs/promises");
|
|
24
|
+
const node_module_1 = require("node:module");
|
|
25
|
+
const node_path_1 = require("node:path");
|
|
26
|
+
/**
|
|
27
|
+
* Node kinds that open a scope (their `name` becomes the `scope` of everything inside), and the
|
|
28
|
+
* kinds a `left` field must have to count as an assignment-style definition. ONE list for both
|
|
29
|
+
* walkers — the napi one in `symbols.ts` and the one below — so they cannot drift apart.
|
|
30
|
+
*/
|
|
31
|
+
exports.SCOPE_KINDS = [
|
|
32
|
+
"class_declaration",
|
|
33
|
+
"class_definition",
|
|
34
|
+
"class",
|
|
35
|
+
"module",
|
|
36
|
+
"interface_declaration",
|
|
37
|
+
"enum_declaration",
|
|
38
|
+
];
|
|
39
|
+
exports.ID_KINDS = [
|
|
40
|
+
"identifier",
|
|
41
|
+
"constant",
|
|
42
|
+
"type_identifier",
|
|
43
|
+
];
|
|
44
|
+
// Anchored on THIS file, like every other resolution in the package: under pnpm the consumer's
|
|
45
|
+
// root does not contain our dependencies. `__filename` because the package compiles to CommonJS.
|
|
46
|
+
const require_ = (0, node_module_1.createRequire)(__filename);
|
|
47
|
+
const PKG = "@vscode/tree-sitter-wasm";
|
|
48
|
+
let runtime = null;
|
|
49
|
+
const languages = new Map();
|
|
50
|
+
async function startRuntime() {
|
|
51
|
+
const entry = require_.resolve(PKG);
|
|
52
|
+
// The runtime is a UMD/CommonJS module: `import()` exposes it as `default`.
|
|
53
|
+
const mod = (await import(PKG));
|
|
54
|
+
const rt = mod.default ?? mod;
|
|
55
|
+
await rt.Parser.init();
|
|
56
|
+
return { rt, dir: (0, node_path_1.dirname)(entry), parser: new rt.Parser() };
|
|
57
|
+
}
|
|
58
|
+
async function language(id) {
|
|
59
|
+
runtime ??= startRuntime();
|
|
60
|
+
const { rt, dir } = await runtime;
|
|
61
|
+
let lang = languages.get(id);
|
|
62
|
+
if (lang === undefined) {
|
|
63
|
+
lang = (0, promises_1.readFile)((0, node_path_1.join)(dir, `tree-sitter-${id}.wasm`)).then((bytes) => rt.Language.load(bytes));
|
|
64
|
+
languages.set(id, lang);
|
|
65
|
+
}
|
|
66
|
+
return lang;
|
|
67
|
+
}
|
|
68
|
+
/** First line only: Node appends a multi-line "Require stack:" that would split one finding. */
|
|
69
|
+
function firstLine(e) {
|
|
70
|
+
const text = e instanceof Error ? e.message : String(e);
|
|
71
|
+
return text.split("\n")[0];
|
|
72
|
+
}
|
|
73
|
+
const loadResult = new Map();
|
|
74
|
+
/**
|
|
75
|
+
* Load `lang`'s grammar once per process. Resolves to `null` on success, or the load error's own
|
|
76
|
+
* text — the caller reports it verbatim as "not checked", never as a missing symbol.
|
|
77
|
+
*/
|
|
78
|
+
function loadWasmGrammar(lang) {
|
|
79
|
+
let result = loadResult.get(lang);
|
|
80
|
+
if (result === undefined) {
|
|
81
|
+
result = language(lang).then(() => null, (e) => firstLine(e));
|
|
82
|
+
loadResult.set(lang, result);
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* THE PREVIOUS WALK, NOT A QUERY: every node with a `name` field (its text), plus every node whose
|
|
88
|
+
* `left` field is a bare identifier / constant / type_identifier, with the nearest enclosing
|
|
89
|
+
* class/module name as `scope`. The native-grammar code had no per-language patterns to
|
|
90
|
+
* translate; a tags.scm-style query would be a DIFFERENT, narrower definition of "defined".
|
|
91
|
+
*/
|
|
92
|
+
function extract(root) {
|
|
93
|
+
const scopeKinds = new Set(exports.SCOPE_KINDS);
|
|
94
|
+
const idKinds = new Set(exports.ID_KINDS);
|
|
95
|
+
const out = [];
|
|
96
|
+
const walk = (node, scope) => {
|
|
97
|
+
const line = node.startPosition.row + 1;
|
|
98
|
+
const name = node.childForFieldName("name");
|
|
99
|
+
if (name)
|
|
100
|
+
out.push({ name: name.text, kind: node.type, scope, line });
|
|
101
|
+
const left = node.childForFieldName("left");
|
|
102
|
+
if (left && idKinds.has(left.type))
|
|
103
|
+
out.push({ name: left.text, kind: node.type, scope, line });
|
|
104
|
+
const next = scopeKinds.has(node.type) && name ? name.text : scope;
|
|
105
|
+
for (const child of node.children)
|
|
106
|
+
walk(child, next);
|
|
107
|
+
};
|
|
108
|
+
walk(root, "");
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
/** Parse `code` and return its definitions. Rejects on a parse failure — never resolves []. */
|
|
112
|
+
async function wasmDefinedSymbols(code, lang) {
|
|
113
|
+
const grammar = await language(lang);
|
|
114
|
+
// `runtime` is set by `language()`; one parser, re-pointed per call. Safe without a lock:
|
|
115
|
+
// setLanguage → parse → walk runs to completion with no `await` in between.
|
|
116
|
+
const { parser } = await runtime;
|
|
117
|
+
parser.setLanguage(grammar);
|
|
118
|
+
const tree = parser.parse(code);
|
|
119
|
+
if (!tree)
|
|
120
|
+
throw new Error(`tree-sitter (${lang}) returned no syntax tree`);
|
|
121
|
+
try {
|
|
122
|
+
return extract(tree.rootNode);
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
tree.delete();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=tree-sitter-wasm.js.map
|
package/dist/eval-surface.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// 🔴 PUBLIC ENTRY POINT `vigiles/eval` — every export here is a promise to users. The default for a
|
|
3
|
+
// symbol is INTERNAL. It is exported only if (a) a NAMED external consumer uses it, or (b) it is
|
|
4
|
+
// a deliberate extension point listed in STABILITY.md (the adapter kit is the example). "Might
|
|
5
|
+
// be useful" is neither. Review point: the diff of `api-surface/vigiles-eval.api.md`, which
|
|
6
|
+
// `npm run api:check` fails on.
|
|
2
7
|
/**
|
|
3
8
|
* `vigiles/eval` — the **paid** surface: every runtime export here can call a
|
|
4
9
|
* model, and therefore can spend money.
|
package/dist/exclude.d.ts
CHANGED
|
@@ -8,12 +8,10 @@ export interface ExcludeSet {
|
|
|
8
8
|
/** The user's patterns, as written (for messages). */
|
|
9
9
|
readonly patterns: readonly string[];
|
|
10
10
|
/**
|
|
11
|
-
* The
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* The function face for `globSync`, correct whatever the glob's `cwd` is. A
|
|
12
|
+
* bare directory name excludes its subtree (`bench` → `bench`, `bench/**`),
|
|
13
|
+
* which is what "tsconfig-style" promises.
|
|
14
14
|
*/
|
|
15
|
-
readonly ignore: readonly string[];
|
|
16
|
-
/** The function face for `globSync`, correct whatever the glob's `cwd` is. */
|
|
17
15
|
readonly globIgnore: IgnoreLike;
|
|
18
16
|
/** Is this root-relative path excluded (floor or user pattern)? */
|
|
19
17
|
matches(rel: string): boolean;
|
package/dist/exclude.js
CHANGED
|
@@ -4,8 +4,9 @@ exports.excludesNothing = exports.EXCLUDE_FLOOR = void 0;
|
|
|
4
4
|
exports.excludeSet = excludeSet;
|
|
5
5
|
exports.excludedBy = excludedBy;
|
|
6
6
|
/**
|
|
7
|
-
* The ONE exclusion policy for every walk that polices the user's repository (#192) — the parsed `.vigilesrc.json#exclude` as an `ExcludeSet`, built ONCE where `loadConfig()` runs and taken as a REQUIRED parameter by every in-scope discovery (`findSpecs`, `findInstructionFiles`, `discoverNestedBundles`, `collectDocumentedRules`, `gatherInstructionFiles` in cli.ts; the
|
|
8
|
-
*
|
|
7
|
+
* The ONE exclusion policy for every walk that polices the user's repository (#192) — the parsed `.vigilesrc.json#exclude` as an `ExcludeSet`, built ONCE where `loadConfig()` runs and taken as a REQUIRED parameter by every in-scope discovery (`findSpecs`, `findInstructionFiles`, `discoverNestedBundles`, `collectDocumentedRules`, `gatherInstructionFiles` in cli.ts; the `globIgnore` face handed to `findDocRefs`, `findOrphanDocs` (`repoExclude`), `discoverScripts`, `computeScriptCoverage`; the whole set to `findUntestedSurfaces`/`skillTestNudge`/`scanPlugin`).
|
|
8
|
+
* Faces: `globIgnore` (an `IgnoreLike` keyed on the path's position relative to the REPO root, so a glob rooted anywhere — `vigiles lint some/dir`, a nested bundle — still applies a root-relative exclude), `matches`/`explain` (a root-relative path), and `excludedBy` below (an absolute path).
|
|
9
|
+
* 🔴 There is deliberately NO string-list face any more (#281). It was `ignore`, correct only for a glob rooted AT `root` — a precondition that lived in a comment, and two callers that globbed from a nested bundle broke it: the repo exclude never reached the bundle, and a root-relative pattern aliased into it. `core/glob-ignore.ts` unions a detector's own string floor with `globIgnore` instead.
|
|
9
10
|
* A bare directory name excludes its subtree, as tsconfig/ESLint do — measured 2026-09-03: glob's own string `ignore` treated `bench` and `bench/` as matching NOTHING while the minimatch helper in `discoverNestedBundles` accepted them, so the two walks that honoured `exclude` disagreed.
|
|
10
11
|
* The floor (node_modules/dist/.git/.vigiles) lives here, not per walk.
|
|
11
12
|
* `exclude` filters DISCOVERY only: an explicitly named path is processed and ONE line names the pattern it matched (rg/tsc semantics with ESLint's loudness; never prettier's silent 'all clean').
|
|
@@ -57,7 +58,6 @@ function excludeSet(root, patterns) {
|
|
|
57
58
|
return {
|
|
58
59
|
root,
|
|
59
60
|
patterns: user,
|
|
60
|
-
ignore: [...exports.EXCLUDE_FLOOR, ...user.flatMap((p) => [p, `${p}/**`])],
|
|
61
61
|
globIgnore: {
|
|
62
62
|
ignored: (p) => matches(relOf(p)),
|
|
63
63
|
childrenIgnored: (p) => matches(relOf(p)),
|
package/dist/hook-install.js
CHANGED
|
@@ -265,15 +265,30 @@ function mergeHooksJson(existing, compiled, hookPath) {
|
|
|
265
265
|
const before = existing.hooks ?? {};
|
|
266
266
|
const rewritten = Object.fromEntries(Object.entries(compiled).map(([event, entries]) => [
|
|
267
267
|
event,
|
|
268
|
-
[
|
|
269
|
-
...(before[event] ?? [])
|
|
270
|
-
.map((e) => withoutHookCommands(e, hookPath))
|
|
271
|
-
.filter((e) => e !== null),
|
|
272
|
-
...entries,
|
|
273
|
-
],
|
|
268
|
+
replaceInPlace(before[event] ?? [], (e) => withoutHookCommands(e, hookPath), entries),
|
|
274
269
|
]));
|
|
275
270
|
return { ...existing, hooks: { ...before, ...rewritten } };
|
|
276
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* Put `fresh` where this hook's old entry stood, not at the end. Appending made
|
|
274
|
+
* a recompile whose wiring changed read as a reshuffle: measured on a real
|
|
275
|
+
* settings.json, one guard gained `|| exit 2` and the diff showed three entries
|
|
276
|
+
* swapping places. `strip` returns the entry unchanged when it is not ours, a
|
|
277
|
+
* narrowed entry when it shared a matcher with ours, or null when it was only
|
|
278
|
+
* ours. A hook wired for the first time is still appended.
|
|
279
|
+
*/
|
|
280
|
+
function replaceInPlace(list, strip, fresh) {
|
|
281
|
+
const at = list.findIndex((e) => strip(e) !== e);
|
|
282
|
+
const slot = at === -1 ? list.length : at;
|
|
283
|
+
return [
|
|
284
|
+
...list.flatMap((e, i) => {
|
|
285
|
+
const kept = strip(e);
|
|
286
|
+
const here = kept === null ? [] : [kept];
|
|
287
|
+
return i === slot ? [...here, ...fresh] : here;
|
|
288
|
+
}),
|
|
289
|
+
...(slot === list.length ? fresh : []),
|
|
290
|
+
];
|
|
291
|
+
}
|
|
277
292
|
/** Flatten a CC-shaped entry to Codex's flat `{matcher?, command}` form. */
|
|
278
293
|
function toTomlEntries(entries) {
|
|
279
294
|
return entries.flatMap((e) => e.hooks.map((h) => e.matcher === undefined
|
|
@@ -291,10 +306,8 @@ function mergeHooksToml(existing, compiled, hookPath) {
|
|
|
291
306
|
const before = existing.hooks ?? {};
|
|
292
307
|
const rewritten = Object.fromEntries(Object.entries(compiled).map(([event, entries]) => [
|
|
293
308
|
event,
|
|
294
|
-
[
|
|
295
|
-
|
|
296
|
-
...toTomlEntries(entries),
|
|
297
|
-
],
|
|
309
|
+
replaceInPlace(before[event] ?? [], (e) => managesHook({ hooks: [{ type: "command", command: e.command }] }, hookPath) ? null : e, // prettier-ignore
|
|
310
|
+
toTomlEntries(entries)),
|
|
298
311
|
]));
|
|
299
312
|
return { ...existing, hooks: { ...before, ...rewritten } };
|
|
300
313
|
}
|
package/dist/hook.js
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.admissibleWrites = exports.isStateWrite = exports.isStateNeed = exports.isValidStateKey = exports.stateFact = exports.record = exports.state = exports.provider = exports.defineProvider = exports.dangerously = exports.provide = exports.HookCompileError = exports.verifyHookStamp = exports.stampHook = exports.checkHookImports = exports.compileHookProgram = exports.invalidToolPatterns = exports.matchesTool = exports.outcomeWrites = exports.injectionOf = exports.hookNeeds = exports.hookRouting = exports.dispatchKind = exports.decisionExitCode = exports.runHookProgram = exports.runReact = exports.runInject = exports.decideStopGate = exports.decidePromptGate = exports.decideFileGate = exports.decideProgram = exports.responseView = exports.nothing = exports.notice = exports.run = exports.experimental_defineReact = exports.inject = exports.experimental_defineInject = exports.hookMode = exports.gateAction = exports.pathView = exports.commandView = exports.ask = exports.deny = exports.allow = exports.tools = exports.experimental_defineStopGate = exports.experimental_definePromptGate = exports.experimental_defineFileGate = exports.experimental_defineHook = void 0;
|
|
4
4
|
exports.leafCommandsNormalized = exports.HookStateError = exports.durationSeconds = void 0;
|
|
5
|
+
// 🔴 PUBLIC ENTRY POINT `vigiles/hook` — every export here is a promise to users. The default for a
|
|
6
|
+
// symbol is INTERNAL. It is exported only if (a) a NAMED external consumer uses it, or (b) it is
|
|
7
|
+
// a deliberate extension point listed in STABILITY.md (the adapter kit is the example). "Might
|
|
8
|
+
// be useful" is neither. Review point: the diff of `api-surface/vigiles-hook.api.md`, which
|
|
9
|
+
// `npm run api:check` fails on.
|
|
5
10
|
/**
|
|
6
11
|
* `vigiles/hook` — the **closed vocabulary** for authoring a compiled hook.
|
|
7
12
|
*
|
package/dist/jest.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
// 🔴 PUBLIC ENTRY POINT `vigiles/jest` — every export here is a promise to users. The default for a
|
|
4
|
+
// symbol is INTERNAL. It is exported only if (a) a NAMED external consumer uses it, or (b) it is
|
|
5
|
+
// a deliberate extension point listed in STABILITY.md (the adapter kit is the example). "Might
|
|
6
|
+
// be useful" is neither. Review point: the diff of `api-surface/vigiles-jest.api.md`, which
|
|
7
|
+
// `npm run api:check` fails on.
|
|
3
8
|
/* eslint-disable max-params, @typescript-eslint/no-explicit-any --
|
|
4
9
|
The matcher signatures mirror the runtime vigilesMatchers (positional args);
|
|
5
10
|
`Check<any>` matches the runtime generic for the type-only augmentation. */
|
package/dist/linting.d.ts
CHANGED
|
@@ -1,34 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `vigiles/linting` — Pillar 1 entry point:
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* `vigiles/linting` — Pillar 1 entry point: what a spec AUTHOR imports to describe a CLAUDE.md,
|
|
3
|
+
* a SKILL.md or an agent — the builders, the verified-reference constructors and their types.
|
|
4
|
+
* Compiling is the CLI's job (`vigiles compile` / `vigiles lint`), not this subpath's.
|
|
5
5
|
*
|
|
6
|
-
* Curated (named, not `export *`) so the internal compiler validators, hash
|
|
7
|
-
*
|
|
8
|
-
* the api reports, and the docs site (the CLI imports those from the source).
|
|
6
|
+
* Curated (named, not `export *`) so the internal compiler, validators, hash helpers and the
|
|
7
|
+
* linter cross-reference ENGINE stay out of the public surface, the api reports and the docs.
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* documentation of a decision and were descriptions of the opposite one; a
|
|
17
|
-
* header nobody re-reads is where an `export *` hides best.
|
|
18
|
-
*
|
|
19
|
-
* WHAT THE CURATION DROPS (28 symbols, measured — nothing in this repo imported
|
|
20
|
-
* any of them from here; every in-repo user takes them from `vigiles/spec`, and
|
|
21
|
-
* the one live consumer of this subpath in the docs takes `compileAgent`): the
|
|
22
|
-
* typed-COMPOSITION family — `experimental_pipe`/`_pipeStep`/`_start`/
|
|
23
|
-
* `_andThen`/`_needs`, `Pipeline`, `PipeStep`, `Supplies`, `Handoff`,
|
|
24
|
-
* `NeedsContract`, `OkOf`, `TypedAgentSpec`, `TypedOutcome`, `Shape`,
|
|
25
|
-
* `OutputFieldType` and the `result()` builder. Those verify HANDOFFS between
|
|
26
|
-
* workers; they compile to nothing and lint nothing, so they are not pillar 1.
|
|
27
|
-
*
|
|
28
|
-
* ⚠️ The cut is not a clean slice along that line, and pretending otherwise
|
|
29
|
-
* would strand a signature: the `result()` FUNCTION leaves, but the
|
|
30
|
-
* `OutputContract` TYPE stays, because `compileAgent`/`compileSkill` name it in
|
|
31
|
-
* their own types. A consumer who needs to BUILD one imports `vigiles/spec`.
|
|
9
|
+
* WHAT THE CURATION DROPS (28 symbols, measured 2026-08-21 — nothing in this repo imported any
|
|
10
|
+
* of them from here; every in-repo user takes them from `vigiles/spec`): the typed-COMPOSITION
|
|
11
|
+
* family — `experimental_pipe`/`_pipeStep`/`_start`/`_andThen`/`_needs`, `Pipeline`, `PipeStep`,
|
|
12
|
+
* `Supplies`, `Handoff`, `NeedsContract`, `OkOf`, `TypedAgentSpec`, `TypedOutcome`, `Shape`,
|
|
13
|
+
* `OutputFieldType` and the `result()` builder. Those verify HANDOFFS between workers; they
|
|
14
|
+
* compile to nothing and lint nothing, so they are not pillar 1.
|
|
32
15
|
*/
|
|
33
16
|
export { instructionFile, prose, experimental_effect, enforce, guidance, guard, file, cmd, symbol, ref, dir, glob, project, experimental_skill, experimental_agent,
|
|
34
17
|
/** @deprecated Renamed to `instructionFile`. Removed one major AFTER the one that introduces it. */
|
|
@@ -38,6 +21,4 @@ instructions,
|
|
|
38
21
|
/** @deprecated Renamed to `experimental_agent`. Removed one major AFTER the one that introduces it. */
|
|
39
22
|
agent, } from "./core/spec.js";
|
|
40
23
|
export { BUILTIN_LINTERS, type BuiltinLinter, type LinterRule, type VigilesRef, type EnforcementRef, type KnownLinterRules, type KnownProjectFiles, type KnownNpmScripts, type KnownAgentName, type StrictLinterRule, type StrictFile, type StrictCmd, type ToolVocabulary, type OpenToolVocabulary, type AllowedAt, type AuthoredPurity, type EnforceRule, type GuidanceRule, type GuardRule, type Rule, type VerifiedPath, type VerifiedCmd, type VerifiedRef, type VerifiedDir, type VerifiedGlob, type FileRef, type CmdRef, type SkillRef, type SymbolRef, type DirRef, type GlobRef, type Ref, type EffectRegion, type InstructionFragment, type InstructionTarget, type ClaudeSpec, type Gate, type RoleGate, type ProjectRole, type SkillInput, type SkillStep, type SkillSpec, type SkillSpecInput, type AgentSpec, type AgentSpecInput, type Railway, type RailwayStep, type OutputContract, } from "./core/spec.js";
|
|
41
|
-
export { compileClaude, compileSkill, compileAgent, compileRailway, CompileError, } from "./core/compile.js";
|
|
42
|
-
export type { CompileClaudeOptions, CompileClaudeResult, CompileSkillResult, CompileAgentResult, CompileRailwayOptions, CompileRailwayResult, } from "./core/compile.js";
|
|
43
24
|
//# sourceMappingURL=linting.d.ts.map
|
package/dist/linting.js
CHANGED
|
@@ -1,38 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// 🔴 PUBLIC ENTRY POINT `vigiles/linting` — every export here is a promise to users. The default for a
|
|
3
|
+
// symbol is INTERNAL. It is exported only if (a) a NAMED external consumer uses it, or (b) it is
|
|
4
|
+
// a deliberate extension point listed in STABILITY.md (the adapter kit is the example). "Might
|
|
5
|
+
// be useful" is neither. Review point: the diff of `api-surface/vigiles-linting.api.md`, which
|
|
6
|
+
// `npm run api:check` fails on.
|
|
2
7
|
/**
|
|
3
|
-
* `vigiles/linting` — Pillar 1 entry point:
|
|
4
|
-
*
|
|
5
|
-
*
|
|
8
|
+
* `vigiles/linting` — Pillar 1 entry point: what a spec AUTHOR imports to describe a CLAUDE.md,
|
|
9
|
+
* a SKILL.md or an agent — the builders, the verified-reference constructors and their types.
|
|
10
|
+
* Compiling is the CLI's job (`vigiles compile` / `vigiles lint`), not this subpath's.
|
|
6
11
|
*
|
|
7
|
-
* Curated (named, not `export *`) so the internal compiler validators, hash
|
|
8
|
-
*
|
|
9
|
-
* the api reports, and the docs site (the CLI imports those from the source).
|
|
12
|
+
* Curated (named, not `export *`) so the internal compiler, validators, hash helpers and the
|
|
13
|
+
* linter cross-reference ENGINE stay out of the public surface, the api reports and the docs.
|
|
10
14
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* documentation of a decision and were descriptions of the opposite one; a
|
|
18
|
-
* header nobody re-reads is where an `export *` hides best.
|
|
19
|
-
*
|
|
20
|
-
* WHAT THE CURATION DROPS (28 symbols, measured — nothing in this repo imported
|
|
21
|
-
* any of them from here; every in-repo user takes them from `vigiles/spec`, and
|
|
22
|
-
* the one live consumer of this subpath in the docs takes `compileAgent`): the
|
|
23
|
-
* typed-COMPOSITION family — `experimental_pipe`/`_pipeStep`/`_start`/
|
|
24
|
-
* `_andThen`/`_needs`, `Pipeline`, `PipeStep`, `Supplies`, `Handoff`,
|
|
25
|
-
* `NeedsContract`, `OkOf`, `TypedAgentSpec`, `TypedOutcome`, `Shape`,
|
|
26
|
-
* `OutputFieldType` and the `result()` builder. Those verify HANDOFFS between
|
|
27
|
-
* workers; they compile to nothing and lint nothing, so they are not pillar 1.
|
|
28
|
-
*
|
|
29
|
-
* ⚠️ The cut is not a clean slice along that line, and pretending otherwise
|
|
30
|
-
* would strand a signature: the `result()` FUNCTION leaves, but the
|
|
31
|
-
* `OutputContract` TYPE stays, because `compileAgent`/`compileSkill` name it in
|
|
32
|
-
* their own types. A consumer who needs to BUILD one imports `vigiles/spec`.
|
|
15
|
+
* WHAT THE CURATION DROPS (28 symbols, measured 2026-08-21 — nothing in this repo imported any
|
|
16
|
+
* of them from here; every in-repo user takes them from `vigiles/spec`): the typed-COMPOSITION
|
|
17
|
+
* family — `experimental_pipe`/`_pipeStep`/`_start`/`_andThen`/`_needs`, `Pipeline`, `PipeStep`,
|
|
18
|
+
* `Supplies`, `Handoff`, `NeedsContract`, `OkOf`, `TypedAgentSpec`, `TypedOutcome`, `Shape`,
|
|
19
|
+
* `OutputFieldType` and the `result()` builder. Those verify HANDOFFS between workers; they
|
|
20
|
+
* compile to nothing and lint nothing, so they are not pillar 1.
|
|
33
21
|
*/
|
|
34
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.
|
|
23
|
+
exports.BUILTIN_LINTERS = exports.agent = exports.instructions = exports.claude = exports.experimental_agent = exports.experimental_skill = exports.project = exports.glob = exports.dir = exports.ref = exports.symbol = exports.cmd = exports.file = exports.guard = exports.guidance = exports.enforce = exports.experimental_effect = exports.prose = exports.instructionFile = void 0;
|
|
36
24
|
// --- the spec authoring builders: rules, refs, prose, and the three spec kinds ---
|
|
37
25
|
var spec_js_1 = require("./core/spec.js");
|
|
38
26
|
// instruction files
|
|
@@ -67,12 +55,11 @@ Object.defineProperty(exports, "instructions", { enumerable: true, get: function
|
|
|
67
55
|
Object.defineProperty(exports, "agent", { enumerable: true, get: function () { return spec_js_1.agent; } });
|
|
68
56
|
var spec_js_2 = require("./core/spec.js");
|
|
69
57
|
Object.defineProperty(exports, "BUILTIN_LINTERS", { enumerable: true, get: function () { return spec_js_2.BUILTIN_LINTERS; } });
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
Object.defineProperty(exports, "compileRailway", { enumerable: true, get: function () { return compile_js_1.compileRailway; } });
|
|
58
|
+
// NO COMPILE ENTRY POINTS HERE (removed in the major that ships #257). `compileClaude`,
|
|
59
|
+
// `compileSkill`, `compileAgent`, `compileRailway` and their option/result types were public
|
|
60
|
+
// with no external caller — measured across the repos that depend on vigiles, every import is a
|
|
61
|
+
// spec builder — and the promise froze them synchronous while the symbol check they run became
|
|
62
|
+
// async. Spec authors run `vigiles compile`; the CLI imports the compiler from source.
|
|
76
63
|
// core/linters is the cross-reference ENGINE (checkLinterRule/editDistance/…),
|
|
77
64
|
// consumed by compile — not part of the public authoring surface.
|
|
78
65
|
//# sourceMappingURL=linting.js.map
|
package/dist/scan.d.ts
CHANGED
|
@@ -423,9 +423,9 @@ export declare function scanPlugin(dir: string, layout: PluginLayout, dialect: H
|
|
|
423
423
|
* would be twenty-odd mechanical edits for one behavioural change.
|
|
424
424
|
*
|
|
425
425
|
* ⚠️ Omitting it is NOT "the repo excludes nothing" — it is "this caller has
|
|
426
|
-
* no ExcludeSet to give", and the walk then reads everything.
|
|
427
|
-
* `
|
|
428
|
-
*
|
|
426
|
+
* no ExcludeSet to give", and the walk then reads everything. `audit` and
|
|
427
|
+
* every `lint` rule checker supply one (the checkers through the per-bundle
|
|
428
|
+
* context `overBundles` builds, so a new checker cannot forget it).
|
|
429
429
|
*/
|
|
430
430
|
excludes?: ExcludeSet;
|
|
431
431
|
/**
|
package/dist/scan.js
CHANGED
|
@@ -230,13 +230,14 @@ function scanPlugin(dir, layout, dialect, opts = {}) {
|
|
|
230
230
|
const coverage = (0, test_coverage_js_1.findUntestedSurfaces)({
|
|
231
231
|
basePath: dir,
|
|
232
232
|
layout: lay,
|
|
233
|
-
// The SAME `.vigilesrc.json#exclude
|
|
234
|
-
//
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
|
|
233
|
+
// The SAME `.vigilesrc.json#exclude`. Untested-surface discovery is a
|
|
234
|
+
// second walk over the same trees, so leaving it out would have excluded a
|
|
235
|
+
// skill from the GRADE while still naming it in "Untested surfaces: 1" — a
|
|
236
|
+
// report contradicting itself about whether the file exists. Passed WHOLE,
|
|
237
|
+
// not as a pattern list: `dir` is often not the repo root (`audit plugins/p`),
|
|
238
|
+
// and a root-relative list globbed from here matched nothing it named —
|
|
239
|
+
// `inventory.skills: 1` beside `untested: 2` (#281, D7).
|
|
240
|
+
excludes: opts.excludes,
|
|
240
241
|
});
|
|
241
242
|
const caveats = (0, test_coverage_js_1.coverageCaveats)(coverage);
|
|
242
243
|
return {
|
package/dist/test-coverage.d.ts
CHANGED
|
@@ -60,6 +60,8 @@
|
|
|
60
60
|
* magnitude in cost without saying which. {@link UntestedReport} therefore carries
|
|
61
61
|
* a per-tier {@link CoverageTier} alongside the (unchanged) union fields.
|
|
62
62
|
*/
|
|
63
|
+
import { type ExcludeSet } from "./exclude.js";
|
|
64
|
+
import type { RepoPath } from "./core/frame.js";
|
|
63
65
|
import { type PluginLayout } from "./core/layout.js";
|
|
64
66
|
import { type CoverageEvidence, type EvidenceCounts } from "./coverage-evidence.js";
|
|
65
67
|
export type SurfaceKind = "skill" | "agent" | "hook";
|
|
@@ -185,8 +187,14 @@ export interface UntestedReport {
|
|
|
185
187
|
readonly evals: CoverageTier;
|
|
186
188
|
}
|
|
187
189
|
export interface TestCoverageOptions {
|
|
188
|
-
/**
|
|
190
|
+
/** The bundle whose surfaces are discovered. Defaults to `process.cwd()`. */
|
|
189
191
|
readonly basePath?: string;
|
|
192
|
+
/**
|
|
193
|
+
* The directory `include`, `exclude`, the coverage artifact and every REPORTED
|
|
194
|
+
* path are relative to — where `.vigilesrc.json` lives. Defaults to `basePath`.
|
|
195
|
+
* Differs from it for a nested bundle under `bundles: "all"` (#281).
|
|
196
|
+
*/
|
|
197
|
+
readonly root?: string;
|
|
190
198
|
/** Scan skills under `skills/` and `.claude/skills/`. Default true. */
|
|
191
199
|
readonly skills?: boolean;
|
|
192
200
|
/** Scan subagents under `agents/` and `.claude/agents/`. Default true. */
|
|
@@ -210,8 +218,17 @@ export interface TestCoverageOptions {
|
|
|
210
218
|
* `mjs` was silently ignored on any TypeScript-shaped repo.
|
|
211
219
|
*/
|
|
212
220
|
readonly testExtension?: string;
|
|
213
|
-
/**
|
|
221
|
+
/**
|
|
222
|
+
* The rule's own `exclude` globs, relative to `root` (added to
|
|
223
|
+
* node_modules/dist/.git/.vigiles). NARROWS on top of {@link excludes}.
|
|
224
|
+
*/
|
|
214
225
|
readonly exclude?: readonly string[];
|
|
226
|
+
/**
|
|
227
|
+
* The repo-wide `.vigilesrc.json#exclude`. It carries its own root, so it is
|
|
228
|
+
* applied correctly whichever directory is being discovered — a string list
|
|
229
|
+
* here was correct only when that directory WAS the repo root (#281).
|
|
230
|
+
*/
|
|
231
|
+
readonly excludes?: ExcludeSet;
|
|
215
232
|
/**
|
|
216
233
|
* Harness layout — where skills/agents live, the plugin-root token, the
|
|
217
234
|
* manifest/settings paths. Defaults to Claude Code; a non-CC adapter passes its
|
|
@@ -266,7 +283,7 @@ export declare function coverageEvidenceCounts(report: UntestedReport): Evidence
|
|
|
266
283
|
* Returns `null` when the edited file isn't a skill/agent surface, or when it is
|
|
267
284
|
* covered on both tiers. Never throws — a nudge must not disrupt an edit.
|
|
268
285
|
*/
|
|
269
|
-
export declare function skillTestNudge(filePath:
|
|
286
|
+
export declare function skillTestNudge(filePath: RepoPath, options: TestCoverageOptions): string | null;
|
|
270
287
|
/**
|
|
271
288
|
* What the PAID eval tier measures for a surface of this kind — or `null` when
|
|
272
289
|
* it measures nothing for it.
|
package/dist/test-coverage.js
CHANGED
|
@@ -71,10 +71,13 @@ exports.coverageCaveats = coverageCaveats;
|
|
|
71
71
|
exports.formatUntestedReport = formatUntestedReport;
|
|
72
72
|
const node_fs_1 = require("node:fs");
|
|
73
73
|
const node_path_1 = require("node:path");
|
|
74
|
+
const minimatch_1 = require("minimatch");
|
|
74
75
|
const test_file_ext_js_1 = require("./core/test-file-ext.js");
|
|
75
76
|
const assert_never_js_1 = require("./core/assert-never.js");
|
|
76
77
|
const ts_runner_caps_js_1 = require("./ts-runner-caps.js");
|
|
77
78
|
const glob_1 = require("glob");
|
|
79
|
+
const glob_ignore_js_1 = require("./core/glob-ignore.js");
|
|
80
|
+
const exclude_js_1 = require("./exclude.js");
|
|
78
81
|
const layout_js_1 = require("./core/layout.js");
|
|
79
82
|
const coverage_evidence_js_1 = require("./coverage-evidence.js");
|
|
80
83
|
const coverage_artifact_js_1 = require("./coverage-artifact.js");
|
|
@@ -427,27 +430,47 @@ function tierOf(considered, tests, index, tier, globs) {
|
|
|
427
430
|
*/
|
|
428
431
|
function findUntestedSurfaces(options) {
|
|
429
432
|
const basePath = options.basePath ?? process.cwd();
|
|
433
|
+
const root = options.root ?? basePath;
|
|
430
434
|
const { layout } = options;
|
|
431
|
-
const
|
|
435
|
+
const ruleIgnore = [...DEFAULT_IGNORE, ...(options.exclude ?? [])];
|
|
436
|
+
const ignore = (0, glob_ignore_js_1.withIgnored)(ruleIgnore, options.excludes?.globIgnore);
|
|
432
437
|
const globs = options.include ?? DEFAULT_TEST_GLOBS;
|
|
433
|
-
|
|
438
|
+
// #281: surfaces are FOUND under the bundle and then re-expressed from `root`,
|
|
439
|
+
// so every later comparison (colocation, `{surface}` globs, the run index,
|
|
440
|
+
// exclude, the printed path) happens in ONE frame.
|
|
441
|
+
const prefix = (0, node_path_1.relative)(root, basePath).split(node_path_1.sep).join("/");
|
|
442
|
+
const toRoot = (s) => prefix === "" ? s : { ...s, path: `${prefix}/${s.path}` };
|
|
443
|
+
const repoExcluded = (0, exclude_js_1.excludedBy)(options.excludes);
|
|
444
|
+
const excluded = (p) => ruleIgnore.some((g) => (0, minimatch_1.minimatch)(p, g, { dot: true })) ||
|
|
445
|
+
repoExcluded((0, node_path_1.join)(root, p));
|
|
446
|
+
// Discovery globs from the BUNDLE, so it gets only the frame-free floor; the
|
|
447
|
+
// rule's patterns are root-relative and the repo's carry their own root, so
|
|
448
|
+
// both are applied below, to the root-relative path.
|
|
449
|
+
const floor = [...DEFAULT_IGNORE];
|
|
450
|
+
const found = [];
|
|
434
451
|
if (options.skills !== false)
|
|
435
|
-
|
|
452
|
+
found.push(...discoverSkills(basePath, floor, layout));
|
|
436
453
|
if (options.agents !== false)
|
|
437
|
-
|
|
454
|
+
found.push(...discoverAgents(basePath, floor, layout));
|
|
438
455
|
if (options.hooks !== false)
|
|
439
|
-
|
|
456
|
+
found.push(...discoverHooks(basePath, layout));
|
|
457
|
+
// Hooks were never subject to `ignore` (a compiled hook lives under the
|
|
458
|
+
// default-ignored `.vigiles/`); keep that, and re-apply exclude to the kinds
|
|
459
|
+
// whose discovery glob used it — now from `root`, where the patterns live.
|
|
460
|
+
const surfaces = found
|
|
461
|
+
.map(toRoot)
|
|
462
|
+
.filter((s) => s.kind === "hook" || !excluded(s.path));
|
|
440
463
|
// Every skill/agent/hook is held to the requirement — only an explicit
|
|
441
464
|
// `vigiles:ignore-test` marker exempts a surface (a visible, deliberate skip).
|
|
442
465
|
const considered = surfaces.filter((s) => !s.ignored);
|
|
443
466
|
const exempt = surfaces.length - considered.length;
|
|
444
|
-
const tests = discoverTests(
|
|
467
|
+
const tests = discoverTests(root, globs, ignore);
|
|
445
468
|
const split = partitionTests(tests);
|
|
446
469
|
// The run record, if there is one. NO artifact ⇒ an empty index ⇒ every
|
|
447
470
|
// decision below falls through to colocation, byte-for-byte as before: a fresh
|
|
448
471
|
// clone and someone else's repo must not get one extra nudge from this tier.
|
|
449
|
-
const runIndex = (0, coverage_artifact_js_1.indexRuns)((0, coverage_artifact_js_1.readCoverageArtifact)(
|
|
450
|
-
const abs = (0, node_path_1.join)(
|
|
472
|
+
const runIndex = (0, coverage_artifact_js_1.indexRuns)((0, coverage_artifact_js_1.readCoverageArtifact)(root), (p) => {
|
|
473
|
+
const abs = (0, node_path_1.join)(root, p);
|
|
451
474
|
return (0, node_fs_1.existsSync)(abs) ? (0, coverage_artifact_js_1.surfaceSha)(read(abs)) : null;
|
|
452
475
|
},
|
|
453
476
|
// The SCRIPT that did the exercising has to still be here too — a deleted or
|
|
@@ -455,7 +478,7 @@ function findUntestedSurfaces(options) {
|
|
|
455
478
|
// record is permanent, unfalsifiable coverage. `canonicalScript` first: one
|
|
456
479
|
// file has several legitimate spellings (`x.mjs`, `./x.mjs`, absolute), and
|
|
457
480
|
// the artifact records whichever one was typed.
|
|
458
|
-
(by) => (0, node_fs_1.existsSync)((0, node_path_1.join)(
|
|
481
|
+
(by) => (0, node_fs_1.existsSync)((0, node_path_1.join)(root, (0, coverage_artifact_js_1.canonicalScript)(by, root))));
|
|
459
482
|
const union = tierOf(considered, tests, runIndex, undefined, globs);
|
|
460
483
|
return {
|
|
461
484
|
total: considered.length,
|
|
@@ -477,8 +500,8 @@ function findUntestedSurfaces(options) {
|
|
|
477
500
|
}),
|
|
478
501
|
legacyCoversFiles: tests
|
|
479
502
|
.map((t) => t.path)
|
|
480
|
-
.filter((path) => read((0, node_path_1.join)(
|
|
481
|
-
retiredTestNames: retiredTestNamesFor(
|
|
503
|
+
.filter((path) => read((0, node_path_1.join)(root, path)).includes(LEGACY_COVERS)),
|
|
504
|
+
retiredTestNames: retiredTestNamesFor(root, union.untested),
|
|
482
505
|
decisions: union.decisions,
|
|
483
506
|
harness: tierOf(considered, split.harness, runIndex, "harness", globs),
|
|
484
507
|
evals: tierOf(considered, split.evals, runIndex, "eval", globs),
|
|
@@ -549,9 +572,12 @@ function skillTestNudge(filePath, options) {
|
|
|
549
572
|
catch {
|
|
550
573
|
return null; // a broken scan must never surface as a broken edit
|
|
551
574
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
575
|
+
// 🔴 EQUALITY, IN ONE FRAME (#281, D6). This used to accept any path ENDING in
|
|
576
|
+
// a surface's path, so editing `plugins/p/skills/x/SKILL.md` matched the root
|
|
577
|
+
// bundle's `skills/x/SKILL.md` and reported THAT skill's coverage as the
|
|
578
|
+
// edited one's. The caller now hands a `RepoPath` and the report's paths are
|
|
579
|
+
// relative to the same `root`, so a suffix has nothing left to rescue.
|
|
580
|
+
const isTarget = (s) => s.path === filePath;
|
|
555
581
|
const untested = report.untested.find(isTarget);
|
|
556
582
|
if (untested)
|
|
557
583
|
return (`vigiles: you edited ${untested.path}, and nothing measures whether it ` +
|
package/dist/test.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// 🔴 PUBLIC ENTRY POINT `vigiles` — every export here is a promise to users. The default for a
|
|
3
|
+
// symbol is INTERNAL. It is exported only if (a) a NAMED external consumer uses it, or (b) it is
|
|
4
|
+
// a deliberate extension point listed in STABILITY.md (the adapter kit is the example). "Might
|
|
5
|
+
// be useful" is neither. Review point: the diff of `api-surface/vigiles.api.md`, which
|
|
6
|
+
// `npm run api:check` fails on.
|
|
2
7
|
/**
|
|
3
8
|
* `vigiles` (the package root) — the **free** testing surface: everything you can
|
|
4
9
|
* run without a model call, and therefore without a bill.
|
package/dist/vitest.mjs
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
// 🔴 PUBLIC ENTRY POINT `vigiles/vitest` — every export here is a promise to users. The default for a
|
|
2
|
+
// symbol is INTERNAL. It is exported only if (a) a NAMED external consumer uses it, or (b) it is
|
|
3
|
+
// a deliberate extension point listed in STABILITY.md (the adapter kit is the example). "Might
|
|
4
|
+
// be useful" is neither. Review point: the diff of `api-surface/vigiles-vitest.api.md`, which
|
|
5
|
+
// `npm run api:check` fails on.
|
|
1
6
|
/* eslint-disable max-params, @typescript-eslint/no-explicit-any --
|
|
2
7
|
The matcher signatures mirror the runtime vigilesMatchers (positional args),
|
|
3
8
|
and `Matchers<T = any>` must match @vitest/expect's generic default to merge. */
|