vigiles 14.6.7 → 14.8.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 (53) hide show
  1. package/dist/adapters/claude-code/agent-runtime.d.ts +2 -19
  2. package/dist/adapters/claude-code/agent-runtime.js +5 -30
  3. package/dist/adapters/claude-code/agent-tools.d.ts +20 -0
  4. package/dist/adapters/claude-code/agent-tools.js +40 -0
  5. package/dist/audit-report.d.ts +2 -2
  6. package/dist/audit-report.template.html +15 -15
  7. package/dist/audit-score.d.ts +1 -1
  8. package/dist/audit-score.js +20 -20
  9. package/dist/audit-verdict.d.ts +2 -2
  10. package/dist/audit-verdict.js +5 -5
  11. package/dist/core/assert-never.d.ts +9 -0
  12. package/dist/core/assert-never.js +14 -0
  13. package/dist/core/description-overlap.js +2 -2
  14. package/dist/core/edit-distance.d.ts +12 -0
  15. package/dist/core/edit-distance.js +36 -0
  16. package/dist/core/effects.js +3 -3
  17. package/dist/core/hash.d.ts +1 -2
  18. package/dist/core/hash.js +6 -4
  19. package/dist/core/hook-block-ineffective.d.ts +55 -6
  20. package/dist/core/hook-block-ineffective.js +9 -14
  21. package/dist/core/hook-events.js +2 -2
  22. package/dist/core/linters.d.ts +2 -6
  23. package/dist/core/linters.js +4 -29
  24. package/dist/core/mcp-contract-message.d.ts +22 -0
  25. package/dist/core/mcp-contract-message.js +29 -0
  26. package/dist/core/mcp.d.ts +4 -12
  27. package/dist/core/mcp.js +3 -14
  28. package/dist/core/ncd.d.ts +12 -0
  29. package/dist/core/ncd.js +50 -0
  30. package/dist/core/plugin-dir-layout.d.ts +5 -5
  31. package/dist/core/plugin-dir-layout.js +10 -22
  32. package/dist/core/proofs.d.ts +2 -11
  33. package/dist/core/proofs.js +4 -39
  34. package/dist/core/skill-resources.d.ts +3 -3
  35. package/dist/core/skill-resources.js +9 -8
  36. package/dist/core/tool-contract.js +2 -2
  37. package/dist/leaderboard.d.ts +2 -51
  38. package/dist/leaderboard.js +20 -225
  39. package/dist/optimize.d.ts +1 -1
  40. package/dist/optimize.js +3 -3
  41. package/dist/posix-path.d.ts +40 -0
  42. package/dist/posix-path.js +293 -0
  43. package/dist/scan-core.d.ts +154 -0
  44. package/dist/scan-core.js +690 -0
  45. package/dist/scan-files.d.ts +28 -0
  46. package/dist/scan-files.js +489 -0
  47. package/dist/scan.d.ts +11 -34
  48. package/dist/scan.js +55 -668
  49. package/dist/score-core.d.ts +73 -0
  50. package/dist/score-core.js +226 -0
  51. package/dist/test-coverage-files.d.ts +11 -0
  52. package/dist/test-coverage-files.js +208 -0
  53. package/package.json +1 -1
@@ -1,3 +1,7 @@
1
+ import { mcpContractToolMessage } from "./mcp-contract-message.js";
2
+ import type { McpContractToolError, McpContractToolReason } from "./mcp-contract-message.js";
3
+ export { mcpContractToolMessage };
4
+ export type { McpContractToolError, McpContractToolReason };
1
5
  export interface McpServerConfig {
2
6
  readonly command: string;
3
7
  readonly args?: readonly string[];
@@ -43,19 +47,7 @@ export declare function loadMcpServers(cwd: string): Record<string, McpServerCon
43
47
  * to an undeclared server, an unreachable server, or a missing tool is an error.
44
48
  */
45
49
  export declare function verifyMcpRefs(markdown: string, mcpServers: Record<string, McpServerConfig>, timeoutMs?: number): Promise<McpRefError[]>;
46
- export type McpContractToolReason = "server-unreachable" | "tool-missing";
47
- export interface McpContractToolError {
48
- /** The full `mcp__server__tool` reference (restriction suffix stripped). */
49
- readonly tool: string;
50
- readonly server: string;
51
- /** The tool segment (what's looked up on the server). */
52
- readonly toolName: string;
53
- readonly reason: McpContractToolReason;
54
- readonly suggestions: string[];
55
- }
56
50
  export declare function verifyMcpContractTools(tools: readonly string[], servers: Record<string, McpServerConfig>, dialect: import("./dialect.js").HarnessDialect, timeoutMs?: number): Promise<McpContractToolError[]>;
57
- /** Human-readable message for a contract-tool error (with "did you mean"). */
58
- export declare function mcpContractToolMessage(e: McpContractToolError): string;
59
51
  /** Human-readable message for an MCP reference error (with "did you mean"). */
60
52
  export declare function mcpRefMessage(e: McpRefError): string;
61
53
  //# sourceMappingURL=mcp.d.ts.map
package/dist/core/mcp.js CHANGED
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mcpContractToolMessage = void 0;
3
4
  exports.listMcpTools = listMcpTools;
4
5
  exports.verifyMcpTool = verifyMcpTool;
5
6
  exports.parseMcpRefs = parseMcpRefs;
6
7
  exports.loadMcpServers = loadMcpServers;
7
8
  exports.verifyMcpRefs = verifyMcpRefs;
8
9
  exports.verifyMcpContractTools = verifyMcpContractTools;
9
- exports.mcpContractToolMessage = mcpContractToolMessage;
10
10
  exports.mcpRefMessage = mcpRefMessage;
11
11
  /**
12
12
  * Minimal MCP client over stdio — start a server, do the JSON-RPC handshake, and
@@ -24,6 +24,8 @@ const node_path_1 = require("node:path");
24
24
  const refs_js_1 = require("./refs.js");
25
25
  const hash_js_1 = require("./hash.js");
26
26
  const mcp_tool_js_1 = require("./mcp-tool.js");
27
+ const mcp_contract_message_js_1 = require("./mcp-contract-message.js");
28
+ Object.defineProperty(exports, "mcpContractToolMessage", { enumerable: true, get: function () { return mcp_contract_message_js_1.mcpContractToolMessage; } });
27
29
  function dispatch(line, pending) {
28
30
  let msg;
29
31
  try {
@@ -283,19 +285,6 @@ async function verifyMcpContractTools(tools, servers, dialect, timeoutMs = 10000
283
285
  }
284
286
  return errors;
285
287
  }
286
- /** Human-readable message for a contract-tool error (with "did you mean"). */
287
- function mcpContractToolMessage(e) {
288
- switch (e.reason) {
289
- case "server-unreachable":
290
- return `MCP tool "${e.tool}" — server "${e.server}" failed to start`;
291
- case "tool-missing":
292
- return `MCP tool "${e.tool}" not found on server "${e.server}"${e.suggestions.length > 0
293
- ? ` — did you mean ${e.suggestions.map((s) => `"${s}"`).join(", ")}?`
294
- : ""}`;
295
- default:
296
- return (0, hash_js_1.assertNever)(e.reason);
297
- }
298
- }
299
288
  /** Human-readable message for an MCP reference error (with "did you mean"). */
300
289
  function mcpRefMessage(e) {
301
290
  switch (e.reason) {
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Normalized Compression Distance — information-theoretic similarity.
3
+ *
4
+ * NCD(x, y) = (C(xy) - min(C(x), C(y))) / max(C(x), C(y))
5
+ *
6
+ * Range: [0, 1+ε] where 0 = identical information content.
7
+ * Deterministic. No model dependency. Approximates the universal distance metric.
8
+ *
9
+ * Reference: Li, Chen, Li, Ma, Vitányi (2004) "The Similarity Metric"
10
+ */
11
+ export declare function ncd(a: string, b: string): number;
12
+ //# sourceMappingURL=ncd.d.ts.map
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ncd = ncd;
4
+ /**
5
+ * Normalized Compression Distance (NCD) — the model-free similarity engine.
6
+ *
7
+ * Extracted from proofs.ts as a NODE-FREE leaf: it depends only on `gzipSync`
8
+ * (aliased to `pako` in the browser build) and `TextEncoder` (a Web/Node global),
9
+ * so the description-overlap detector can reach it WITHOUT dragging proofs.ts's
10
+ * `node:crypto` (hash.js) import into the in-browser audit bundle. proofs.ts
11
+ * re-exports `ncd` for its existing consumers; the detector imports it from here.
12
+ *
13
+ * `TextEncoder` (not `Buffer.from`) keeps the byte input identical across Node and
14
+ * the browser and removes the node-only `Buffer` global — utf-8 bytes are the same
15
+ * either way, so gzip sees identical input and the compressed length matches.
16
+ */
17
+ const node_zlib_1 = require("node:zlib");
18
+ const utf8 = new TextEncoder();
19
+ /**
20
+ * Compressed size of a string via gzip — approximates Kolmogorov complexity
21
+ * (the length of the shortest program that produces the string).
22
+ */
23
+ function compressedSize(s) {
24
+ return (0, node_zlib_1.gzipSync)(utf8.encode(s), { level: 9 }).length;
25
+ }
26
+ /**
27
+ * Normalized Compression Distance — information-theoretic similarity.
28
+ *
29
+ * NCD(x, y) = (C(xy) - min(C(x), C(y))) / max(C(x), C(y))
30
+ *
31
+ * Range: [0, 1+ε] where 0 = identical information content.
32
+ * Deterministic. No model dependency. Approximates the universal distance metric.
33
+ *
34
+ * Reference: Li, Chen, Li, Ma, Vitányi (2004) "The Similarity Metric"
35
+ */
36
+ function ncd(a, b) {
37
+ if (a === b)
38
+ return 0;
39
+ if (a.length === 0 && b.length === 0)
40
+ return 0;
41
+ const ca = compressedSize(a);
42
+ const cb = compressedSize(b);
43
+ const cab = compressedSize(a + b);
44
+ const minC = Math.min(ca, cb);
45
+ const maxC = Math.max(ca, cb);
46
+ if (maxC === 0)
47
+ return 0;
48
+ return (cab - minC) / maxC;
49
+ }
50
+ //# sourceMappingURL=ncd.js.map
@@ -6,13 +6,13 @@ export interface PluginLayoutFinding {
6
6
  readonly message: string;
7
7
  }
8
8
  export interface PluginLayoutOptions {
9
- /** Injectable: does this path exist? (default: node:fs existsSync) */
10
- readonly existsSync?: (p: string) => boolean;
9
+ /** REQUIRED, injected: does this path exist? (disk: node:fs existsSync) */
10
+ readonly existsSync: (p: string) => boolean;
11
11
  /**
12
- * Injectable: is this path a directory? (default: node:fs
12
+ * REQUIRED, injected: is this path a directory? (disk: node:fs
13
13
  * statSync(p).isDirectory(), returning false on any throw)
14
14
  */
15
- readonly isDirectory?: (p: string) => boolean;
15
+ readonly isDirectory: (p: string) => boolean;
16
16
  }
17
17
  /**
18
18
  * Surface directories found nested INSIDE the manifest directory, where they are
@@ -26,5 +26,5 @@ export interface PluginLayoutOptions {
26
26
  * Returns `[]` when the manifest dir doesn't exist or holds no misplaced surface
27
27
  * dirs.
28
28
  */
29
- export declare function pluginDirLayoutIssues(manifestDir: string, surfaceDirNames: readonly string[], opts?: PluginLayoutOptions): PluginLayoutFinding[];
29
+ export declare function pluginDirLayoutIssues(manifestDir: string, surfaceDirNames: readonly string[], opts: PluginLayoutOptions): PluginLayoutFinding[];
30
30
  //# sourceMappingURL=plugin-dir-layout.d.ts.map
@@ -12,10 +12,11 @@ exports.pluginDirLayoutIssues = pluginDirLayoutIssues;
12
12
  * completely invisible to the harness. Only `plugin.json` belongs inside the
13
13
  * manifest directory; everything else must live at the root.
14
14
  *
15
- * Pure + FP-safe: the only IO is an injectable `existsSync` and `isDirectory`
16
- * (defaults: node:fs), mirroring the pattern in core/skill-resources.ts and the
17
- * loader, so the detector is fully testable with fakes and never touches the
18
- * filesystem in tests.
15
+ * Pure + FP-safe + node-free: the only IO is a REQUIRED, injected `existsSync`
16
+ * and `isDirectory` (the disk caller passes `node:fs`; the browser engine passes
17
+ * a map-backed pair), so the detector is fully testable with fakes, never touches
18
+ * the filesystem in tests, and statically imports no `node:` builtin — it bundles
19
+ * clean in a browser (path ops come from the node-free `posix-path`).
19
20
  *
20
21
  * Harness-agnostic: the surface directory names are INJECTED from the layout
21
22
  * (PluginLayout.skillDir / agentDir / commandDir / hookDir, or equivalent), never
@@ -23,23 +24,10 @@ exports.pluginDirLayoutIssues = pluginDirLayoutIssues;
23
24
  * `plugin-dir-layout` rule) and `vigiles audit` (the read-only report) — one
24
25
  * detector, no drift.
25
26
  */
26
- const node_fs_1 = require("node:fs");
27
- const node_path_1 = require("node:path");
27
+ const posix_path_js_1 = require("../posix-path.js");
28
28
  // ---------------------------------------------------------------------------
29
29
  // Detector
30
30
  // ---------------------------------------------------------------------------
31
- /**
32
- * Default `isDirectory` implementation — wraps statSync so that a missing or
33
- * unreadable path returns `false` instead of throwing.
34
- */
35
- function defaultIsDirectory(p) {
36
- try {
37
- return (0, node_fs_1.statSync)(p).isDirectory();
38
- }
39
- catch {
40
- return false;
41
- }
42
- }
43
31
  /**
44
32
  * Surface directories found nested INSIDE the manifest directory, where they are
45
33
  * invisible to the harness.
@@ -53,12 +41,12 @@ function defaultIsDirectory(p) {
53
41
  * dirs.
54
42
  */
55
43
  function pluginDirLayoutIssues(manifestDir, surfaceDirNames, opts) {
56
- const exists = opts?.existsSync ?? node_fs_1.existsSync;
57
- const isDir = opts?.isDirectory ?? defaultIsDirectory;
58
- const manifestBase = (0, node_path_1.basename)(manifestDir);
44
+ const exists = opts.existsSync;
45
+ const isDir = opts.isDirectory;
46
+ const manifestBase = (0, posix_path_js_1.basename)(manifestDir);
59
47
  const findings = [];
60
48
  for (const name of surfaceDirNames) {
61
- const candidate = (0, node_path_1.join)(manifestDir, name);
49
+ const candidate = (0, posix_path_js_1.join)(manifestDir, name);
62
50
  if (exists(candidate) && isDir(candidate)) {
63
51
  findings.push({
64
52
  dir: name,
@@ -10,6 +10,7 @@
10
10
  * 5. MerkleHistory — tamper-evident spec evolution audit trail
11
11
  * 6. propertyTest() — random mutation + invariant checking
12
12
  */
13
+ import { ncd } from "./ncd.js";
13
14
  import type { Rule, ClaudeSpec } from "./spec.js";
14
15
  export interface MonotonicityViolation {
15
16
  ruleId: string;
@@ -49,17 +50,7 @@ export declare function latticeJoin(a: Rule["_kind"], b: Rule["_kind"]): Rule["_
49
50
  export declare function latticeMeet(a: Rule["_kind"], b: Rule["_kind"]): Rule["_kind"];
50
51
  /** Get the numeric strength of a rule kind. */
51
52
  export declare function ruleStrength(kind: Rule["_kind"]): number;
52
- /**
53
- * Normalized Compression Distance — information-theoretic similarity.
54
- *
55
- * NCD(x, y) = (C(xy) - min(C(x), C(y))) / max(C(x), C(y))
56
- *
57
- * Range: [0, 1+ε] where 0 = identical information content.
58
- * Deterministic. No model dependency. Approximates the universal distance metric.
59
- *
60
- * Reference: Li, Chen, Li, Ma, Vitányi (2004) "The Similarity Metric"
61
- */
62
- export declare function ncd(a: string, b: string): number;
53
+ export { ncd };
63
54
  export interface NCDPair {
64
55
  idA: string;
65
56
  idB: string;
@@ -12,19 +12,19 @@
12
12
  * 6. propertyTest() — random mutation + invariant checking
13
13
  */
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.MerkleHistory = exports.BloomFilter = void 0;
15
+ exports.MerkleHistory = exports.BloomFilter = exports.ncd = void 0;
16
16
  exports.checkMonotonicity = checkMonotonicity;
17
17
  exports.latticeJoin = latticeJoin;
18
18
  exports.latticeMeet = latticeMeet;
19
19
  exports.ruleStrength = ruleStrength;
20
- exports.ncd = ncd;
21
20
  exports.findSimilarRules = findSimilarRules;
22
21
  exports.ruleToBloomFilter = ruleToBloomFilter;
23
22
  exports.fixedPoint = fixedPoint;
24
23
  exports.propertyTest = propertyTest;
25
24
  exports.fitness = fitness;
26
- const node_zlib_1 = require("node:zlib");
27
25
  const hash_js_1 = require("./hash.js");
26
+ const ncd_js_1 = require("./ncd.js");
27
+ Object.defineProperty(exports, "ncd", { enumerable: true, get: function () { return ncd_js_1.ncd; } });
28
28
  // ---------------------------------------------------------------------------
29
29
  // 1. Monotonicity Lattice — partial order on rule strength
30
30
  // ---------------------------------------------------------------------------
@@ -127,41 +127,6 @@ function latticeMeet(a, b) {
127
127
  function ruleStrength(kind) {
128
128
  return STRENGTH[kind];
129
129
  }
130
- // ---------------------------------------------------------------------------
131
- // 2. Normalized Compression Distance (NCD)
132
- // ---------------------------------------------------------------------------
133
- /**
134
- * Compute the compressed size of a string using gzip.
135
- * This approximates Kolmogorov complexity — the length of the shortest
136
- * program that produces the string.
137
- */
138
- function compressedSize(s) {
139
- return (0, node_zlib_1.gzipSync)(Buffer.from(s, "utf-8"), { level: 9 }).length;
140
- }
141
- /**
142
- * Normalized Compression Distance — information-theoretic similarity.
143
- *
144
- * NCD(x, y) = (C(xy) - min(C(x), C(y))) / max(C(x), C(y))
145
- *
146
- * Range: [0, 1+ε] where 0 = identical information content.
147
- * Deterministic. No model dependency. Approximates the universal distance metric.
148
- *
149
- * Reference: Li, Chen, Li, Ma, Vitányi (2004) "The Similarity Metric"
150
- */
151
- function ncd(a, b) {
152
- if (a === b)
153
- return 0;
154
- if (a.length === 0 && b.length === 0)
155
- return 0;
156
- const ca = compressedSize(a);
157
- const cb = compressedSize(b);
158
- const cab = compressedSize(a + b);
159
- const minC = Math.min(ca, cb);
160
- const maxC = Math.max(ca, cb);
161
- if (maxC === 0)
162
- return 0;
163
- return (cab - minC) / maxC;
164
- }
165
130
  /**
166
131
  * Find all rule pairs with NCD below a similarity threshold.
167
132
  * Returns pairs sorted by distance (most similar first).
@@ -175,7 +140,7 @@ function findSimilarRules(rules, threshold = 0.5) {
175
140
  const [idB, ruleB] = entries[j];
176
141
  const textA = ruleToText(ruleA);
177
142
  const textB = ruleToText(ruleB);
178
- const d = ncd(textA, textB);
143
+ const d = (0, ncd_js_1.ncd)(textA, textB);
179
144
  if (d < threshold) {
180
145
  pairs.push({ idA, idB, distance: d });
181
146
  }
@@ -12,8 +12,8 @@ export interface SkillResourceFinding {
12
12
  readonly line: number;
13
13
  }
14
14
  export interface SkillResourceOptions {
15
- /** Injectable existence check (default: node:fs existsSync). */
16
- readonly existsSync?: (p: string) => boolean;
15
+ /** REQUIRED, injected existence check (disk: node:fs existsSync). */
16
+ readonly existsSync: (p: string) => boolean;
17
17
  /**
18
18
  * Repo root, used only together with `sharedDirs` (below). Off by default.
19
19
  */
@@ -39,5 +39,5 @@ export interface SkillResourceOptions {
39
39
  * The shared detector behind both `vigiles lint` (the `skill-resource-resolves`
40
40
  * rule) and `vigiles audit` (the read-only report) — one detector, no drift.
41
41
  */
42
- export declare function skillResourceIssues(skillBody: string, skillDir: string, opts?: SkillResourceOptions): SkillResourceFinding[];
42
+ export declare function skillResourceIssues(skillBody: string, skillDir: string, opts: SkillResourceOptions): SkillResourceFinding[];
43
43
  //# sourceMappingURL=skill-resources.d.ts.map
@@ -34,11 +34,12 @@ exports.skillResourceIssues = skillResourceIssues;
34
34
  * (example / e.g. / such as / would be / template / →). Markdown links are
35
35
  * unchanged — a link is already an act-on-it reference. See `inlinePathIsUsed`.
36
36
  *
37
- * Pure: the only IO is an injectable `existsSync` (default node:fs), mirroring
38
- * core/refs.ts and the loader so the detector is testable with a fake.
37
+ * Pure + node-free: the only IO is a REQUIRED, injected `existsSync` (the disk
38
+ * caller passes `node:fs`; the browser engine a map-backed check), so the
39
+ * detector is testable with a fake and statically imports no `node:` builtin —
40
+ * it bundles clean in a browser (path ops come from the node-free `posix-path`).
39
41
  */
40
- const node_fs_1 = require("node:fs");
41
- const node_path_1 = require("node:path");
42
+ const posix_path_js_1 = require("../posix-path.js");
42
43
  // ---------------------------------------------------------------------------
43
44
  // Shapes we match vs deliberately skip (FP-safety)
44
45
  // ---------------------------------------------------------------------------
@@ -202,19 +203,19 @@ function candidatesInLine(line, lineNo) {
202
203
  * The shared detector behind both `vigiles lint` (the `skill-resource-resolves`
203
204
  * rule) and `vigiles audit` (the read-only report) — one detector, no drift.
204
205
  */
205
- function skillResourceIssues(skillBody, skillDir, opts = {}) {
206
- const exists = opts.existsSync ?? node_fs_1.existsSync;
206
+ function skillResourceIssues(skillBody, skillDir, opts) {
207
+ const exists = opts.existsSync;
207
208
  const sharedDirs = new Set(opts.sharedDirs ?? []);
208
209
  // A ref resolves if it exists under the skill's own dir. If (and only if) its
209
210
  // first segment is a DECLARED shared dir, it may also resolve against the repo
210
211
  // root — the opt-in shared-tree case. No shared dirs → skill-dir-only (unchanged).
211
212
  const resolvesAnywhere = (rel) => {
212
- if (exists((0, node_path_1.resolve)(skillDir, rel)))
213
+ if (exists((0, posix_path_js_1.resolve)(skillDir, rel)))
213
214
  return true;
214
215
  const firstSeg = rel.split("/")[0];
215
216
  return (opts.repoRoot !== undefined &&
216
217
  sharedDirs.has(firstSeg) &&
217
- exists((0, node_path_1.resolve)(opts.repoRoot, rel)));
218
+ exists((0, posix_path_js_1.resolve)(opts.repoRoot, rel)));
218
219
  };
219
220
  const findings = [];
220
221
  const seen = new Set();
@@ -4,7 +4,7 @@ exports.closestTool = closestTool;
4
4
  exports.confidentToolIssues = confidentToolIssues;
5
5
  exports.disallowedToolIssues = disallowedToolIssues;
6
6
  exports.verifyToolContract = verifyToolContract;
7
- const linters_js_1 = require("./linters.js");
7
+ const edit_distance_js_1 = require("./edit-distance.js");
8
8
  /**
9
9
  * Closest known built-in tool by edit distance (≤ 2), for a "did you mean" hint.
10
10
  * The ≤ 2 bound is deliberately tight: a suggestion is a CONFIDENCE signal (this
@@ -15,7 +15,7 @@ function closestTool(tool, dialect) {
15
15
  let best = null;
16
16
  let bestDistance = Infinity;
17
17
  for (const known of dialect.builtinAgentTools) {
18
- const d = (0, linters_js_1.editDistance)(tool.toLowerCase(), known.toLowerCase());
18
+ const d = (0, edit_distance_js_1.editDistance)(tool.toLowerCase(), known.toLowerCase());
19
19
  if (d < bestDistance) {
20
20
  bestDistance = d;
21
21
  best = known;
@@ -10,57 +10,8 @@
10
10
  * The behavioural columns (real trigger-rate, observed egress, safety) need a
11
11
  * model and stack on top later; this part runs anywhere in CI for free.
12
12
  */
13
- import { type ScanReport } from "./scan.js";
14
- export interface PluginScore {
15
- readonly dir: string;
16
- readonly name: string;
17
- /** 0–100 structural-health score (100 = no structural issues found). */
18
- readonly score: number;
19
- readonly grade: "A" | "B" | "C" | "D" | "F";
20
- /** Human-readable deductions, worst first. */
21
- readonly issues: readonly string[];
22
- readonly report: ScanReport;
23
- }
24
- export declare const W_MISSING_HOOK = 15;
25
- export declare const W_NO_DESCRIPTION = 10;
26
- export declare const W_DANGLING_REF = 8;
27
- export declare const W_OVERLAP = 8;
28
- export declare const W_NO_CONTRACT = 5;
29
- export declare const W_TRIFECTA = 10;
30
- /** Map a 0–100 structural-health score to its letter grade (A ≥90 … F <60). */
31
- export declare function gradeFor(score: number): PluginScore["grade"];
32
- /** One deduction: a count, its per-item weight, and the label if non-zero. */
33
- export interface Deduction {
34
- readonly n: number;
35
- readonly weight: number;
36
- readonly label: string;
37
- }
38
- /**
39
- * The COMPLETE graded-penalty list a report incurs — the single source of truth
40
- * BOTH the leaderboard's single health number and the audit's category rings
41
- * read, so the overall can never drift between the two surfaces. Each entry is a
42
- * graded penalty; untested surfaces are deliberately ABSENT (they're advisory,
43
- * surfaced separately, never scored).
44
- */
45
- export declare function reportDeductions(r: ScanReport): Deduction[];
46
- /** True when a report has no loadable plugin surface at all (the empty machine). */
47
- export declare function isEmptyMachine(r: ScanReport): boolean;
48
- /**
49
- * THE shared integrity score — `100 − Σ(all graded penalties)`, clamped to
50
- * [0,100]. Both the leaderboard's single health number AND the audit's headline
51
- * overall read this, so the two can never disagree (the summed model is the
52
- * honest one — averaging rings would dilute a real problem). Returns the score
53
- * plus the per-item deductions so callers render their own issue/finding lists.
54
- */
55
- export declare function computeIntegrityScore(deductions: readonly Deduction[]): {
56
- score: number;
57
- penalty: number;
58
- };
59
- /** Deterministic structural-health score for one scanned plugin. */
60
- export declare function scoreReport(r: ScanReport): {
61
- score: number;
62
- issues: string[];
63
- };
13
+ import { type PluginScore } from "./score-core.js";
14
+ export { type PluginScore, type Deduction, W_MISSING_HOOK, W_NO_DESCRIPTION, W_DANGLING_REF, W_OVERLAP, W_NO_CONTRACT, W_TRIFECTA, gradeFor, reportDeductions, isEmptyMachine, computeIntegrityScore, scoreReport, } from "./score-core.js";
64
15
  /** Scan + score each directory, ranked best-first (ties broken by name). */
65
16
  export declare function rankPlugins(dirs: readonly string[]): PluginScore[];
66
17
  /** Format a ranked leaderboard as human-readable text. */