vigiles 15.0.3 → 15.2.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/cli.js +108 -10
- package/dist/core/bash-effects.d.ts +20 -0
- package/dist/core/bash-effects.js +41 -1
- package/dist/core/hook-program.d.ts +167 -28
- package/dist/core/hook-program.js +251 -37
- package/dist/core/hook-providers.d.ts +22 -5
- package/dist/core/hook-providers.js +13 -1
- package/dist/core/hook-state.d.ts +307 -0
- package/dist/core/hook-state.js +349 -0
- package/dist/core/sidecar.d.ts +16 -0
- package/dist/core/sidecar.js +23 -8
- package/dist/hook.d.ts +3 -1
- package/dist/hook.js +18 -1
- package/package.json +1 -1
package/dist/core/sidecar.d.ts
CHANGED
|
@@ -30,6 +30,22 @@ export declare function computePerFileHashes(inputFiles: string[], basePath: str
|
|
|
30
30
|
* Recurses so that nested targets (e.g. `.github/copilot-instructions.md`,
|
|
31
31
|
* which lives at `.vigiles/.github/copilot-instructions.md.inputs.json`)
|
|
32
32
|
* are not silently skipped.
|
|
33
|
+
*
|
|
34
|
+
* 🔴 A DIRECTORY SYMLINK IS NOT DESCENDED INTO — this walk classified entries
|
|
35
|
+
* with a bare `statSync().isDirectory()`, which FOLLOWS a link, so a link inside
|
|
36
|
+
* `.vigiles/` pointing at a directory OUTSIDE it was walked (manifests from a
|
|
37
|
+
* foreign tree entering the audit under reconstructed target names), and a cycle
|
|
38
|
+
* — `.vigiles/loop -> .vigiles`, or a link to any ancestor — re-walked the same
|
|
39
|
+
* tree once per lap. Measured 2026-08-13 by reverting this call: ONE manifest was
|
|
40
|
+
* reported FORTY-ONE times, as `Real.md`, `loop/Real.md`, `loop/loop/Real.md` …
|
|
41
|
+
* until the kernel's link limit stopped it. Unlike the loader's walk it did not
|
|
42
|
+
* throw, and that is not a mitigation: the `catch` below swallowed the `ELOOP` and
|
|
43
|
+
* turned a crash into a silently multiplied audit. Third instance of the class in
|
|
44
|
+
* this repo; the decision is {@link entryOf} in `fs-walk.ts`, which carries the
|
|
45
|
+
* full rationale: a symlinked FILE is still read (it cannot recurse, and a
|
|
46
|
+
* manifest reached through one is a real manifest), termination is by
|
|
47
|
+
* construction rather than a visited-set, and an unreadable entry is `"skip"`
|
|
48
|
+
* rather than a throw — which is exactly what the `try`/`continue` here did.
|
|
33
49
|
*/
|
|
34
50
|
export declare function iterateSidecars(basePath: string, fn: (target: string, manifest: SidecarManifest) => void): void;
|
|
35
51
|
//# sourceMappingURL=sidecar.d.ts.map
|
package/dist/core/sidecar.js
CHANGED
|
@@ -18,6 +18,7 @@ exports.computePerFileHashes = computePerFileHashes;
|
|
|
18
18
|
exports.iterateSidecars = iterateSidecars;
|
|
19
19
|
const node_fs_1 = require("node:fs");
|
|
20
20
|
const node_path_1 = require("node:path");
|
|
21
|
+
const fs_walk_js_1 = require("../fs-walk.js");
|
|
21
22
|
const hash_js_1 = require("./hash.js");
|
|
22
23
|
const SIDECAR_ROOT = ".vigiles";
|
|
23
24
|
const MANIFEST_SUFFIX = ".inputs.json";
|
|
@@ -60,6 +61,22 @@ function computePerFileHashes(inputFiles, basePath) {
|
|
|
60
61
|
* Recurses so that nested targets (e.g. `.github/copilot-instructions.md`,
|
|
61
62
|
* which lives at `.vigiles/.github/copilot-instructions.md.inputs.json`)
|
|
62
63
|
* are not silently skipped.
|
|
64
|
+
*
|
|
65
|
+
* 🔴 A DIRECTORY SYMLINK IS NOT DESCENDED INTO — this walk classified entries
|
|
66
|
+
* with a bare `statSync().isDirectory()`, which FOLLOWS a link, so a link inside
|
|
67
|
+
* `.vigiles/` pointing at a directory OUTSIDE it was walked (manifests from a
|
|
68
|
+
* foreign tree entering the audit under reconstructed target names), and a cycle
|
|
69
|
+
* — `.vigiles/loop -> .vigiles`, or a link to any ancestor — re-walked the same
|
|
70
|
+
* tree once per lap. Measured 2026-08-13 by reverting this call: ONE manifest was
|
|
71
|
+
* reported FORTY-ONE times, as `Real.md`, `loop/Real.md`, `loop/loop/Real.md` …
|
|
72
|
+
* until the kernel's link limit stopped it. Unlike the loader's walk it did not
|
|
73
|
+
* throw, and that is not a mitigation: the `catch` below swallowed the `ELOOP` and
|
|
74
|
+
* turned a crash into a silently multiplied audit. Third instance of the class in
|
|
75
|
+
* this repo; the decision is {@link entryOf} in `fs-walk.ts`, which carries the
|
|
76
|
+
* full rationale: a symlinked FILE is still read (it cannot recurse, and a
|
|
77
|
+
* manifest reached through one is a real manifest), termination is by
|
|
78
|
+
* construction rather than a visited-set, and an unreadable entry is `"skip"`
|
|
79
|
+
* rather than a throw — which is exactly what the `try`/`continue` here did.
|
|
63
80
|
*/
|
|
64
81
|
function iterateSidecars(basePath, fn) {
|
|
65
82
|
const root = (0, node_path_1.resolve)(basePath, SIDECAR_ROOT);
|
|
@@ -77,17 +94,15 @@ function walk(dir, root, basePath, fn) {
|
|
|
77
94
|
}
|
|
78
95
|
for (const entry of entries) {
|
|
79
96
|
const fullPath = (0, node_path_1.resolve)(dir, entry);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
isDir = (0, node_fs_1.statSync)(fullPath).isDirectory();
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (isDir) {
|
|
97
|
+
const { kind } = (0, fs_walk_js_1.entryOf)(fullPath);
|
|
98
|
+
if (kind === "dir") {
|
|
88
99
|
walk(fullPath, root, basePath, fn);
|
|
89
100
|
continue;
|
|
90
101
|
}
|
|
102
|
+
// "skip" covers what the old bare `statSync` handled by throwing (a dangling
|
|
103
|
+
// link, an unreadable entry) AND the symlinked directory it silently followed.
|
|
104
|
+
if (kind === "skip")
|
|
105
|
+
continue;
|
|
91
106
|
if (!entry.endsWith(MANIFEST_SUFFIX))
|
|
92
107
|
continue;
|
|
93
108
|
// Reconstruct the target name from the path relative to .vigiles/
|
package/dist/hook.d.ts
CHANGED
|
@@ -45,9 +45,11 @@
|
|
|
45
45
|
* tool calls. A gate is a strong default, never an unbypassable wall. See
|
|
46
46
|
* `docs/compiled-hooks.md`.
|
|
47
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";
|
|
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, injectionOf, outcomeWrites, matchesTool, invalidToolPatterns, compileHookProgram, checkHookImports, stampHook, verifyHookStamp, HookCompileError, } from "./core/hook-program.js";
|
|
49
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
50
|
export { provide, dangerously, defineProvider, provider, } from "./core/hook-providers.js";
|
|
51
|
+
export { state, record, stateFact, isValidStateKey, isStateNeed, isStateWrite, admissibleWrites, durationSeconds, HookStateError, } from "./core/hook-state.js";
|
|
52
|
+
export type { StateFact, StateEntry, StateNeed, StateWrite, Duration, } from "./core/hook-state.js";
|
|
51
53
|
export type { ProviderName, ProviderResults, HookCtx, NeedSpec, InlineProvider, RegisteredProvider, RegisteredRef, ProviderRegistry, } from "./core/hook-providers.js";
|
|
52
54
|
export { leafCommandsNormalized } from "./core/bash-effects.js";
|
|
53
55
|
export type { NormalizedLeaf, LeafRedirect } from "./core/bash-effects.js";
|
package/dist/hook.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.isStateWrite = exports.isStateNeed = exports.isValidStateKey = exports.stateFact = exports.record = exports.state = exports.provider = exports.defineProvider = exports.dangerously = exports.provide = exports.HookCompileError = exports.verifyHookStamp = exports.stampHook = exports.checkHookImports = exports.compileHookProgram = exports.invalidToolPatterns = exports.matchesTool = exports.outcomeWrites = exports.injectionOf = 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
|
+
exports.leafCommandsNormalized = exports.HookStateError = exports.durationSeconds = exports.admissibleWrites = void 0;
|
|
4
5
|
/**
|
|
5
6
|
* `vigiles/hook` — the **closed vocabulary** for authoring a compiled hook.
|
|
6
7
|
*
|
|
@@ -84,6 +85,10 @@ Object.defineProperty(exports, "decisionExitCode", { enumerable: true, get: func
|
|
|
84
85
|
Object.defineProperty(exports, "dispatchKind", { enumerable: true, get: function () { return hook_program_js_1.dispatchKind; } });
|
|
85
86
|
Object.defineProperty(exports, "hookRouting", { enumerable: true, get: function () { return hook_program_js_1.hookRouting; } });
|
|
86
87
|
Object.defineProperty(exports, "hookNeeds", { enumerable: true, get: function () { return hook_program_js_1.hookNeeds; } });
|
|
88
|
+
Object.defineProperty(exports, "injectionOf", { enumerable: true, get: function () { return hook_program_js_1.injectionOf; } });
|
|
89
|
+
Object.defineProperty(exports, "outcomeWrites", { enumerable: true, get: function () { return hook_program_js_1.outcomeWrites; } });
|
|
90
|
+
Object.defineProperty(exports, "matchesTool", { enumerable: true, get: function () { return hook_program_js_1.matchesTool; } });
|
|
91
|
+
Object.defineProperty(exports, "invalidToolPatterns", { enumerable: true, get: function () { return hook_program_js_1.invalidToolPatterns; } });
|
|
87
92
|
// compile + integrity
|
|
88
93
|
Object.defineProperty(exports, "compileHookProgram", { enumerable: true, get: function () { return hook_program_js_1.compileHookProgram; } });
|
|
89
94
|
Object.defineProperty(exports, "checkHookImports", { enumerable: true, get: function () { return hook_program_js_1.checkHookImports; } });
|
|
@@ -95,6 +100,18 @@ Object.defineProperty(exports, "provide", { enumerable: true, get: function () {
|
|
|
95
100
|
Object.defineProperty(exports, "dangerously", { enumerable: true, get: function () { return hook_providers_js_1.dangerously; } });
|
|
96
101
|
Object.defineProperty(exports, "defineProvider", { enumerable: true, get: function () { return hook_providers_js_1.defineProvider; } });
|
|
97
102
|
Object.defineProperty(exports, "provider", { enumerable: true, get: function () { return hook_providers_js_1.provider; } });
|
|
103
|
+
// Runtime-owned named state: `state(k)` in `needs` reads a fact, `record(k)` in a
|
|
104
|
+
// return value declares one. The whole design note lives in `core/hook-state.ts`.
|
|
105
|
+
var hook_state_js_1 = require("./core/hook-state.js");
|
|
106
|
+
Object.defineProperty(exports, "state", { enumerable: true, get: function () { return hook_state_js_1.state; } });
|
|
107
|
+
Object.defineProperty(exports, "record", { enumerable: true, get: function () { return hook_state_js_1.record; } });
|
|
108
|
+
Object.defineProperty(exports, "stateFact", { enumerable: true, get: function () { return hook_state_js_1.stateFact; } });
|
|
109
|
+
Object.defineProperty(exports, "isValidStateKey", { enumerable: true, get: function () { return hook_state_js_1.isValidStateKey; } });
|
|
110
|
+
Object.defineProperty(exports, "isStateNeed", { enumerable: true, get: function () { return hook_state_js_1.isStateNeed; } });
|
|
111
|
+
Object.defineProperty(exports, "isStateWrite", { enumerable: true, get: function () { return hook_state_js_1.isStateWrite; } });
|
|
112
|
+
Object.defineProperty(exports, "admissibleWrites", { enumerable: true, get: function () { return hook_state_js_1.admissibleWrites; } });
|
|
113
|
+
Object.defineProperty(exports, "durationSeconds", { enumerable: true, get: function () { return hook_state_js_1.durationSeconds; } });
|
|
114
|
+
Object.defineProperty(exports, "HookStateError", { enumerable: true, get: function () { return hook_state_js_1.HookStateError; } });
|
|
98
115
|
// Operation-normalized leaf extraction — the robust matching primitive a
|
|
99
116
|
// hardened guard is built on (see examples/harness/safe-bash-guard-v2.mjs).
|
|
100
117
|
var bash_effects_js_1 = require("./core/bash-effects.js");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigiles",
|
|
3
|
-
"version": "15.0
|
|
3
|
+
"version": "15.2.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",
|