mcprigor 1.3.1 → 1.5.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/README.md +19 -2
- package/dist/audit.d.ts +44 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +157 -0
- package/dist/audit.js.map +1 -0
- package/dist/cli.js +283 -10
- package/dist/cli.js.map +1 -1
- package/dist/composition.d.ts +42 -0
- package/dist/composition.d.ts.map +1 -0
- package/dist/composition.js +130 -0
- package/dist/composition.js.map +1 -0
- package/dist/coverage.d.ts +33 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/coverage.js +83 -0
- package/dist/coverage.js.map +1 -0
- package/dist/export.d.ts +20 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +422 -0
- package/dist/export.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/language.js +1 -1
- package/dist/language.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +4 -1
- package/dist/loader.js.map +1 -1
- package/dist/monitor.d.ts +22 -0
- package/dist/monitor.d.ts.map +1 -0
- package/dist/monitor.js +71 -0
- package/dist/monitor.js.map +1 -0
- package/dist/perf.d.ts +37 -0
- package/dist/perf.d.ts.map +1 -0
- package/dist/perf.js +90 -0
- package/dist/perf.js.map +1 -0
- package/dist/publish.d.ts +19 -0
- package/dist/publish.d.ts.map +1 -0
- package/dist/publish.js +58 -0
- package/dist/publish.js.map +1 -0
- package/dist/qa-language.d.ts.map +1 -1
- package/dist/qa-language.js +46 -1
- package/dist/qa-language.js.map +1 -1
- package/dist/reporters.d.ts +5 -2
- package/dist/reporters.d.ts.map +1 -1
- package/dist/reporters.js +26 -5
- package/dist/reporters.js.map +1 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +31 -15
- package/dist/runner.js.map +1 -1
- package/dist/schema.d.ts +47 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +10 -1
- package/dist/schema.js.map +1 -1
- package/dist/timeline.d.ts +18 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +59 -0
- package/dist/timeline.js.map +1 -0
- package/dist/types.d.ts +19 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +73 -3
- package/dist/workspace.js.map +1 -1
- package/docs/CLI-REFERENCE.md +136 -1
- package/docs/COVERAGE.md +37 -0
- package/docs/ENGINEER-SETUP.md +1 -1
- package/docs/EVIDENCE.md +11 -0
- package/docs/GITHUB-ACTION.md +82 -0
- package/docs/LANGUAGE-SPEC.md +28 -7
- package/docs/MONITORING.md +62 -0
- package/docs/MULTI-SERVER-COMPOSITIONS.md +103 -0
- package/docs/PERFORMANCE-GOVERNANCE.md +85 -0
- package/docs/PLAIN-LANGUAGE-COOKBOOK.md +28 -0
- package/docs/PUBLISHING.md +53 -0
- package/docs/QA-WORKSPACE.md +5 -1
- package/docs/README.md +7 -0
- package/docs/SECURITY-AUDIT.md +77 -0
- package/editors/mcpr-language.json +2 -2
- package/editors/vscode/package.json +1 -1
- package/editors/vscode/syntaxes/mcpr.tmLanguage.json +2 -2
- package/package.json +1 -1
- package/workspace-assets/app.js +113 -1
- package/workspace-assets/index.html +17 -0
- package/workspace-assets/style.css +13 -2
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { readFile, rename, writeFile } from "node:fs/promises";
|
|
2
|
+
import YAML from "yaml";
|
|
3
|
+
import { canonicalize, fingerprint } from "./canonical.js";
|
|
4
|
+
import { compareContracts } from "./contract.js";
|
|
5
|
+
import { discoverTarget } from "./discovery.js";
|
|
6
|
+
/** Discover every named server and detect namespace/schema conflicts deterministically. */
|
|
7
|
+
export async function discoverComposition(servers) {
|
|
8
|
+
const names = Object.keys(servers).sort();
|
|
9
|
+
if (names.length < 2)
|
|
10
|
+
throw new Error("MCP-COMP-000 A composition needs at least two named servers");
|
|
11
|
+
const documents = await Promise.all(names.map(async (name) => [name, await discoverTarget(servers[name])]));
|
|
12
|
+
const discovered = Object.fromEntries(documents);
|
|
13
|
+
const issues = compositionIssues(discovered);
|
|
14
|
+
const stableServers = Object.fromEntries(Object.entries(discovered).map(([name, document]) => [name, { server: document.server, protocolVersion: document.protocolVersion, tools: document.tools, resources: document.resources, resourceTemplates: document.resourceTemplates, prompts: document.prompts }]));
|
|
15
|
+
const contract = canonicalize({ servers: stableServers, issues });
|
|
16
|
+
return { schemaVersion: 1, kind: "mcprigor-composition", discoveredAt: new Date().toISOString(), fingerprint: fingerprint(contract), servers: discovered, issues };
|
|
17
|
+
}
|
|
18
|
+
export function compositionIssues(servers) {
|
|
19
|
+
const issues = [];
|
|
20
|
+
const toolIndex = namedIndex(servers, "tools", "name");
|
|
21
|
+
for (const [name, occurrences] of toolIndex) {
|
|
22
|
+
if (occurrences.length < 2)
|
|
23
|
+
continue;
|
|
24
|
+
const serverNames = occurrences.map((item) => item.server).sort();
|
|
25
|
+
issues.push({ code: "MCP-COMP-001", severity: "potentially-breaking", kind: "tool-collision", name, servers: serverNames, message: `Tool “${name}” is advertised by ${serverNames.join(", ")}` });
|
|
26
|
+
const schemas = new Set(occurrences.map((item) => JSON.stringify(canonicalize({ inputSchema: item.value.inputSchema, outputSchema: item.value.outputSchema }))));
|
|
27
|
+
if (schemas.size > 1)
|
|
28
|
+
issues.push({ code: "MCP-COMP-002", severity: "breaking", kind: "tool-schema-conflict", name, servers: serverNames, message: `Tool “${name}” has conflicting schemas across ${serverNames.join(", ")}` });
|
|
29
|
+
}
|
|
30
|
+
for (const [name, occurrences] of namedIndex(servers, "resources", "uri"))
|
|
31
|
+
if (occurrences.length > 1) {
|
|
32
|
+
const serverNames = occurrences.map((item) => item.server).sort();
|
|
33
|
+
issues.push({ code: "MCP-COMP-003", severity: "breaking", kind: "resource-collision", name, servers: serverNames, message: `Resource URI “${name}” is owned by multiple servers: ${serverNames.join(", ")}` });
|
|
34
|
+
}
|
|
35
|
+
for (const [name, occurrences] of namedIndex(servers, "resourceTemplates", "uriTemplate"))
|
|
36
|
+
if (occurrences.length > 1) {
|
|
37
|
+
const serverNames = occurrences.map((item) => item.server).sort();
|
|
38
|
+
issues.push({ code: "MCP-COMP-003", severity: "breaking", kind: "resource-collision", name, servers: serverNames, message: `Resource template “${name}” is owned by multiple servers: ${serverNames.join(", ")}` });
|
|
39
|
+
}
|
|
40
|
+
for (const [name, occurrences] of namedIndex(servers, "prompts", "name"))
|
|
41
|
+
if (occurrences.length > 1) {
|
|
42
|
+
const serverNames = occurrences.map((item) => item.server).sort();
|
|
43
|
+
issues.push({ code: "MCP-COMP-004", severity: "potentially-breaking", kind: "prompt-collision", name, servers: serverNames, message: `Prompt “${name}” is advertised by ${serverNames.join(", ")}` });
|
|
44
|
+
}
|
|
45
|
+
return issues.sort((a, b) => severityRank(a.severity) - severityRank(b.severity) || a.name.localeCompare(b.name) || a.code.localeCompare(b.code));
|
|
46
|
+
}
|
|
47
|
+
function namedIndex(servers, surface, key) {
|
|
48
|
+
const index = new Map();
|
|
49
|
+
for (const [server, document] of Object.entries(servers))
|
|
50
|
+
for (const item of document[surface]) {
|
|
51
|
+
if (!item || typeof item !== "object" || typeof item[key] !== "string")
|
|
52
|
+
continue;
|
|
53
|
+
const name = String(item[key]);
|
|
54
|
+
const values = index.get(name) ?? [];
|
|
55
|
+
values.push({ server, value: item });
|
|
56
|
+
index.set(name, values);
|
|
57
|
+
}
|
|
58
|
+
return index;
|
|
59
|
+
}
|
|
60
|
+
export async function writeCompositionLock(lock, file) {
|
|
61
|
+
const temporary = `${file}.${process.pid}.tmp`;
|
|
62
|
+
await writeFile(temporary, file.endsWith(".json") ? JSON.stringify(lock, null, 2) + "\n" : YAML.stringify(lock, { sortMapEntries: true }), "utf8");
|
|
63
|
+
await rename(temporary, file);
|
|
64
|
+
}
|
|
65
|
+
export async function readCompositionLock(file) {
|
|
66
|
+
const source = await readFile(file, "utf8");
|
|
67
|
+
const value = file.endsWith(".json") ? JSON.parse(source) : YAML.parse(source);
|
|
68
|
+
if (!value || typeof value !== "object" || value.kind !== "mcprigor-composition" || value.schemaVersion !== 1 || !value.servers || typeof value.servers !== "object" || !Array.isArray(value.issues))
|
|
69
|
+
throw new Error(`MCP-COMP-LOCK-001 ${file} is not an MCP Rigor composition lock`);
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
export async function updateCompositionLock(file, servers) {
|
|
73
|
+
const before = await readCompositionLock(file);
|
|
74
|
+
const after = await discoverComposition(servers);
|
|
75
|
+
const diff = compareCompositions(before, after);
|
|
76
|
+
await writeCompositionLock(after, file);
|
|
77
|
+
return diff;
|
|
78
|
+
}
|
|
79
|
+
/** Compare the entire fleet: added/removed servers, each contract, and collision-set changes. */
|
|
80
|
+
export function compareCompositions(before, after) {
|
|
81
|
+
const changes = [];
|
|
82
|
+
const serverDiffs = {};
|
|
83
|
+
const oldNames = new Set(Object.keys(before.servers));
|
|
84
|
+
const newNames = new Set(Object.keys(after.servers));
|
|
85
|
+
for (const name of [...oldNames].sort()) {
|
|
86
|
+
if (!newNames.has(name))
|
|
87
|
+
changes.push({ severity: "breaking", code: "MCP-COMP-DRIFT-001", path: `servers.${name}`, message: `Server “${name}” was removed from the composition` });
|
|
88
|
+
else {
|
|
89
|
+
const diff = compareContracts(before.servers[name], after.servers[name]);
|
|
90
|
+
serverDiffs[name] = diff;
|
|
91
|
+
for (const change of diff.changes)
|
|
92
|
+
changes.push({ ...change, path: `servers.${name}.${change.path}`, message: `${name}: ${change.message}` });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (const name of [...newNames].sort())
|
|
96
|
+
if (!oldNames.has(name))
|
|
97
|
+
changes.push({ severity: "non-breaking", code: "MCP-COMP-DRIFT-002", path: `servers.${name}`, message: `Server “${name}” was added to the composition` });
|
|
98
|
+
const issueKey = (issue) => `${issue.code}\0${issue.name}\0${issue.servers.join(",")}`;
|
|
99
|
+
const oldIssues = new Map(before.issues.map((issue) => [issueKey(issue), issue]));
|
|
100
|
+
const newIssues = new Map(after.issues.map((issue) => [issueKey(issue), issue]));
|
|
101
|
+
const compositionChanges = [];
|
|
102
|
+
for (const [key, issue] of newIssues)
|
|
103
|
+
if (!oldIssues.has(key))
|
|
104
|
+
compositionChanges.push({ severity: issue.severity === "notice" ? "non-breaking" : issue.severity, code: "MCP-COMP-DRIFT-010", message: `New composition conflict: ${issue.message}` });
|
|
105
|
+
for (const [key, issue] of oldIssues)
|
|
106
|
+
if (!newIssues.has(key))
|
|
107
|
+
compositionChanges.push({ severity: "non-breaking", code: "MCP-COMP-DRIFT-011", message: `Composition conflict resolved: ${issue.message}` });
|
|
108
|
+
const all = [...changes, ...compositionChanges.map((item) => ({ ...item, path: "composition.issues" }))];
|
|
109
|
+
return { status: all.length ? "changed" : "unchanged", breaking: all.filter((item) => item.severity === "breaking").length, potentiallyBreaking: all.filter((item) => item.severity === "potentially-breaking").length, nonBreaking: all.filter((item) => item.severity === "non-breaking").length, servers: serverDiffs, changes, compositionChanges };
|
|
110
|
+
}
|
|
111
|
+
export function compositionReport(lock) {
|
|
112
|
+
const lines = [`MCP Rigor composition — ${Object.keys(lock.servers).length} servers`, `Combined fingerprint: ${lock.fingerprint}`, `${lock.issues.length} namespace/schema issue${lock.issues.length === 1 ? "" : "s"}`];
|
|
113
|
+
for (const issue of lock.issues)
|
|
114
|
+
lines.push(`${issue.severity === "breaking" ? "✗" : "!"} ${issue.message} [${issue.code}]`);
|
|
115
|
+
if (!lock.issues.length)
|
|
116
|
+
lines.push("✓ No tool, schema, resource URI, or prompt-name collisions detected.");
|
|
117
|
+
return lines.join("\n");
|
|
118
|
+
}
|
|
119
|
+
export function compositionDriftReport(diff) {
|
|
120
|
+
if (diff.status === "unchanged")
|
|
121
|
+
return "No MCP composition drift detected.";
|
|
122
|
+
const lines = [`${diff.breaking} breaking, ${diff.potentiallyBreaking} potentially breaking, ${diff.nonBreaking} non-breaking composition changes`];
|
|
123
|
+
for (const change of diff.changes)
|
|
124
|
+
lines.push(`${change.severity === "breaking" ? "✗" : change.severity === "potentially-breaking" ? "!" : "✓"} ${change.message} [${change.code}]`);
|
|
125
|
+
for (const change of diff.compositionChanges)
|
|
126
|
+
lines.push(`${change.severity === "breaking" ? "✗" : change.severity === "potentially-breaking" ? "!" : "✓"} ${change.message} [${change.code}]`);
|
|
127
|
+
return lines.join("\n");
|
|
128
|
+
}
|
|
129
|
+
function severityRank(value) { return value === "breaking" ? 0 : value === "potentially-breaking" ? 1 : 2; }
|
|
130
|
+
//# sourceMappingURL=composition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composition.js","sourceRoot":"","sources":["../src/composition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DiscoveryDocument, Suite } from "./types.js";
|
|
2
|
+
export interface CoverageItem {
|
|
3
|
+
kind: "tool" | "resource" | "resource-template" | "prompt" | "schema";
|
|
4
|
+
name: string;
|
|
5
|
+
covered: boolean;
|
|
6
|
+
detail?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface CoverageResult {
|
|
9
|
+
schemaVersion: 1;
|
|
10
|
+
score: number;
|
|
11
|
+
covered: number;
|
|
12
|
+
total: number;
|
|
13
|
+
surfaces: {
|
|
14
|
+
tools: Fraction;
|
|
15
|
+
resources: Fraction;
|
|
16
|
+
resourceTemplates: Fraction;
|
|
17
|
+
prompts: Fraction;
|
|
18
|
+
schemaBranches: Fraction;
|
|
19
|
+
};
|
|
20
|
+
items: CoverageItem[];
|
|
21
|
+
}
|
|
22
|
+
interface Fraction {
|
|
23
|
+
covered: number;
|
|
24
|
+
total: number;
|
|
25
|
+
percent: number;
|
|
26
|
+
}
|
|
27
|
+
/** Static deterministic coverage: what the suite references vs the discovered MCP contract. */
|
|
28
|
+
export declare function measureCoverage(suite: Suite): Promise<CoverageResult>;
|
|
29
|
+
export declare function coverageAgainst(suite: Suite, contract: DiscoveryDocument): CoverageResult;
|
|
30
|
+
export declare function coverageReport(result: CoverageResult): string;
|
|
31
|
+
export declare function coverageMarkdown(result: CoverageResult): string;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../src/coverage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAY,MAAM,YAAY,CAAC;AAErE,MAAM,WAAW,YAAY;IAAG,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,mBAAmB,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;AACxJ,MAAM,WAAW,cAAc;IAAG,aAAa,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE;QAAE,KAAK,EAAE,QAAQ,CAAC;QAAC,SAAS,EAAE,QAAQ,CAAC;QAAC,iBAAiB,EAAE,QAAQ,CAAC;QAAC,OAAO,EAAE,QAAQ,CAAC;QAAC,cAAc,EAAE,QAAQ,CAAA;KAAE,CAAC;IAAC,KAAK,EAAE,YAAY,EAAE,CAAA;CAAE;AACxP,UAAU,QAAQ;IAAG,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAEtE,+FAA+F;AAC/F,wBAAsB,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,cAAc,CAAC,CAAuE;AACnJ,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,iBAAiB,GAAG,cAAc,CA2BzF;AA0BD,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAI7D;AACD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAAke"}
|
package/dist/coverage.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { discoverTarget } from "./discovery.js";
|
|
2
|
+
/** Static deterministic coverage: what the suite references vs the discovered MCP contract. */
|
|
3
|
+
export async function measureCoverage(suite) { return coverageAgainst(suite, await discoverTarget(suite.target)); }
|
|
4
|
+
export function coverageAgainst(suite, contract) {
|
|
5
|
+
const items = [];
|
|
6
|
+
const steps = suite.tests.flatMap((test) => test.steps);
|
|
7
|
+
const tools = contract.tools;
|
|
8
|
+
for (const tool of tools.filter((x) => x.name)) {
|
|
9
|
+
const calls = steps.filter((step) => "tool" in step && step.tool.name === tool.name);
|
|
10
|
+
items.push({ kind: "tool", name: tool.name, covered: calls.length > 0, detail: calls.length ? `${calls.length} call${calls.length === 1 ? "" : "s"}` : "never called" });
|
|
11
|
+
const schemas = schemaBranches(tool.name, tool.inputSchema);
|
|
12
|
+
for (const branch of schemas)
|
|
13
|
+
items.push({ kind: "schema", name: branch.name, covered: calls.some((call) => branch.matches(call.tool.arguments ?? {})), detail: `tool ${tool.name}` });
|
|
14
|
+
}
|
|
15
|
+
const requestSteps = steps.filter((step) => "request" in step);
|
|
16
|
+
for (const resource of contract.resources.filter((x) => x.uri)) {
|
|
17
|
+
const covered = requestSteps.some((step) => step.request.method === "resources/read" && step.request.params?.uri === resource.uri);
|
|
18
|
+
items.push({ kind: "resource", name: resource.uri, covered, detail: covered ? "read by suite" : "never read" });
|
|
19
|
+
}
|
|
20
|
+
for (const template of contract.resourceTemplates.filter((x) => x.uriTemplate)) {
|
|
21
|
+
const prefix = template.uriTemplate.split("{")[0];
|
|
22
|
+
const covered = requestSteps.some((step) => step.request.method === "resources/read" && typeof step.request.params?.uri === "string" && String(step.request.params.uri).startsWith(prefix));
|
|
23
|
+
items.push({ kind: "resource-template", name: template.uriTemplate, covered, detail: covered ? "matching URI read by suite" : "never matched by a resource read" });
|
|
24
|
+
}
|
|
25
|
+
for (const prompt of contract.prompts.filter((x) => x.name)) {
|
|
26
|
+
const covered = requestSteps.some((step) => step.request.method === "prompts/get" && step.request.params?.name === prompt.name);
|
|
27
|
+
items.push({ kind: "prompt", name: prompt.name, covered, detail: covered ? "requested by suite" : "never requested" });
|
|
28
|
+
}
|
|
29
|
+
const fraction = (kind) => { const list = items.filter((x) => x.kind === kind); const covered = list.filter((x) => x.covered).length; return { covered, total: list.length, percent: list.length ? Math.round(covered / list.length * 100) : 100 }; };
|
|
30
|
+
const covered = items.filter((x) => x.covered).length;
|
|
31
|
+
const total = items.length;
|
|
32
|
+
return { schemaVersion: 1, score: total ? Math.round(covered / total * 100) : 100, covered, total, surfaces: { tools: fraction("tool"), resources: fraction("resource"), resourceTemplates: fraction("resource-template"), prompts: fraction("prompt"), schemaBranches: fraction("schema") }, items };
|
|
33
|
+
}
|
|
34
|
+
function schemaBranches(tool, schema) {
|
|
35
|
+
const out = [];
|
|
36
|
+
const walk = (node, path, getter) => {
|
|
37
|
+
if (!node || typeof node !== "object" || Array.isArray(node))
|
|
38
|
+
return;
|
|
39
|
+
const record = node;
|
|
40
|
+
if (record.properties && typeof record.properties === "object")
|
|
41
|
+
for (const [key, child] of Object.entries(record.properties)) {
|
|
42
|
+
const get = (value) => value && typeof value === "object" ? value[key] : undefined;
|
|
43
|
+
out.push({ name: `${tool}:${path}.properties.${key}`, matches: (value) => get(getter(value)) !== undefined });
|
|
44
|
+
walk(child, `${path}.properties.${key}`, (value) => get(getter(value)));
|
|
45
|
+
}
|
|
46
|
+
if (Array.isArray(record.enum))
|
|
47
|
+
for (const option of record.enum)
|
|
48
|
+
out.push({ name: `${tool}:${path}.enum=${JSON.stringify(option)}`, matches: (value) => Object.is(getter(value), option) });
|
|
49
|
+
for (const keyword of ["oneOf", "anyOf"])
|
|
50
|
+
if (Array.isArray(record[keyword]))
|
|
51
|
+
record[keyword].forEach((branch, index) => out.push({ name: `${tool}:${path}.${keyword}[${index}]`, matches: (value) => shallowMatch(getter(value), branch) }));
|
|
52
|
+
};
|
|
53
|
+
walk(schema, "$", (value) => value);
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
function shallowMatch(value, schema) {
|
|
57
|
+
if (!schema || typeof schema !== "object")
|
|
58
|
+
return false;
|
|
59
|
+
const s = schema;
|
|
60
|
+
if ("const" in s)
|
|
61
|
+
return Object.is(value, s.const);
|
|
62
|
+
if (Array.isArray(s.enum))
|
|
63
|
+
return s.enum.some((x) => Object.is(x, value));
|
|
64
|
+
if (s.required && Array.isArray(s.required))
|
|
65
|
+
return !!value && typeof value === "object" && s.required.every((key) => typeof key === "string" && key in value);
|
|
66
|
+
if (typeof s.type === "string")
|
|
67
|
+
return s.type === "array" ? Array.isArray(value) : s.type === "object" ? !!value && typeof value === "object" && !Array.isArray(value) : typeof value === s.type;
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
export function coverageReport(result) {
|
|
71
|
+
const lines = [`MCP Rigor coverage: ${result.score}% (${result.covered}/${result.total})`, `Tools ${result.surfaces.tools.percent}% · Resources ${result.surfaces.resources.percent}% · Templates ${result.surfaces.resourceTemplates.percent}% · Prompts ${result.surfaces.prompts.percent}% · Schema branches ${result.surfaces.schemaBranches.percent}%`];
|
|
72
|
+
const missing = result.items.filter((x) => !x.covered);
|
|
73
|
+
if (!missing.length)
|
|
74
|
+
lines.push("✓ Every discovered surface and schema branch is covered.");
|
|
75
|
+
else {
|
|
76
|
+
lines.push("", "Uncovered:");
|
|
77
|
+
for (const item of missing)
|
|
78
|
+
lines.push(`○ ${item.kind}: ${item.name} — ${item.detail ?? "not exercised"}`);
|
|
79
|
+
}
|
|
80
|
+
return lines.join("\n");
|
|
81
|
+
}
|
|
82
|
+
export function coverageMarkdown(result) { return [`# MCP Rigor coverage — ${result.score}%`, "", `**${result.covered}/${result.total}** discovered coverage units exercised.`, "", "| Surface | Covered | Total | Percent |", "|---|---:|---:|---:|", ...Object.entries(result.surfaces).map(([name, x]) => `| ${name} | ${x.covered} | ${x.total} | ${x.percent}% |`), "", "## Uncovered", "", ...result.items.filter((x) => !x.covered).map((x) => `- **${x.kind}** \`${x.name}\` — ${x.detail ?? "not exercised"}`), ""].join("\n"); }
|
|
83
|
+
//# sourceMappingURL=coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../src/coverage.ts"],"names":[],"mappings":"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"}
|
package/dist/export.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AuditResult } from "./audit.js";
|
|
2
|
+
import type { RunResult } from "./types.js";
|
|
3
|
+
import type { HistoryEntry } from "./workspace.js";
|
|
4
|
+
export declare function csvRows(rows: Array<Array<unknown>>): string;
|
|
5
|
+
/** One row per test of a single run. */
|
|
6
|
+
export declare function runCsv(result: RunResult): string;
|
|
7
|
+
/** One row per test occurrence across history — the raw trend data. */
|
|
8
|
+
export declare function historyCsv(entries: HistoryEntry[]): string;
|
|
9
|
+
/** Aggregated per-test trend: totals, pass rate, average duration. */
|
|
10
|
+
export declare function trendsCsv(entries: HistoryEntry[]): string;
|
|
11
|
+
/** Full run report as a designed PDF: header band, stat cards, striped test table, failure detail. */
|
|
12
|
+
export declare function runPdf(result: RunResult): Buffer;
|
|
13
|
+
/** Historical trends as a designed PDF: overview cards, per-suite run timelines, per-test pass-rate bars. */
|
|
14
|
+
export declare function trendsPdf(entries: HistoryEntry[], scope?: string): Buffer;
|
|
15
|
+
/** Designed security audit PDF: score/grade, severity cards, and finding detail. */
|
|
16
|
+
export declare function auditPdf(result: AuditResult): Buffer;
|
|
17
|
+
export declare function auditCsv(result: AuditResult): string;
|
|
18
|
+
export declare function writeRunCsv(result: RunResult, file: string): Promise<void>;
|
|
19
|
+
export declare function writeRunPdf(result: RunResult, file: string): Promise<void>;
|
|
20
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AASnD,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,MAAM,CAE3D;AAED,wCAAwC;AACxC,wBAAgB,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAIhD;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAO1D;AAED,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAkBzD;AAkLD,sGAAsG;AACtG,wBAAgB,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAsDhD;AAED,6GAA6G;AAC7G,wBAAgB,SAAS,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CA4DzE;AAED,oFAAoF;AACpF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAsCpD;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAIpD;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAmD;AACpI,wBAAsB,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAA2C"}
|