vigiles 6.0.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +189 -88
- package/dist/action-gate.js +1 -1
- package/dist/adapters/claude-code/agent-runtime.d.ts +46 -11
- package/dist/adapters/claude-code/agent-runtime.js +95 -24
- package/dist/adapters/claude-code/effect-region.js +1 -1
- package/dist/adapters/claude-code/skill-runtime.d.ts +1 -1
- package/dist/adapters/claude-code/skill-runtime.js +1 -1
- package/dist/adapters/codex/hook-protocol.js +3 -0
- package/dist/adapters/codex/mock-model.js +1 -1
- package/dist/cli-commands.d.ts +19 -0
- package/dist/cli-commands.js +47 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +1054 -201
- package/dist/core/adopt.d.ts +65 -0
- package/dist/core/adopt.js +199 -0
- package/dist/core/bash-effects.d.ts +12 -0
- package/dist/core/bash-effects.js +31 -0
- package/dist/core/capability-diff.d.ts +46 -0
- package/dist/core/capability-diff.js +97 -0
- package/dist/core/compose.d.ts +1 -1
- package/dist/core/compose.js +1 -1
- package/dist/core/evolve.d.ts +4 -0
- package/dist/core/evolve.js +4 -0
- package/dist/core/frontmatter.d.ts +8 -7
- package/dist/core/frontmatter.js +8 -7
- package/dist/core/generate-harness.d.ts +1 -1
- package/dist/core/generate-harness.js +3 -3
- package/dist/core/generate-schema.js +1 -1
- package/dist/core/guards.d.ts +126 -0
- package/dist/core/guards.js +309 -0
- package/dist/core/harness-driver.d.ts +1 -1
- package/dist/core/hook-program.d.ts +459 -0
- package/dist/core/hook-program.js +468 -0
- package/dist/core/hook-protocol.d.ts +7 -0
- package/dist/core/hook-providers.d.ts +138 -0
- package/dist/core/hook-providers.js +155 -0
- package/dist/core/hook-spec.d.ts +74 -0
- package/dist/core/hook-spec.js +130 -0
- package/dist/core/inline.d.ts +6 -6
- package/dist/core/inline.js +7 -7
- package/dist/core/integrity.d.ts +31 -0
- package/dist/core/integrity.js +45 -0
- package/dist/core/mcp-tool.d.ts +12 -0
- package/dist/core/mcp-tool.js +20 -0
- package/dist/core/mcp.d.ts +13 -0
- package/dist/core/mcp.js +67 -0
- package/dist/core/orphans.js +1 -1
- package/dist/core/spec.d.ts +40 -2
- package/dist/core/spec.js +16 -1
- package/dist/core/types.d.ts +37 -5
- package/dist/core/validate.js +26 -26
- package/dist/dialect-drift.d.ts +65 -0
- package/dist/dialect-drift.js +216 -0
- package/dist/eval.d.ts +40 -5
- package/dist/eval.js +59 -5
- package/dist/guardrail-check.d.ts +85 -0
- package/dist/guardrail-check.js +152 -0
- package/dist/harness-assert.d.ts +10 -0
- package/dist/harness-assert.js +30 -0
- package/dist/hook-install.d.ts +43 -0
- package/dist/hook-install.js +91 -0
- package/dist/hook.d.ts +52 -0
- package/dist/hook.js +98 -0
- package/dist/leaderboard.d.ts +6 -0
- package/dist/leaderboard.js +43 -1
- package/dist/linting.d.ts +9 -5
- package/dist/linting.js +17 -5
- package/dist/optimize.js +1 -1
- package/dist/scaffold-test.js +21 -7
- package/dist/scan-behavioral.d.ts +60 -0
- package/dist/scan-behavioral.js +239 -1
- package/dist/scan-trigger-suggest.d.ts +54 -0
- package/dist/scan-trigger-suggest.js +70 -0
- package/dist/scan.d.ts +31 -1
- package/dist/scan.js +65 -3
- package/dist/score-explainer.js +1 -1
- package/dist/self-command-refs.d.ts +21 -0
- package/dist/self-command-refs.js +125 -0
- package/dist/setup-plan.d.ts +59 -1
- package/dist/setup-plan.js +103 -5
- package/dist/testing.d.ts +5 -3
- package/dist/testing.js +37 -23
- package/dist/tool-intercept.d.ts +4 -4
- package/dist/tool-intercept.js +5 -5
- package/dist/unit.d.ts +2 -0
- package/dist/unit.js +8 -1
- package/hooks/post-edit.sh +1 -1
- package/hooks/refs-nudge.sh +1 -1
- package/package.json +5 -3
- package/skills/adopt-spec/SKILL.md +7 -7
- package/skills/linter-docs/eslint.md +1 -1
- package/skills/strengthen/SKILL.md +1 -1
package/dist/hook.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `vigiles/hook` — the **closed vocabulary** for authoring a compiled hook.
|
|
3
|
+
*
|
|
4
|
+
* A hook today is opaque shell (`bash guard.sh`): un-analyzable, and the author
|
|
5
|
+
* hand-writes the fragile parts (exit code, JSON field, a `grep` matcher) that
|
|
6
|
+
* cause the #1 verified hook pain — FALSE CONFIDENCE (a guardrail that looks
|
|
7
|
+
* like it blocks but silently doesn't). Invert it: author a **pure typed
|
|
8
|
+
* function** `(event) => Decision` against THIS surface, and `vigiles
|
|
9
|
+
* compile` emits the harness protocol for you. The whole false-confidence
|
|
10
|
+
* class becomes UNREPRESENTABLE — you never write the exit code or the field.
|
|
11
|
+
*
|
|
12
|
+
* The roles, each with its own output type so a category mistake is a `tsc`
|
|
13
|
+
* error, not a silent no-op:
|
|
14
|
+
* - `defineHook` / `defineFileGate` — a **gate** returns a `Decision`
|
|
15
|
+
* (`allow`/`deny`/`ask`); `deny` is the only thing that blocks.
|
|
16
|
+
* - `definePromptGate` — a **prompt gate** (UserPromptSubmit) sees the prompt
|
|
17
|
+
* TEXT and may `deny` to block it (a security filter).
|
|
18
|
+
* - `defineStopGate` — a **stop gate** (Stop/SubagentStop) may `deny` to keep
|
|
19
|
+
* the agent going (gate-until-tests-pass).
|
|
20
|
+
* - `defineInject` — an **inject** returns an `Injection` (context text); it
|
|
21
|
+
* has no `deny`, so "block on a SessionStart hook" won't compile.
|
|
22
|
+
* - `defineReact` — a **react** (PostToolUse) returns a `Reaction`; it sees the
|
|
23
|
+
* tool RESPONSE, its `run(cmd)` is effect-classified at construction, and it
|
|
24
|
+
* can't block (the tool already ran).
|
|
25
|
+
*
|
|
26
|
+
* Every gate takes a `mode`: `enforce` (default, blocks) or `observe` (the
|
|
27
|
+
* shadow/rollout mode — records what it WOULD block, never blocks). `observe` is
|
|
28
|
+
* harness-neutral (it just exits 0 + writes a local record).
|
|
29
|
+
*
|
|
30
|
+
* Matching is AST-backed (`command.runs("git push", { force })`), so it catches
|
|
31
|
+
* `cd x && git push -f` that the native `Bash(git:*)` glob misses.
|
|
32
|
+
*
|
|
33
|
+
* A gate may also decide on EXTERNAL STATE by declaring `needs` (e.g.
|
|
34
|
+
* `needs: ["git.branch"]`): the trusted runtime gathers those read-only facts and
|
|
35
|
+
* hands them in as `e.ctx` — the hook still does zero I/O, and reading an
|
|
36
|
+
* undeclared fact is a `tsc` error. Built-ins:
|
|
37
|
+
* `git.branch`/`git.isDirty`/`git.root`/`cwd`/`os.platform`/`env.isCI`. For a
|
|
38
|
+
* one-off off-catalog fact, the lightweight opt-out is an
|
|
39
|
+
* inline `provide(name, cmd)` (read-only) or `dangerously(name, cmd)` (the loud
|
|
40
|
+
* escape) right in `needs`. See `research/hook-context-providers.md`.
|
|
41
|
+
*
|
|
42
|
+
* ⚠️ Honest scope: compile/verify fix the hook's AUTHORING + LOGIC. They do NOT
|
|
43
|
+
* change DELIVERY — Claude Code's own subagent-bypass (#34692) means a
|
|
44
|
+
* PreToolUse hook (compiled or hand-written) does not fire for a subagent's
|
|
45
|
+
* tool calls. A gate is a strong default, never an unbypassable wall. See
|
|
46
|
+
* `docs/compiled-hooks.md`.
|
|
47
|
+
*/
|
|
48
|
+
export { defineHook, defineFileGate, definePromptGate, defineStopGate, tool, tools, allow, deny, ask, commandView, pathView, gateAction, hookMode, defineInject, inject, defineReact, run, notice, nothing, responseView, decideProgram, decideFileGate, decidePromptGate, decideStopGate, runInject, runReact, runHookProgram, decisionExitCode, dispatchKind, hookRouting, hookNeeds, compileHookProgram, checkHookImports, stampHook, verifyHookStamp, HookCompileError, } from "./core/hook-program.js";
|
|
49
|
+
export type { Decision, HookMode, GateAction, CommandView, PathView, ResponseView, BashToolEvent, FileToolEvent, PromptEvent, StopEvent, ReactEvent, SessionEvent, HookProgram, FileGateHook, PromptGateHook, StopGateHook, InjectHook, ReactHook, AnyHook, DispatchKind, Injection, Reaction, RunReaction, CompiledHookProgram, CompileHookOptions, RawHookEvent, HookProgramOutcome, } from "./core/hook-program.js";
|
|
50
|
+
export { provide, dangerously, defineProvider, provider, } from "./core/hook-providers.js";
|
|
51
|
+
export type { ProviderName, ProviderResults, HookCtx, NeedSpec, InlineProvider, RegisteredProvider, RegisteredRef, ProviderRegistry, } from "./core/hook-providers.js";
|
|
52
|
+
//# sourceMappingURL=hook.d.ts.map
|
package/dist/hook.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.provider = exports.defineProvider = exports.dangerously = exports.provide = exports.HookCompileError = exports.verifyHookStamp = exports.stampHook = exports.checkHookImports = exports.compileHookProgram = exports.hookNeeds = exports.hookRouting = exports.dispatchKind = exports.decisionExitCode = exports.runHookProgram = exports.runReact = exports.runInject = exports.decideStopGate = exports.decidePromptGate = exports.decideFileGate = exports.decideProgram = exports.responseView = exports.nothing = exports.notice = exports.run = exports.defineReact = exports.inject = exports.defineInject = exports.hookMode = exports.gateAction = exports.pathView = exports.commandView = exports.ask = exports.deny = exports.allow = exports.tools = exports.tool = exports.defineStopGate = exports.definePromptGate = exports.defineFileGate = exports.defineHook = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `vigiles/hook` — the **closed vocabulary** for authoring a compiled hook.
|
|
6
|
+
*
|
|
7
|
+
* A hook today is opaque shell (`bash guard.sh`): un-analyzable, and the author
|
|
8
|
+
* hand-writes the fragile parts (exit code, JSON field, a `grep` matcher) that
|
|
9
|
+
* cause the #1 verified hook pain — FALSE CONFIDENCE (a guardrail that looks
|
|
10
|
+
* like it blocks but silently doesn't). Invert it: author a **pure typed
|
|
11
|
+
* function** `(event) => Decision` against THIS surface, and `vigiles
|
|
12
|
+
* compile` emits the harness protocol for you. The whole false-confidence
|
|
13
|
+
* class becomes UNREPRESENTABLE — you never write the exit code or the field.
|
|
14
|
+
*
|
|
15
|
+
* The roles, each with its own output type so a category mistake is a `tsc`
|
|
16
|
+
* error, not a silent no-op:
|
|
17
|
+
* - `defineHook` / `defineFileGate` — a **gate** returns a `Decision`
|
|
18
|
+
* (`allow`/`deny`/`ask`); `deny` is the only thing that blocks.
|
|
19
|
+
* - `definePromptGate` — a **prompt gate** (UserPromptSubmit) sees the prompt
|
|
20
|
+
* TEXT and may `deny` to block it (a security filter).
|
|
21
|
+
* - `defineStopGate` — a **stop gate** (Stop/SubagentStop) may `deny` to keep
|
|
22
|
+
* the agent going (gate-until-tests-pass).
|
|
23
|
+
* - `defineInject` — an **inject** returns an `Injection` (context text); it
|
|
24
|
+
* has no `deny`, so "block on a SessionStart hook" won't compile.
|
|
25
|
+
* - `defineReact` — a **react** (PostToolUse) returns a `Reaction`; it sees the
|
|
26
|
+
* tool RESPONSE, its `run(cmd)` is effect-classified at construction, and it
|
|
27
|
+
* can't block (the tool already ran).
|
|
28
|
+
*
|
|
29
|
+
* Every gate takes a `mode`: `enforce` (default, blocks) or `observe` (the
|
|
30
|
+
* shadow/rollout mode — records what it WOULD block, never blocks). `observe` is
|
|
31
|
+
* harness-neutral (it just exits 0 + writes a local record).
|
|
32
|
+
*
|
|
33
|
+
* Matching is AST-backed (`command.runs("git push", { force })`), so it catches
|
|
34
|
+
* `cd x && git push -f` that the native `Bash(git:*)` glob misses.
|
|
35
|
+
*
|
|
36
|
+
* A gate may also decide on EXTERNAL STATE by declaring `needs` (e.g.
|
|
37
|
+
* `needs: ["git.branch"]`): the trusted runtime gathers those read-only facts and
|
|
38
|
+
* hands them in as `e.ctx` — the hook still does zero I/O, and reading an
|
|
39
|
+
* undeclared fact is a `tsc` error. Built-ins:
|
|
40
|
+
* `git.branch`/`git.isDirty`/`git.root`/`cwd`/`os.platform`/`env.isCI`. For a
|
|
41
|
+
* one-off off-catalog fact, the lightweight opt-out is an
|
|
42
|
+
* inline `provide(name, cmd)` (read-only) or `dangerously(name, cmd)` (the loud
|
|
43
|
+
* escape) right in `needs`. See `research/hook-context-providers.md`.
|
|
44
|
+
*
|
|
45
|
+
* ⚠️ Honest scope: compile/verify fix the hook's AUTHORING + LOGIC. They do NOT
|
|
46
|
+
* change DELIVERY — Claude Code's own subagent-bypass (#34692) means a
|
|
47
|
+
* PreToolUse hook (compiled or hand-written) does not fire for a subagent's
|
|
48
|
+
* tool calls. A gate is a strong default, never an unbypassable wall. See
|
|
49
|
+
* `docs/compiled-hooks.md`.
|
|
50
|
+
*/
|
|
51
|
+
var hook_program_js_1 = require("./core/hook-program.js");
|
|
52
|
+
// gate vocabulary
|
|
53
|
+
Object.defineProperty(exports, "defineHook", { enumerable: true, get: function () { return hook_program_js_1.defineHook; } });
|
|
54
|
+
Object.defineProperty(exports, "defineFileGate", { enumerable: true, get: function () { return hook_program_js_1.defineFileGate; } });
|
|
55
|
+
Object.defineProperty(exports, "definePromptGate", { enumerable: true, get: function () { return hook_program_js_1.definePromptGate; } });
|
|
56
|
+
Object.defineProperty(exports, "defineStopGate", { enumerable: true, get: function () { return hook_program_js_1.defineStopGate; } });
|
|
57
|
+
Object.defineProperty(exports, "tool", { enumerable: true, get: function () { return hook_program_js_1.tool; } });
|
|
58
|
+
Object.defineProperty(exports, "tools", { enumerable: true, get: function () { return hook_program_js_1.tools; } });
|
|
59
|
+
Object.defineProperty(exports, "allow", { enumerable: true, get: function () { return hook_program_js_1.allow; } });
|
|
60
|
+
Object.defineProperty(exports, "deny", { enumerable: true, get: function () { return hook_program_js_1.deny; } });
|
|
61
|
+
Object.defineProperty(exports, "ask", { enumerable: true, get: function () { return hook_program_js_1.ask; } });
|
|
62
|
+
Object.defineProperty(exports, "commandView", { enumerable: true, get: function () { return hook_program_js_1.commandView; } });
|
|
63
|
+
Object.defineProperty(exports, "pathView", { enumerable: true, get: function () { return hook_program_js_1.pathView; } });
|
|
64
|
+
Object.defineProperty(exports, "gateAction", { enumerable: true, get: function () { return hook_program_js_1.gateAction; } });
|
|
65
|
+
Object.defineProperty(exports, "hookMode", { enumerable: true, get: function () { return hook_program_js_1.hookMode; } });
|
|
66
|
+
// inject vocabulary
|
|
67
|
+
Object.defineProperty(exports, "defineInject", { enumerable: true, get: function () { return hook_program_js_1.defineInject; } });
|
|
68
|
+
Object.defineProperty(exports, "inject", { enumerable: true, get: function () { return hook_program_js_1.inject; } });
|
|
69
|
+
// react vocabulary
|
|
70
|
+
Object.defineProperty(exports, "defineReact", { enumerable: true, get: function () { return hook_program_js_1.defineReact; } });
|
|
71
|
+
Object.defineProperty(exports, "run", { enumerable: true, get: function () { return hook_program_js_1.run; } });
|
|
72
|
+
Object.defineProperty(exports, "notice", { enumerable: true, get: function () { return hook_program_js_1.notice; } });
|
|
73
|
+
Object.defineProperty(exports, "nothing", { enumerable: true, get: function () { return hook_program_js_1.nothing; } });
|
|
74
|
+
Object.defineProperty(exports, "responseView", { enumerable: true, get: function () { return hook_program_js_1.responseView; } });
|
|
75
|
+
// runtime + decode (used by the `vigiles hook-runtime run-program` runtime and tests)
|
|
76
|
+
Object.defineProperty(exports, "decideProgram", { enumerable: true, get: function () { return hook_program_js_1.decideProgram; } });
|
|
77
|
+
Object.defineProperty(exports, "decideFileGate", { enumerable: true, get: function () { return hook_program_js_1.decideFileGate; } });
|
|
78
|
+
Object.defineProperty(exports, "decidePromptGate", { enumerable: true, get: function () { return hook_program_js_1.decidePromptGate; } });
|
|
79
|
+
Object.defineProperty(exports, "decideStopGate", { enumerable: true, get: function () { return hook_program_js_1.decideStopGate; } });
|
|
80
|
+
Object.defineProperty(exports, "runInject", { enumerable: true, get: function () { return hook_program_js_1.runInject; } });
|
|
81
|
+
Object.defineProperty(exports, "runReact", { enumerable: true, get: function () { return hook_program_js_1.runReact; } });
|
|
82
|
+
Object.defineProperty(exports, "runHookProgram", { enumerable: true, get: function () { return hook_program_js_1.runHookProgram; } });
|
|
83
|
+
Object.defineProperty(exports, "decisionExitCode", { enumerable: true, get: function () { return hook_program_js_1.decisionExitCode; } });
|
|
84
|
+
Object.defineProperty(exports, "dispatchKind", { enumerable: true, get: function () { return hook_program_js_1.dispatchKind; } });
|
|
85
|
+
Object.defineProperty(exports, "hookRouting", { enumerable: true, get: function () { return hook_program_js_1.hookRouting; } });
|
|
86
|
+
Object.defineProperty(exports, "hookNeeds", { enumerable: true, get: function () { return hook_program_js_1.hookNeeds; } });
|
|
87
|
+
// compile + integrity
|
|
88
|
+
Object.defineProperty(exports, "compileHookProgram", { enumerable: true, get: function () { return hook_program_js_1.compileHookProgram; } });
|
|
89
|
+
Object.defineProperty(exports, "checkHookImports", { enumerable: true, get: function () { return hook_program_js_1.checkHookImports; } });
|
|
90
|
+
Object.defineProperty(exports, "stampHook", { enumerable: true, get: function () { return hook_program_js_1.stampHook; } });
|
|
91
|
+
Object.defineProperty(exports, "verifyHookStamp", { enumerable: true, get: function () { return hook_program_js_1.verifyHookStamp; } });
|
|
92
|
+
Object.defineProperty(exports, "HookCompileError", { enumerable: true, get: function () { return hook_program_js_1.HookCompileError; } });
|
|
93
|
+
var hook_providers_js_1 = require("./core/hook-providers.js");
|
|
94
|
+
Object.defineProperty(exports, "provide", { enumerable: true, get: function () { return hook_providers_js_1.provide; } });
|
|
95
|
+
Object.defineProperty(exports, "dangerously", { enumerable: true, get: function () { return hook_providers_js_1.dangerously; } });
|
|
96
|
+
Object.defineProperty(exports, "defineProvider", { enumerable: true, get: function () { return hook_providers_js_1.defineProvider; } });
|
|
97
|
+
Object.defineProperty(exports, "provider", { enumerable: true, get: function () { return hook_providers_js_1.provider; } });
|
|
98
|
+
//# sourceMappingURL=hook.js.map
|
package/dist/leaderboard.d.ts
CHANGED
|
@@ -32,4 +32,10 @@ export declare function scoreReport(r: ScanReport): {
|
|
|
32
32
|
export declare function rankPlugins(dirs: readonly string[]): PluginScore[];
|
|
33
33
|
/** Format a ranked leaderboard as human-readable text. */
|
|
34
34
|
export declare function formatLeaderboard(scores: readonly PluginScore[]): string;
|
|
35
|
+
/**
|
|
36
|
+
* Format a ranked leaderboard as a Markdown table — the PUBLISHABLE form (a README,
|
|
37
|
+
* a gist, the leaderboard site). Shows the top 2 deductions per plugin; the full
|
|
38
|
+
* breakdown is in `--json`. Sibling of the plain-text {@link formatLeaderboard}.
|
|
39
|
+
*/
|
|
40
|
+
export declare function formatLeaderboardMarkdown(scores: readonly PluginScore[]): string;
|
|
35
41
|
//# sourceMappingURL=leaderboard.d.ts.map
|
package/dist/leaderboard.js
CHANGED
|
@@ -16,8 +16,27 @@ exports.gradeFor = gradeFor;
|
|
|
16
16
|
exports.scoreReport = scoreReport;
|
|
17
17
|
exports.rankPlugins = rankPlugins;
|
|
18
18
|
exports.formatLeaderboard = formatLeaderboard;
|
|
19
|
+
exports.formatLeaderboardMarkdown = formatLeaderboardMarkdown;
|
|
20
|
+
const node_fs_1 = require("node:fs");
|
|
19
21
|
const node_path_1 = require("node:path");
|
|
20
22
|
const scan_js_1 = require("./scan.js");
|
|
23
|
+
/** The plugin's declared name (`.claude-plugin/plugin.json`), for a real label in
|
|
24
|
+
* the ranking instead of a SHA-pinned dir basename. Falls back to the basename. */
|
|
25
|
+
function pluginLabel(dir) {
|
|
26
|
+
const p = (0, node_path_1.join)(dir, ".claude-plugin", "plugin.json");
|
|
27
|
+
if ((0, node_fs_1.existsSync)(p)) {
|
|
28
|
+
try {
|
|
29
|
+
const name = JSON.parse((0, node_fs_1.readFileSync)(p, "utf-8"))
|
|
30
|
+
.name;
|
|
31
|
+
if (typeof name === "string" && name.length > 0)
|
|
32
|
+
return name;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// fall through to the basename
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return (0, node_path_1.basename)(dir) || dir;
|
|
39
|
+
}
|
|
21
40
|
// Penalty weights — broken-at-runtime costs most, footguns less, nudges least.
|
|
22
41
|
const W_MISSING_HOOK = 15; // a hook script that doesn't exist → never runs
|
|
23
42
|
const W_NO_DESCRIPTION = 10; // a skill with no usable description → can't trigger
|
|
@@ -139,7 +158,7 @@ function rankPlugins(dirs) {
|
|
|
139
158
|
const { score, issues } = scoreReport(report);
|
|
140
159
|
return {
|
|
141
160
|
dir,
|
|
142
|
-
name: (
|
|
161
|
+
name: pluginLabel(dir),
|
|
143
162
|
score,
|
|
144
163
|
grade: gradeFor(score),
|
|
145
164
|
issues,
|
|
@@ -164,4 +183,27 @@ function formatLeaderboard(scores) {
|
|
|
164
183
|
out.push("", "Structural health only (no model). Weights: missing hook -15, no-description", "skill -10, broken intra-plugin ref -8, agent-without-tool-contract -5,", "untested surface -3.");
|
|
165
184
|
return out.join("\n");
|
|
166
185
|
}
|
|
186
|
+
const LEADERBOARD_METHOD = "_Structural health only (deterministic, no model): missing hook −15, " +
|
|
187
|
+
"no-description skill −10, broken intra-plugin ref −8, " +
|
|
188
|
+
"agent-without-tool-contract −5, untested surface −3. " +
|
|
189
|
+
"Behavioural columns (trigger-rate, collisions, egress) stack on top._";
|
|
190
|
+
/**
|
|
191
|
+
* Format a ranked leaderboard as a Markdown table — the PUBLISHABLE form (a README,
|
|
192
|
+
* a gist, the leaderboard site). Shows the top 2 deductions per plugin; the full
|
|
193
|
+
* breakdown is in `--json`. Sibling of the plain-text {@link formatLeaderboard}.
|
|
194
|
+
*/
|
|
195
|
+
function formatLeaderboardMarkdown(scores) {
|
|
196
|
+
const lines = [
|
|
197
|
+
`### Plugin health leaderboard (${String(scores.length)} scanned)`,
|
|
198
|
+
"",
|
|
199
|
+
"| # | grade | score | plugin | top issues |",
|
|
200
|
+
"| --: | :--: | --: | :-- | :-- |",
|
|
201
|
+
];
|
|
202
|
+
scores.forEach((s, i) => {
|
|
203
|
+
const issues = s.issues.length > 0 ? s.issues.slice(0, 2).join("; ") : "— clean";
|
|
204
|
+
lines.push(`| ${String(i + 1)} | ${s.grade} | ${String(s.score)} | \`${s.name}\` | ${issues} |`);
|
|
205
|
+
});
|
|
206
|
+
lines.push("", LEADERBOARD_METHOD);
|
|
207
|
+
return lines.join("\n");
|
|
208
|
+
}
|
|
167
209
|
//# sourceMappingURL=leaderboard.js.map
|
package/dist/linting.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `vigiles/linting` — Pillar 1 entry point: the **linting layer** for instruction
|
|
3
|
-
* files. Re-exports the spec builders/types
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* files. Re-exports the spec builders/types + the public compile entry points
|
|
4
|
+
* under one concern-named import. This is the canonical pillar-1 surface; the
|
|
5
|
+
* spec builders are also at the package root (`vigiles`).
|
|
6
|
+
*
|
|
7
|
+
* Curated (named, not `export *`) so the internal compiler validators, hash
|
|
8
|
+
* helpers, and the linter cross-reference ENGINE stay out of the public surface,
|
|
9
|
+
* the api reports, and the docs site (the CLI imports those from the source).
|
|
6
10
|
*/
|
|
7
11
|
export * from "./core/spec.js";
|
|
8
|
-
export
|
|
9
|
-
export
|
|
12
|
+
export { compileClaude, compileSkill, compileAgent, compileRailway, CompileError, } from "./core/compile.js";
|
|
13
|
+
export type { CompileClaudeOptions, CompileClaudeResult, CompileSkillResult, CompileAgentResult, CompileRailwayOptions, CompileRailwayResult, } from "./core/compile.js";
|
|
10
14
|
//# sourceMappingURL=linting.d.ts.map
|
package/dist/linting.js
CHANGED
|
@@ -14,13 +14,25 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.compileRailway = exports.compileAgent = exports.compileSkill = exports.compileClaude = void 0;
|
|
17
18
|
/**
|
|
18
19
|
* `vigiles/linting` — Pillar 1 entry point: the **linting layer** for instruction
|
|
19
|
-
* files. Re-exports the spec builders/types
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* files. Re-exports the spec builders/types + the public compile entry points
|
|
21
|
+
* under one concern-named import. This is the canonical pillar-1 surface; the
|
|
22
|
+
* spec builders are also at the package root (`vigiles`).
|
|
23
|
+
*
|
|
24
|
+
* Curated (named, not `export *`) so the internal compiler validators, hash
|
|
25
|
+
* helpers, and the linter cross-reference ENGINE stay out of the public surface,
|
|
26
|
+
* the api reports, and the docs site (the CLI imports those from the source).
|
|
22
27
|
*/
|
|
28
|
+
// The spec authoring builders (claude/enforce/guidance/file/cmd/agent/skill/…).
|
|
23
29
|
__exportStar(require("./core/spec.js"), exports);
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
// Compile: only the public entry points + their option/result types.
|
|
31
|
+
var compile_js_1 = require("./core/compile.js");
|
|
32
|
+
Object.defineProperty(exports, "compileClaude", { enumerable: true, get: function () { return compile_js_1.compileClaude; } });
|
|
33
|
+
Object.defineProperty(exports, "compileSkill", { enumerable: true, get: function () { return compile_js_1.compileSkill; } });
|
|
34
|
+
Object.defineProperty(exports, "compileAgent", { enumerable: true, get: function () { return compile_js_1.compileAgent; } });
|
|
35
|
+
Object.defineProperty(exports, "compileRailway", { enumerable: true, get: function () { return compile_js_1.compileRailway; } });
|
|
36
|
+
// core/linters is the cross-reference ENGINE (checkLinterRule/editDistance/…),
|
|
37
|
+
// consumed by compile — not part of the public authoring surface.
|
|
26
38
|
//# sourceMappingURL=linting.js.map
|
package/dist/optimize.js
CHANGED
|
@@ -66,7 +66,7 @@ const ACTION_LABEL = {
|
|
|
66
66
|
fix: "FIX",
|
|
67
67
|
differentiate: "DIFFERENTIATE",
|
|
68
68
|
};
|
|
69
|
-
const measureHint = (dir) => `\`vigiles
|
|
69
|
+
const measureHint = (dir) => `\`vigiles measure ${dir} --prompts=<file>\` — real-model, runs on your subscription`;
|
|
70
70
|
/** Render an optimization plan for the CLI. */
|
|
71
71
|
function formatOptimize(rep) {
|
|
72
72
|
const head = `Harness health: ${String(rep.score)}/100 (${rep.grade}) — ${rep.dir}`;
|
package/dist/scaffold-test.js
CHANGED
|
@@ -45,21 +45,35 @@ function header(title, run) {
|
|
|
45
45
|
function hookScaffold(input) {
|
|
46
46
|
const cmd = input.hookCommand ?? `bash ${input.path}`;
|
|
47
47
|
return `${header(`Starter unit test for the \`${input.name}\` hook.`, `npx vigiles test ${suggestedPath(input)}`)}
|
|
48
|
-
import {
|
|
48
|
+
import {
|
|
49
|
+
runHook,
|
|
50
|
+
assertHookAllowed,
|
|
51
|
+
verifyGuardrail,
|
|
52
|
+
formatGuardrailReport,
|
|
53
|
+
// assertBlocksDisasters, // uncomment to gate CI on the battery (see below)
|
|
54
|
+
} from "vigiles/unit";
|
|
55
|
+
|
|
56
|
+
const cmd = ${JSON.stringify(cmd)};
|
|
49
57
|
|
|
58
|
+
// 1) A benign event should pass through.
|
|
50
59
|
// TODO: set the event + input your hook actually inspects (PreToolUse/Bash shown).
|
|
51
|
-
const
|
|
60
|
+
const benign = {
|
|
52
61
|
hook_event_name: "PreToolUse",
|
|
53
62
|
tool_name: "Bash",
|
|
54
63
|
tool_input: { command: "echo hello" },
|
|
55
64
|
};
|
|
65
|
+
assertHookAllowed(runHook(cmd, benign));
|
|
66
|
+
console.log("✓ ${input.name}: allowed the benign event");
|
|
56
67
|
|
|
57
|
-
|
|
68
|
+
// 2) SAFETY: if this is a guard, PROVE it blocks the dangerous battery (the #1 hook
|
|
69
|
+
// pain is a guard that silently doesn't — exit 1 instead of 2, wrong jq path, …).
|
|
70
|
+
// This prints a coverage map; it does NOT fail by default (your hook may not be
|
|
71
|
+
// meant to block all of these).
|
|
72
|
+
console.log(formatGuardrailReport(cmd, verifyGuardrail(cmd)));
|
|
58
73
|
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
console.log("✓ ${input.name}: hook allowed the benign event");
|
|
74
|
+
// 3) To GATE CI: declare what this guard MUST block, then assert it. Uncomment +
|
|
75
|
+
// pick the categories your hook is responsible for:
|
|
76
|
+
// assertBlocksDisasters(cmd, { categories: ["destructive-git"] });
|
|
63
77
|
`;
|
|
64
78
|
}
|
|
65
79
|
/** A skill → the eval tier (`measureTriggerRate`): does its description FIRE? */
|
|
@@ -70,4 +70,64 @@ export declare function probePluginTriggersWith(dir: string, promptSet: TriggerP
|
|
|
70
70
|
export declare function probePluginTriggers(dir: string, promptSet: TriggerPromptSet, opts?: ProbeOptions): Promise<BehavioralReport>;
|
|
71
71
|
/** Format the behavioral column as a scan-report section. */
|
|
72
72
|
export declare function formatBehavioralReport(b: BehavioralReport): string;
|
|
73
|
+
/** Knobs for the selection-collision measurement. */
|
|
74
|
+
export interface SelectionOptions {
|
|
75
|
+
/** Repeats per prompt (default 1). */
|
|
76
|
+
readonly trials?: number;
|
|
77
|
+
/** Selector model — defaults to Sonnet (a weaker model under-selects). */
|
|
78
|
+
readonly model?: string;
|
|
79
|
+
/** Parallel runs across the prompts × trials grid (default 1). */
|
|
80
|
+
readonly concurrency?: number;
|
|
81
|
+
/** Which harness drives it (default `"claude-code"`; others report n/a). */
|
|
82
|
+
readonly harness?: ProbeHarness;
|
|
83
|
+
}
|
|
84
|
+
/** One run's outcome for the matrix: which of the plugin's OWN skills fired. */
|
|
85
|
+
interface SelectionRun {
|
|
86
|
+
readonly intended: string;
|
|
87
|
+
readonly firedBare: readonly string[];
|
|
88
|
+
}
|
|
89
|
+
export interface SkillSelectionStat {
|
|
90
|
+
readonly skill: string;
|
|
91
|
+
/** Fraction of its own prompts on which it fired (matrix diagonal). */
|
|
92
|
+
readonly recall: number;
|
|
93
|
+
/** Fraction of its own prompts on which a SIBLING skill also/instead fired. */
|
|
94
|
+
readonly collisionRate: number;
|
|
95
|
+
/** Non-errored runs measured for this skill. */
|
|
96
|
+
readonly n: number;
|
|
97
|
+
/** Sibling skills that fired on this skill's prompts, by rate (desc, rate>0). */
|
|
98
|
+
readonly collidesWith: readonly {
|
|
99
|
+
readonly skill: string;
|
|
100
|
+
readonly rate: number;
|
|
101
|
+
}[];
|
|
102
|
+
}
|
|
103
|
+
export interface SelectionReport {
|
|
104
|
+
/** False when the harness CLI / auth is absent, or the harness has no selector. */
|
|
105
|
+
readonly available: boolean;
|
|
106
|
+
/** Matrix axes — the plugin's model-invocable skill names (bare). */
|
|
107
|
+
readonly skills: readonly string[];
|
|
108
|
+
/** matrix[i][j] = times skill j fired when skill i's prompt was given. */
|
|
109
|
+
readonly matrix: readonly (readonly number[])[];
|
|
110
|
+
readonly perSkill: readonly SkillSelectionStat[];
|
|
111
|
+
/** Plugin-level: fraction of all runs where a non-intended skill fired. */
|
|
112
|
+
readonly collisionRate: number;
|
|
113
|
+
readonly n: number;
|
|
114
|
+
readonly note?: string;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Pure aggregation: fold per-run fired-skill sets into the N×N selection matrix +
|
|
118
|
+
* per-skill recall/collision + the plugin-level collision rate. Separated from the
|
|
119
|
+
* model-driving so it's unit-testable with synthetic runs (no model).
|
|
120
|
+
*/
|
|
121
|
+
export declare function buildSelectionReport(skills: readonly string[], runs: readonly SelectionRun[]): SelectionReport;
|
|
122
|
+
/** The injectable core (for tests): drive the matrix via a fake/real probe. */
|
|
123
|
+
export declare function measurePluginSelectionWith(dir: string, promptSet: TriggerPromptSet, probe: HarnessProbe, opts?: SelectionOptions): Promise<SelectionReport>;
|
|
124
|
+
/**
|
|
125
|
+
* Measure a plugin's cross-skill selection-collision matrix against the real
|
|
126
|
+
* harness (Claude Code only — Codex has no skill-selection event). Needs the
|
|
127
|
+
* `claude` CLI + model auth; degrades to `available: false` otherwise.
|
|
128
|
+
*/
|
|
129
|
+
export declare function measurePluginSelection(dir: string, promptSet: TriggerPromptSet, opts?: SelectionOptions): Promise<SelectionReport>;
|
|
130
|
+
/** Format the selection-collision matrix as a scan-report section. */
|
|
131
|
+
export declare function formatSelectionReport(r: SelectionReport): string;
|
|
132
|
+
export {};
|
|
73
133
|
//# sourceMappingURL=scan-behavioral.d.ts.map
|