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.
- package/dist/adapters/claude-code/agent-runtime.d.ts +2 -19
- package/dist/adapters/claude-code/agent-runtime.js +5 -30
- package/dist/adapters/claude-code/agent-tools.d.ts +20 -0
- package/dist/adapters/claude-code/agent-tools.js +40 -0
- package/dist/audit-report.d.ts +2 -2
- package/dist/audit-report.template.html +15 -15
- package/dist/audit-score.d.ts +1 -1
- package/dist/audit-score.js +20 -20
- package/dist/audit-verdict.d.ts +2 -2
- package/dist/audit-verdict.js +5 -5
- package/dist/core/assert-never.d.ts +9 -0
- package/dist/core/assert-never.js +14 -0
- package/dist/core/description-overlap.js +2 -2
- package/dist/core/edit-distance.d.ts +12 -0
- package/dist/core/edit-distance.js +36 -0
- package/dist/core/effects.js +3 -3
- package/dist/core/hash.d.ts +1 -2
- package/dist/core/hash.js +6 -4
- package/dist/core/hook-block-ineffective.d.ts +55 -6
- package/dist/core/hook-block-ineffective.js +9 -14
- package/dist/core/hook-events.js +2 -2
- package/dist/core/linters.d.ts +2 -6
- package/dist/core/linters.js +4 -29
- package/dist/core/mcp-contract-message.d.ts +22 -0
- package/dist/core/mcp-contract-message.js +29 -0
- package/dist/core/mcp.d.ts +4 -12
- package/dist/core/mcp.js +3 -14
- package/dist/core/ncd.d.ts +12 -0
- package/dist/core/ncd.js +50 -0
- package/dist/core/plugin-dir-layout.d.ts +5 -5
- package/dist/core/plugin-dir-layout.js +10 -22
- package/dist/core/proofs.d.ts +2 -11
- package/dist/core/proofs.js +4 -39
- package/dist/core/skill-resources.d.ts +3 -3
- package/dist/core/skill-resources.js +9 -8
- package/dist/core/tool-contract.js +2 -2
- package/dist/leaderboard.d.ts +2 -51
- package/dist/leaderboard.js +20 -225
- package/dist/optimize.d.ts +1 -1
- package/dist/optimize.js +3 -3
- package/dist/posix-path.d.ts +40 -0
- package/dist/posix-path.js +293 -0
- package/dist/scan-core.d.ts +154 -0
- package/dist/scan-core.js +690 -0
- package/dist/scan-files.d.ts +28 -0
- package/dist/scan-files.js +489 -0
- package/dist/scan.d.ts +11 -34
- package/dist/scan.js +55 -668
- package/dist/score-core.d.ts +73 -0
- package/dist/score-core.js +226 -0
- package/dist/test-coverage-files.d.ts +11 -0
- package/dist/test-coverage-files.js +208 -0
- package/package.json +1 -1
package/dist/core/mcp.d.ts
CHANGED
|
@@ -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
|
package/dist/core/ncd.js
ADDED
|
@@ -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
|
-
/**
|
|
10
|
-
readonly existsSync
|
|
9
|
+
/** REQUIRED, injected: does this path exist? (disk: node:fs existsSync) */
|
|
10
|
+
readonly existsSync: (p: string) => boolean;
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
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
|
|
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
|
|
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
|
|
16
|
-
* (
|
|
17
|
-
*
|
|
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
|
|
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
|
|
57
|
-
const isDir = opts
|
|
58
|
-
const manifestBase = (0,
|
|
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,
|
|
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,
|
package/dist/core/proofs.d.ts
CHANGED
|
@@ -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;
|
package/dist/core/proofs.js
CHANGED
|
@@ -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
|
-
/**
|
|
16
|
-
readonly existsSync
|
|
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
|
|
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
|
|
38
|
-
*
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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;
|
package/dist/leaderboard.d.ts
CHANGED
|
@@ -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
|
|
14
|
-
export
|
|
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. */
|