vigiles 15.0.2 → 15.0.3

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 (82) hide show
  1. package/dist/adapters/claude-code/layout.js +3 -0
  2. package/dist/adapters/claude-code/run-scripts.d.ts +21 -9
  3. package/dist/adapters/claude-code/run-scripts.js +33 -22
  4. package/dist/adapters/codex/driver.js +3 -1
  5. package/dist/adapters/codex/eval.js +5 -0
  6. package/dist/audit-score.js +32 -6
  7. package/dist/check-count.d.ts +62 -3
  8. package/dist/check-count.js +123 -5
  9. package/dist/check.d.ts +55 -0
  10. package/dist/check.js +91 -0
  11. package/dist/cli.js +456 -54
  12. package/dist/core/bash-effects.d.ts +41 -0
  13. package/dist/core/bash-effects.js +278 -0
  14. package/dist/core/foreign-runner.d.ts +185 -0
  15. package/dist/core/foreign-runner.js +228 -0
  16. package/dist/core/harness-driver.d.ts +18 -1
  17. package/dist/core/hook-program.d.ts +319 -20
  18. package/dist/core/hook-program.js +743 -49
  19. package/dist/core/layout.d.ts +13 -0
  20. package/dist/core/lethal-trifecta.d.ts +93 -0
  21. package/dist/core/lethal-trifecta.js +409 -65
  22. package/dist/core/markdown.d.ts +32 -0
  23. package/dist/core/markdown.js +36 -0
  24. package/dist/core/merge-conflict.d.ts +50 -0
  25. package/dist/core/merge-conflict.js +84 -0
  26. package/dist/core/test-file-ext.d.ts +80 -0
  27. package/dist/core/test-file-ext.js +90 -0
  28. package/dist/core/types.d.ts +11 -0
  29. package/dist/coverage-artifact.d.ts +383 -0
  30. package/dist/coverage-artifact.js +586 -0
  31. package/dist/coverage-evidence.d.ts +87 -79
  32. package/dist/coverage-evidence.js +212 -211
  33. package/dist/coverage-probe.d.ts +125 -0
  34. package/dist/coverage-probe.js +700 -0
  35. package/dist/doc-commands.d.ts +119 -0
  36. package/dist/doc-commands.js +158 -0
  37. package/dist/eval-lock.d.ts +9 -0
  38. package/dist/eval-lock.js +14 -2
  39. package/dist/eval.js +28 -0
  40. package/dist/fs-walk.d.ts +80 -0
  41. package/dist/fs-walk.js +148 -0
  42. package/dist/harness-assert.js +42 -3
  43. package/dist/harness-test.js +31 -2
  44. package/dist/judge.js +4 -0
  45. package/dist/leaderboard.d.ts +16 -1
  46. package/dist/leaderboard.js +19 -2
  47. package/dist/load-hook.js +6 -1
  48. package/dist/mock-model.d.ts +58 -4
  49. package/dist/mock-model.js +133 -5
  50. package/dist/observe.d.ts +1 -1
  51. package/dist/observe.js +44 -1
  52. package/dist/plugin-loader.js +52 -13
  53. package/dist/run-hook.d.ts +58 -0
  54. package/dist/run-hook.js +70 -0
  55. package/dist/run-script.js +75 -0
  56. package/dist/scaffold-test.d.ts +3 -0
  57. package/dist/scaffold-test.js +10 -5
  58. package/dist/scan-behavioral.js +4 -0
  59. package/dist/scan-core.d.ts +22 -0
  60. package/dist/scan-core.js +46 -14
  61. package/dist/scan-files.js +19 -2
  62. package/dist/scan.d.ts +22 -5
  63. package/dist/scan.js +67 -13
  64. package/dist/skill-contract.d.ts +46 -0
  65. package/dist/skill-contract.js +201 -0
  66. package/dist/skill-refs.d.ts +67 -0
  67. package/dist/skill-refs.js +117 -0
  68. package/dist/test-coverage-files.d.ts +7 -1
  69. package/dist/test-coverage-files.js +66 -55
  70. package/dist/test-coverage.d.ts +155 -19
  71. package/dist/test-coverage.js +430 -91
  72. package/dist/testing.d.ts +8 -2
  73. package/dist/testing.js +19 -1
  74. package/dist/trigger-containment.d.ts +85 -0
  75. package/dist/trigger-containment.js +125 -0
  76. package/dist/ts-runner-caps.d.ts +16 -0
  77. package/dist/ts-runner-caps.js +43 -0
  78. package/dist/unit.d.ts +2 -2
  79. package/dist/unit.js +2 -1
  80. package/hooks/eval-lock-nudge.sh +14 -6
  81. package/package.json +2 -2
  82. package/skills/test-harness/SKILL.md +68 -2
@@ -50,6 +50,19 @@ export interface PluginLayout {
50
50
  readonly materializeRoot: string;
51
51
  /** Env token expanded to the plugin's absolute root in hook commands. */
52
52
  readonly pluginRootToken: string;
53
+ /**
54
+ * Tokens that root a path at the PROJECT being scanned, braced form
55
+ * (`${CLAUDE_PROJECT_DIR}`); the unbraced spelling is derived. Optional — a
56
+ * harness with no such variable omits it.
57
+ *
58
+ * 🔴 SEPARATE FROM {@link pluginRootToken}, and its absence made a whole
59
+ * surface kind invisible. `hookScripts` stripped only the plugin token, so a
60
+ * project's own `"$CLAUDE_PROJECT_DIR/.claude/hooks/x.sh"` — Claude Code's
61
+ * DOCUMENTED spelling for a project hook, because hooks do not run with a
62
+ * stable cwd — failed `existsSync` and was dropped. MEASURED on a real
63
+ * consumer repo: `audit` listed sixteen hooks and the SURFACE list held zero.
64
+ */
65
+ readonly projectRootTokens?: readonly string[];
53
66
  /** Standalone MCP config file, e.g. `.mcp.json`. */
54
67
  readonly mcpConfigFile: string;
55
68
  /** Manifest key declaring MCP servers, e.g. `mcpServers`. */
@@ -34,6 +34,11 @@
34
34
  * footgun note, not a hard defect), an inherits-all trifecta is reported as
35
35
  * `"advisory"`; an EXPLICIT all-three contract is the `"hard"` flag.
36
36
  *
37
+ * 🔴 SUBAGENTS ONLY. Everything above is the SUBAGENT reading, where `tools:` is a
38
+ * documented rail that really does bound the unit. It is NOT how a SKILL works —
39
+ * a skill's `allowed-tools:` is a PRE-APPROVAL, not a fence. See
40
+ * {@link skillTrifectaIssue} for the skill path and the measurement behind it.
41
+ *
37
42
  * Pure + ONE detector (one-detector-no-drift) — intended to be reused by `scan`
38
43
  * (the read-only audit) and a future `lethal-trifecta` lint rule. The dialect is
39
44
  * injected (core ⊄ adapter) so it generalizes across harnesses (Codex's `shell`
@@ -62,6 +67,19 @@ export interface TrifectaLegs {
62
67
  * reported as advisory in line with the inherits-all stance.
63
68
  */
64
69
  export type TrifectaSeverity = "hard" | "advisory";
70
+ /**
71
+ * How much of a fence a SKILL's `disallowed-tools:` actually is — set only on
72
+ * findings produced by {@link skillTrifectaIssue}, absent on subagent findings.
73
+ *
74
+ * - `"none"` — no `disallowed-tools:` line (or an unreadable block, which yields
75
+ * the same thing): the skill inherits every tool the session grants. This is
76
+ * the DEFAULT state of every skill in the ecosystem, which is why the report
77
+ * aggregates it into one line instead of repeating it per skill.
78
+ * - `"ineffective"` — a `disallowed-tools:` line exists but does not deny every
79
+ * built-in supplier of any one leg, so no leg is closed. That one is per-skill:
80
+ * an author who believed they had fenced and had not.
81
+ */
82
+ export type SkillFenceState = "none" | "ineffective";
65
83
  /**
66
84
  * A lethal-trifecta finding — emitted ONLY when all three legs are non-empty (or,
67
85
  * for the inherits-all case, when the contract inherits all tools). The `legs`
@@ -74,7 +92,38 @@ export interface TrifectaFinding {
74
92
  readonly legs: TrifectaLegs;
75
93
  /** A ready-to-show, actionable message. */
76
94
  readonly message: string;
95
+ /**
96
+ * SKILLS ONLY — the fence state behind the finding ({@link SkillFenceState}).
97
+ * Absent on subagent findings, whose `tools:` rail is a different mechanism.
98
+ * The report reads it to decide aggregate-vs-per-unit presentation.
99
+ */
100
+ readonly fence?: SkillFenceState;
77
101
  }
102
+ /**
103
+ * Does a `Bash(...)` grant still supply the shell's legs — reading a secret and
104
+ * curling it out — or has it been narrowed to a command that cannot?
105
+ *
106
+ * Narrowing the grant is a remedy this tool RECOMMENDS, so the reading has to be able
107
+ * to see a narrowed grant as narrowed: `Bash(node ./scripts/log.mjs:*)` was once read
108
+ * as plain `Bash` — the whole shell, in both leg A and leg C — and an author who took
109
+ * the advice saw the score not move. But the fix for that overshot into the opposite
110
+ * error, and the opposite error is the one that matters (see {@link EFFECT_FREE}), so
111
+ * the answer is now: a grant is bounded ONLY when it pins a program from that list.
112
+ *
113
+ * The honest consequence, stated rather than hidden: narrowing `Bash` to a script of
114
+ * your own (`node ./ledger.mjs`) no longer drops a leg, because nothing here has read
115
+ * that script. The remedy that still works is to drop a leg the checker can SEE — fence
116
+ * the tool off, or narrow to a command whose effects are enumerable.
117
+ *
118
+ * Bash no restriction at all
119
+ * Bash(*) Bash(:*) the wildcard forms
120
+ * Bash(node:*) Bash(node x.mjs:*) an interpreter runs whatever it is handed
121
+ * Bash(sh ...) Bash(curl ...) the shell, and the pinned exfiltrator
122
+ * Bash(echo ready:*) bounded — and only this shape is
123
+ *
124
+ * When in doubt it returns true (keeps the legs): a false "you are exposed" costs the
125
+ * author an argument, a false "you are safe" costs them the finding.
126
+ */
78
127
  export declare function bashGrantIsUnbounded(raw: string): boolean;
79
128
  /**
80
129
  * Classify each tool in a declared contract into the trifecta legs it supplies.
@@ -127,4 +176,48 @@ export interface TrifectaContext {
127
176
  * inherits-all, the `"advisory"` finding. Never the other way round.
128
177
  */
129
178
  export declare function lethalTrifectaIssues(tools: readonly string[], dialect: HarnessDialect, ctx?: TrifectaContext): TrifectaFinding | null;
179
+ /** The legs a `disallowed-tools:` list leaves standing, naming the suppliers. */
180
+ export declare function skillFenceLegs(disallowed: readonly string[], dialect: HarnessDialect): TrifectaLegs;
181
+ /**
182
+ * Whether THIS harness understands a skill-level `disallowed-tools:` at all.
183
+ *
184
+ * Read off the dialect record that already exists — `skillFrontmatter` is exactly
185
+ * "which SKILL.md keys this harness understands", and `disallowed-tools` is one of
186
+ * the Claude-Code-only ones. No new capability flag: a second field saying the
187
+ * same thing is a second thing to keep true, and the compiler already branches on
188
+ * this one (`renderSkillFrontmatter` emits the tool keys under `"claude-code"` and
189
+ * omits them under `"minimal"`).
190
+ */
191
+ export declare function dialectSupportsSkillFence(dialect: HarnessDialect): boolean;
192
+ /**
193
+ * The lethal-trifecta finding for a MODEL-INVOCABLE SKILL, computed from its
194
+ * `disallowed-tools:` — the only skill frontmatter field measured to remove a
195
+ * tool. `allowed-tools:` is not an input here, on purpose: it is a pre-approval,
196
+ * and treating it as a bound is the defect this function exists to correct (see
197
+ * the block comment above for the measurement).
198
+ *
199
+ * 🔴 AND IT IS A CLAUDE-CODE MECHANISM, which this applied to every harness. On a
200
+ * Codex repo (`skillFrontmatter: "minimal"` — name + description only, and our own
201
+ * compiler drops the tool keys there) every skill was reported as holding all
202
+ * three legs, scored against Safety, and handed the remedy "add a
203
+ * `disallowed-tools:` line". That line is INERT in Codex: the author does the
204
+ * work, the harness ignores the key, the finding returns, and the score never
205
+ * moves. A remedy the target cannot apply is worse than no finding — it is a floor
206
+ * dressed up as a defect, and it teaches people that the Safety number is fake.
207
+ *
208
+ * So the detector runs only where the fence exists ({@link dialectSupportsSkillFence}).
209
+ * This is a claim about the MECHANISM, not about the risk: a Codex skill really
210
+ * does hold every leg, and bounding it is a session/config-level question that
211
+ * belongs to a Codex-specific detector, not to a Claude Code one applied by
212
+ * default. Subagent findings are unaffected — `tools:` is a different mechanism,
213
+ * with its own dialect handling.
214
+ *
215
+ * @param disallowed `disallowed-tools:` as declared, or `null` when the line is
216
+ * absent — the two are NOT the same: an explicit empty list still denies nothing,
217
+ * but the message should not tell an author who wrote the line that they didn't.
218
+ * @returns `null` once the fence closes at least one leg (Rule of Two satisfied,
219
+ * among the built-ins — see {@link FENCE_SUPPLIERS} for the stated limit), and
220
+ * `null` for any harness with no skill fence to close it with.
221
+ */
222
+ export declare function skillTrifectaIssue(disallowed: readonly string[] | null, dialect: HarnessDialect, ctx?: TrifectaContext): TrifectaFinding | null;
130
223
  //# sourceMappingURL=lethal-trifecta.d.ts.map