vigiles 3.0.0 → 4.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +2 -2
- package/README.md +35 -22
- package/action.yml +4 -4
- package/dist/adapters/claude-code/adapter.js +1 -1
- package/dist/claude-code.d.ts +1 -1
- package/dist/claude-code.js +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +387 -162
- package/dist/e2e.d.ts +1 -1
- package/dist/e2e.js +1 -1
- package/dist/{adapters/claude-code/eval-cache.d.ts → eval-cache.d.ts} +1 -1
- package/dist/{adapters/claude-code/eval-cache.js → eval-cache.js} +1 -1
- package/dist/{adapters/claude-code/eval.js → eval.js} +2 -2
- package/dist/harness-assert.d.ts +8 -8
- package/dist/harness-assert.js +5 -5
- package/dist/{adapters/claude-code/harness-test.d.ts → harness-test.d.ts} +4 -4
- package/dist/{adapters/claude-code/harness-test.js → harness-test.js} +4 -4
- package/dist/integration.d.ts +3 -3
- package/dist/integration.js +2 -3
- package/dist/{adapters/claude-code/mock-model.d.ts → mock-model.d.ts} +2 -2
- package/dist/{adapters/claude-code/run-hook.d.ts → run-hook.d.ts} +1 -1
- package/dist/{adapters/claude-code/run-hook.js → run-hook.js} +1 -1
- package/dist/{adapters/claude-code/sandbox.js → sandbox.js} +1 -1
- package/dist/setup-plan.d.ts +47 -7
- package/dist/setup-plan.js +104 -29
- package/dist/testing.d.ts +8 -3
- package/dist/testing.js +8 -3
- package/dist/unit.d.ts +2 -2
- package/dist/unit.js +1 -1
- package/hooks/session-start.sh +3 -3
- package/package.json +6 -6
- package/skills/audit-feedback-loop/SKILL.md +0 -76
- package/skills/enforce-rules-format/SKILL.md +0 -71
- package/skills/generate-logo/SKILL.md +0 -103
- package/skills/pr-to-lint-rule/SKILL.md +0 -97
- /package/dist/{adapters/claude-code/egress-entry.d.ts → egress-entry.d.ts} +0 -0
- /package/dist/{adapters/claude-code/egress-entry.js → egress-entry.js} +0 -0
- /package/dist/{adapters/claude-code/egress-proxy.d.ts → egress-proxy.d.ts} +0 -0
- /package/dist/{adapters/claude-code/egress-proxy.js → egress-proxy.js} +0 -0
- /package/dist/{adapters/claude-code/egress.d.ts → egress.d.ts} +0 -0
- /package/dist/{adapters/claude-code/egress.js → egress.js} +0 -0
- /package/dist/{adapters/claude-code/eval-baseline.d.ts → eval-baseline.d.ts} +0 -0
- /package/dist/{adapters/claude-code/eval-baseline.js → eval-baseline.js} +0 -0
- /package/dist/{adapters/claude-code/eval.d.ts → eval.d.ts} +0 -0
- /package/dist/{adapters/claude-code/judge.d.ts → judge.d.ts} +0 -0
- /package/dist/{adapters/claude-code/judge.js → judge.js} +0 -0
- /package/dist/{adapters/claude-code/mock-entry.d.ts → mock-entry.d.ts} +0 -0
- /package/dist/{adapters/claude-code/mock-entry.js → mock-entry.js} +0 -0
- /package/dist/{adapters/claude-code/mock-model.js → mock-model.js} +0 -0
- /package/dist/{adapters/claude-code/sandbox.d.ts → sandbox.d.ts} +0 -0
- /package/dist/{adapters/claude-code/stats.d.ts → stats.d.ts} +0 -0
- /package/dist/{adapters/claude-code/stats.js → stats.js} +0 -0
package/dist/e2e.d.ts
CHANGED
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
* [`vigiles/eval`](./eval.ts) + [`vigiles/judge`](./judge.ts), not from here.
|
|
16
16
|
*/
|
|
17
17
|
export * from "./integration.js";
|
|
18
|
-
export { egressRoutes } from "./
|
|
18
|
+
export { egressRoutes } from "./run-hook.js";
|
|
19
19
|
//# sourceMappingURL=e2e.d.ts.map
|
package/dist/e2e.js
CHANGED
|
@@ -34,6 +34,6 @@ exports.egressRoutes = void 0;
|
|
|
34
34
|
__exportStar(require("./integration.js"), exports);
|
|
35
35
|
// The real-egress capability probe (the egress-using runHook is already re-exported
|
|
36
36
|
// via the integration→unit chain).
|
|
37
|
-
var run_hook_js_1 = require("./
|
|
37
|
+
var run_hook_js_1 = require("./run-hook.js");
|
|
38
38
|
Object.defineProperty(exports, "egressRoutes", { enumerable: true, get: function () { return run_hook_js_1.egressRoutes; } });
|
|
39
39
|
//# sourceMappingURL=e2e.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type SHA256Hash } from "
|
|
1
|
+
import { type SHA256Hash } from "./core/hash.js";
|
|
2
2
|
import type { RunOut } from "./eval.js";
|
|
3
3
|
/** Cache behaviour: never touch the cache / read-only / read-and-write. */
|
|
4
4
|
export type CacheMode = "off" | "read" | "readwrite";
|
|
@@ -24,7 +24,7 @@ exports.restoreDir = restoreDir;
|
|
|
24
24
|
*/
|
|
25
25
|
const node_fs_1 = require("node:fs");
|
|
26
26
|
const node_path_1 = require("node:path");
|
|
27
|
-
const hash_js_1 = require("
|
|
27
|
+
const hash_js_1 = require("./core/hash.js");
|
|
28
28
|
const MAX_SNAPSHOT_FILE_BYTES = 1024 * 1024;
|
|
29
29
|
const SKIP_DIRS = new Set(["node_modules", ".git"]);
|
|
30
30
|
/**
|
|
@@ -39,8 +39,8 @@ const node_child_process_1 = require("node:child_process");
|
|
|
39
39
|
const node_fs_1 = require("node:fs");
|
|
40
40
|
const node_os_1 = require("node:os");
|
|
41
41
|
const node_path_1 = require("node:path");
|
|
42
|
-
const plugin_loader_js_1 = require("./plugin-loader.js");
|
|
43
|
-
const runtime_js_1 = require("./runtime.js");
|
|
42
|
+
const plugin_loader_js_1 = require("./adapters/claude-code/plugin-loader.js");
|
|
43
|
+
const runtime_js_1 = require("./adapters/claude-code/runtime.js");
|
|
44
44
|
const harness_test_js_1 = require("./harness-test.js");
|
|
45
45
|
const eval_cache_js_1 = require("./eval-cache.js");
|
|
46
46
|
function writeFiles(cwd, files) {
|
package/dist/harness-assert.d.ts
CHANGED
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
* `expect(...).toHaveCreated(...)` sugar. The signature is identical for
|
|
14
14
|
* vitest and jest, so the same object supports both.
|
|
15
15
|
*/
|
|
16
|
-
import { type HarnessTestSpec, type HarnessTestResult, type ToolCall, type Trace } from "./
|
|
17
|
-
import type { EvalReport, TriggerRateReport } from "./
|
|
18
|
-
import type { HookRunResult, EgressAttempt } from "./
|
|
16
|
+
import { type HarnessTestSpec, type HarnessTestResult, type ToolCall, type Trace } from "./harness-test.js";
|
|
17
|
+
import type { EvalReport, TriggerRateReport } from "./eval.js";
|
|
18
|
+
import type { HookRunResult, EgressAttempt } from "./run-hook.js";
|
|
19
19
|
import type { OutputContract } from "./core/spec.js";
|
|
20
20
|
import { type ParsedAgentResult } from "./adapters/claude-code/agent-result.js";
|
|
21
|
-
import { type BaselineFile, type DiffOptions } from "./
|
|
22
|
-
export { compareArms } from "./
|
|
23
|
-
export type { Comparison } from "./
|
|
24
|
-
export { diffReports, toBaselineFile, parseBaselineFile, readBaseline, writeBaseline, formatBaselineDiff, diffToJUnit, } from "./
|
|
25
|
-
export type { BaselineFile, BaselineDiff, MetricDiff, DiffStatus, DiffOptions, } from "./
|
|
21
|
+
import { type BaselineFile, type DiffOptions } from "./eval-baseline.js";
|
|
22
|
+
export { compareArms } from "./stats.js";
|
|
23
|
+
export type { Comparison } from "./stats.js";
|
|
24
|
+
export { diffReports, toBaselineFile, parseBaselineFile, readBaseline, writeBaseline, formatBaselineDiff, diffToJUnit, } from "./eval-baseline.js";
|
|
25
|
+
export type { BaselineFile, BaselineDiff, MetricDiff, DiffStatus, DiffOptions, } from "./eval-baseline.js";
|
|
26
26
|
/**
|
|
27
27
|
* Run a harness test, hand the result to `fn`, and always clean up the sandbox.
|
|
28
28
|
* Returns whatever `fn` returns. Use this instead of calling `cleanup()` by
|
package/dist/harness-assert.js
CHANGED
|
@@ -57,15 +57,15 @@ exports.assertTriggerRate = assertTriggerRate;
|
|
|
57
57
|
* `expect(...).toHaveCreated(...)` sugar. The signature is identical for
|
|
58
58
|
* vitest and jest, so the same object supports both.
|
|
59
59
|
*/
|
|
60
|
-
const harness_test_js_1 = require("./
|
|
60
|
+
const harness_test_js_1 = require("./harness-test.js");
|
|
61
61
|
const agent_result_js_1 = require("./adapters/claude-code/agent-result.js");
|
|
62
|
-
const stats_js_1 = require("./
|
|
63
|
-
const eval_baseline_js_1 = require("./
|
|
62
|
+
const stats_js_1 = require("./stats.js");
|
|
63
|
+
const eval_baseline_js_1 = require("./eval-baseline.js");
|
|
64
64
|
// Re-export the significance primitives so the whole eval-analysis surface lives
|
|
65
65
|
// behind `vigiles/harness-assert` (no separate entry point).
|
|
66
|
-
var stats_js_2 = require("./
|
|
66
|
+
var stats_js_2 = require("./stats.js");
|
|
67
67
|
Object.defineProperty(exports, "compareArms", { enumerable: true, get: function () { return stats_js_2.compareArms; } });
|
|
68
|
-
var eval_baseline_js_2 = require("./
|
|
68
|
+
var eval_baseline_js_2 = require("./eval-baseline.js");
|
|
69
69
|
Object.defineProperty(exports, "diffReports", { enumerable: true, get: function () { return eval_baseline_js_2.diffReports; } });
|
|
70
70
|
Object.defineProperty(exports, "toBaselineFile", { enumerable: true, get: function () { return eval_baseline_js_2.toBaselineFile; } });
|
|
71
71
|
Object.defineProperty(exports, "parseBaselineFile", { enumerable: true, get: function () { return eval_baseline_js_2.parseBaselineFile; } });
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { HarnessAdapter } from "
|
|
2
|
-
import type { HarnessTestDriver, ToolCall, HookFire, ParsedRun, ModelTurn, ModelRequest } from "
|
|
1
|
+
import type { HarnessAdapter } from "./core/adapter.js";
|
|
2
|
+
import type { HarnessTestDriver, ToolCall, HookFire, ParsedRun, ModelTurn, ModelRequest } from "./core/harness-driver.js";
|
|
3
3
|
import { type SandboxMode } from "./sandbox.js";
|
|
4
4
|
export { scriptModel } from "./mock-model.js";
|
|
5
|
-
export type { ModelTurn, ModelRequest, ToolCall, HookFire, HarnessTestDriver, } from "
|
|
6
|
-
export { loadPlugin, resolveHarness } from "./plugin-loader.js";
|
|
5
|
+
export type { ModelTurn, ModelRequest, ToolCall, HookFire, HarnessTestDriver, } from "./core/harness-driver.js";
|
|
6
|
+
export { loadPlugin, resolveHarness, } from "./adapters/claude-code/plugin-loader.js";
|
|
7
7
|
export { decideSandbox, specTrusted, sandboxAvailable, type SandboxMode, } from "./sandbox.js";
|
|
8
8
|
export interface HarnessTestSpec {
|
|
9
9
|
/** Fixture files to write in a fresh temp working dir (path → contents). */
|
|
@@ -43,14 +43,14 @@ const node_child_process_1 = require("node:child_process");
|
|
|
43
43
|
const node_fs_1 = require("node:fs");
|
|
44
44
|
const node_os_1 = require("node:os");
|
|
45
45
|
const node_path_1 = require("node:path");
|
|
46
|
-
const adapter_conformance_js_1 = require("
|
|
47
|
-
const runtime_js_1 = require("./runtime.js");
|
|
46
|
+
const adapter_conformance_js_1 = require("./adapter-conformance.js");
|
|
47
|
+
const runtime_js_1 = require("./adapters/claude-code/runtime.js");
|
|
48
48
|
const mock_model_js_1 = require("./mock-model.js");
|
|
49
|
-
const plugin_loader_js_1 = require("./plugin-loader.js");
|
|
49
|
+
const plugin_loader_js_1 = require("./adapters/claude-code/plugin-loader.js");
|
|
50
50
|
const sandbox_js_1 = require("./sandbox.js");
|
|
51
51
|
var mock_model_js_2 = require("./mock-model.js");
|
|
52
52
|
Object.defineProperty(exports, "scriptModel", { enumerable: true, get: function () { return mock_model_js_2.scriptModel; } });
|
|
53
|
-
var plugin_loader_js_2 = require("./plugin-loader.js");
|
|
53
|
+
var plugin_loader_js_2 = require("./adapters/claude-code/plugin-loader.js");
|
|
54
54
|
Object.defineProperty(exports, "loadPlugin", { enumerable: true, get: function () { return plugin_loader_js_2.loadPlugin; } });
|
|
55
55
|
Object.defineProperty(exports, "resolveHarness", { enumerable: true, get: function () { return plugin_loader_js_2.resolveHarness; } });
|
|
56
56
|
var sandbox_js_2 = require("./sandbox.js");
|
package/dist/integration.d.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* imports from here.
|
|
11
11
|
*/
|
|
12
12
|
export * from "./unit.js";
|
|
13
|
-
export * from "./
|
|
14
|
-
export * from "./
|
|
15
|
-
export
|
|
13
|
+
export * from "./harness-test.js";
|
|
14
|
+
export * from "./mock-model.js";
|
|
15
|
+
export type { LoadedPlugin } from "./plugin-loader.js";
|
|
16
16
|
//# sourceMappingURL=integration.d.ts.map
|
package/dist/integration.js
CHANGED
|
@@ -26,7 +26,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
* imports from here.
|
|
27
27
|
*/
|
|
28
28
|
__exportStar(require("./unit.js"), exports);
|
|
29
|
-
__exportStar(require("./
|
|
30
|
-
__exportStar(require("./
|
|
31
|
-
__exportStar(require("./adapters/claude-code/plugin-loader.js"), exports);
|
|
29
|
+
__exportStar(require("./harness-test.js"), exports);
|
|
30
|
+
__exportStar(require("./mock-model.js"), exports);
|
|
32
31
|
//# sourceMappingURL=integration.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ModelTurn, ModelRequest } from "
|
|
2
|
-
export type { ModelTurn, ModelRequest } from "
|
|
1
|
+
import type { ModelTurn, ModelRequest } from "./core/harness-driver.js";
|
|
2
|
+
export type { ModelTurn, ModelRequest } from "./core/harness-driver.js";
|
|
3
3
|
/** Build a scripted model from an ordered list of turns. */
|
|
4
4
|
export declare function scriptModel(turns: readonly ModelTurn[]): ModelTurn[];
|
|
5
5
|
export interface TurnInfo {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HookProtocol } from "
|
|
1
|
+
import type { HookProtocol } from "./core/hook-protocol.js";
|
|
2
2
|
import { type SandboxMode, type EgressAttempt } from "./sandbox.js";
|
|
3
3
|
export type { EgressAttempt };
|
|
4
4
|
/** A hook event payload (the JSON Claude Code writes to the hook's stdin). */
|
|
@@ -38,7 +38,7 @@ const node_child_process_1 = require("node:child_process");
|
|
|
38
38
|
const node_fs_1 = require("node:fs");
|
|
39
39
|
const node_os_1 = require("node:os");
|
|
40
40
|
const node_path_1 = require("node:path");
|
|
41
|
-
const hook_protocol_js_1 = require("./hook-protocol.js");
|
|
41
|
+
const hook_protocol_js_1 = require("./adapters/claude-code/hook-protocol.js");
|
|
42
42
|
const egress_js_1 = require("./egress.js");
|
|
43
43
|
const sandbox_js_1 = require("./sandbox.js");
|
|
44
44
|
/** Parse stdout as a hook JSON decision (pure, testable without a process). */
|
|
@@ -35,7 +35,7 @@ const node_child_process_1 = require("node:child_process");
|
|
|
35
35
|
const node_fs_1 = require("node:fs");
|
|
36
36
|
const node_os_1 = require("node:os");
|
|
37
37
|
const node_path_1 = require("node:path");
|
|
38
|
-
const runtime_js_1 = require("./runtime.js");
|
|
38
|
+
const runtime_js_1 = require("./adapters/claude-code/runtime.js");
|
|
39
39
|
let cachedAvailable;
|
|
40
40
|
/**
|
|
41
41
|
* Whether this environment can ACTUALLY confine untrusted code under bubblewrap.
|
package/dist/setup-plan.d.ts
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
*/
|
|
11
11
|
/** What `vigiles init` will set up. */
|
|
12
12
|
export interface SetupPlan {
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
/**
|
|
13
|
+
/** Lint pillar — verify instruction-file references (specs, types, compile, lint/audit, hooks). */
|
|
14
|
+
lint: boolean;
|
|
15
|
+
/** Test pillar — test the harness (scaffold a starter harness test + CI job). */
|
|
16
16
|
test: boolean;
|
|
17
17
|
/** Wire CI (the `zernie/vigiles@v1` Action; creates a workflow if none). */
|
|
18
18
|
gha: boolean;
|
|
@@ -26,11 +26,17 @@ export interface ParsedSetupArgs {
|
|
|
26
26
|
target?: string;
|
|
27
27
|
strict: boolean;
|
|
28
28
|
yes: boolean;
|
|
29
|
-
|
|
29
|
+
/** Lint pillar — `--lint` → true, `--no-lint` → false, absent → undefined. */
|
|
30
|
+
lint?: boolean;
|
|
31
|
+
/** Test pillar — `--test` → true, `--no-test` → false, absent → undefined. */
|
|
32
|
+
test?: boolean;
|
|
33
|
+
/** `--harness=claude,codex` override (empty = auto-detect). */
|
|
34
|
+
harness?: string;
|
|
30
35
|
gha?: boolean;
|
|
31
36
|
plugin?: boolean;
|
|
32
37
|
}
|
|
33
|
-
/** Parse `init` args into the choices the user pinned.
|
|
38
|
+
/** Parse `init` args into the choices the user pinned. The two pillars are
|
|
39
|
+
* selected with `--lint` / `--test`. */
|
|
34
40
|
export declare function parseSetupArgs(args: readonly string[]): ParsedSetupArgs;
|
|
35
41
|
/** The non-interactive defaults: both pillars, CI, and the plugin. */
|
|
36
42
|
export declare function defaultPlan(strict?: boolean): SetupPlan;
|
|
@@ -41,11 +47,45 @@ export declare function defaultPlan(strict?: boolean): SetupPlan;
|
|
|
41
47
|
*/
|
|
42
48
|
export declare function shouldPrompt(parsed: ParsedSetupArgs, isTTY: boolean): boolean;
|
|
43
49
|
/** Interactive answers (only the fields the prompts cover). */
|
|
44
|
-
export type SetupAnswers = Partial<Pick<SetupPlan, "
|
|
50
|
+
export type SetupAnswers = Partial<Pick<SetupPlan, "lint" | "test" | "gha" | "plugin">>;
|
|
51
|
+
/**
|
|
52
|
+
* How to install vigiles's skills/hooks for ONE harness — the deterministic
|
|
53
|
+
* decision behind the IO in cli.ts, so a CI test asserts WHICH commands an
|
|
54
|
+
* install runs without a network call or a real `claude`/`codex` binary.
|
|
55
|
+
*
|
|
56
|
+
* The method is genuinely harness-specific: Claude Code has a GLOBAL plugin
|
|
57
|
+
* marketplace (installs to ~/.claude/plugins/, nothing in the repo); Codex has
|
|
58
|
+
* no global store — its config is repo-committed (`.codex/`, AGENTS.md), so its
|
|
59
|
+
* instructions are read directly and skills are an opt-in, repo-local concern.
|
|
60
|
+
*/
|
|
61
|
+
export interface InstallPlan {
|
|
62
|
+
harness: string;
|
|
63
|
+
/** Shell commands to auto-run (empty = nothing runnable here). */
|
|
64
|
+
commands: string[];
|
|
65
|
+
/** One-line success message printed after the commands run. */
|
|
66
|
+
successMessage: string;
|
|
67
|
+
/** The equivalent commands a user runs by hand (printed on failure / no-CLI). */
|
|
68
|
+
manualSteps: string[];
|
|
69
|
+
/** Always-printed informational lines (where it installs, caveats). */
|
|
70
|
+
notes: string[];
|
|
71
|
+
/** Whether this method writes files into the consumer's repo (vendoring). */
|
|
72
|
+
vendors: boolean;
|
|
73
|
+
}
|
|
74
|
+
/** Per-harness install plan. `hasClaude` gates the auto-run `claude plugin` CLI
|
|
75
|
+
* (else the same two steps are printed as `/plugin` slash commands).
|
|
76
|
+
*
|
|
77
|
+
* Both methods install GLOBALLY, never into the repo: Claude through its plugin
|
|
78
|
+
* marketplace (~/.claude/plugins/), Codex through the cross-agent `skills` CLI
|
|
79
|
+
* with `-g -y` (the global store ~/.agents/skills/, which Codex reads). Codex
|
|
80
|
+
* gets the skills but NOT hooks — Codex hook wiring (.codex/config.toml [hooks])
|
|
81
|
+
* is not automated yet. */
|
|
82
|
+
export declare function planPluginInstall(harnesses: readonly string[], opts: {
|
|
83
|
+
hasClaude: boolean;
|
|
84
|
+
}): InstallPlan[];
|
|
45
85
|
/**
|
|
46
86
|
* Resolve the final plan: defaults, then flags, then interactive answers (each
|
|
47
87
|
* layer overrides the previous only where it has an opinion). `--target` pins a
|
|
48
|
-
* bare
|
|
88
|
+
* bare lint-pillar spec (no harness scaffold).
|
|
49
89
|
*/
|
|
50
90
|
export declare function resolvePlan(parsed: ParsedSetupArgs, answers?: SetupAnswers): SetupPlan;
|
|
51
91
|
//# sourceMappingURL=setup-plan.d.ts.map
|
package/dist/setup-plan.js
CHANGED
|
@@ -13,28 +13,36 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
13
13
|
exports.parseSetupArgs = parseSetupArgs;
|
|
14
14
|
exports.defaultPlan = defaultPlan;
|
|
15
15
|
exports.shouldPrompt = shouldPrompt;
|
|
16
|
+
exports.planPluginInstall = planPluginInstall;
|
|
16
17
|
exports.resolvePlan = resolvePlan;
|
|
17
18
|
function flagValue(args, prefix) {
|
|
18
19
|
return args.find((a) => a.startsWith(prefix))?.slice(prefix.length);
|
|
19
20
|
}
|
|
20
|
-
/**
|
|
21
|
+
/** `--name` → true, `--no-name` → false, neither present → undefined. */
|
|
22
|
+
function boolFlag(args, name) {
|
|
23
|
+
if (args.includes(`--${name}`))
|
|
24
|
+
return true;
|
|
25
|
+
if (args.includes(`--no-${name}`))
|
|
26
|
+
return false;
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
/** Parse `init` args into the choices the user pinned. The two pillars are
|
|
30
|
+
* selected with `--lint` / `--test`. */
|
|
21
31
|
function parseSetupArgs(args) {
|
|
22
|
-
const pillarsRaw = flagValue(args, "--pillars=");
|
|
23
|
-
const pillars = pillarsRaw === "verify" || pillarsRaw === "test" || pillarsRaw === "both"
|
|
24
|
-
? pillarsRaw
|
|
25
|
-
: undefined;
|
|
26
32
|
return {
|
|
27
33
|
target: flagValue(args, "--target="),
|
|
28
34
|
strict: args.includes("--strict"),
|
|
29
35
|
yes: args.includes("--yes") || args.includes("-y"),
|
|
30
|
-
|
|
36
|
+
lint: boolFlag(args, "lint"),
|
|
37
|
+
test: boolFlag(args, "test"),
|
|
38
|
+
harness: flagValue(args, "--harness="),
|
|
31
39
|
gha: args.includes("--no-gha") ? false : undefined,
|
|
32
40
|
plugin: args.includes("--no-plugin") ? false : undefined,
|
|
33
41
|
};
|
|
34
42
|
}
|
|
35
43
|
/** The non-interactive defaults: both pillars, CI, and the plugin. */
|
|
36
44
|
function defaultPlan(strict = false) {
|
|
37
|
-
return {
|
|
45
|
+
return { lint: true, test: true, gha: true, plugin: true, strict };
|
|
38
46
|
}
|
|
39
47
|
/**
|
|
40
48
|
* Whether to drop into interactive prompts: a human at a TTY who passed neither
|
|
@@ -44,42 +52,109 @@ function defaultPlan(strict = false) {
|
|
|
44
52
|
function shouldPrompt(parsed, isTTY) {
|
|
45
53
|
if (!isTTY || parsed.yes || parsed.target)
|
|
46
54
|
return false;
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
parsed.plugin !== undefined;
|
|
55
|
+
const pillarsPinned = parsed.lint !== undefined || parsed.test !== undefined;
|
|
56
|
+
const allPinned = pillarsPinned && parsed.gha !== undefined && parsed.plugin !== undefined;
|
|
50
57
|
return !allPinned;
|
|
51
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Apply the pillar flags. A positive flag (`--lint` and/or `--test`) is an
|
|
61
|
+
* explicit SELECTION — enable exactly the named pillars. Otherwise default to
|
|
62
|
+
* both and let a `--no-*` flag drop one.
|
|
63
|
+
*/
|
|
64
|
+
function applyPillarFlags(plan, parsed) {
|
|
65
|
+
if (parsed.lint === true || parsed.test === true) {
|
|
66
|
+
plan.lint = parsed.lint === true;
|
|
67
|
+
plan.test = parsed.test === true;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (parsed.lint === false)
|
|
71
|
+
plan.lint = false;
|
|
72
|
+
if (parsed.test === false)
|
|
73
|
+
plan.test = false;
|
|
74
|
+
}
|
|
75
|
+
function applyAnswers(plan, answers) {
|
|
76
|
+
if (answers.lint !== undefined)
|
|
77
|
+
plan.lint = answers.lint;
|
|
78
|
+
if (answers.test !== undefined)
|
|
79
|
+
plan.test = answers.test;
|
|
80
|
+
if (answers.gha !== undefined)
|
|
81
|
+
plan.gha = answers.gha;
|
|
82
|
+
if (answers.plugin !== undefined)
|
|
83
|
+
plan.plugin = answers.plugin;
|
|
84
|
+
}
|
|
85
|
+
/** Per-harness install plan. `hasClaude` gates the auto-run `claude plugin` CLI
|
|
86
|
+
* (else the same two steps are printed as `/plugin` slash commands).
|
|
87
|
+
*
|
|
88
|
+
* Both methods install GLOBALLY, never into the repo: Claude through its plugin
|
|
89
|
+
* marketplace (~/.claude/plugins/), Codex through the cross-agent `skills` CLI
|
|
90
|
+
* with `-g -y` (the global store ~/.agents/skills/, which Codex reads). Codex
|
|
91
|
+
* gets the skills but NOT hooks — Codex hook wiring (.codex/config.toml [hooks])
|
|
92
|
+
* is not automated yet. */
|
|
93
|
+
function planPluginInstall(harnesses, opts) {
|
|
94
|
+
return harnesses.map((harness) => {
|
|
95
|
+
if (harness === "claude") {
|
|
96
|
+
return {
|
|
97
|
+
harness,
|
|
98
|
+
commands: opts.hasClaude
|
|
99
|
+
? [
|
|
100
|
+
"claude plugin marketplace add zernie/vigiles",
|
|
101
|
+
"claude plugin install vigiles@vigiles",
|
|
102
|
+
]
|
|
103
|
+
: [],
|
|
104
|
+
successMessage: "✓ Installed the vigiles plugin (hooks + skills) into ~/.claude/plugins/",
|
|
105
|
+
manualSteps: [
|
|
106
|
+
"/plugin marketplace add zernie/vigiles",
|
|
107
|
+
"/plugin install vigiles@vigiles",
|
|
108
|
+
],
|
|
109
|
+
notes: [
|
|
110
|
+
"Installs globally to ~/.claude/plugins/ — nothing is added to your repo.",
|
|
111
|
+
],
|
|
112
|
+
vendors: false,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (harness === "codex") {
|
|
116
|
+
// The cross-agent `skills` CLI with `-g -y` installs to the global store
|
|
117
|
+
// ~/.agents/skills/ (NOT the repo, and NOT ~/.codex/ — verified against
|
|
118
|
+
// the real CLI). Skills only; Codex hooks (.codex/config.toml [hooks])
|
|
119
|
+
// are not wired automatically.
|
|
120
|
+
return {
|
|
121
|
+
harness,
|
|
122
|
+
commands: ["npx --yes skills add zernie/vigiles -a codex -g -y"],
|
|
123
|
+
successMessage: "✓ Installed the vigiles skills into ~/.agents/skills/ (global, not vendored)",
|
|
124
|
+
manualSteps: ["npx skills add zernie/vigiles -a codex -g -y"],
|
|
125
|
+
notes: [
|
|
126
|
+
"Codex reads AGENTS.md directly; the skills install globally to ~/.agents/skills/ (not the repo).",
|
|
127
|
+
"Codex hooks (.codex/config.toml [hooks]) are not auto-wired yet — add them manually for compile-on-edit.",
|
|
128
|
+
],
|
|
129
|
+
vendors: false,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
harness,
|
|
134
|
+
commands: [],
|
|
135
|
+
successMessage: "",
|
|
136
|
+
manualSteps: [],
|
|
137
|
+
notes: [`No plugin install path for harness '${harness}'.`],
|
|
138
|
+
vendors: false,
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
}
|
|
52
142
|
/**
|
|
53
143
|
* Resolve the final plan: defaults, then flags, then interactive answers (each
|
|
54
144
|
* layer overrides the previous only where it has an opinion). `--target` pins a
|
|
55
|
-
* bare
|
|
145
|
+
* bare lint-pillar spec (no harness scaffold).
|
|
56
146
|
*/
|
|
57
147
|
function resolvePlan(parsed, answers) {
|
|
58
148
|
const plan = defaultPlan(parsed.strict);
|
|
59
|
-
|
|
60
|
-
plan.verify = true;
|
|
61
|
-
plan.test = false;
|
|
62
|
-
}
|
|
63
|
-
else if (parsed.pillars === "test") {
|
|
64
|
-
plan.verify = false;
|
|
65
|
-
plan.test = true;
|
|
66
|
-
}
|
|
149
|
+
applyPillarFlags(plan, parsed);
|
|
67
150
|
if (parsed.gha === false)
|
|
68
151
|
plan.gha = false;
|
|
69
152
|
if (parsed.plugin === false)
|
|
70
153
|
plan.plugin = false;
|
|
71
154
|
if (parsed.target)
|
|
72
155
|
plan.test = false;
|
|
73
|
-
if (answers)
|
|
74
|
-
|
|
75
|
-
plan.verify = answers.verify;
|
|
76
|
-
if (answers.test !== undefined)
|
|
77
|
-
plan.test = answers.test;
|
|
78
|
-
if (answers.gha !== undefined)
|
|
79
|
-
plan.gha = answers.gha;
|
|
80
|
-
if (answers.plugin !== undefined)
|
|
81
|
-
plan.plugin = answers.plugin;
|
|
82
|
-
}
|
|
156
|
+
if (answers)
|
|
157
|
+
applyAnswers(plan, answers);
|
|
83
158
|
return plan;
|
|
84
159
|
}
|
|
85
160
|
//# sourceMappingURL=setup-plan.js.map
|
package/dist/testing.d.ts
CHANGED
|
@@ -4,9 +4,14 @@
|
|
|
4
4
|
* (eval) — plus the runner-agnostic predicates/assertions. Kept deliberately
|
|
5
5
|
* separate from `vigiles/claude-code` so this surface can stay harness-agnostic as
|
|
6
6
|
* more harnesses are added. Granular paths (`vigiles/run-hook`, etc.) still work.
|
|
7
|
+
*
|
|
8
|
+
* It re-exports the composition-root runner modules (which do the Claude-Code
|
|
9
|
+
* default-wiring), never an adapter directly — the `agnostic-surface` eslint
|
|
10
|
+
* boundary forbids importing `src/adapters/*` from here. See
|
|
11
|
+
* `research/adapter-api-design.md`.
|
|
7
12
|
*/
|
|
8
|
-
export * from "./
|
|
9
|
-
export * from "./
|
|
10
|
-
export * from "./
|
|
13
|
+
export * from "./run-hook.js";
|
|
14
|
+
export * from "./harness-test.js";
|
|
15
|
+
export * from "./eval.js";
|
|
11
16
|
export * from "./harness-assert.js";
|
|
12
17
|
//# sourceMappingURL=testing.d.ts.map
|
package/dist/testing.js
CHANGED
|
@@ -20,9 +20,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
20
20
|
* (eval) — plus the runner-agnostic predicates/assertions. Kept deliberately
|
|
21
21
|
* separate from `vigiles/claude-code` so this surface can stay harness-agnostic as
|
|
22
22
|
* more harnesses are added. Granular paths (`vigiles/run-hook`, etc.) still work.
|
|
23
|
+
*
|
|
24
|
+
* It re-exports the composition-root runner modules (which do the Claude-Code
|
|
25
|
+
* default-wiring), never an adapter directly — the `agnostic-surface` eslint
|
|
26
|
+
* boundary forbids importing `src/adapters/*` from here. See
|
|
27
|
+
* `research/adapter-api-design.md`.
|
|
23
28
|
*/
|
|
24
|
-
__exportStar(require("./
|
|
25
|
-
__exportStar(require("./
|
|
26
|
-
__exportStar(require("./
|
|
29
|
+
__exportStar(require("./run-hook.js"), exports);
|
|
30
|
+
__exportStar(require("./harness-test.js"), exports);
|
|
31
|
+
__exportStar(require("./eval.js"), exports);
|
|
27
32
|
__exportStar(require("./harness-assert.js"), exports);
|
|
28
33
|
//# sourceMappingURL=testing.js.map
|
package/dist/unit.d.ts
CHANGED
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
* `vigiles/e2e`.
|
|
13
13
|
*/
|
|
14
14
|
export * from "./harness-assert.js";
|
|
15
|
-
export { runHook, parseHookOutput, decideHook
|
|
16
|
-
export type { HookInput, HookOutput, HookRunResult, RunHookOptions, } from "./
|
|
15
|
+
export { runHook, parseHookOutput, decideHook } from "./run-hook.js";
|
|
16
|
+
export type { HookInput, HookOutput, HookRunResult, RunHookOptions, } from "./run-hook.js";
|
|
17
17
|
//# sourceMappingURL=unit.d.ts.map
|
package/dist/unit.js
CHANGED
|
@@ -29,7 +29,7 @@ exports.decideHook = exports.parseHookOutput = exports.runHook = void 0;
|
|
|
29
29
|
* `vigiles/e2e`.
|
|
30
30
|
*/
|
|
31
31
|
__exportStar(require("./harness-assert.js"), exports);
|
|
32
|
-
var run_hook_js_1 = require("./
|
|
32
|
+
var run_hook_js_1 = require("./run-hook.js");
|
|
33
33
|
Object.defineProperty(exports, "runHook", { enumerable: true, get: function () { return run_hook_js_1.runHook; } });
|
|
34
34
|
Object.defineProperty(exports, "parseHookOutput", { enumerable: true, get: function () { return run_hook_js_1.parseHookOutput; } });
|
|
35
35
|
Object.defineProperty(exports, "decideHook", { enumerable: true, get: function () { return run_hook_js_1.decideHook; } });
|
package/hooks/session-start.sh
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# SessionStart hook — inject a one-line vigiles
|
|
2
|
+
# SessionStart hook — inject a one-line vigiles lint summary into
|
|
3
3
|
# Claude's context at session start and after compaction.
|
|
4
4
|
#
|
|
5
|
-
# Uses `vigiles
|
|
5
|
+
# Uses `vigiles lint --summary` which is designed for this: it
|
|
6
6
|
# silences all per-stage output and prints a single line like
|
|
7
7
|
# vigiles: 3 stale / 2 validation errors / 1 duplicate
|
|
8
8
|
# (or "vigiles: clean") so the injection costs a handful of tokens.
|
|
@@ -24,7 +24,7 @@ fi
|
|
|
24
24
|
|
|
25
25
|
# Prefer local install, fall back to npx.
|
|
26
26
|
if command -v npx &>/dev/null; then
|
|
27
|
-
SUMMARY=$(npx --no-install vigiles
|
|
27
|
+
SUMMARY=$(npx --no-install vigiles lint --summary 2>/dev/null || true)
|
|
28
28
|
else
|
|
29
29
|
exit 0
|
|
30
30
|
fi
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigiles",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "Compile .spec.ts files to instruction files (CLAUDE.md, AGENTS.md) with linter cross-referencing",
|
|
5
5
|
"bin": {
|
|
6
6
|
"vigiles": "dist/cli.js"
|
|
@@ -20,14 +20,14 @@
|
|
|
20
20
|
"./spec": "./dist/core/spec.js",
|
|
21
21
|
"./compile": "./dist/core/compile.js",
|
|
22
22
|
"./linters": "./dist/core/linters.js",
|
|
23
|
-
"./eval": "./dist/
|
|
24
|
-
"./harness-test": "./dist/
|
|
23
|
+
"./eval": "./dist/eval.js",
|
|
24
|
+
"./harness-test": "./dist/harness-test.js",
|
|
25
25
|
"./harness-assert": "./dist/harness-assert.js",
|
|
26
|
-
"./run-hook": "./dist/
|
|
26
|
+
"./run-hook": "./dist/run-hook.js",
|
|
27
27
|
"./plugin-loader": "./dist/adapters/claude-code/plugin-loader.js",
|
|
28
28
|
"./mcp": "./dist/core/mcp.js",
|
|
29
|
-
"./judge": "./dist/
|
|
30
|
-
"./mock-model": "./dist/
|
|
29
|
+
"./judge": "./dist/judge.js",
|
|
30
|
+
"./mock-model": "./dist/mock-model.js",
|
|
31
31
|
"./vitest": {
|
|
32
32
|
"types": "./dist/vitest.d.mts",
|
|
33
33
|
"default": "./dist/vitest.mjs"
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: audit-feedback-loop
|
|
3
|
-
description: Scan the current repo and score its feedback loop maturity for AI-assisted development
|
|
4
|
-
disable-model-invocation: true
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Scan the current repository and score its feedback loop maturity for AI-assisted development.
|
|
8
|
-
|
|
9
|
-
## Instructions
|
|
10
|
-
|
|
11
|
-
Analyze this repository and score its **feedback loop maturity** using the levels below. Check for each signal, then output a summary report.
|
|
12
|
-
|
|
13
|
-
### Maturity Levels
|
|
14
|
-
|
|
15
|
-
**Level 0 — Vibes**
|
|
16
|
-
No CI config, no linter rules, no CLAUDE.md. The AI agent is flying blind.
|
|
17
|
-
|
|
18
|
-
**Level 1 — Guardrails**
|
|
19
|
-
Has CI + standard linters, but no custom rules. The agent gets basic feedback but can't learn project-specific conventions.
|
|
20
|
-
|
|
21
|
-
**Level 2 — Architecture as Code**
|
|
22
|
-
Has custom lint rules, CLAUDE.md rules have enforcement annotations. The agent gets rich, project-specific feedback.
|
|
23
|
-
|
|
24
|
-
**Level 3 — The Organism**
|
|
25
|
-
Has CI + custom rules + screenshot/visual tests + observability + scheduled agent tasks. The entire development loop is instrumented.
|
|
26
|
-
|
|
27
|
-
### Signals to Check
|
|
28
|
-
|
|
29
|
-
Scan the repository for the following and note which exist:
|
|
30
|
-
|
|
31
|
-
1. **CI Configuration**: Look for `.github/workflows/`, `.circleci/`, `Jenkinsfile`, `.gitlab-ci.yml`, `bitbucket-pipelines.yml`, `.travis.yml`, etc.
|
|
32
|
-
2. **Linter Config** (language-aware):
|
|
33
|
-
- **JS/TS**: `eslint.config.*`, `.eslintrc*`, `biome.json`, `.prettierrc*`, `deno.json`
|
|
34
|
-
- **Python**: `pyproject.toml` (look for `[tool.ruff]`, `[tool.pylint]`, `[tool.flake8]`), `setup.cfg`, `.flake8`, `ruff.toml`
|
|
35
|
-
- **Rust**: `clippy.toml`, `.clippy.toml`, `rustfmt.toml`
|
|
36
|
-
- **Go**: `.golangci.yml`, `.golangci.yaml`
|
|
37
|
-
- **Ruby**: `.rubocop.yml`
|
|
38
|
-
- **Java/Kotlin**: `checkstyle.xml`, `pmd.xml`, `detekt.yml`
|
|
39
|
-
3. **Custom Lint Rules**: Look for custom plugins, rule directories, or inline rule definitions in linter configs
|
|
40
|
-
- JS/TS: `eslint-plugin-*`, `eslint-rules/` directories
|
|
41
|
-
- Python: custom Ruff/Pylint plugins, AST-based checks
|
|
42
|
-
- Rust: custom Clippy lints
|
|
43
|
-
- Go: custom analyzers
|
|
44
|
-
4. **CLAUDE.md**: Check if `CLAUDE.md` exists at the repo root
|
|
45
|
-
5. **CLAUDE.md Enforcement**: Check if using vigiles v2 specs (`CLAUDE.md.spec.ts` exists) or v1 annotations (`**Enforced by:**` in CLAUDE.md). v2 specs = higher maturity.
|
|
46
|
-
6. **Type-Safe Specs**: Check for `CLAUDE.md.spec.ts` or `*.spec.ts` files — indicates typed spec compilation via vigiles v2
|
|
47
|
-
7. **Generated Types**: Check for `.vigiles/generated.d.ts` — indicates linter rules are type-checked at authoring time
|
|
48
|
-
8. **Screenshot/Visual Tests**: Look for Playwright (`playwright.config.*`), Cypress (`cypress.config.*`), Chromatic, Percy, BackstopJS configs
|
|
49
|
-
9. **Observability**: Search for imports/usage of `@sentry/`, `dd-trace`, `@datadog/`, `newrelic`, `@opentelemetry/`, `sentry_sdk`, `structlog`, `tracing` (Rust), `opentelemetry` in source files
|
|
50
|
-
10. **Scheduled Agent Tasks**: Look for cron patterns in CI configs, `.github/workflows/` with `schedule:` triggers, or references to scheduled Claude Code tasks
|
|
51
|
-
|
|
52
|
-
### Output Format
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
## Feedback Loop Audit
|
|
56
|
-
|
|
57
|
-
**Repository:** <repo name>
|
|
58
|
-
**Primary language(s):** <detected languages>
|
|
59
|
-
**Score: Level X — <Name>**
|
|
60
|
-
|
|
61
|
-
### Signals Found
|
|
62
|
-
- [x] CI Configuration: <details>
|
|
63
|
-
- [ ] Custom Lint Rules: not found
|
|
64
|
-
- [x] CLAUDE.md: found, 5 enforced / 2 guidance / 1 missing
|
|
65
|
-
...
|
|
66
|
-
|
|
67
|
-
### Recommendations
|
|
68
|
-
1. <Most impactful next step to level up>
|
|
69
|
-
2. <Second recommendation>
|
|
70
|
-
3. <Third recommendation>
|
|
71
|
-
|
|
72
|
-
### How to Level Up
|
|
73
|
-
<Specific, actionable advice for reaching the next maturity level>
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
Be specific about file paths and what you found. Give actionable recommendations tailored to the project's language and toolchain.
|