vigiles 12.0.0 → 12.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.
Files changed (40) hide show
  1. package/README.md +22 -11
  2. package/action.yml +73 -0
  3. package/dist/audit-report.d.ts +11 -0
  4. package/dist/audit-report.js +1 -0
  5. package/dist/audit-report.template.html +36 -26
  6. package/dist/claude-code.d.ts +2 -0
  7. package/dist/claude-code.js +9 -1
  8. package/dist/cli-commands.d.ts +1 -1
  9. package/dist/cli-commands.js +0 -1
  10. package/dist/cli.js +96 -135
  11. package/dist/core/rule-meta.js +8 -0
  12. package/dist/core/skill-description-budget.d.ts +42 -0
  13. package/dist/core/skill-description-budget.js +47 -0
  14. package/dist/core/types.d.ts +9 -0
  15. package/dist/core/validate.js +3 -0
  16. package/dist/doc-command-coverage.d.ts +20 -0
  17. package/dist/doc-command-coverage.js +60 -0
  18. package/dist/eval-cost.d.ts +75 -0
  19. package/dist/eval-cost.js +134 -0
  20. package/dist/eval.d.ts +4 -0
  21. package/dist/eval.js +46 -6
  22. package/dist/observe.d.ts +109 -0
  23. package/dist/observe.js +164 -0
  24. package/dist/research-index.d.ts +31 -0
  25. package/dist/research-index.js +48 -0
  26. package/dist/scaffold-test.js +3 -2
  27. package/dist/scan-behavioral.d.ts +42 -0
  28. package/dist/scan-behavioral.js +67 -0
  29. package/dist/scan.d.ts +3 -23
  30. package/dist/scan.js +18 -69
  31. package/dist/setup-plan.d.ts +1 -1
  32. package/dist/setup-plan.js +1 -0
  33. package/package.json +1 -1
  34. package/skills/adopt-spec/SKILL.md +10 -1
  35. package/skills/debug-my-harness/SKILL.md +56 -0
  36. package/skills/edit-spec/SKILL.md +1 -0
  37. package/skills/strengthen/SKILL.md +4 -0
  38. package/skills/test-harness/SKILL.md +17 -0
  39. package/dist/core/hook-spec.d.ts +0 -74
  40. package/dist/core/hook-spec.js +0 -130
@@ -1,74 +0,0 @@
1
- /** A hook's declared side-effect posture. */
2
- export type HookEffect = "observe" | "mutate";
3
- /** A declared hook (the typed source the compiler reads). */
4
- export interface HookSpec {
5
- /** The harness event, e.g. "PreToolUse" | "PostToolUse". */
6
- readonly event: string;
7
- /** The tool name(s) the hook matches, e.g. ["Bash"] or ["Edit", "Write"]. */
8
- readonly match: readonly string[];
9
- /** The `tool_input` fields the hook extracts (must exist on the matched tools). */
10
- readonly reads: readonly string[];
11
- /** Observe-only (a gate/checker) or allowed to mutate (an action runner). */
12
- readonly effect: HookEffect;
13
- /** Optional command the hook runs — classified against {@link effect}. */
14
- readonly run?: string;
15
- }
16
- /** Build a hook spec (the untyped on-ramp; see `hookFor` for the typed one). */
17
- export declare const hook: (spec: HookSpec) => HookSpec;
18
- /** tool name → the `tool_input` fields it carries (injected; harness-specific). */
19
- export type ToolFieldCatalog = Record<string, readonly string[]>;
20
- export interface HookIssue {
21
- readonly severity: "error" | "warning";
22
- readonly message: string;
23
- }
24
- export interface ValidateHookOptions {
25
- /** The per-tool `tool_input` field catalog for the active harness. */
26
- readonly toolFields: ToolFieldCatalog;
27
- /** The harness's known event names (optional — skips the event check if absent). */
28
- readonly events?: readonly string[];
29
- }
30
- /**
31
- * Validate a hook spec — the compiler half. Flags wrong-field extraction (Check 1)
32
- * and effect misdeclaration (Check 2), plus an unknown event when `events` is given.
33
- * Pure; the same checks `compileHook` enforces before emitting.
34
- */
35
- export declare function validateHook(spec: HookSpec, opts: ValidateHookOptions): HookIssue[];
36
- /** A settings `hooks` block keyed by the spec's event (the generated artifact). */
37
- export interface CompiledHook {
38
- readonly hooks: Record<string, readonly {
39
- readonly matcher: string;
40
- readonly hooks: readonly {
41
- readonly type: "command";
42
- readonly command: string;
43
- }[];
44
- }[]>;
45
- /** field → the extraction expression a generated hook would use (the typed read). */
46
- readonly extractions: Record<string, string>;
47
- }
48
- export declare class HookCompileError extends Error {
49
- }
50
- /**
51
- * Compile a validated hook to its settings block. Refuses (throws) on any error-level
52
- * issue — "an unsafe hook doesn't compile" — so a wrong-field read or a mutating
53
- * observe-hook never ships. The `extractions` map shows the correctly-typed field
54
- * reads the generated hook uses (here as jq paths) — never a hand-typed `jq` string.
55
- */
56
- export declare function compileHook(spec: HookSpec, opts: ValidateHookOptions & {
57
- gateCommand?: string;
58
- }): CompiledHook;
59
- /**
60
- * The typed source for a hook over a field map `M` (tool → field-union) and the
61
- * matched tool(s) `T`. `reads` is constrained to the fields of `T` — a field absent
62
- * from the matched tool is a tsc error. `M` stays unconstrained so a plain interface
63
- * (no index signature) works as the field map.
64
- */
65
- export interface TypedHookSpec<M, T extends keyof M & string> {
66
- readonly event: string;
67
- readonly match: readonly T[];
68
- readonly reads: readonly Extract<M[T], string>[];
69
- readonly effect: HookEffect;
70
- readonly run?: string;
71
- }
72
- /** Build a typed hook; `reads` outside the matched tool's field-union won't compile. */
73
- export declare function hookFor<M, T extends keyof M & string>(spec: TypedHookSpec<M, T>): HookSpec;
74
- //# sourceMappingURL=hook-spec.d.ts.map
@@ -1,130 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HookCompileError = exports.hook = void 0;
4
- exports.validateHook = validateHook;
5
- exports.compileHook = compileHook;
6
- exports.hookFor = hookFor;
7
- /**
8
- * SPIKE — typed, effect-classified HOOKS (the "type-safe bash" angle).
9
- *
10
- * A Claude Code / Codex hook today is hand-written shell in settings.json. Two
11
- * silent footguns dominate, and both are exactly what a COMPILER catches:
12
- *
13
- * 1. WRONG-FIELD EXTRACTION (silent no-op). A PreToolUse event's `tool_input`
14
- * shape depends on the matched tool — `Bash` carries `command`, `Edit`/`Write`
15
- * carry `file_path`. A hook that matches `Bash` but does
16
- * `jq '.tool_input.file_path'` extracts EMPTY forever and never fires; nothing
17
- * tells you. `validateHook` makes "read a field the matched tool never provides"
18
- * an error, and the typed `hookFor` builder makes it a tsc error at edit time.
19
- *
20
- * 2. EFFECT MISDECLARATION ("type-safe bash"). A hook declared observe-only (a
21
- * read-only gate/checker) that actually RUNS a mutating command — `eslint --fix`,
22
- * `git push` — is a side effect masquerading as an observation. We already own a
23
- * deterministic Bash-effect classifier (`bash-effects.ts`), so the command's
24
- * effect class becomes a TYPE: an `effect: "observe"` hook whose `run` command
25
- * classifies as side-effecting/undecidable does NOT compile. No other plugin
26
- * tool has the classifier to make that judgment.
27
- *
28
- * Pure core, harness-agnostic: the per-tool field catalog is INJECTED (a Codex hook
29
- * has different fields), and the Bash classifier is the harness-neutral one. The CC
30
- * field catalog + the typed edit-time builder live in the test (no CC literal in core).
31
- *
32
- * NOT wired to the CLI/public API — a spike to see whether the compile step earns its
33
- * keep on the hook surface. See research/harness-protocol-flow-moat.md.
34
- */
35
- const bash_effects_js_1 = require("./bash-effects.js");
36
- /** Build a hook spec (the untyped on-ramp; see `hookFor` for the typed one). */
37
- const hook = (spec) => spec;
38
- exports.hook = hook;
39
- /** Which matched tools actually carry `field`. */
40
- function toolsProviding(field, match, toolFields) {
41
- return match.filter((t) => (toolFields[t] ?? []).includes(field));
42
- }
43
- /** Check 1 — every read field exists on the matched tool(s). */
44
- function fieldIssues(spec, toolFields) {
45
- const out = [];
46
- for (const field of spec.reads) {
47
- const providers = toolsProviding(field, spec.match, toolFields);
48
- if (providers.length === 0) {
49
- out.push({
50
- severity: "error",
51
- message: `reads "${field}" but no matched tool (${spec.match.join("|")}) provides it — the extraction is always empty (silent no-op)`,
52
- });
53
- }
54
- else if (providers.length < spec.match.length) {
55
- const missing = spec.match.filter((t) => !providers.includes(t));
56
- out.push({
57
- severity: "warning",
58
- message: `reads "${field}", which ${missing.join("/")} does not carry — empty on those events`,
59
- });
60
- }
61
- }
62
- return out;
63
- }
64
- /** Check 2 — an observe-only hook's command must be provably read-only. */
65
- function effectIssues(spec) {
66
- if (spec.effect !== "observe" || spec.run === undefined)
67
- return [];
68
- const cls = (0, bash_effects_js_1.classifyBashCommand)(spec.run);
69
- if (cls === "read-only")
70
- return [];
71
- return [
72
- {
73
- severity: "error",
74
- message: `declared observe-only but its command is ${cls}: "${spec.run}" — an observe hook must not mutate (use effect:"mutate" or a read-only command)`,
75
- },
76
- ];
77
- }
78
- /**
79
- * Validate a hook spec — the compiler half. Flags wrong-field extraction (Check 1)
80
- * and effect misdeclaration (Check 2), plus an unknown event when `events` is given.
81
- * Pure; the same checks `compileHook` enforces before emitting.
82
- */
83
- function validateHook(spec, opts) {
84
- const out = [];
85
- if (opts.events && !opts.events.includes(spec.event)) {
86
- out.push({
87
- severity: "error",
88
- message: `unknown event "${spec.event}" — it will never fire`,
89
- });
90
- }
91
- out.push(...fieldIssues(spec, opts.toolFields));
92
- out.push(...effectIssues(spec));
93
- return out;
94
- }
95
- class HookCompileError extends Error {
96
- }
97
- exports.HookCompileError = HookCompileError;
98
- /**
99
- * Compile a validated hook to its settings block. Refuses (throws) on any error-level
100
- * issue — "an unsafe hook doesn't compile" — so a wrong-field read or a mutating
101
- * observe-hook never ships. The `extractions` map shows the correctly-typed field
102
- * reads the generated hook uses (here as jq paths) — never a hand-typed `jq` string.
103
- */
104
- function compileHook(spec, opts) {
105
- const issues = validateHook(spec, opts);
106
- const errors = issues.filter((i) => i.severity === "error");
107
- if (errors.length > 0) {
108
- throw new HookCompileError(`hook does not compile:\n ${errors.map((e) => e.message).join("\n ")}`);
109
- }
110
- const command = opts.gateCommand ?? "npx vigiles hook-runtime guard";
111
- const extractions = {};
112
- for (const field of spec.reads)
113
- extractions[field] = `.tool_input.${field}`;
114
- return {
115
- hooks: {
116
- [spec.event]: [
117
- {
118
- matcher: spec.match.join("|"),
119
- hooks: [{ type: "command", command }],
120
- },
121
- ],
122
- },
123
- extractions,
124
- };
125
- }
126
- /** Build a typed hook; `reads` outside the matched tool's field-union won't compile. */
127
- function hookFor(spec) {
128
- return spec;
129
- }
130
- //# sourceMappingURL=hook-spec.js.map