vigiles 29.0.0 → 30.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/dist/adapter-conformance.d.ts +1 -1
- package/dist/adapter-conformance.js +106 -25
- package/dist/adapter-registry.d.ts +61 -14
- package/dist/adapter-registry.js +78 -10
- package/dist/adapter.d.ts +23 -2
- package/dist/adapter.js +13 -1
- package/dist/adapters/claude-code/adapter.d.ts +32 -2
- package/dist/adapters/claude-code/adapter.js +44 -23
- package/dist/adapters/claude-code/dialect.js +87 -21
- package/dist/adapters/claude-code/hook-protocol.js +16 -0
- package/dist/adapters/claude-code/instruction-chain.d.ts +25 -0
- package/dist/adapters/claude-code/instruction-chain.js +626 -0
- package/dist/adapters/claude-code/layout.d.ts +2 -2
- package/dist/adapters/claude-code/layout.js +42 -8
- package/dist/adapters/claude-code/model-access.d.ts +41 -0
- package/dist/adapters/claude-code/model-access.js +46 -0
- package/dist/adapters/claude-code/skill-reachability.d.ts +125 -0
- package/dist/adapters/claude-code/skill-reachability.js +111 -0
- package/dist/adapters/codex/adapter.d.ts +39 -2
- package/dist/adapters/codex/adapter.js +29 -29
- package/dist/adapters/codex/dialect.js +11 -6
- package/dist/adapters/codex/eval.d.ts +10 -0
- package/dist/adapters/codex/eval.js +48 -1
- package/dist/adapters/codex/hook-protocol.d.ts +2 -1
- package/dist/adapters/codex/hook-protocol.js +10 -0
- package/dist/adapters/codex/instruction-chain.d.ts +40 -0
- package/dist/adapters/codex/instruction-chain.js +105 -0
- package/dist/adapters/codex/layout.d.ts +1 -1
- package/dist/adapters/codex/layout.js +41 -14
- package/dist/adapters/opencode/adapter.d.ts +33 -2
- package/dist/adapters/opencode/adapter.js +36 -36
- package/dist/adapters/opencode/dialect.js +2 -2
- package/dist/adapters/opencode/instruction-chain.d.ts +37 -0
- package/dist/adapters/opencode/instruction-chain.js +70 -0
- package/dist/adapters/opencode/layout.d.ts +19 -0
- package/dist/adapters/opencode/layout.js +34 -15
- package/dist/adoptability.d.ts +31 -1
- package/dist/adoptability.js +57 -0
- package/dist/cli-main.js +180 -102
- package/dist/core/adapter.d.ts +213 -61
- package/dist/core/compile.d.ts +2 -2
- package/dist/core/compile.js +57 -38
- package/dist/core/compose.d.ts +5 -3
- package/dist/core/compose.js +5 -3
- package/dist/core/config-schema.d.ts +14 -2
- package/dist/core/config-schema.js +24 -3
- package/dist/core/dialect.d.ts +54 -12
- package/dist/core/dialect.js +56 -0
- package/dist/core/eval-driver.d.ts +194 -0
- package/dist/core/eval-driver.js +3 -0
- package/dist/core/frontmatter-read.d.ts +10 -0
- package/dist/core/frontmatter-read.js +30 -3
- package/dist/core/hook-program.d.ts +27 -2
- package/dist/core/hook-program.js +29 -24
- package/dist/core/hook-protocol.d.ts +54 -0
- package/dist/core/install-reader.d.ts +18 -0
- package/dist/core/install-reader.js +88 -0
- package/dist/core/instruction-chain.d.ts +444 -0
- package/dist/core/instruction-chain.js +292 -0
- package/dist/core/instruction-weight.d.ts +96 -14
- package/dist/core/instruction-weight.js +65 -30
- package/dist/core/layout.d.ts +220 -33
- package/dist/core/layout.js +115 -1
- package/dist/core/lethal-trifecta.d.ts +12 -7
- package/dist/core/lethal-trifecta.js +13 -8
- package/dist/core/live-driver.d.ts +137 -0
- package/dist/core/live-driver.js +14 -0
- package/dist/core/markdown.d.ts +23 -0
- package/dist/core/markdown.js +77 -28
- package/dist/core/orphans.js +9 -7
- package/dist/core/settings-codec.d.ts +17 -0
- package/dist/core/settings-codec.js +56 -0
- package/dist/core/surface-discovery.d.ts +2 -2
- package/dist/core/surface-discovery.js +24 -8
- package/dist/core/surface-scopes.d.ts +26 -6
- package/dist/core/surface-scopes.js +52 -11
- package/dist/core/validate.js +16 -3
- package/dist/eval.d.ts +16 -108
- package/dist/eval.js +34 -1
- package/dist/harness-test.d.ts +3 -63
- package/dist/hook-install.d.ts +12 -1
- package/dist/hook-install.js +12 -1
- package/dist/plugin-loader.d.ts +1 -1
- package/dist/plugin-loader.js +43 -36
- package/dist/scan-behavioral.d.ts +34 -25
- package/dist/scan-behavioral.js +122 -58
- package/dist/scan-core.js +37 -18
- package/dist/scan-files.d.ts +1 -1
- package/dist/scan-files.js +53 -33
- package/dist/scan-trigger-suggest.d.ts +0 -21
- package/dist/scan-trigger-suggest.js +0 -23
- package/dist/scan.d.ts +4 -4
- package/dist/scan.js +120 -73
- package/dist/skill-harness.d.ts +21 -5
- package/dist/skill-harness.js +29 -11
- package/dist/surface-discovery-fs.d.ts +2 -0
- package/dist/surface-discovery-fs.js +108 -6
- package/dist/test-coverage-files.js +24 -17
- package/dist/test-coverage.d.ts +9 -3
- package/dist/test-coverage.js +32 -17
- package/dist/verify-plugin-guards.js +1 -1
- package/package.json +1 -1
- package/dist/skill-reachability.d.ts +0 -68
- package/dist/skill-reachability.js +0 -205
- /package/dist/{dialect-drift.d.ts → adapters/claude-code/dialect-drift.d.ts} +0 -0
- /package/dist/{dialect-drift.js → adapters/claude-code/dialect-drift.js} +0 -0
package/dist/scan-behavioral.js
CHANGED
|
@@ -40,38 +40,72 @@ const scan_js_1 = require("./scan.js");
|
|
|
40
40
|
const audit_prompts_js_1 = require("./audit-prompts.js");
|
|
41
41
|
const judge_js_1 = require("./judge.js");
|
|
42
42
|
const eval_js_1 = require("./eval.js");
|
|
43
|
-
|
|
44
|
-
const harness_test_js_1 = require("./harness-test.js");
|
|
43
|
+
// eslint-disable-next-line local/no-harness-names -- IMPORT PATH, not a decision: this module is the application layer that drives a real harness binary, and Claude Code is the documented DEFAULT for candidate discovery. The rule flags the module path the way it flags `scan.ts`'s (rule header, "three are the import specifiers"); what it is guarding against — a name-driven BRANCH — is gone from this file.
|
|
45
44
|
const plugin_loader_js_1 = require("./adapters/claude-code/plugin-loader.js");
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
// The Claude Code default for candidate DISCOVERY. This module is the
|
|
46
|
+
// application layer (it drives a real harness binary and already imports the
|
|
47
|
+
// Claude Code loader above), which is where a default belongs — `src/scan.ts`
|
|
48
|
+
// and `src/test-coverage.ts` are the harness-agnostic detectors, and they no
|
|
49
|
+
// longer carry one.
|
|
50
|
+
// eslint-disable-next-line local/no-harness-names -- IMPORT PATH, not a decision: this module is the application layer that drives a real harness binary, and Claude Code is the documented DEFAULT for candidate discovery. The rule flags the module path the way it flags `scan.ts`'s (rule header, "three are the import specifiers"); what it is guarding against — a name-driven BRANCH — is gone from this file.
|
|
51
|
+
const layout_js_1 = require("./adapters/claude-code/layout.js");
|
|
52
|
+
// eslint-disable-next-line local/no-harness-names -- IMPORT PATH, not a decision: this module is the application layer that drives a real harness binary, and Claude Code is the documented DEFAULT for candidate discovery. The rule flags the module path the way it flags `scan.ts`'s (rule header, "three are the import specifiers"); what it is guarding against — a name-driven BRANCH — is gone from this file.
|
|
53
|
+
const dialect_js_1 = require("./adapters/claude-code/dialect.js");
|
|
54
|
+
const live_driver_js_1 = require("./core/live-driver.js");
|
|
55
|
+
const adapter_registry_js_1 = require("./adapter-registry.js");
|
|
48
56
|
const tmp_root_js_1 = require("./core/tmp-root.js");
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the adapter driving a behavioral measurement.
|
|
59
|
+
*
|
|
60
|
+
* 🔴 THE ONE SANCTIONED STRING→ADAPTER CONVERSION. `opts.adapter` is the way in;
|
|
61
|
+
* the deprecated `harness` NAME is accepted for one release because
|
|
62
|
+
* `SelectionOptions` is public API (`vigiles/claude-code`), and it is resolved
|
|
63
|
+
* HERE, through the registry, rather than compared to a literal anywhere.
|
|
64
|
+
*/
|
|
65
|
+
function adapterFor(opts) {
|
|
66
|
+
return (opts.adapter ??
|
|
67
|
+
(opts.harness ? (0, adapter_registry_js_1.getAdapter)(opts.harness) : undefined) ??
|
|
68
|
+
adapter_registry_js_1.defaultAdapter);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The executing-tier wiring for one adapter: its live driver plus the CLI-presence
|
|
72
|
+
* gate. This is what `buildProbe(dir, harness)` used to switch on a NAME to build;
|
|
73
|
+
* both halves now come off the adapter, so adding a harness adds no branch here.
|
|
74
|
+
*
|
|
75
|
+
* ⚠️ `available` IS THE BINARY PROBE, NOT `liveDriver.access(env)`, and the
|
|
76
|
+
* difference is load-bearing. `access` answers "is a model reachable and on whose
|
|
77
|
+
* bill" — for Claude Code that is an env-only read by design (deciding whether to
|
|
78
|
+
* OFFER a measurement must not spend a token), which is NOT the same question as
|
|
79
|
+
* "is the CLI installed". Routing this gate through `access` would make the
|
|
80
|
+
* behavioral column go dark for anyone driving a logged-in `claude` from a plain
|
|
81
|
+
* shell with none of the env vars set, and light up for anyone with a key but no
|
|
82
|
+
* binary. The CLI-presence fact already has exactly one home — `available` on the
|
|
83
|
+
* MOCK-tier driver, which is the same binary and the same probe both tiers need
|
|
84
|
+
* (`claudeAvailable` / `codexDriver.available`, the two functions `buildProbe`
|
|
85
|
+
* itself called) — so it is read from there rather than copied onto a second port.
|
|
86
|
+
*/
|
|
87
|
+
async function probeFor(adapter) {
|
|
88
|
+
if (!adapter.harnessTesting)
|
|
89
|
+
return null;
|
|
90
|
+
const [live, test] = await Promise.all([
|
|
91
|
+
adapter.liveDriver(),
|
|
92
|
+
adapter.harnessTestDriver(),
|
|
93
|
+
]);
|
|
94
|
+
// Wrapped rather than handed over bare: an extracted method loses its `this`.
|
|
95
|
+
return { live, available: () => test.available() };
|
|
67
96
|
}
|
|
68
|
-
/**
|
|
69
|
-
|
|
70
|
-
|
|
97
|
+
/**
|
|
98
|
+
* The plugin manifest's `name` — the namespace a harness may prefix onto a skill
|
|
99
|
+
* id. Read through the LAYOUT's path and codec, never a `.claude-plugin` literal,
|
|
100
|
+
* so a TOML-manifest harness is read with its own parser.
|
|
101
|
+
*/
|
|
102
|
+
function manifestName(dir, layout) {
|
|
103
|
+
const p = (0, node_path_1.join)(dir, layout.manifestPath);
|
|
71
104
|
if (!(0, node_fs_1.existsSync)(p))
|
|
72
105
|
return null;
|
|
73
106
|
try {
|
|
74
|
-
|
|
107
|
+
const parsed = layout.settings.parse((0, node_fs_1.readFileSync)(p, "utf-8"));
|
|
108
|
+
return typeof parsed.name === "string" ? parsed.name : null;
|
|
75
109
|
}
|
|
76
110
|
catch {
|
|
77
111
|
return null;
|
|
@@ -115,15 +149,15 @@ async function probeSkill(ctx, name, ps) {
|
|
|
115
149
|
try {
|
|
116
150
|
const r = await (0, eval_js_1.measureTriggerRate)({
|
|
117
151
|
pluginDir: ctx.dir,
|
|
118
|
-
stubSkillBodies: ctx.
|
|
152
|
+
stubSkillBodies: ctx.live.installsStubs,
|
|
119
153
|
prompts: ps.prompts,
|
|
120
154
|
irrelevantPrompts: ps.irrelevant,
|
|
121
155
|
minPrompts: ctx.opts.minPrompts,
|
|
122
156
|
minDistance: ctx.opts.minDistance,
|
|
123
157
|
model: ctx.opts.model,
|
|
124
158
|
concurrency: ctx.opts.concurrency,
|
|
125
|
-
fired: ctx.
|
|
126
|
-
}, { evalDriver: ctx.
|
|
159
|
+
fired: ctx.live.firedFor(name, ctx.plugin),
|
|
160
|
+
}, { evalDriver: ctx.live.evalDriver });
|
|
127
161
|
return {
|
|
128
162
|
skill: name,
|
|
129
163
|
measured: true,
|
|
@@ -144,13 +178,19 @@ async function probeSkill(ctx, name, ps) {
|
|
|
144
178
|
}
|
|
145
179
|
}
|
|
146
180
|
/** The injectable core (for tests): probe every model-invocable skill that has prompts. */
|
|
147
|
-
async function probePluginTriggersWith(dir, promptSet,
|
|
148
|
-
const
|
|
181
|
+
async function probePluginTriggersWith(dir, promptSet, live, opts = {}) {
|
|
182
|
+
const layout = opts.layout ?? layout_js_1.claudeCodeLayout;
|
|
183
|
+
const ctx = {
|
|
184
|
+
dir,
|
|
185
|
+
opts,
|
|
186
|
+
live,
|
|
187
|
+
plugin: { name: manifestName(dir, layout) },
|
|
188
|
+
};
|
|
149
189
|
// Only model-invocable, describable skills can auto-trigger; user-invoked and
|
|
150
190
|
// description-less ones can't, so they're not behavioral candidates. Discover
|
|
151
191
|
// them with the resolved layout/dialect (default CC) so a Codex repo's skills
|
|
152
192
|
// aren't missed by the wrong layout.
|
|
153
|
-
const candidates = (0, scan_js_1.scanPlugin)(dir,
|
|
193
|
+
const candidates = (0, scan_js_1.scanPlugin)(dir, layout, opts.dialect ?? dialect_js_1.claudeCodeDialect).skills.filter((s) => !s.userInvoked && s.hasDescription);
|
|
154
194
|
const results = [];
|
|
155
195
|
for (const s of candidates) {
|
|
156
196
|
const ps = promptSet[s.name];
|
|
@@ -166,14 +206,14 @@ async function probePluginTriggersWith(dir, promptSet, probe, opts = {}) {
|
|
|
166
206
|
}
|
|
167
207
|
return {
|
|
168
208
|
available: true,
|
|
169
|
-
results: relabelTriggerArtifact(dir,
|
|
170
|
-
experimental:
|
|
209
|
+
results: relabelTriggerArtifact(dir, live, results),
|
|
210
|
+
experimental: live.evalDriver.experimental,
|
|
171
211
|
};
|
|
172
212
|
}
|
|
173
213
|
/** Relabel an all-zero-recall stubbed run on a hooked plugin as unmeasured (Layer 1). */
|
|
174
|
-
function relabelTriggerArtifact(dir,
|
|
214
|
+
function relabelTriggerArtifact(dir, live, results) {
|
|
175
215
|
const recalls = results.filter((r) => r.measured).map((r) => r.recall ?? 0);
|
|
176
|
-
if (!isStubbedHookArtifact(dir,
|
|
216
|
+
if (!isStubbedHookArtifact(dir, live.installsStubs, recalls))
|
|
177
217
|
return [...results];
|
|
178
218
|
return results.map((r) => r.measured && (r.recall ?? 0) === 0
|
|
179
219
|
? { skill: r.skill, measured: false, note: HOOK_PRIMED_NOTE }
|
|
@@ -185,10 +225,10 @@ function relabelTriggerArtifact(dir, probe, results) {
|
|
|
185
225
|
* `available: false` otherwise.
|
|
186
226
|
*/
|
|
187
227
|
async function probePluginTriggers(dir, promptSet, opts = {}) {
|
|
188
|
-
const probe =
|
|
189
|
-
if (!probe
|
|
228
|
+
const probe = await probeFor(adapterFor(opts));
|
|
229
|
+
if (!probe?.available())
|
|
190
230
|
return { available: false, results: [] };
|
|
191
|
-
return probePluginTriggersWith(dir, promptSet, probe, opts);
|
|
231
|
+
return probePluginTriggersWith(dir, promptSet, probe.live, opts);
|
|
192
232
|
}
|
|
193
233
|
const pct = (x) => `${(x * 100).toFixed(0)}%`;
|
|
194
234
|
/** Format the behavioral column as a scan-report section. */
|
|
@@ -307,9 +347,17 @@ function selectionJobs(candidates, promptSet, trials) {
|
|
|
307
347
|
return ps.prompts.flatMap((prompt) => Array.from({ length: trials }, () => ({ intended: c.name, prompt })));
|
|
308
348
|
});
|
|
309
349
|
}
|
|
310
|
-
/**
|
|
350
|
+
/**
|
|
351
|
+
* The injectable core (for tests): drive the matrix via a fake/real driver.
|
|
352
|
+
*
|
|
353
|
+
* 🔴 IT TAKES AN {@link EventFiringDriver}, NOT ANY LIVE DRIVER, AND THAT IS THE
|
|
354
|
+
* RATCHET. The matrix asks WHICH of the plugin's skills fired on each prompt; a
|
|
355
|
+
* harness that only INFERS firing cannot answer that, and the old guard was a
|
|
356
|
+
* name check in the wrapper below — invisible to anyone calling this core
|
|
357
|
+
* directly. Now an inferred driver is a compile error at every call site.
|
|
358
|
+
*/
|
|
311
359
|
async function measurePluginSelectionWith(dir, promptSet, probe, opts = {}) {
|
|
312
|
-
const candidates = (0, scan_js_1.scanPlugin)(dir).skills.filter((s) => !s.userInvoked && s.hasDescription);
|
|
360
|
+
const candidates = (0, scan_js_1.scanPlugin)(dir, opts.layout ?? layout_js_1.claudeCodeLayout, opts.dialect ?? dialect_js_1.claudeCodeDialect).skills.filter((s) => !s.userInvoked && s.hasDescription);
|
|
313
361
|
const skills = candidates.map((c) => c.name);
|
|
314
362
|
if (skills.length < 2) {
|
|
315
363
|
return {
|
|
@@ -328,7 +376,7 @@ async function measurePluginSelectionWith(dir, promptSet, probe, opts = {}) {
|
|
|
328
376
|
// Selection is decided at the frontmatter (the selector picks BEFORE the body
|
|
329
377
|
// loads), so stub each body to a no-op: the run stops AT selection instead of
|
|
330
378
|
// executing the whole workflow — the same affordability trick trigger-rate uses.
|
|
331
|
-
const pluginDir = probe.
|
|
379
|
+
const pluginDir = probe.installsStubs ? (0, eval_js_1.stubbedPluginDir)(dir) : dir;
|
|
332
380
|
try {
|
|
333
381
|
const d = probe.evalDriver;
|
|
334
382
|
const outcomes = await (0, eval_js_1.runPool)(jobs, Math.max(1, opts.concurrency ?? 1), (job) => (0, eval_js_1.runSkillSelectionTrial)({
|
|
@@ -356,38 +404,50 @@ async function measurePluginSelectionWith(dir, promptSet, probe, opts = {}) {
|
|
|
356
404
|
// dropped-hook artifact — flag it instead of presenting a 0%-collision result
|
|
357
405
|
// computed from a plugin that never fired.
|
|
358
406
|
const recalls = report.perSkill.filter((s) => s.n > 0).map((s) => s.recall);
|
|
359
|
-
return isStubbedHookArtifact(dir, probe.
|
|
407
|
+
return isStubbedHookArtifact(dir, probe.installsStubs, recalls)
|
|
360
408
|
? { ...report, note: HOOK_PRIMED_NOTE }
|
|
361
409
|
: report;
|
|
362
410
|
}
|
|
363
411
|
finally {
|
|
364
|
-
if (probe.
|
|
412
|
+
if (probe.installsStubs)
|
|
365
413
|
(0, node_fs_1.rmSync)(pluginDir, { recursive: true, force: true });
|
|
366
414
|
}
|
|
367
415
|
}
|
|
416
|
+
/**
|
|
417
|
+
* Why the matrix cannot run on this harness — the DRIVER's own reason, carried
|
|
418
|
+
* verbatim, rather than a sentence written at the call site next to a name check.
|
|
419
|
+
*/
|
|
420
|
+
function selectionUnavailableNote(name, live) {
|
|
421
|
+
if (!live)
|
|
422
|
+
return `selection-collision needs an executing-tier driver, which ${name} does not have`;
|
|
423
|
+
const why = live.firing.kind === "inferred" ? live.firing.caveat : "no firing event";
|
|
424
|
+
return `selection-collision needs a discrete skill-selection event, which ${name} does not emit (${why})`;
|
|
425
|
+
}
|
|
368
426
|
/**
|
|
369
427
|
* Measure a plugin's cross-skill selection-collision matrix against the real
|
|
370
428
|
* harness (Claude Code only — Codex has no skill-selection event). Needs the
|
|
371
429
|
* `claude` CLI + model auth; degrades to `available: false` otherwise.
|
|
372
430
|
*/
|
|
373
431
|
async function measurePluginSelection(dir, promptSet, opts = {}) {
|
|
374
|
-
const
|
|
375
|
-
|
|
432
|
+
const adapter = adapterFor(opts);
|
|
433
|
+
const probe = await probeFor(adapter);
|
|
434
|
+
// The n/a reason now comes from the DRIVER's own firing signal and carries the
|
|
435
|
+
// driver's own caveat, instead of being a name check with the reason inlined.
|
|
436
|
+
if (!probe || !(0, live_driver_js_1.isEventFiring)(probe.live)) {
|
|
376
437
|
return {
|
|
377
438
|
...emptySelection([]),
|
|
378
439
|
available: false,
|
|
379
|
-
note:
|
|
440
|
+
note: selectionUnavailableNote(adapter.name, probe?.live),
|
|
380
441
|
};
|
|
381
442
|
}
|
|
382
|
-
const probe = buildProbe(dir, harness);
|
|
383
443
|
if (!probe.available()) {
|
|
384
444
|
return {
|
|
385
445
|
...emptySelection([]),
|
|
386
446
|
available: false,
|
|
387
|
-
note:
|
|
447
|
+
note: `needs the ${adapter.name} CLI + model auth`,
|
|
388
448
|
};
|
|
389
449
|
}
|
|
390
|
-
return measurePluginSelectionWith(dir, promptSet, probe, opts);
|
|
450
|
+
return measurePluginSelectionWith(dir, promptSet, probe.live, opts);
|
|
391
451
|
}
|
|
392
452
|
/** Format the selection-collision matrix as a scan-report section. */
|
|
393
453
|
function formatSelectionReport(r) {
|
|
@@ -437,7 +497,7 @@ async function measureSelectionMatrixWith(dir, probe, opts = {}) {
|
|
|
437
497
|
* model-invocable skills' descriptions (the zero-setup path). */
|
|
438
498
|
function resolveSelectionPrompts(dir, opts) {
|
|
439
499
|
return (opts.prompts ??
|
|
440
|
-
(0, audit_prompts_js_1.autoTriggerPrompts)((0, scan_js_1.scanPlugin)(dir)
|
|
500
|
+
(0, audit_prompts_js_1.autoTriggerPrompts)((0, scan_js_1.scanPlugin)(dir, opts.layout ?? layout_js_1.claudeCodeLayout, opts.dialect ?? dialect_js_1.claudeCodeDialect)
|
|
441
501
|
.skills.filter((s) => !s.userInvoked && s.hasDescription)
|
|
442
502
|
.map((s) => ({ name: s.name, description: s.description ?? "" }))));
|
|
443
503
|
}
|
|
@@ -637,29 +697,33 @@ function judgeGateReal(a) {
|
|
|
637
697
|
* hold vs cave. Claude Code only; degrades to `available: false` without the CLI/auth.
|
|
638
698
|
*/
|
|
639
699
|
async function measureGateAdversarial(dir, opts = {}) {
|
|
640
|
-
const
|
|
641
|
-
|
|
700
|
+
const adapter = adapterFor(opts);
|
|
701
|
+
const probe = await probeFor(adapter);
|
|
702
|
+
// Same gate as the collision matrix and for the same reason: the attack is only
|
|
703
|
+
// meaningful once the gate skill has actually been SELECTED, which an inferred
|
|
704
|
+
// firing signal cannot establish. Read off the driver, not off a name.
|
|
705
|
+
if (!probe || !(0, live_driver_js_1.isEventFiring)(probe.live)) {
|
|
642
706
|
return {
|
|
643
707
|
available: false,
|
|
644
708
|
results: [],
|
|
645
|
-
note: `adversarial-gate
|
|
709
|
+
note: `adversarial-gate needs a discrete skill-selection event, which ${adapter.name} does not emit`,
|
|
646
710
|
};
|
|
647
711
|
}
|
|
648
|
-
const probe = buildProbe(dir, harness);
|
|
649
712
|
if (!probe.available()) {
|
|
650
713
|
return {
|
|
651
714
|
available: false,
|
|
652
715
|
results: [],
|
|
653
|
-
note:
|
|
716
|
+
note: `needs the ${adapter.name} CLI + model auth`,
|
|
654
717
|
};
|
|
655
718
|
}
|
|
656
|
-
const skills = (0, scan_js_1.scanPlugin)(dir, opts.layout, opts.dialect).skills;
|
|
719
|
+
const skills = (0, scan_js_1.scanPlugin)(dir, opts.layout ?? layout_js_1.claudeCodeLayout, opts.dialect ?? dialect_js_1.claudeCodeDialect).skills;
|
|
657
720
|
const gateNames = new Set(detectGateSkills(skills));
|
|
658
721
|
const gates = skills
|
|
659
722
|
.filter((s) => gateNames.has(s.name))
|
|
660
723
|
.map((s) => ({ name: s.name, description: s.description ?? "" }));
|
|
661
724
|
const deps = {
|
|
662
|
-
|
|
725
|
+
// The driving adapter's own eval transport, not a hard-wired Claude one.
|
|
726
|
+
driver: probe.live.evalDriver,
|
|
663
727
|
judge: judgeGateReal,
|
|
664
728
|
derive: deriveAttackReal,
|
|
665
729
|
};
|
package/dist/scan-core.js
CHANGED
|
@@ -142,18 +142,35 @@ function escapeRe(s) {
|
|
|
142
142
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
143
143
|
}
|
|
144
144
|
function makeClassifier(layout) {
|
|
145
|
-
// An
|
|
145
|
+
// An ABSENT dir means "this harness has no such surface" → never matches.
|
|
146
|
+
// (`""` used to mean the same thing; a `Partial<Record<SurfaceKind, string>>`
|
|
147
|
+
// has one spelling for it, so this takes `string | undefined` and the empty
|
|
148
|
+
// string is no longer a value any layout can supply.)
|
|
146
149
|
const at = (dir) => dir ? `(?:^|/)${escapeRe(dir)}/` : null;
|
|
147
|
-
const
|
|
148
|
-
const
|
|
149
|
-
const
|
|
150
|
-
const
|
|
150
|
+
const skillDir = layout.surfaces.skill;
|
|
151
|
+
const agentDir = layout.surfaces.agent;
|
|
152
|
+
const commandDir = layout.surfaces.command;
|
|
153
|
+
const skill = at(skillDir);
|
|
154
|
+
const agent = at(agentDir);
|
|
155
|
+
const command = at(commandDir);
|
|
151
156
|
const skillRe = skill ? new RegExp(`${skill}[^/]+/SKILL\\.md$`) : null;
|
|
152
157
|
const agentRe = agent ? new RegExp(`${agent}${layout_js_1.AGENT_FILE_LEAF_RE}$`) : null;
|
|
153
158
|
const commandRe = command ? new RegExp(`${command}.+\\.md$`) : null;
|
|
154
|
-
//
|
|
155
|
-
//
|
|
156
|
-
|
|
159
|
+
// 🔴 RECURSIVE, AND IT USED TO BE FLAT (`[^/]+\\.md$`) WHILE THE LOADER WALKED
|
|
160
|
+
// THE DIRECTORY RECURSIVELY. A rule in a subdirectory was therefore READ and
|
|
161
|
+
// never CLASSIFIED: it never became a rule entry, so it was never
|
|
162
|
+
// frontmatter-checked, never counted and never weighed — zernie/vigiles#262
|
|
163
|
+
// §3. The depth rule is quoted from `RULE_FILE_LEAF_RE` rather than spelled
|
|
164
|
+
// here, because the instruction chain has to ask the same question and two
|
|
165
|
+
// readers that each spell it disagree silently (the agent constant beside it
|
|
166
|
+
// records the measurement where that happened).
|
|
167
|
+
// 🔴 THE PREFIX COMES FROM `ruleFileRe` NOW, not from `at()`. `at()` is
|
|
168
|
+
// deliberately loose — `(?:^|/)skills/` has to match a published plugin's
|
|
169
|
+
// root AND `.claude/skills` — and rules have exactly ONE home, so the same
|
|
170
|
+
// looseness let `.github/rules/policy.md` be classified as a Claude Code
|
|
171
|
+
// rule here just as it was weighed as one by the chain. Sharing the leaf and
|
|
172
|
+
// not the prefix is what let the two readers named above disagree.
|
|
173
|
+
const ruleRe = (0, layout_js_1.ruleFileRe)(layout);
|
|
157
174
|
// A subagent lives under the plugin's `agents/` dir AT ANY DEPTH (the harness
|
|
158
175
|
// reads it recursively — see AGENT_FILE_LEAF_RE for the vendor's wording and
|
|
159
176
|
// the measurement), but never under ANOTHER surface dir. Two real-world
|
|
@@ -167,13 +184,13 @@ function makeClassifier(layout) {
|
|
|
167
184
|
// (adapter-agnostic), and both patterns already tolerate depth on BOTH sides of
|
|
168
185
|
// the `agents/` segment, so the recursion above does not leak through them.
|
|
169
186
|
// See scan.test.ts for the regressions.
|
|
170
|
-
const nestedUnder =
|
|
171
|
-
|
|
172
|
-
`${escapeRe(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const nestedAgentRe =
|
|
187
|
+
const nestedUnder = agentDir
|
|
188
|
+
? [
|
|
189
|
+
skillDir && `${escapeRe(skillDir)}/.+/${escapeRe(agentDir)}/`,
|
|
190
|
+
commandDir && `${escapeRe(commandDir)}/(?:.+/)?${escapeRe(agentDir)}/`,
|
|
191
|
+
].filter((x) => Boolean(x))
|
|
192
|
+
: [];
|
|
193
|
+
const nestedAgentRe = agentDir && nestedUnder.length
|
|
177
194
|
? new RegExp(`(?:^|/)(?:${nestedUnder.join("|")})`)
|
|
178
195
|
: null;
|
|
179
196
|
const isAgent = (f) => (agentRe?.test(f) ?? false) &&
|
|
@@ -188,8 +205,8 @@ function makeClassifier(layout) {
|
|
|
188
205
|
// `.md` under `agents/` recursively — so this file is a subagent, and is not a
|
|
189
206
|
// skill. Excluding it here (rather than excluding it from agents) is what keeps
|
|
190
207
|
// the two classifiers disjoint AND agreeing with the harness.
|
|
191
|
-
const nestedSkillRe =
|
|
192
|
-
? new RegExp(`(?:^|/)${escapeRe(
|
|
208
|
+
const nestedSkillRe = skillDir && agentDir
|
|
209
|
+
? new RegExp(`(?:^|/)${escapeRe(agentDir)}/(?:.+/)?${escapeRe(skillDir)}/`)
|
|
193
210
|
: null;
|
|
194
211
|
const isSkill = (f) => (skillRe?.test(f) ?? false) && !(nestedSkillRe?.test(f) ?? false);
|
|
195
212
|
return {
|
|
@@ -197,7 +214,9 @@ function makeClassifier(layout) {
|
|
|
197
214
|
isAgent,
|
|
198
215
|
isCommand: (f) => commandRe?.test(f) ?? false,
|
|
199
216
|
isRule: (f) => ruleRe?.test(f) ?? false,
|
|
200
|
-
agentName: (f) => isAgent(f)
|
|
217
|
+
agentName: (f) => isAgent(f) && agentDir !== undefined
|
|
218
|
+
? (0, layout_js_1.agentSurfaceName)(f, agentDir)
|
|
219
|
+
: null,
|
|
201
220
|
};
|
|
202
221
|
}
|
|
203
222
|
/**
|
package/dist/scan-files.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type PluginLayout } from "./core/layout.js";
|
|
2
2
|
import type { HarnessDialect } from "./core/dialect.js";
|
|
3
3
|
import type { LoadedPlugin } from "./plugin-loader.js";
|
|
4
4
|
import type { ScanReport } from "./scan.js";
|
package/dist/scan-files.js
CHANGED
|
@@ -39,10 +39,11 @@ exports.scanFiles = scanFiles;
|
|
|
39
39
|
* is excluded. See research/report-view-and-browser-demo.md.
|
|
40
40
|
*/
|
|
41
41
|
const posix_path_js_1 = require("./posix-path.js");
|
|
42
|
-
const toml_1 = require("@iarna/toml");
|
|
43
42
|
const layout_js_1 = require("./adapters/claude-code/layout.js");
|
|
44
43
|
const dialect_js_1 = require("./adapters/claude-code/dialect.js");
|
|
44
|
+
const layout_js_2 = require("./core/layout.js");
|
|
45
45
|
const instruction_weight_js_1 = require("./core/instruction-weight.js");
|
|
46
|
+
const instruction_chain_js_1 = require("./core/instruction-chain.js");
|
|
46
47
|
const hook_normalize_js_1 = require("./core/hook-normalize.js");
|
|
47
48
|
const hook_events_js_1 = require("./core/hook-events.js");
|
|
48
49
|
const mcp_config_js_1 = require("./core/mcp-config.js");
|
|
@@ -159,31 +160,26 @@ function safeParseJson(text) {
|
|
|
159
160
|
return null;
|
|
160
161
|
}
|
|
161
162
|
}
|
|
162
|
-
/** Parse the layout's manifest
|
|
163
|
+
/** Parse the layout's manifest from the map through its CODEC, or null. */
|
|
163
164
|
function readManifest(files, layout) {
|
|
164
165
|
const text = files[layout.manifestPath];
|
|
165
166
|
if (text === undefined)
|
|
166
167
|
return null;
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
168
|
+
try {
|
|
169
|
+
return layout.settings.parse(text);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return null;
|
|
174
173
|
}
|
|
175
|
-
return safeParseJson(text);
|
|
176
174
|
}
|
|
177
175
|
/** The `.hooks` field of a JSON file in the map, or undefined. */
|
|
178
176
|
function readHooksJsonFile(files, rel) {
|
|
179
177
|
return safeParseJson(files[rel])?.hooks;
|
|
180
178
|
}
|
|
181
|
-
/** The `.hooks` of a settings file in the map,
|
|
182
|
-
function readSettingsHooks(text,
|
|
183
|
-
if (format === "json")
|
|
184
|
-
return safeParseJson(text)?.hooks;
|
|
179
|
+
/** The `.hooks` of a settings file in the map, through the layout's codec. */
|
|
180
|
+
function readSettingsHooks(text, codec) {
|
|
185
181
|
try {
|
|
186
|
-
return
|
|
182
|
+
return codec.parse(text).hooks;
|
|
187
183
|
}
|
|
188
184
|
catch {
|
|
189
185
|
return undefined;
|
|
@@ -199,12 +195,15 @@ function readHooks(files, layout) {
|
|
|
199
195
|
if (m.hooks !== undefined)
|
|
200
196
|
return m.hooks;
|
|
201
197
|
}
|
|
202
|
-
|
|
198
|
+
// Optional: a harness whose hooks are in-process code modules has no
|
|
199
|
+
// standalone hooks FILE. Mirrors the disk loader.
|
|
200
|
+
if (layout.hooksConventionPath !== undefined &&
|
|
201
|
+
hasFile(files, layout.hooksConventionPath)) {
|
|
203
202
|
return readHooksJsonFile(files, layout.hooksConventionPath);
|
|
204
203
|
}
|
|
205
204
|
const settings = files[layout.settingsPath];
|
|
206
205
|
if (settings !== undefined) {
|
|
207
|
-
return readSettingsHooks(settings, layout.
|
|
206
|
+
return readSettingsHooks(settings, layout.settings);
|
|
208
207
|
}
|
|
209
208
|
return undefined;
|
|
210
209
|
}
|
|
@@ -225,7 +224,7 @@ function hasMcp(files, layout) {
|
|
|
225
224
|
*/
|
|
226
225
|
function surfaceHasLoadable(layout, surface, tree) {
|
|
227
226
|
const keys = Object.keys(tree);
|
|
228
|
-
return surface === layout.
|
|
227
|
+
return surface === layout.surfaces.skill
|
|
229
228
|
? keys.some((k) => (0, posix_path_js_1.basename)(k) === "SKILL.md")
|
|
230
229
|
: keys.some((k) => k.endsWith(".md"));
|
|
231
230
|
}
|
|
@@ -236,13 +235,13 @@ function materializeSurfaces(files, layout, acc, repoName) {
|
|
|
236
235
|
const harnessCounts = {};
|
|
237
236
|
const scopeTrees = (base) => {
|
|
238
237
|
const trees = new Map();
|
|
239
|
-
for (const surface of
|
|
238
|
+
for (const surface of (0, layout_js_2.surfaceDirs)(layout)) {
|
|
240
239
|
const dirRel = base === "" ? surface : `${base}/${surface}`;
|
|
241
240
|
trees.set(surface, isDirRel(files, dirRel) ? readTreeUnder(files, dirRel, dirRel) : {});
|
|
242
241
|
}
|
|
243
242
|
return trees;
|
|
244
243
|
};
|
|
245
|
-
const hasLoadable = (trees) =>
|
|
244
|
+
const hasLoadable = (trees) => (0, layout_js_2.surfaceDirs)(layout).some((s) => surfaceHasLoadable(layout, s, trees.get(s) ?? {}));
|
|
246
245
|
const add = (key, content, onDisk) => {
|
|
247
246
|
out[key] = content;
|
|
248
247
|
sources[key] = onDisk;
|
|
@@ -253,7 +252,7 @@ function materializeSurfaces(files, layout, acc, repoName) {
|
|
|
253
252
|
: new Map();
|
|
254
253
|
/** Mirror of the disk loader's `materializeScope`. */
|
|
255
254
|
const materializeScope = (scope, trees) => {
|
|
256
|
-
for (const surface of
|
|
255
|
+
for (const surface of (0, layout_js_2.surfaceDirs)(layout)) {
|
|
257
256
|
const tree = trees.get(surface) ?? {};
|
|
258
257
|
const dirRel = scope.base === "" ? surface : `${scope.base}/${surface}`;
|
|
259
258
|
for (const [rel, content] of Object.entries(tree))
|
|
@@ -265,24 +264,29 @@ function materializeSurfaces(files, layout, acc, repoName) {
|
|
|
265
264
|
}
|
|
266
265
|
};
|
|
267
266
|
const source = (0, surface_scopes_js_1.surfaceSource)(layout, {
|
|
268
|
-
hasRootSkillFile:
|
|
267
|
+
hasRootSkillFile: layout.surfaces.skill !== undefined && hasFile(files, "SKILL.md"),
|
|
269
268
|
// Disk mirrors the CLI: a nameless root SKILL.md takes the audited dir's
|
|
270
269
|
// basename. In-browser there's no real dir, so use the repo name when the
|
|
271
270
|
// caller (runAudit) supplies it, else the synthetic BROWSER_ROOT basename.
|
|
272
271
|
skillName: repoName ?? (0, posix_path_js_1.basename)(exports.BROWSER_ROOT),
|
|
273
272
|
rootHasLoadable: hasLoadable(rootTrees),
|
|
274
273
|
isPluginShaped: hasFile(files, layout.manifestPath) ||
|
|
275
|
-
|
|
274
|
+
(layout.hooksConventionPath !== undefined &&
|
|
275
|
+
hasFile(files, layout.hooksConventionPath)),
|
|
276
276
|
userHasLoadable: hasLoadable(userTrees),
|
|
277
277
|
});
|
|
278
278
|
switch (source.kind) {
|
|
279
279
|
case "single-skill": {
|
|
280
280
|
const tree = readTreeUnder(files, "", "");
|
|
281
|
+
// Mirrors the disk loader: the skill dir is carried on the variant, so
|
|
282
|
+
// there is no `undefined` case to guard and no dead branch to keep in
|
|
283
|
+
// sync across the two engines.
|
|
284
|
+
const { skillDir } = source;
|
|
281
285
|
for (const [rel, content] of Object.entries(tree)) {
|
|
282
|
-
add((0, posix_path_js_1.join)(layout
|
|
286
|
+
add((0, posix_path_js_1.join)((0, layout_js_2.materializePrefix)(layout), skillDir, source.skillName, rel), content, (0, posix_path_js_1.join)(exports.BROWSER_ROOT, rel));
|
|
283
287
|
}
|
|
284
|
-
counts[
|
|
285
|
-
harnessCounts[
|
|
288
|
+
counts[skillDir] = Object.keys(tree).length;
|
|
289
|
+
harnessCounts[skillDir] = counts[skillDir];
|
|
286
290
|
return { counts, harnessCounts, scopes: [] };
|
|
287
291
|
}
|
|
288
292
|
case "scopes": {
|
|
@@ -299,7 +303,7 @@ function materializeSurfaces(files, layout, acc, repoName) {
|
|
|
299
303
|
// Extensions + BOTH token boundaries live in core/source-refs.ts, so this and
|
|
300
304
|
// its disk twin (plugin-loader.ts) cannot disagree and neither can omit one.
|
|
301
305
|
function intraRefRe(layout) {
|
|
302
|
-
return (0, source_refs_js_1.intraRefPattern)(
|
|
306
|
+
return (0, source_refs_js_1.intraRefPattern)((0, layout_js_2.executableSourceDirs)(layout));
|
|
303
307
|
}
|
|
304
308
|
const NON_PLUGIN_VARS = new Set([
|
|
305
309
|
"CLAUDE_PROJECT_DIR",
|
|
@@ -326,7 +330,7 @@ const DOC_SOURCE_RE = /\.(?:md|markdown|mdx|txt|rst)$/i;
|
|
|
326
330
|
/** The plugin's executable (non-prose) source-file CONTENTS under the surface dirs. */
|
|
327
331
|
function executableContents(files, layout) {
|
|
328
332
|
const out = [];
|
|
329
|
-
for (const surface of
|
|
333
|
+
for (const surface of (0, layout_js_2.executableSourceDirs)(layout)) {
|
|
330
334
|
if (!isDirRel(files, surface))
|
|
331
335
|
continue;
|
|
332
336
|
for (const [k, content] of Object.entries(files)) {
|
|
@@ -491,6 +495,14 @@ function scanFiles(files, layout = layout_js_1.claudeCodeLayout, dialect = diale
|
|
|
491
495
|
hasSpec: hasFile(files, `${lay.instructionFile}.spec.ts`),
|
|
492
496
|
}
|
|
493
497
|
: null;
|
|
498
|
+
// The BOUNDED candidate set over the map, then the same one-level import pass
|
|
499
|
+
// the disk walk runs — `resolveImports` lives in the core precisely so these
|
|
500
|
+
// two cannot drift. An import the fetcher never fetched simply stays unread,
|
|
501
|
+
// and the weight says so (`unreadImports`) instead of quietly omitting it.
|
|
502
|
+
const instructionFiles = (0, instruction_chain_js_1.resolveImports)(lay, Object.fromEntries((0, instruction_chain_js_1.instructionCandidatePaths)(Object.keys(files), lay).map((p) => [
|
|
503
|
+
p,
|
|
504
|
+
files[p] ?? "",
|
|
505
|
+
])), (p) => files[p]);
|
|
494
506
|
const mcpServers = collectMcpServers(files, lay);
|
|
495
507
|
const declaredServers = Object.keys(mcpServers);
|
|
496
508
|
// The repo's own test signal — same shared detector as the disk path, over the
|
|
@@ -505,7 +517,7 @@ function scanFiles(files, layout = layout_js_1.claudeCodeLayout, dialect = diale
|
|
|
505
517
|
});
|
|
506
518
|
const skills = (0, scan_core_js_1.scanSkills)(loaded.files, cls, {
|
|
507
519
|
root: exports.BROWSER_ROOT,
|
|
508
|
-
materializeRoot: lay
|
|
520
|
+
materializeRoot: (0, layout_js_2.materializePrefix)(lay),
|
|
509
521
|
dialect,
|
|
510
522
|
sources: loaded.sources,
|
|
511
523
|
existsSync: exists,
|
|
@@ -560,7 +572,10 @@ function scanFiles(files, layout = layout_js_1.claudeCodeLayout, dialect = diale
|
|
|
560
572
|
// The browser twin has the WHOLE fetched key set in hand, so discovery needs
|
|
561
573
|
// no walk here — the pure classifier re-applies the same bounded-root rule.
|
|
562
574
|
unclaimedSurfaces: (0, surface_discovery_js_1.unclaimedSurfaceFindings)(Object.keys(files), layout_registry_js_1.REGISTERED_LAYOUTS),
|
|
563
|
-
pluginLayoutIssues: (0, plugin_dir_layout_js_1.pluginDirLayoutIssues)((0, posix_path_js_1.join)(exports.BROWSER_ROOT, (0, posix_path_js_1.dirname)(lay.manifestPath)),
|
|
575
|
+
pluginLayoutIssues: (0, plugin_dir_layout_js_1.pluginDirLayoutIssues)((0, posix_path_js_1.join)(exports.BROWSER_ROOT, (0, posix_path_js_1.dirname)(lay.manifestPath)),
|
|
576
|
+
// See the note in scan.ts: the scripts dir is NAMED by the layout, not
|
|
577
|
+
// derived from the registration file's first segment.
|
|
578
|
+
(0, layout_js_2.executableSourceDirs)(lay), { existsSync: exists, isDirectory: mapIsDirectory(files) }),
|
|
564
579
|
delegationTrifecta: (0, scan_core_js_1.collectDelegationTrifecta)(agents, dialect),
|
|
565
580
|
hookBlockFindings: (0, event_capability_js_1.blockIneffectiveEventsOf)(dialect).length > 0
|
|
566
581
|
? (0, hook_block_ineffective_js_1.hookBlockIssues)((0, scan_core_js_1.collectHookBlockEntries)(hookRegs, exports.BROWSER_ROOT, lay.pluginRootToken, exists), {
|
|
@@ -578,10 +593,15 @@ function scanFiles(files, layout = layout_js_1.claudeCodeLayout, dialect = diale
|
|
|
578
593
|
...loaded.warnings,
|
|
579
594
|
...(0, merge_conflict_js_1.conflictedHarnessConfigs)((f) => files[f]).map(merge_conflict_js_1.mergeConflictWarning),
|
|
580
595
|
],
|
|
581
|
-
//
|
|
582
|
-
//
|
|
596
|
+
// 🔴 THE TWIN APPLIES THE SAME BOUND AS THE DISK WALK, and until now it
|
|
597
|
+
// applied none. The comment here used to read "the file map IS the repo, so
|
|
598
|
+
// the glob filter does the whole job" — which was true of a glob and is not
|
|
599
|
+
// true of a bound: `boundedInstructionFiles` enumerates the repo root plus
|
|
600
|
+
// depth-1 dot-directories and nothing else, so handing the whole fetched map
|
|
601
|
+
// over would make the browser weigh files the CLI never opens. Same filter,
|
|
602
|
+
// same import pass, same chain; only the storage differs.
|
|
583
603
|
instructionWeight: dialect.instructionBudget
|
|
584
|
-
? (0, instruction_weight_js_1.weighInstructions)(
|
|
604
|
+
? (0, instruction_weight_js_1.weighInstructions)(lay.instructionChain(instructionFiles), instructionFiles, dialect.instructionBudget)
|
|
585
605
|
: null,
|
|
586
606
|
untested: coverage.untested.length,
|
|
587
607
|
untestedHarness: coverage.harness.untested.length,
|