vigiles 16.1.1 → 16.1.3
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 +17 -0
- package/dist/adapters/claude-code/dialect.d.ts +19 -13
- package/dist/adapters/claude-code/dialect.js +40 -62
- package/dist/adapters/claude-code/vocabulary.d.ts +133 -0
- package/dist/adapters/claude-code/vocabulary.js +208 -0
- package/dist/core/bash-effects.d.ts +57 -0
- package/dist/core/bash-effects.js +147 -0
- package/dist/core/compile.js +6 -1
- package/dist/core/dialect.d.ts +27 -0
- package/dist/core/hook-events.d.ts +32 -15
- package/dist/core/hook-events.js +23 -29
- package/dist/core/hook-program.js +12 -4
- package/dist/core/markdown.d.ts +53 -0
- package/dist/core/markdown.js +99 -0
- package/dist/core/rule-meta.js +2 -2
- package/dist/core/skill-resources.js +58 -57
- package/dist/core/source-refs.d.ts +118 -0
- package/dist/core/source-refs.js +206 -0
- package/dist/core/tool-contract.d.ts +69 -30
- package/dist/core/tool-contract.js +59 -57
- package/dist/core/vocabulary-consistency.d.ts +35 -0
- package/dist/core/vocabulary-consistency.js +81 -0
- package/dist/core/vocabulary.d.ts +138 -0
- package/dist/core/vocabulary.js +262 -0
- package/dist/coverage-evidence.js +15 -3
- package/dist/plugin-loader.js +22 -28
- package/dist/scan-core.d.ts +8 -1
- package/dist/scan-core.js +105 -20
- package/dist/scan-files.js +17 -20
- package/dist/scan.d.ts +24 -0
- package/dist/scan.js +8 -1
- package/package.json +1 -1
package/dist/scan-files.js
CHANGED
|
@@ -52,10 +52,12 @@ const hook_block_ineffective_js_1 = require("./core/hook-block-ineffective.js");
|
|
|
52
52
|
const hook_matcher_js_1 = require("./core/hook-matcher.js");
|
|
53
53
|
const test_coverage_files_js_1 = require("./test-coverage-files.js");
|
|
54
54
|
const coverage_evidence_js_1 = require("./coverage-evidence.js");
|
|
55
|
+
const source_refs_js_1 = require("./core/source-refs.js");
|
|
55
56
|
const scan_core_js_1 = require("./scan-core.js");
|
|
56
57
|
// Zero imports of its own — pure string work, safe in the browser engine.
|
|
57
58
|
const skill_refs_js_1 = require("./skill-refs.js");
|
|
58
59
|
const merge_conflict_js_1 = require("./core/merge-conflict.js");
|
|
60
|
+
const scan_core_js_2 = require("./scan-core.js");
|
|
59
61
|
/**
|
|
60
62
|
* The synthetic absolute root every path in a browser scan resolves against. A
|
|
61
63
|
* pure, deterministic string (never `process.cwd()`), so `join`/`relative` stay
|
|
@@ -284,9 +286,10 @@ function materializeSurfaces(files, layout, acc, repoName) {
|
|
|
284
286
|
// ---------------------------------------------------------------------------
|
|
285
287
|
// Dangling intra-plugin refs (mirrors plugin-loader.ts danglingRefs)
|
|
286
288
|
// ---------------------------------------------------------------------------
|
|
287
|
-
|
|
289
|
+
// Extensions + BOTH token boundaries live in core/source-refs.ts, so this and
|
|
290
|
+
// its disk twin (plugin-loader.ts) cannot disagree and neither can omit one.
|
|
288
291
|
function intraRefRe(layout) {
|
|
289
|
-
return
|
|
292
|
+
return (0, source_refs_js_1.intraRefPattern)(layout.intraRefDirs);
|
|
290
293
|
}
|
|
291
294
|
const NON_PLUGIN_VARS = new Set([
|
|
292
295
|
"CLAUDE_PROJECT_DIR",
|
|
@@ -295,10 +298,14 @@ const NON_PLUGIN_VARS = new Set([
|
|
|
295
298
|
"PWD",
|
|
296
299
|
"OLDPWD",
|
|
297
300
|
]);
|
|
298
|
-
/** Mirror of plugin-loader.ts `isPluginRooted
|
|
301
|
+
/** Mirror of plugin-loader.ts `isPluginRooted`, including its boundary test:
|
|
302
|
+
* a match preceded by a path-segment character landed INSIDE a longer name
|
|
303
|
+
* (`claude-agents/`) and refers to nothing. */
|
|
299
304
|
function isPluginRooted(content, idx) {
|
|
300
|
-
|
|
301
|
-
|
|
305
|
+
// Start-of-content is handled by `startsAtSeparator` itself (`idx <= 0`), not
|
|
306
|
+
// by a guard here — see the twin in plugin-loader.ts.
|
|
307
|
+
if (content[idx - 1] !== "/")
|
|
308
|
+
return (0, source_refs_js_1.startsAtSeparator)(content, idx);
|
|
302
309
|
const seg = /([^\s"'`(=:/]*)$/.exec(content.slice(0, idx - 1))?.[1] ?? "";
|
|
303
310
|
const varName = /^\$\{?(\w+)\}?$/.exec(seg)?.[1];
|
|
304
311
|
if (varName !== undefined)
|
|
@@ -306,19 +313,6 @@ function isPluginRooted(content, idx) {
|
|
|
306
313
|
return false;
|
|
307
314
|
}
|
|
308
315
|
const DOC_SOURCE_RE = /\.(?:md|markdown|mdx|txt|rst)$/i;
|
|
309
|
-
// A `.sh`/`.bash`/`.cmd` SCRIPT's own `#`-led comments are prose, not code — a
|
|
310
|
-
// usage comment (`# bash skills/<plugin>/hooks/setup.sh`, written as it would be
|
|
311
|
-
// invoked from the REPO CHECKOUT root) is not a real file operation any more than
|
|
312
|
-
// a path mentioned in a doc file is (issue #110). Mirror of plugin-loader.ts
|
|
313
|
-
// `SCRIPT_COMMENT_RE`.
|
|
314
|
-
const SCRIPT_COMMENT_RE = /\.(?:sh|bash|cmd)$/i;
|
|
315
|
-
/** Mirror of plugin-loader.ts `stripShellComments`. */
|
|
316
|
-
function stripShellComments(content) {
|
|
317
|
-
return content
|
|
318
|
-
.split("\n")
|
|
319
|
-
.filter((line) => !line.trimStart().startsWith("#"))
|
|
320
|
-
.join("\n");
|
|
321
|
-
}
|
|
322
316
|
/** The plugin's executable (non-prose) source-file CONTENTS under the surface dirs. */
|
|
323
317
|
function executableContents(files, layout) {
|
|
324
318
|
const out = [];
|
|
@@ -332,7 +326,8 @@ function executableContents(files, layout) {
|
|
|
332
326
|
continue;
|
|
333
327
|
if (byteLen(content) > MAX_SKILL_FILE_BYTES)
|
|
334
328
|
continue;
|
|
335
|
-
|
|
329
|
+
// A full-line comment is prose in EVERY language, not only in shell.
|
|
330
|
+
out.push((0, source_refs_js_1.stripFullLineComments)(k, content));
|
|
336
331
|
}
|
|
337
332
|
}
|
|
338
333
|
return out;
|
|
@@ -475,7 +470,8 @@ function scanFiles(files, layout = layout_js_1.claudeCodeLayout, dialect = diale
|
|
|
475
470
|
const hookRegs = (0, hook_normalize_js_1.normalizeHooks)(loaded.settings.hooks);
|
|
476
471
|
const { hooks, inline, manual } = (0, scan_core_js_1.scanHooks)(hookRegs, exports.BROWSER_ROOT, lay.pluginRootToken, exists);
|
|
477
472
|
const eventNames = (0, hook_normalize_js_1.hookEventNames)(loaded.settings.hooks);
|
|
478
|
-
const
|
|
473
|
+
const allHookEventIssues = (0, hook_events_js_1.verifyHookEvents)(eventNames, dialect);
|
|
474
|
+
const hookEventIssues = (0, hook_events_js_1.scoredIssues)(allHookEventIssues);
|
|
479
475
|
const instructions = loaded.files[lay.instructionFile] !== undefined
|
|
480
476
|
? {
|
|
481
477
|
file: lay.instructionFile,
|
|
@@ -534,6 +530,7 @@ function scanFiles(files, layout = layout_js_1.claudeCodeLayout, dialect = diale
|
|
|
534
530
|
sources: loaded.sources,
|
|
535
531
|
})).map(skill_refs_js_1.formatSkillRefIssue),
|
|
536
532
|
hookEventIssues,
|
|
533
|
+
vocabularyNotes: (0, scan_core_js_2.collectVocabularyNotes)(allHookEventIssues, agents),
|
|
537
534
|
frontmatterIssues: remap((0, scan_core_js_1.frontmatterIssuesFor)(loaded.files, cls)),
|
|
538
535
|
frontmatterValueIssues: remap((0, scan_core_js_1.frontmatterValueIssuesFor)(loaded.files, cls)),
|
|
539
536
|
skillMetaIssues: remap((0, scan_core_js_1.skillMetaIssuesFor)(loaded.files, cls)),
|
package/dist/scan.d.ts
CHANGED
|
@@ -78,6 +78,12 @@ export interface ScanAgent {
|
|
|
78
78
|
readonly toolIssues: readonly ToolIssue[];
|
|
79
79
|
/** MCP tool entries naming a server the plugin doesn't declare (can't resolve). */
|
|
80
80
|
readonly mcpToolIssues: readonly McpToolIssue[];
|
|
81
|
+
/**
|
|
82
|
+
* ADVISORY tool findings — a real tool withheld only under a condition vigiles
|
|
83
|
+
* cannot see, or a name not in its capture. Surfaced via `vocabularyNotes`,
|
|
84
|
+
* never scored. Optional: absence is not a claim of zero.
|
|
85
|
+
*/
|
|
86
|
+
readonly toolNotes?: readonly ToolIssue[];
|
|
81
87
|
/** `disallowedTools:` block-list entries that are typos of a real tool (block nothing). */
|
|
82
88
|
readonly disallowedToolIssues: readonly ToolIssue[];
|
|
83
89
|
/**
|
|
@@ -102,6 +108,12 @@ export interface ScanAgent {
|
|
|
102
108
|
readonly trifecta: TrifectaFinding | null;
|
|
103
109
|
}
|
|
104
110
|
/** A lethal-trifecta finding tagged with the surface (subagent/skill) that holds it. */
|
|
111
|
+
/** One advisory vocabulary finding, tagged with the surface that carries it. */
|
|
112
|
+
export interface VocabularyNote {
|
|
113
|
+
/** Where it was found — a hook event key, or an agent's path. */
|
|
114
|
+
readonly where: string;
|
|
115
|
+
readonly message: string;
|
|
116
|
+
}
|
|
105
117
|
export interface ScanTrifectaFinding {
|
|
106
118
|
readonly path: string;
|
|
107
119
|
readonly kind: "subagent" | "skill";
|
|
@@ -218,6 +230,18 @@ export interface ScanReport {
|
|
|
218
230
|
readonly skillRefIssues?: readonly string[];
|
|
219
231
|
/** Hooks registered under an event name the harness doesn't define (typo / dead). */
|
|
220
232
|
readonly hookEventIssues: readonly HookEventIssue[];
|
|
233
|
+
/**
|
|
234
|
+
* ADVISORY vocabulary findings — names vigiles could not confirm, and real
|
|
235
|
+
* names the platform withholds only under a condition it cannot see. Surfaced
|
|
236
|
+
* and NEVER scored, which is the point: the two failure modes this replaced
|
|
237
|
+
* were silence (which reads as approval and hides vigiles's own staleness) and
|
|
238
|
+
* an error (which blames the user for our gap). Neither is a verdict, so these
|
|
239
|
+
* get a third channel instead of a grade.
|
|
240
|
+
*
|
|
241
|
+
* OPTIONAL because absence is not a claim: a producer predating this field
|
|
242
|
+
* reports nothing rather than reporting zero.
|
|
243
|
+
*/
|
|
244
|
+
readonly vocabularyNotes?: readonly VocabularyNote[];
|
|
221
245
|
/** Skills/agents missing a required frontmatter field (name; agents also description). */
|
|
222
246
|
readonly frontmatterIssues: readonly FrontmatterIssue[];
|
|
223
247
|
/** Agent frontmatter fields with an invalid value (a typo of a real model/color). */
|
package/dist/scan.js
CHANGED
|
@@ -153,7 +153,8 @@ function scanPlugin(dir, layout, dialect = dialect_js_1.claudeCodeDialect, opts
|
|
|
153
153
|
// object keys only and returns [] for an array. We don't interpret a format we
|
|
154
154
|
// don't own.
|
|
155
155
|
const eventNames = (0, hook_normalize_js_1.hookEventNames)(loaded.settings.hooks);
|
|
156
|
-
const
|
|
156
|
+
const allHookEventIssues = (0, hook_events_js_1.verifyHookEvents)(eventNames, dialect);
|
|
157
|
+
const hookEventIssues = (0, hook_events_js_1.scoredIssues)(allHookEventIssues);
|
|
157
158
|
const instructions = loaded.files[lay.instructionFile] !== undefined
|
|
158
159
|
? {
|
|
159
160
|
file: lay.instructionFile,
|
|
@@ -211,6 +212,7 @@ function scanPlugin(dir, layout, dialect = dialect_js_1.claudeCodeDialect, opts
|
|
|
211
212
|
sources: loaded.sources,
|
|
212
213
|
})).map(skill_refs_js_1.formatSkillRefIssue),
|
|
213
214
|
hookEventIssues,
|
|
215
|
+
vocabularyNotes: (0, scan_core_js_1.collectVocabularyNotes)(allHookEventIssues, agents),
|
|
214
216
|
frontmatterIssues: remap((0, scan_core_js_1.frontmatterIssuesFor)(loaded.files, cls)),
|
|
215
217
|
frontmatterValueIssues: remap((0, scan_core_js_1.frontmatterValueIssuesFor)(loaded.files, cls)),
|
|
216
218
|
skillMetaIssues: remap((0, scan_core_js_1.skillMetaIssuesFor)(loaded.files, cls)),
|
|
@@ -468,6 +470,11 @@ function formatScanReport(r) {
|
|
|
468
470
|
out.push(...section("Hooks", hookLines, r.hooks.length + r.inlineHooks));
|
|
469
471
|
out.push(...section("Broken references", r.danglingRefs.map((ref) => ` ✗ ${ref} (referenced but MISSING)`)));
|
|
470
472
|
out.push(...section("Hook events", r.hookEventIssues.map((i) => ` ✗ ${i.message}`)));
|
|
473
|
+
// Advisory, never scored — a name vigiles cannot confirm, or a real one the
|
|
474
|
+
// platform withholds only under a condition it cannot see. Printed with `·`
|
|
475
|
+
// rather than `✗` so it reads as a note about vigiles's knowledge, not a
|
|
476
|
+
// defect in the repo being audited.
|
|
477
|
+
out.push(...section("Vocabulary notes (advisory, not graded)", (r.vocabularyNotes ?? []).map((n) => ` · ${n.where}: ${n.message}`)));
|
|
471
478
|
out.push(...section("Frontmatter", [
|
|
472
479
|
...r.frontmatterIssues.map((i) => ` ✗ ${i.message}`),
|
|
473
480
|
...r.frontmatterValueIssues.map((i) => ` ✗ ${i.message}`),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigiles",
|
|
3
|
-
"version": "16.1.
|
|
3
|
+
"version": "16.1.3",
|
|
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",
|