vigiles 33.3.0 → 35.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/action.yml +45 -8
- package/dist/adapters/codex/driver.js +2 -1
- package/dist/adapters/codex/mock-model.d.ts +3 -2
- package/dist/adapters/codex/mock-model.js +15 -3
- package/dist/cli-flag-check.js +1 -0
- package/dist/cli-main.js +253 -56
- package/dist/core/config-schema.d.ts +53 -34
- package/dist/core/config-schema.js +42 -0
- package/dist/core/harness-driver.d.ts +5 -2
- package/dist/core/presets.d.ts +44 -0
- package/dist/core/presets.js +44 -0
- package/dist/core/script-overrun.d.ts +32 -0
- package/dist/core/script-overrun.js +42 -0
- package/dist/core/validate.js +1 -1
- package/dist/doc-test-script-coverage.d.ts +1 -1
- package/dist/doc-test-script-coverage.js +1 -1
- package/dist/eval-lock.d.ts +5 -6
- package/dist/eval-lock.js +5 -6
- package/dist/harness-test.d.ts +35 -1
- package/dist/harness-test.js +100 -10
- package/dist/mock-model.d.ts +4 -1
- package/dist/mock-model.js +42 -11
- package/dist/setup-plan.d.ts +93 -25
- package/dist/setup-plan.js +133 -67
- package/dist/vigilesrc.schema.json +6 -0
- package/package.json +1 -2
package/dist/setup-plan.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* on a prompt. See docs/agent-setup.md.
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.SHIPPED_SKILLS = exports.NUDGE_RULES = exports.WORKFLOW_RULES =
|
|
13
|
+
exports.SHIPPED_SKILLS = exports.NUDGE_RULES = exports.WORKFLOW_RULES = void 0;
|
|
14
14
|
exports.parseSetupArgs = parseSetupArgs;
|
|
15
15
|
exports.defaultPlan = defaultPlan;
|
|
16
16
|
exports.mergeProjectConfig = mergeProjectConfig;
|
|
@@ -21,7 +21,12 @@ exports.planPluginInstall = planPluginInstall;
|
|
|
21
21
|
exports.shouldRunGlobalInstall = shouldRunGlobalInstall;
|
|
22
22
|
exports.codexPluginHooks = codexPluginHooks;
|
|
23
23
|
exports.applyCodexPluginHooks = applyCodexPluginHooks;
|
|
24
|
+
exports.adoptionState = adoptionState;
|
|
25
|
+
exports.rerunScope = rerunScope;
|
|
26
|
+
exports.missingVigilesDevDep = missingVigilesDevDep;
|
|
27
|
+
exports.fullSetupFollowUps = fullSetupFollowUps;
|
|
24
28
|
exports.resolvePlan = resolvePlan;
|
|
29
|
+
const presets_js_1 = require("./core/presets.js");
|
|
25
30
|
function flagValue(args, prefix) {
|
|
26
31
|
return args.find((a) => a.startsWith(prefix))?.slice(prefix.length);
|
|
27
32
|
}
|
|
@@ -48,6 +53,7 @@ function parseSetupArgs(args) {
|
|
|
48
53
|
gha: args.includes("--no-gha") ? false : undefined,
|
|
49
54
|
plugin: args.includes("--no-plugin") ? false : undefined,
|
|
50
55
|
ciOnly: args.includes("--ci-only"),
|
|
56
|
+
full: args.includes("--full"),
|
|
51
57
|
};
|
|
52
58
|
}
|
|
53
59
|
/** The non-interactive defaults: both pillars, CI, and the plugin. `scaffoldSpecs`
|
|
@@ -66,39 +72,6 @@ function defaultPlan(strict = false) {
|
|
|
66
72
|
force: false,
|
|
67
73
|
};
|
|
68
74
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Pure config-merge for what `vigiles init` writes to `.vigilesrc.json`: record
|
|
71
|
-
* the `harness` if absent, add strict rule severities if `--strict`, NEVER
|
|
72
|
-
* clobber an existing key. Returns the merged config, or `null` when nothing
|
|
73
|
-
* changed (so the IO layer skips the write). The IO (read/parse/write + the
|
|
74
|
-
* malformed-file guard) stays in cli.ts.
|
|
75
|
-
*/
|
|
76
|
-
/**
|
|
77
|
-
* The structural rules `init` gates BY DEFAULT (severity `error`, so a broken
|
|
78
|
-
* surface fails `vigiles lint`). Every one is HIGH-PRECISION / FP-safe — it fires
|
|
79
|
-
* only on a genuine defect (a never-available/typo'd tool, a subagent missing
|
|
80
|
-
* `name`/`description`, a typo'd hook event, a dead hook script, a broken MCP
|
|
81
|
-
* ref, two skills that collide in the selector) — so a well-formed plugin stays
|
|
82
|
-
* green and catching real breakage out of the box never cries wolf.
|
|
83
|
-
*
|
|
84
|
-
* Deliberately EXCLUDES `require-instructions-spec` and the workflow-forcing rules:
|
|
85
|
-
* those make a CLEAN repo fail (you simply haven't written the spec/test yet), so
|
|
86
|
-
* they stay opt-in under `--strict` (progressive adoption — see
|
|
87
|
-
* `STRICT_EXTRA_RULES`).
|
|
88
|
-
*
|
|
89
|
-
* This is the **`structural`** rule group (see research/install-enforcement-dx.md).
|
|
90
|
-
*/
|
|
91
|
-
exports.STRUCTURAL_RULES = [
|
|
92
|
-
"subagent-tool-contract",
|
|
93
|
-
"subagent-frontmatter",
|
|
94
|
-
"hook-events",
|
|
95
|
-
"hook-script-exists",
|
|
96
|
-
"mcp-config",
|
|
97
|
-
"mcp-tool-resolves",
|
|
98
|
-
"mcp-hook-target-resolves",
|
|
99
|
-
"disallowed-tools-contract",
|
|
100
|
-
"description-overlap",
|
|
101
|
-
];
|
|
102
75
|
/**
|
|
103
76
|
* The **`workflow`** group — the WORKFLOW-FORCING / opinionated tier `--strict`
|
|
104
77
|
* gates, which a clean repo can still fail because you haven't done the work yet:
|
|
@@ -147,41 +120,53 @@ exports.NUDGE_RULES = [
|
|
|
147
120
|
// than config. See docs/rules/doc-refs.md.
|
|
148
121
|
"doc-refs",
|
|
149
122
|
];
|
|
123
|
+
/**
|
|
124
|
+
* Pure config-merge for what `vigiles init` writes to `.vigilesrc.json`: record
|
|
125
|
+
* the harnesses if absent, gate the structural rules by EXTENDING the
|
|
126
|
+
* `vigiles:recommended` preset (never by writing each rule), add the workflow
|
|
127
|
+
* rules on `--strict`, and NEVER clobber an existing key or severity. Returns
|
|
128
|
+
* the merged config, or `null` when nothing changed (so the IO layer skips the
|
|
129
|
+
* write). The IO (read/parse/write + the malformed-file guard) stays in cli.ts.
|
|
130
|
+
*
|
|
131
|
+
* 🔴 THE PRESET, NOT NINE LINES (#338). Written lines are a snapshot of the
|
|
132
|
+
* structural group on the day `init` ran, so a repo adopted earlier never got a
|
|
133
|
+
* rule added to the group later; the preset is resolved by the loader on every
|
|
134
|
+
* run (`src/core/presets.ts`).
|
|
135
|
+
*
|
|
136
|
+
* `--report-only` is the exception and stays EXPLICIT: it promises that nothing
|
|
137
|
+
* fails CI, and extending a preset that later gains a rule at `error` would
|
|
138
|
+
* break that promise on an upgrade. So it writes the same rules at `warn`.
|
|
139
|
+
*/
|
|
150
140
|
function mergeProjectConfig(existing, opts) {
|
|
151
|
-
const config = { ...existing };
|
|
152
|
-
let changed = false;
|
|
153
141
|
// The NESTED key (#240). `init` writes the declaration with no roots — a repo
|
|
154
142
|
// whose surfaces sit where its harness reads them needs none, and a root is a
|
|
155
|
-
// fact only the owner knows.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
config.rules = rules;
|
|
183
|
-
}
|
|
184
|
-
return changed ? config : null;
|
|
143
|
+
// fact only the owner knows.
|
|
144
|
+
const harnesses = existing.harnesses === undefined
|
|
145
|
+
? { harnesses: Object.fromEntries(opts.harnesses.map((h) => [h, {}])) }
|
|
146
|
+
: {};
|
|
147
|
+
const gate = opts.lint === false ? {} : lintGate(existing, opts);
|
|
148
|
+
const added = { ...harnesses, ...gate };
|
|
149
|
+
return Object.keys(added).length === 0 ? null : { ...existing, ...added };
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* The lint-layer keys `init` adds: `extends` and/or the `rules` it fills.
|
|
153
|
+
* Only the keys that CHANGE are returned, so an already-satisfied config
|
|
154
|
+
* yields `{}` and is not rewritten.
|
|
155
|
+
*/
|
|
156
|
+
function lintGate(existing, opts) {
|
|
157
|
+
const workflow = opts.strict ? exports.WORKFLOW_RULES : [];
|
|
158
|
+
const explicit = opts.reportOnly
|
|
159
|
+
? [...presets_js_1.RECOMMENDED_RULES, ...workflow]
|
|
160
|
+
: workflow;
|
|
161
|
+
const severity = opts.reportOnly ? "warn" : "error";
|
|
162
|
+
const before = (existing.rules ?? {});
|
|
163
|
+
// Never clobber a severity the user already set — only fill the undefined ones.
|
|
164
|
+
const filled = Object.fromEntries(explicit.filter((r) => before[r] === undefined).map((r) => [r, severity]));
|
|
165
|
+
const rules = Object.keys(filled).length === 0 ? {} : { rules: { ...before, ...filled } };
|
|
166
|
+
const preset = opts.reportOnly || existing.extends !== undefined
|
|
167
|
+
? {}
|
|
168
|
+
: { extends: presets_js_1.RECOMMENDED_PRESET };
|
|
169
|
+
return { ...preset, ...rules };
|
|
185
170
|
}
|
|
186
171
|
/**
|
|
187
172
|
* Whether to drop into interactive prompts: a human at a TTY who passed neither
|
|
@@ -288,7 +273,7 @@ function gateOnlyInvitation(plan) {
|
|
|
288
273
|
const gateOnly = !plan.plugin && !plan.scaffoldSpecs;
|
|
289
274
|
if (!gateOnly)
|
|
290
275
|
return null;
|
|
291
|
-
return "→ Want your agent to maintain this + measure whether your skills fire? Run `npx vigiles init` and choose 'full' (installs the skills). Optional — the gate above already works.";
|
|
276
|
+
return "→ Want your agent to maintain this + measure whether your skills fire? Run `npx vigiles init --full` and choose 'full' (installs the skills). Optional — the gate above already works.";
|
|
292
277
|
}
|
|
293
278
|
/**
|
|
294
279
|
* The SHIPPED consumer skills (the `skills/` dir, published via `plugin.json`) —
|
|
@@ -470,6 +455,87 @@ function applyCodexPluginHooks(existing) {
|
|
|
470
455
|
}
|
|
471
456
|
return { ...existing, hooks };
|
|
472
457
|
}
|
|
458
|
+
/** {@link AdoptionState} from the two disk facts that decide it. */
|
|
459
|
+
function adoptionState(facts) {
|
|
460
|
+
if (facts.hasConfig)
|
|
461
|
+
return { kind: "adopted", evidence: ".vigilesrc.json" };
|
|
462
|
+
const [spec] = facts.specs;
|
|
463
|
+
return spec === undefined
|
|
464
|
+
? { kind: "fresh" }
|
|
465
|
+
: { kind: "adopted", evidence: spec };
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Which setup a run performs: the full one, or the minimal re-run (#338).
|
|
469
|
+
*
|
|
470
|
+
* MINIMAL only when the repo is adopted AND the run named nothing that asks for
|
|
471
|
+
* more. A flag that selects or widens the setup (`--full`, `--strict`,
|
|
472
|
+
* `--ci-only`, `--report-only`, `--force`, `--target=`, a positive `--lint` /
|
|
473
|
+
* `--test`) is an explicit request and keeps today's behaviour; the narrowing
|
|
474
|
+
* flags (`--no-*`, `--harness=`, `--yes`) do not, because they can only make a
|
|
475
|
+
* run do less.
|
|
476
|
+
*/
|
|
477
|
+
function rerunScope(parsed, state) {
|
|
478
|
+
if (state.kind === "fresh")
|
|
479
|
+
return "full";
|
|
480
|
+
const asksForMore = parsed.full ||
|
|
481
|
+
parsed.strict ||
|
|
482
|
+
parsed.ciOnly ||
|
|
483
|
+
parsed.reportOnly ||
|
|
484
|
+
parsed.force ||
|
|
485
|
+
parsed.target !== undefined ||
|
|
486
|
+
parsed.lint === true ||
|
|
487
|
+
parsed.test === true;
|
|
488
|
+
return asksForMore ? "full" : "minimal";
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* The `devDependencies` a minimal re-run writes, or null to leave package.json
|
|
492
|
+
* alone. It ADDS vigiles when no dependency field declares it and never edits an
|
|
493
|
+
* existing declaration: rewriting `^33.3.0` to `^33` loosens a pin the owner
|
|
494
|
+
* chose, and moving it between fields is a decision, not a missing piece.
|
|
495
|
+
*/
|
|
496
|
+
function missingVigilesDevDep(pkg, spec) {
|
|
497
|
+
const declared = pkg.dependencies?.vigiles !== undefined ||
|
|
498
|
+
pkg.devDependencies?.vigiles !== undefined;
|
|
499
|
+
return declared ? null : { ...pkg.devDependencies, vigiles: spec };
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* The lines a minimal re-run prints about what it did NOT do: each thing a full
|
|
503
|
+
* setup would add here, then the flag that does it. Empty when nothing is
|
|
504
|
+
* missing, so a fully set-up repo is not told to run anything.
|
|
505
|
+
*/
|
|
506
|
+
function fullSetupFollowUps(gap) {
|
|
507
|
+
const configLine = {
|
|
508
|
+
missing: `write .vigilesrc.json with your harnesses and "extends": "${presets_js_1.RECOMMENDED_PRESET}" (structural rules fail CI)`,
|
|
509
|
+
"no-preset": `add "extends": "${presets_js_1.RECOMMENDED_PRESET}" to .vigilesrc.json (structural rules fail CI)`,
|
|
510
|
+
"has-preset": null,
|
|
511
|
+
};
|
|
512
|
+
const items = [
|
|
513
|
+
gap.workflow
|
|
514
|
+
? "create .github/workflows/vigiles.yml (a CI workflow — new CI minutes)"
|
|
515
|
+
: null,
|
|
516
|
+
configLine[gap.config],
|
|
517
|
+
gap.harnessTest
|
|
518
|
+
? "scaffold vigiles.harness.mjs (a starter harness test)"
|
|
519
|
+
: null,
|
|
520
|
+
gap.unspecced.length > 0
|
|
521
|
+
? `write specs for ${String(gap.unspecced.length)} hand-written file(s): ${gap.unspecced.join(", ")}`
|
|
522
|
+
: null,
|
|
523
|
+
gap.generated
|
|
524
|
+
? "generate .vigiles/generated.d.ts and .vigiles/schema.json"
|
|
525
|
+
: null,
|
|
526
|
+
...gap.installs,
|
|
527
|
+
gap.devDep === null
|
|
528
|
+
? null
|
|
529
|
+
: `set the vigiles devDependency to ${gap.devDep.to} (yours: ${gap.devDep.from})`,
|
|
530
|
+
].filter((l) => l !== null);
|
|
531
|
+
return items.length === 0
|
|
532
|
+
? []
|
|
533
|
+
: [
|
|
534
|
+
"A full setup would also:",
|
|
535
|
+
...items.map((l) => ` - ${l}`),
|
|
536
|
+
"Run `npx vigiles init --full` for that (flags such as --no-gha still apply).",
|
|
537
|
+
];
|
|
538
|
+
}
|
|
473
539
|
/**
|
|
474
540
|
* Resolve the final plan: defaults, then flags, then interactive answers (each
|
|
475
541
|
* layer overrides the previous only where it has an opinion). `--target` pins a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigiles",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "35.0.0",
|
|
4
4
|
"description": "Audit, test and measure the harness your AI agent runs on — grade your CLAUDE.md / AGENTS.md, skills, subagents and hooks, run them against a scripted model, and measure whether they actually fire.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -83,7 +83,6 @@
|
|
|
83
83
|
"test:unit": "npm run build && vitest run --project unit",
|
|
84
84
|
"test:integration": "npm run build && vitest run --project integration",
|
|
85
85
|
"test:e2e": "npm run build && vitest run --project e2e",
|
|
86
|
-
"test:cli-e2e": "bash test/e2e/run.sh",
|
|
87
86
|
"test:harness": "npm run build && node dist/cli.js test",
|
|
88
87
|
"test:eval": "npm run build && node dist/cli.js eval --all",
|
|
89
88
|
"test:vitest": "npm run build && vitest run --project runners",
|