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
package/README.md
CHANGED
|
@@ -163,7 +163,7 @@ Every one of these is **valid markdown** — parses fine, does the wrong thing.
|
|
|
163
163
|
| `test` | Does the harness behave? | No — a scripted stand-in | Every commit |
|
|
164
164
|
| `eval` | Does a skill actually help? | Yes — your subscription | On demand |
|
|
165
165
|
|
|
166
|
-
**One engine, two doors.** `audit` is the local report; **`lint` is the CI gate** that fails the build on the same deterministic checks — broken refs, bad tool contracts, dead hooks, skill collisions (Proofs 1–2). `test` and `eval` go further: past _does it exist_ to _does it work_. (`init` / `compile` / `eject` manage the optional typed-spec layer for the structural rules no linter can express — a graduation step you rarely run by hand.) [How the verbs relate →](docs/commands-and-how-they-relate.md)
|
|
166
|
+
**One engine, two doors.** `audit` is the local report; **`lint` is the CI gate** that fails the build on the same deterministic checks — broken refs, bad tool contracts, dead hooks, skill collisions (Proofs 1–2). `test` and `eval` go further: past _does it exist_ to _does it work_. (`init` / `compile` / `eject` manage the optional typed-spec layer for the structural rules no linter can express — a graduation step you rarely run by hand. If you use a spec, run `compile` in CI too: it is what re-derives that spec's refs, while `lint` verifies the compiled file is intact.) [How the verbs relate →](docs/commands-and-how-they-relate.md)
|
|
167
167
|
|
|
168
168
|
### 🔎 Lint — your instructions stop lying
|
|
169
169
|
|
|
@@ -6,6 +6,9 @@ exports.claudeCodeHookProtocol = {
|
|
|
6
6
|
blockExitCode: 2,
|
|
7
7
|
denyDecisionValues: ["block", "deny"],
|
|
8
8
|
eventEnvVars: [],
|
|
9
|
+
// `{"continue": false}` stops the turn outright and returns `stopReason` to
|
|
10
|
+
// the agent — a stronger stop than a per-call deny, and a documented one.
|
|
11
|
+
haltsTurnField: "continue",
|
|
9
12
|
// Events that honor `hookSpecificOutput.additionalContext` (developer-context
|
|
10
13
|
// injection). Covers vigiles's shipped inject hooks: the SessionStart lint
|
|
11
14
|
// summary and the PostToolUse refs / eval-lock nudges.
|
|
@@ -16,6 +16,8 @@ exports.claudeCodeLayout = {
|
|
|
16
16
|
skillDir: "skills",
|
|
17
17
|
agentDir: "agents",
|
|
18
18
|
commandDir: "commands",
|
|
19
|
+
// `.claude/rules/*.md` — path-scoped project instructions (see PluginLayout).
|
|
20
|
+
rulesDir: "rules",
|
|
19
21
|
materializeRoot: ".claude",
|
|
20
22
|
pluginRootToken: "${CLAUDE_PLUGIN_ROOT}",
|
|
21
23
|
// Both names Claude Code uses for the project root (mirrors the
|
|
@@ -24,6 +24,7 @@ exports.formatScriptSummary = formatScriptSummary;
|
|
|
24
24
|
const node_child_process_1 = require("node:child_process");
|
|
25
25
|
const node_os_1 = require("node:os");
|
|
26
26
|
const node_path_1 = require("node:path");
|
|
27
|
+
const node_url_1 = require("node:url");
|
|
27
28
|
const node_fs_1 = require("node:fs");
|
|
28
29
|
const node_os_2 = require("node:os");
|
|
29
30
|
const glob_1 = require("glob");
|
|
@@ -250,10 +251,23 @@ async function runScripts(files, cwd, env = {}, opts = {}) {
|
|
|
250
251
|
return;
|
|
251
252
|
}
|
|
252
253
|
const countFile = (0, node_path_1.join)(countDir, `${String(i)}.count`);
|
|
253
|
-
|
|
254
|
+
// Resolve a harness's bare `vigiles` import from the CLI's OWN install, so
|
|
255
|
+
// running the gate does not require installing the package into the
|
|
256
|
+
// project — which, in a repo that already has a package.json, drags in the
|
|
257
|
+
// entire dependency tree (measured at 840 packages against vigiles' 42,
|
|
258
|
+
// #184). Only rescues that specifier, and only after normal resolution
|
|
259
|
+
// fails, so a locally installed copy still wins.
|
|
260
|
+
const selfRoot = (0, node_path_1.resolve)(__dirname, "..", "..", "..");
|
|
261
|
+
const hook = (0, node_url_1.pathToFileURL)((0, node_path_1.join)(selfRoot, "dist", "harness-resolve-hooks.mjs")).href;
|
|
262
|
+
const child = (0, node_child_process_1.spawn)("node", ["--import", hookImport(hook), ...argv], {
|
|
254
263
|
cwd,
|
|
255
264
|
stdio: ["ignore", "pipe", "pipe"],
|
|
256
|
-
env: {
|
|
265
|
+
env: {
|
|
266
|
+
...process.env,
|
|
267
|
+
...env,
|
|
268
|
+
VIGILES_SELF_ROOT: selfRoot,
|
|
269
|
+
[check_count_js_1.CHECK_COUNT_ENV]: countFile,
|
|
270
|
+
},
|
|
257
271
|
});
|
|
258
272
|
const chunks = [];
|
|
259
273
|
child.stdout.on("data", (c) => chunks.push(c));
|
|
@@ -376,4 +390,14 @@ function formatScriptSummary(results) {
|
|
|
376
390
|
}
|
|
377
391
|
return lines.join("\n");
|
|
378
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* A `--import` argument that registers the resolver hook without a temp file:
|
|
395
|
+
* a data: URL calling `module.register`. Inline because writing a shim into the
|
|
396
|
+
* user's tree to run their tests would be a side effect the runner has no
|
|
397
|
+
* business having.
|
|
398
|
+
*/
|
|
399
|
+
function hookImport(hookHref) {
|
|
400
|
+
const src = `import {register} from "node:module";register(${JSON.stringify(hookHref)});`;
|
|
401
|
+
return `data:text/javascript,${encodeURIComponent(src)}`;
|
|
402
|
+
}
|
|
379
403
|
//# sourceMappingURL=run-scripts.js.map
|
package/dist/cli-flag-check.js
CHANGED
|
@@ -78,7 +78,7 @@ exports.COMMAND_FLAGS = {
|
|
|
78
78
|
],
|
|
79
79
|
compile: [],
|
|
80
80
|
eject: ["--keep-spec"],
|
|
81
|
-
lint: ["--summary", "--json"],
|
|
81
|
+
lint: ["--bundles=", "--summary", "--json", "--json-out="],
|
|
82
82
|
// handleRunScripts (free tier — no lock flags).
|
|
83
83
|
test: ["--min=", "--all", "--yes", "--no-interactive", "--no-skip"],
|
|
84
84
|
// handleRunScripts + resolveEvalLockEnv + the trials knob.
|
|
@@ -95,6 +95,7 @@ exports.COMMAND_FLAGS = {
|
|
|
95
95
|
audit: [
|
|
96
96
|
"--json",
|
|
97
97
|
"--md",
|
|
98
|
+
"--single",
|
|
98
99
|
"--out=",
|
|
99
100
|
"--no-html",
|
|
100
101
|
"--no-json",
|
package/dist/cli.d.ts
CHANGED
|
@@ -9,6 +9,127 @@
|
|
|
9
9
|
* `self-command-refs.test.ts` did not catch it because it guards against refs to
|
|
10
10
|
* REMOVED commands, not against a list that merely stops growing.
|
|
11
11
|
*/
|
|
12
|
+
import type { RuleSeverity } from "./core/types.js";
|
|
12
13
|
/** Reason the most recent `loadSpec()` returned null, or null if it succeeded. */
|
|
13
14
|
export declare function specLoadFailureReason(): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Structured lint report used by --json, --summary, and exit-code logic.
|
|
17
|
+
*/
|
|
18
|
+
interface LintReport {
|
|
19
|
+
hashErrors: number;
|
|
20
|
+
validationErrors: number;
|
|
21
|
+
inlineErrors: number;
|
|
22
|
+
inlineRules: number;
|
|
23
|
+
frontmatterErrors: number;
|
|
24
|
+
frontmatterRules: number;
|
|
25
|
+
specRefIssues: number;
|
|
26
|
+
specRefErrors: number;
|
|
27
|
+
duplicatePairs: number;
|
|
28
|
+
/** Severity of `duplicate-instructions` — carried so the exit code can tier it. */
|
|
29
|
+
duplicateSeverity: RuleSeverity;
|
|
30
|
+
coverageEnabled: number;
|
|
31
|
+
coverageDocumented: number;
|
|
32
|
+
strengthenSuggestions: number;
|
|
33
|
+
integrityErrors: number;
|
|
34
|
+
coverageErrors: number;
|
|
35
|
+
orphanCount: number;
|
|
36
|
+
/** Severity of `orphan-docs` — carried so the exit code can tier it (#181). */
|
|
37
|
+
orphanSeverity: RuleSeverity;
|
|
38
|
+
untestedSurfaces: number;
|
|
39
|
+
untestedErrors: number;
|
|
40
|
+
toolContractIssues: number;
|
|
41
|
+
toolContractErrors: number;
|
|
42
|
+
hookEventIssues: number;
|
|
43
|
+
hookEventErrors: number;
|
|
44
|
+
frontmatterSchemaIssues: number;
|
|
45
|
+
frontmatterSchemaErrors: number;
|
|
46
|
+
mcpConfigIssues: number;
|
|
47
|
+
mcpConfigErrors: number;
|
|
48
|
+
skillFrontmatterIssues: number;
|
|
49
|
+
skillFrontmatterErrors: number;
|
|
50
|
+
mcpToolIssues: number;
|
|
51
|
+
mcpToolErrors: number;
|
|
52
|
+
hookScriptIssues: number;
|
|
53
|
+
hookScriptErrors: number;
|
|
54
|
+
disallowedToolIssues: number;
|
|
55
|
+
disallowedToolErrors: number;
|
|
56
|
+
descriptionOverlapIssues: number;
|
|
57
|
+
descriptionOverlapErrors: number;
|
|
58
|
+
descriptionBudgetIssues: number;
|
|
59
|
+
descriptionBudgetErrors: number;
|
|
60
|
+
frontmatterValidIssues: number;
|
|
61
|
+
frontmatterValidErrors: number;
|
|
62
|
+
mcpHookIssues: number;
|
|
63
|
+
mcpHookErrors: number;
|
|
64
|
+
preferCompiledHookIssues: number;
|
|
65
|
+
preferCompiledHookErrors: number;
|
|
66
|
+
lethalTrifectaIssues: number;
|
|
67
|
+
lethalTrifectaErrors: number;
|
|
68
|
+
skillResourceIssues: number;
|
|
69
|
+
skillResourceErrors: number;
|
|
70
|
+
skillFenceIssues: number;
|
|
71
|
+
skillFenceErrors: number;
|
|
72
|
+
pluginLayoutIssues: number;
|
|
73
|
+
pluginLayoutErrors: number;
|
|
74
|
+
delegationTrifectaIssues: number;
|
|
75
|
+
delegationTrifectaErrors: number;
|
|
76
|
+
hookBlockIssues: number;
|
|
77
|
+
hookBlockErrors: number;
|
|
78
|
+
hookMatcherIssues: number;
|
|
79
|
+
hookMatcherErrors: number;
|
|
80
|
+
docRefErrors: number;
|
|
81
|
+
symbolRefErrors: number;
|
|
82
|
+
mcpRefErrors: number;
|
|
83
|
+
files: string[];
|
|
84
|
+
/**
|
|
85
|
+
* Findings / errors / warnings for the whole run — the same numbers the
|
|
86
|
+
* human-readable summary line prints, so a consumer never has to reconstruct
|
|
87
|
+
* them by counting output lines (#183, and the generic-consumer half of #181).
|
|
88
|
+
*/
|
|
89
|
+
totals?: {
|
|
90
|
+
findings: number;
|
|
91
|
+
errors: number;
|
|
92
|
+
warnings: number;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/** Exit codes: 0 clean, 1 warnings only, 2 hard errors. */
|
|
96
|
+
/**
|
|
97
|
+
* The run's totals, derived from the report itself.
|
|
98
|
+
*
|
|
99
|
+
* 🔴 ONE SOURCE, because the two numbers disagreeing IS the bug (#183). The
|
|
100
|
+
* human-readable log had no total, and counting its `⚠` lines gave a different
|
|
101
|
+
* number from the JSON — 21 against 88 on a real repo — because some checks print
|
|
102
|
+
* one line per finding and others one line carrying a count. Both numbers were
|
|
103
|
+
* right and nothing said why they differed, so "vigiles reports 21 warnings" and
|
|
104
|
+
* "88 warnings" were equally defensible readings of one run.
|
|
105
|
+
*
|
|
106
|
+
* Counted GENERICALLY off the `*Issues` / `*Errors` / count keys rather than a
|
|
107
|
+
* hand-maintained list, so a rule added later is included by existing, not by
|
|
108
|
+
* somebody remembering. `orphanCount` and `duplicatePairs` are named explicitly
|
|
109
|
+
* only because they predate the `*Issues` convention (#181).
|
|
110
|
+
*/
|
|
111
|
+
export declare function lintTotals(report: LintReport): {
|
|
112
|
+
findings: number;
|
|
113
|
+
errors: number;
|
|
114
|
+
warnings: number;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Nested plugin bundles under a lint root — a directory that is itself a harness
|
|
118
|
+
* (its own `.claude-plugin/plugin.json`, or its own skills dir) and is NOT the
|
|
119
|
+
* root being linted.
|
|
120
|
+
*
|
|
121
|
+
* 🔴 WHY THIS EXISTS. Every per-surface check reads ONE root, so in a monorepo
|
|
122
|
+
* holding `skills/` plus `plugins/ * /skills/` the nested skills were never scored
|
|
123
|
+
* and nothing said so. Measured on a fixture: 4 skills over the description
|
|
124
|
+
* budget, `lint .` reported 2, exit 0 — a repo reads that as green-with-2 while
|
|
125
|
+
* the other 2 carry the same defect (#185). The failure is silent, which is the
|
|
126
|
+
* shape this repo treats as worse than a loud one.
|
|
127
|
+
*
|
|
128
|
+
* Deliberately shallow (one level under a container dir): deep recursion would
|
|
129
|
+
* sweep vendored corpora — this repo's own `test/dogfood/` holds real pinned
|
|
130
|
+
* third-party plugins — and scoring someone else's vendored plugin as if it were
|
|
131
|
+
* yours is the false-positive that gets a gate switched off.
|
|
132
|
+
*/
|
|
133
|
+
export declare function discoverNestedBundles(root: string, exclude?: readonly string[]): string[];
|
|
134
|
+
export {};
|
|
14
135
|
//# sourceMappingURL=cli.d.ts.map
|