mcprigor 1.0.0-rc.1
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/LICENSE +17 -0
- package/README.md +233 -0
- package/dist/assertions.d.ts +4 -0
- package/dist/assertions.d.ts.map +1 -0
- package/dist/assertions.js +101 -0
- package/dist/assertions.js.map +1 -0
- package/dist/author.d.ts +57 -0
- package/dist/author.d.ts.map +1 -0
- package/dist/author.js +134 -0
- package/dist/author.js.map +1 -0
- package/dist/canonical.d.ts +4 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +17 -0
- package/dist/canonical.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +265 -0
- package/dist/cli.js.map +1 -0
- package/dist/contract.d.ts +28 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +138 -0
- package/dist/contract.js.map +1 -0
- package/dist/data.d.ts +24 -0
- package/dist/data.d.ts.map +1 -0
- package/dist/data.js +367 -0
- package/dist/data.js.map +1 -0
- package/dist/discovery.d.ts +6 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +82 -0
- package/dist/discovery.js.map +1 -0
- package/dist/errors.d.ts +19 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +40 -0
- package/dist/errors.js.map +1 -0
- package/dist/extension-host.d.ts +20 -0
- package/dist/extension-host.d.ts.map +1 -0
- package/dist/extension-host.js +52 -0
- package/dist/extension-host.js.map +1 -0
- package/dist/extension-sdk.d.ts +22 -0
- package/dist/extension-sdk.d.ts.map +1 -0
- package/dist/extension-sdk.js +3 -0
- package/dist/extension-sdk.js.map +1 -0
- package/dist/extension-worker.d.ts +2 -0
- package/dist/extension-worker.d.ts.map +1 -0
- package/dist/extension-worker.js +27 -0
- package/dist/extension-worker.js.map +1 -0
- package/dist/extensions.d.ts +15 -0
- package/dist/extensions.d.ts.map +1 -0
- package/dist/extensions.js +60 -0
- package/dist/extensions.js.map +1 -0
- package/dist/imports.d.ts +7 -0
- package/dist/imports.d.ts.map +1 -0
- package/dist/imports.js +41 -0
- package/dist/imports.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/language.d.ts +34 -0
- package/dist/language.d.ts.map +1 -0
- package/dist/language.js +102 -0
- package/dist/language.js.map +1 -0
- package/dist/loader.d.ts +4 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +51 -0
- package/dist/loader.js.map +1 -0
- package/dist/parity.d.ts +23 -0
- package/dist/parity.d.ts.map +1 -0
- package/dist/parity.js +77 -0
- package/dist/parity.js.map +1 -0
- package/dist/path.d.ts +3 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +71 -0
- package/dist/path.js.map +1 -0
- package/dist/qa-advanced.d.ts +8 -0
- package/dist/qa-advanced.d.ts.map +1 -0
- package/dist/qa-advanced.js +239 -0
- package/dist/qa-advanced.js.map +1 -0
- package/dist/qa-language.d.ts +4 -0
- package/dist/qa-language.d.ts.map +1 -0
- package/dist/qa-language.js +385 -0
- package/dist/qa-language.js.map +1 -0
- package/dist/qa-loader.d.ts +4 -0
- package/dist/qa-loader.d.ts.map +1 -0
- package/dist/qa-loader.js +22 -0
- package/dist/qa-loader.js.map +1 -0
- package/dist/redact.d.ts +7 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +63 -0
- package/dist/redact.js.map +1 -0
- package/dist/replay.d.ts +17 -0
- package/dist/replay.d.ts.map +1 -0
- package/dist/replay.js +48 -0
- package/dist/replay.js.map +1 -0
- package/dist/reporters.d.ts +6 -0
- package/dist/reporters.d.ts.map +1 -0
- package/dist/reporters.js +52 -0
- package/dist/reporters.js.map +1 -0
- package/dist/runner.d.ts +16 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +304 -0
- package/dist/runner.js.map +1 -0
- package/dist/schema.d.ts +446 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +117 -0
- package/dist/schema.js.map +1 -0
- package/dist/session.d.ts +5 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +111 -0
- package/dist/session.js.map +1 -0
- package/dist/snapshots.d.ts +28 -0
- package/dist/snapshots.d.ts.map +1 -0
- package/dist/snapshots.js +87 -0
- package/dist/snapshots.js.map +1 -0
- package/dist/starter.d.ts +3 -0
- package/dist/starter.d.ts.map +1 -0
- package/dist/starter.js +34 -0
- package/dist/starter.js.map +1 -0
- package/dist/state.d.ts +13 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +29 -0
- package/dist/state.js.map +1 -0
- package/dist/trace.d.ts +57 -0
- package/dist/trace.d.ts.map +1 -0
- package/dist/trace.js +94 -0
- package/dist/trace.js.map +1 -0
- package/dist/types.d.ts +245 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/workspace.d.ts +10 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +144 -0
- package/dist/workspace.js.map +1 -0
- package/docs/CLI-REFERENCE.md +167 -0
- package/docs/COMPATIBILITY.md +42 -0
- package/docs/CONTRACT-DRIFT.md +42 -0
- package/docs/DATA-AND-REUSE.md +213 -0
- package/docs/DATA-ENGINEERING.md +96 -0
- package/docs/ENGINEER-SETUP.md +176 -0
- package/docs/ERROR-MODEL.md +24 -0
- package/docs/EVIDENCE.md +58 -0
- package/docs/EXTENSION-SDK.md +76 -0
- package/docs/FILE-EXTENSION.md +52 -0
- package/docs/GETTING-STARTED.md +126 -0
- package/docs/GUIDED-AUTHORING.md +80 -0
- package/docs/LANDSCAPE.md +81 -0
- package/docs/LANGUAGE-SPEC.md +317 -0
- package/docs/MCP-NATIVE.md +111 -0
- package/docs/PLAIN-LANGUAGE-COOKBOOK.md +219 -0
- package/docs/QA-GUIDE.md +128 -0
- package/docs/QA-WORKSPACE.md +78 -0
- package/docs/README.md +55 -0
- package/docs/SECURITY-AND-RETENTION.md +37 -0
- package/docs/SNAPSHOTS-AND-REPLAY.md +85 -0
- package/docs/SPECIFICATION.md +178 -0
- package/docs/STATE-AND-DEPENDENCIES.md +106 -0
- package/docs/TRANSPORT-PARITY.md +98 -0
- package/docs/TROUBLESHOOTING.md +199 -0
- package/editors/mcpr-language.json +16 -0
- package/package.json +70 -0
- package/workspace-assets/app.js +1 -0
- package/workspace-assets/index.html +1 -0
- package/workspace-assets/style.css +1 -0
package/dist/session.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
4
|
+
import { CreateMessageRequestSchema, ElicitRequestSchema, ListRootsRequestSchema, LoggingMessageNotificationSchema, ProgressNotificationSchema, PromptListChangedNotificationSchema, ResourceListChangedNotificationSchema, ResourceUpdatedNotificationSchema, ResultSchema, TaskStatusNotificationSchema, ToolListChangedNotificationSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { RigorError } from "./errors.js";
|
|
6
|
+
const activeSessions = new Set();
|
|
7
|
+
export function createSession(target) { const session = new SdkSession(target, () => activeSessions.delete(session)); activeSessions.add(session); return session; }
|
|
8
|
+
export async function shutdownSessions() { await Promise.allSettled([...activeSessions].map((session) => session.close())); activeSessions.clear(); }
|
|
9
|
+
export function installSignalCleanup() { const handler = () => { void shutdownSessions().finally(() => { process.exitCode = 130; }); }; process.once("SIGINT", handler); process.once("SIGTERM", handler); return () => { process.off("SIGINT", handler); process.off("SIGTERM", handler); }; }
|
|
10
|
+
class SdkSession {
|
|
11
|
+
target;
|
|
12
|
+
disposed;
|
|
13
|
+
client = new Client({ name: "mcprigor", version: "1.0.0-rc.1" }, { capabilities: { roots: { listChanged: true }, sampling: {}, elicitation: { form: {}, url: {} } } });
|
|
14
|
+
messages = [];
|
|
15
|
+
diagnosticBytes = 0;
|
|
16
|
+
nativeEvents = [];
|
|
17
|
+
sequence = 0;
|
|
18
|
+
behavior = {};
|
|
19
|
+
transport;
|
|
20
|
+
waiters = [];
|
|
21
|
+
constructor(target, disposed) {
|
|
22
|
+
this.target = target;
|
|
23
|
+
this.disposed = disposed;
|
|
24
|
+
this.installHandlers();
|
|
25
|
+
}
|
|
26
|
+
configureClient(behavior) { this.behavior = behavior; }
|
|
27
|
+
async connect() {
|
|
28
|
+
if (this.target.transport === "stdio") {
|
|
29
|
+
const env = this.target.env ? { ...process.env, ...this.target.env } : undefined;
|
|
30
|
+
this.transport = new StdioClientTransport({ command: this.target.command, args: this.target.args, cwd: this.target.cwd, env, stderr: "pipe" });
|
|
31
|
+
this.transport.stderr?.on("data", (chunk) => { if (this.diagnosticBytes >= 64 * 1024)
|
|
32
|
+
return; const text = String(chunk).slice(0, 16 * 1024).trimEnd(); this.diagnosticBytes += Buffer.byteLength(text); this.messages.push(text); });
|
|
33
|
+
}
|
|
34
|
+
else
|
|
35
|
+
this.transport = new StreamableHTTPClientTransport(new URL(this.target.url), { requestInit: { headers: this.target.headers } });
|
|
36
|
+
try {
|
|
37
|
+
await this.client.connect(this.transport, { timeout: 10_000 });
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
await this.client.close().catch(() => { });
|
|
41
|
+
this.disposed();
|
|
42
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
43
|
+
if (/ENOENT|spawn/i.test(message))
|
|
44
|
+
throw new RigorError("server-spawn", "MCP-SPAWN-001", message, undefined, error);
|
|
45
|
+
throw new RigorError(/timeout/i.test(message) ? "timeout" : "initialization", /timeout/i.test(message) ? "MCP-TIMEOUT-001" : "MCP-INIT-001", message, undefined, error);
|
|
46
|
+
}
|
|
47
|
+
const server = this.client.getServerVersion();
|
|
48
|
+
return { protocolVersion: this.transport instanceof StreamableHTTPClientTransport ? this.transport.protocolVersion : undefined, serverName: server?.name, serverVersion: server?.version, capabilities: this.client.getServerCapabilities() };
|
|
49
|
+
}
|
|
50
|
+
async request(method, params, timeoutMs = 10_000) { return this.client.request({ method, params: params }, ResultSchema, { timeout: timeoutMs }); }
|
|
51
|
+
async nativeRequest(method, params, options = {}) {
|
|
52
|
+
const progress = [];
|
|
53
|
+
const taskEvents = [];
|
|
54
|
+
const controller = new AbortController();
|
|
55
|
+
const timer = options.cancelAfterMs ? setTimeout(() => controller.abort(new Error("MCP request cancelled by test")), options.cancelAfterMs) : undefined;
|
|
56
|
+
try {
|
|
57
|
+
if (options.task && method === "tools/call") {
|
|
58
|
+
for await (const event of this.client.experimental.tasks.callToolStream(params, undefined, { timeout: options.timeoutMs, signal: controller.signal })) {
|
|
59
|
+
taskEvents.push(event);
|
|
60
|
+
if (event.type === "result")
|
|
61
|
+
return { result: event.result, progress, taskEvents };
|
|
62
|
+
if (event.type === "error")
|
|
63
|
+
throw event.error;
|
|
64
|
+
}
|
|
65
|
+
throw new Error("MCP-TASK-001 Task stream ended without a result");
|
|
66
|
+
}
|
|
67
|
+
const result = await this.client.request({ method, params: params }, ResultSchema, { timeout: options.timeoutMs, signal: controller.signal, onprogress: options.progress ? (event) => progress.push(event) : undefined });
|
|
68
|
+
return { result, progress, taskEvents };
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
if (timer)
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
events() { return structuredClone(this.nativeEvents); }
|
|
76
|
+
awaitEvent(method, timeoutMs = 5_000) {
|
|
77
|
+
const existing = this.nativeEvents.find((event) => event.method === method);
|
|
78
|
+
if (existing)
|
|
79
|
+
return Promise.resolve(structuredClone(existing));
|
|
80
|
+
return new Promise((resolve, reject) => { const timer = setTimeout(() => { this.waiters = this.waiters.filter((item) => item.timer !== timer); reject(new Error(`MCP-EVENT-001 Timed out waiting for ${method}`)); }, timeoutMs); this.waiters.push({ method, resolve, reject, timer }); });
|
|
81
|
+
}
|
|
82
|
+
async subscribe(uri) { return this.client.subscribeResource({ uri }); }
|
|
83
|
+
async unsubscribe(uri) { return this.client.unsubscribeResource({ uri }); }
|
|
84
|
+
async setLoggingLevel(level) { return this.client.setLoggingLevel(level); }
|
|
85
|
+
async close() { for (const waiter of this.waiters) {
|
|
86
|
+
clearTimeout(waiter.timer);
|
|
87
|
+
waiter.reject(new RigorError("cancellation", "MCP-CANCEL-001", "Session closed while waiting for an event"));
|
|
88
|
+
} this.waiters = []; try {
|
|
89
|
+
await this.client.close();
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
throw new RigorError("cleanup", "MCP-CLEANUP-002", error instanceof Error ? error.message : String(error), undefined, error);
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
this.disposed();
|
|
96
|
+
} }
|
|
97
|
+
diagnostics() { return [...this.messages]; }
|
|
98
|
+
installHandlers() {
|
|
99
|
+
const notificationSchemas = [ProgressNotificationSchema, LoggingMessageNotificationSchema, ResourceUpdatedNotificationSchema, ResourceListChangedNotificationSchema, ToolListChangedNotificationSchema, PromptListChangedNotificationSchema, TaskStatusNotificationSchema];
|
|
100
|
+
for (const schema of notificationSchemas)
|
|
101
|
+
this.client.setNotificationHandler(schema, (notification) => this.pushEvent(notification.method, notification.params));
|
|
102
|
+
this.client.setRequestHandler(ListRootsRequestSchema, async () => ({ roots: this.behavior.roots ?? [] }));
|
|
103
|
+
this.client.setRequestHandler(CreateMessageRequestSchema, async () => ({ model: this.behavior.sampling?.model ?? "mcprigor-fixture", role: "assistant", content: { type: "text", text: this.behavior.sampling?.text ?? "deterministic response" }, stopReason: "endTurn" }));
|
|
104
|
+
this.client.setRequestHandler(ElicitRequestSchema, async () => ({ action: this.behavior.elicitation?.action ?? "decline", ...(this.behavior.elicitation?.content ? { content: this.behavior.elicitation.content } : {}) }));
|
|
105
|
+
}
|
|
106
|
+
pushEvent(method, params) { const event = { method, params, sequence: ++this.sequence }; this.nativeEvents.push(event); for (const waiter of this.waiters.filter((item) => item.method === method)) {
|
|
107
|
+
clearTimeout(waiter.timer);
|
|
108
|
+
waiter.resolve(structuredClone(event));
|
|
109
|
+
} this.waiters = this.waiters.filter((item) => item.method !== method); }
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EACL,0BAA0B,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,gCAAgC,EACzG,0BAA0B,EAAE,mCAAmC,EAAE,qCAAqC,EACtG,iCAAiC,EAAE,YAAY,EAAE,4BAA4B,EAAE,iCAAiC,GACjH,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAe,CAAC;AAC9C,MAAM,UAAU,aAAa,CAAC,MAAc,IAAiB,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC;AACzL,MAAM,CAAC,KAAK,UAAU,gBAAgB,KAAoB,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AACpK,MAAM,UAAU,oBAAoB,KAAiB,MAAM,OAAO,GAAG,GAAG,EAAE,GAAG,KAAK,gBAAgB,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE3S,MAAM,UAAU;IAKe;IAAiC;IAJ7C,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAS,EAAE,CAAC,CAAC;IAC9K,QAAQ,GAAa,EAAE,CAAC;IAAS,eAAe,GAAG,CAAC,CAAC;IAAkB,YAAY,GAAkB,EAAE,CAAC;IAAS,QAAQ,GAAG,CAAC,CAAC;IACvI,QAAQ,GAAmB,EAAE,CAAC;IAAS,SAAS,CAAwD;IACxG,OAAO,GAA4H,EAAE,CAAC;IAC9I,YAA6B,MAAc,EAAmB,QAAoB;QAArD,WAAM,GAAN,MAAM,CAAQ;QAAmB,aAAQ,GAAR,QAAQ,CAAY;QAAI,IAAI,CAAC,eAAe,EAAE,CAAC;IAAC,CAAC;IAE/G,eAAe,CAAC,QAAwB,IAAU,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC;IAC7E,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;YACtC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAA4B,CAAC,CAAC,CAAC,SAAS,CAAC;YAC3G,IAAI,CAAC,SAAS,GAAG,IAAI,oBAAoB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;YAC/I,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,IAAI,CAAC,eAAe,IAAI,EAAE,GAAG,IAAI;gBAAE,OAAO,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxO,CAAC;;YAAM,IAAI,CAAC,SAAS,GAAG,IAAI,6BAA6B,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACvI,IAAI,CAAC;YAAC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAAC,CAAC;QACvE,OAAO,KAAK,EAAE,CAAC;YAAC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YAAC,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAAC,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC;gBAAE,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;YAAC,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAAC,CAAC;QACnb,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC9C,OAAO,EAAE,eAAe,EAAE,IAAI,CAAC,SAAS,YAAY,6BAA6B,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,qBAAqB,EAAE,EAAE,CAAC;IAChP,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,MAAgB,EAAE,SAAS,GAAG,MAAM,IAAsB,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAA6C,EAAE,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9N,KAAK,CAAC,aAAa,CAAC,MAAc,EAAE,MAAgB,EAAE,UAAgC,EAAE;QACtF,MAAM,QAAQ,GAAc,EAAE,CAAC;QAAC,MAAM,UAAU,GAAc,EAAE,CAAC;QAAC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QAC3G,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACxJ,IAAI,CAAC;YACH,IAAI,OAAO,CAAC,IAAI,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;gBAC5C,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,cAAc,CAAC,MAAa,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;oBAC7J,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAAC,IAAK,KAAa,CAAC,IAAI,KAAK,QAAQ;wBAAE,OAAO,EAAE,MAAM,EAAG,KAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;oBAC7H,IAAK,KAAa,CAAC,IAAI,KAAK,OAAO;wBAAE,MAAO,KAAa,CAAC,KAAK,CAAC;gBAClE,CAAC;gBACD,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;YACrE,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAa,EAAE,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;YACjO,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;QAC1C,CAAC;gBAAS,CAAC;YAAC,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAAC,CAAC;IAC/C,CAAC;IACD,MAAM,KAAoB,OAAO,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACtE,UAAU,CAAC,MAAc,EAAE,SAAS,GAAG,KAAK;QAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QAAC,IAAI,QAAQ;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC7I,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,uCAAuC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9R,CAAC;IACD,KAAK,CAAC,SAAS,CAAC,GAAW,IAAsB,OAAO,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IACjG,KAAK,CAAC,WAAW,CAAC,GAAW,IAAsB,OAAO,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IACrG,KAAK,CAAC,eAAe,CAAC,KAAa,IAAsB,OAAO,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,KAAY,CAAC,CAAC,CAAC,CAAC;IAC5G,KAAK,CAAC,KAAK,KAAoB,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAAC,MAAM,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,cAAc,EAAE,gBAAgB,EAAE,2CAA2C,CAAC,CAAC,CAAC;IAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC;QAAC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAAC,MAAM,IAAI,UAAU,CAAC,SAAS,EAAE,iBAAiB,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IAAC,CAAC;YAAS,CAAC;QAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IAAC,CAAC,CAAC,CAAC;IACpb,WAAW,KAAe,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAE9C,eAAe;QACrB,MAAM,mBAAmB,GAAG,CAAC,0BAA0B,EAAE,gCAAgC,EAAE,iCAAiC,EAAE,qCAAqC,EAAE,iCAAiC,EAAE,mCAAmC,EAAE,4BAA4B,CAAU,CAAC;QACpR,KAAK,MAAM,MAAM,IAAI,mBAAmB;YAAE,IAAI,CAAC,MAAM,CAAC,sBAAsB,CAAC,MAAa,EAAE,CAAC,YAAiB,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7K,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1G,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,IAAI,kBAAkB,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,IAAI,wBAAwB,EAAE,EAAE,UAAU,EAAE,SAAS,EAAU,CAAA,CAAC,CAAC;QACpR,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,IAAI,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAU,CAAA,CAAC,CAAC;IACrO,CAAC;IACO,SAAS,CAAC,MAAc,EAAE,MAAe,IAAU,MAAM,KAAK,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;QAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAAC,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;IAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;CACnX"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface SnapshotFile {
|
|
2
|
+
schemaVersion: 1;
|
|
3
|
+
snapshots: Record<string, unknown>;
|
|
4
|
+
}
|
|
5
|
+
export interface SnapshotOptions {
|
|
6
|
+
file: string;
|
|
7
|
+
update?: boolean;
|
|
8
|
+
ignore?: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare class SnapshotStore {
|
|
11
|
+
private readonly options;
|
|
12
|
+
private data;
|
|
13
|
+
private dirty;
|
|
14
|
+
constructor(options: SnapshotOptions);
|
|
15
|
+
load(): Promise<void>;
|
|
16
|
+
match(name: string, actual: unknown, ignore?: string[]): void;
|
|
17
|
+
save(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export interface SemanticChange {
|
|
20
|
+
path: string;
|
|
21
|
+
kind: "added" | "removed" | "changed";
|
|
22
|
+
before?: unknown;
|
|
23
|
+
after?: unknown;
|
|
24
|
+
}
|
|
25
|
+
export declare function semanticDiff(before: unknown, after: unknown, path?: string, changes?: SemanticChange[]): SemanticChange[];
|
|
26
|
+
export declare function renderSemanticDiff(changes: SemanticChange[]): string;
|
|
27
|
+
export declare function normalizeSnapshot(value: unknown, ignore: string[]): unknown;
|
|
28
|
+
//# sourceMappingURL=snapshots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshots.d.ts","sourceRoot":"","sources":["../src/snapshots.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAAG,aAAa,EAAE,CAAC,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE;AACtF,MAAM,WAAW,eAAe;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE;AAEtF,qBAAa,aAAa;IAEZ,OAAO,CAAC,QAAQ,CAAC,OAAO;IADpC,OAAO,CAAC,IAAI,CAAqD;IAAC,OAAO,CAAC,KAAK,CAAS;gBAC3D,OAAO,EAAE,eAAe;IAC/C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAC3B,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAE,MAAM,EAAO,GAAG,IAAI;IAM3D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE;AAC1H,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,SAAM,EAAE,OAAO,GAAE,cAAc,EAAO,GAAG,cAAc,EAAE,CAK1H;AACD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,CAAqS;AAC1W,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAA0H"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { canonicalize } from "./canonical.js";
|
|
4
|
+
export class SnapshotStore {
|
|
5
|
+
options;
|
|
6
|
+
data = { schemaVersion: 1, snapshots: {} };
|
|
7
|
+
dirty = false;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
}
|
|
11
|
+
async load() { try {
|
|
12
|
+
const value = JSON.parse(await readFile(resolve(this.options.file), "utf8"));
|
|
13
|
+
if (value.schemaVersion !== 1 || !value.snapshots)
|
|
14
|
+
throw new Error("invalid format");
|
|
15
|
+
this.data = value;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error.code !== "ENOENT")
|
|
19
|
+
throw new Error(`MCP-SNAPSHOT-001 Cannot load snapshot: ${error instanceof Error ? error.message : String(error)}`);
|
|
20
|
+
} }
|
|
21
|
+
match(name, actual, ignore = []) {
|
|
22
|
+
const normalized = normalizeSnapshot(actual, [...(this.options.ignore ?? []), ...ignore]);
|
|
23
|
+
if (!(name in this.data.snapshots)) {
|
|
24
|
+
if (!this.options.update)
|
|
25
|
+
throw new Error(`MCP-SNAPSHOT-002 Snapshot “${name}” does not exist. Re-run with --update-snapshots.`);
|
|
26
|
+
this.data.snapshots[name] = normalized;
|
|
27
|
+
this.dirty = true;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const expected = this.data.snapshots[name];
|
|
31
|
+
const changes = semanticDiff(expected, normalized);
|
|
32
|
+
if (changes.length) {
|
|
33
|
+
if (this.options.update) {
|
|
34
|
+
this.data.snapshots[name] = normalized;
|
|
35
|
+
this.dirty = true;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`MCP-SNAPSHOT-003 Snapshot “${name}” changed:\n${renderSemanticDiff(changes)}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async save() { if (!this.dirty)
|
|
42
|
+
return; const file = resolve(this.options.file); await mkdir(dirname(file), { recursive: true }); await writeFile(file, JSON.stringify(canonicalize(this.data), null, 2) + "\n", "utf8"); }
|
|
43
|
+
}
|
|
44
|
+
export function semanticDiff(before, after, path = "$", changes = []) {
|
|
45
|
+
if (Object.is(before, after))
|
|
46
|
+
return changes;
|
|
47
|
+
if (Array.isArray(before) && Array.isArray(after)) {
|
|
48
|
+
const length = Math.max(before.length, after.length);
|
|
49
|
+
for (let i = 0; i < length; i++) {
|
|
50
|
+
if (i >= before.length)
|
|
51
|
+
changes.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
|
|
52
|
+
else if (i >= after.length)
|
|
53
|
+
changes.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
|
|
54
|
+
else
|
|
55
|
+
semanticDiff(before[i], after[i], `${path}[${i}]`, changes);
|
|
56
|
+
}
|
|
57
|
+
return changes;
|
|
58
|
+
}
|
|
59
|
+
if (record(before) && record(after)) {
|
|
60
|
+
const keys = [...new Set([...Object.keys(before), ...Object.keys(after)])].sort();
|
|
61
|
+
for (const key of keys) {
|
|
62
|
+
if (!(key in before))
|
|
63
|
+
changes.push({ path: `${path}.${key}`, kind: "added", after: after[key] });
|
|
64
|
+
else if (!(key in after))
|
|
65
|
+
changes.push({ path: `${path}.${key}`, kind: "removed", before: before[key] });
|
|
66
|
+
else
|
|
67
|
+
semanticDiff(before[key], after[key], `${path}.${key}`, changes);
|
|
68
|
+
}
|
|
69
|
+
return changes;
|
|
70
|
+
}
|
|
71
|
+
changes.push({ path, kind: "changed", before, after });
|
|
72
|
+
return changes;
|
|
73
|
+
}
|
|
74
|
+
export function renderSemanticDiff(changes) { return changes.map((item) => item.kind === "added" ? `+ ${item.path}: ${JSON.stringify(item.after)}` : item.kind === "removed" ? `- ${item.path}: ${JSON.stringify(item.before)}` : `- ${item.path}: ${JSON.stringify(item.before)}\n+ ${item.path}: ${JSON.stringify(item.after)}`).join("\n"); }
|
|
75
|
+
export function normalizeSnapshot(value, ignore) { const clone = structuredClone(value); for (const path of ignore)
|
|
76
|
+
removePath(clone, path); return canonicalize(clone); }
|
|
77
|
+
function removePath(value, path) { if (!path.startsWith("$.") || !record(value))
|
|
78
|
+
return; const parts = path.slice(2).replace(/\[(\d+)\]/g, ".$1").split("."); let current = value; for (let i = 0; i < parts.length - 1; i++) {
|
|
79
|
+
current = current?.[parts[i]];
|
|
80
|
+
if (current == null)
|
|
81
|
+
return;
|
|
82
|
+
} if (Array.isArray(current))
|
|
83
|
+
current.splice(Number(parts.at(-1)), 1);
|
|
84
|
+
else if (record(current))
|
|
85
|
+
delete current[parts.at(-1)]; }
|
|
86
|
+
function record(value) { return typeof value === "object" && value !== null && !Array.isArray(value); }
|
|
87
|
+
//# sourceMappingURL=snapshots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshots.js","sourceRoot":"","sources":["../src/snapshots.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const starterTemplate = "# MCP Rigor \u2014 plain-language acceptance tests\nSuite: \"My MCP server\"\n\n# For a local server:\nServer: node dist/server.js\n\n# Or replace the line above with:\n# MCP URL: http://localhost:3000/mcp\n\nTest: \"The calculator adds two numbers\"\n Require: tools\n\n Call tool \"add\" with:\n a: 2\n b: 3\n\n Expect \"structuredContent.sum\" equals 5\n Save \"structuredContent.sum\" as \"answer\"\n";
|
|
2
|
+
export declare function writeStarter(file: string, force?: boolean): Promise<void>;
|
|
3
|
+
//# sourceMappingURL=starter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"starter.d.ts","sourceRoot":"","sources":["../src/starter.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,eAAe,maAkB3B,CAAC;AAEF,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ7E"}
|
package/dist/starter.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { access, writeFile } from "node:fs/promises";
|
|
2
|
+
export const starterTemplate = `# MCP Rigor — plain-language acceptance tests
|
|
3
|
+
Suite: "My MCP server"
|
|
4
|
+
|
|
5
|
+
# For a local server:
|
|
6
|
+
Server: node dist/server.js
|
|
7
|
+
|
|
8
|
+
# Or replace the line above with:
|
|
9
|
+
# MCP URL: http://localhost:3000/mcp
|
|
10
|
+
|
|
11
|
+
Test: "The calculator adds two numbers"
|
|
12
|
+
Require: tools
|
|
13
|
+
|
|
14
|
+
Call tool "add" with:
|
|
15
|
+
a: 2
|
|
16
|
+
b: 3
|
|
17
|
+
|
|
18
|
+
Expect "structuredContent.sum" equals 5
|
|
19
|
+
Save "structuredContent.sum" as "answer"
|
|
20
|
+
`;
|
|
21
|
+
export async function writeStarter(file, force = false) {
|
|
22
|
+
if (!force) {
|
|
23
|
+
try {
|
|
24
|
+
await access(file);
|
|
25
|
+
throw new Error(`QA-INIT-001 ${file} already exists. Choose another name or add --force.`);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (error instanceof Error && error.message.startsWith("QA-INIT-001"))
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
await writeFile(file, starterTemplate, "utf8");
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=starter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"starter.js","sourceRoot":"","sources":["../src/starter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;CAkB9B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY,EAAE,KAAK,GAAG,KAAK;IAC5D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,CAAC;YAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YAAC,MAAM,IAAI,KAAK,CAAC,eAAe,IAAI,sDAAsD,CAAC,CAAC;QAAC,CAAC;QACvH,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC;gBAAE,MAAM,KAAK,CAAC;QACrF,CAAC;IACH,CAAC;IACD,MAAM,SAAS,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC;AACjD,CAAC"}
|
package/dist/state.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Target } from "./types.js";
|
|
2
|
+
export interface PersistedState {
|
|
3
|
+
formatVersion: 1;
|
|
4
|
+
createdAt: string;
|
|
5
|
+
targetFingerprint: string;
|
|
6
|
+
suiteFingerprint: string;
|
|
7
|
+
outputs: Record<string, unknown>;
|
|
8
|
+
integrity: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function targetFingerprint(target: Target): string;
|
|
11
|
+
export declare function readState(file: string, target: Target, allowTargetMismatch?: boolean): Promise<PersistedState>;
|
|
12
|
+
export declare function writeState(file: string, target: Target, suite: unknown, outputs: Record<string, unknown>): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,CAAC,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,UAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,CAQlH;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAO9H"}
|
package/dist/state.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { chmod, readFile, rename, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, basename, join } from "node:path";
|
|
3
|
+
import { fingerprint } from "./canonical.js";
|
|
4
|
+
export function targetFingerprint(target) {
|
|
5
|
+
if (target.transport === "stdio")
|
|
6
|
+
return fingerprint({ transport: target.transport, command: target.command, args: target.args ?? [], cwd: target.cwd });
|
|
7
|
+
return fingerprint({ transport: target.transport, url: target.url });
|
|
8
|
+
}
|
|
9
|
+
export async function readState(file, target, allowTargetMismatch = false) {
|
|
10
|
+
const value = JSON.parse(await readFile(file, "utf8"));
|
|
11
|
+
if (value.formatVersion !== 1 || typeof value.outputs !== "object" || !value.outputs)
|
|
12
|
+
throw new Error("MCP-STATE-001 State file format is invalid");
|
|
13
|
+
const expectedIntegrity = fingerprint({ ...value, integrity: undefined });
|
|
14
|
+
if (value.integrity !== expectedIntegrity)
|
|
15
|
+
throw new Error("MCP-STATE-002 State file integrity check failed");
|
|
16
|
+
const current = targetFingerprint(target);
|
|
17
|
+
if (!allowTargetMismatch && value.targetFingerprint !== current)
|
|
18
|
+
throw new Error("MCP-STATE-003 State file belongs to a different MCP target. Use --allow-state-target-mismatch only after reviewing it.");
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
export async function writeState(file, target, suite, outputs) {
|
|
22
|
+
const core = { formatVersion: 1, createdAt: new Date().toISOString(), targetFingerprint: targetFingerprint(target), suiteFingerprint: fingerprint(suite), outputs };
|
|
23
|
+
const value = { ...core, integrity: fingerprint({ ...core, integrity: undefined }) };
|
|
24
|
+
const temporary = join(dirname(file), `.${basename(file)}.${process.pid}.tmp`);
|
|
25
|
+
await writeFile(temporary, `${JSON.stringify(value, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
|
|
26
|
+
await chmod(temporary, 0o600);
|
|
27
|
+
await rename(temporary, file);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAY7C,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,IAAI,MAAM,CAAC,SAAS,KAAK,OAAO;QAAE,OAAO,WAAW,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IACzJ,OAAO,WAAW,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,MAAc,EAAE,mBAAmB,GAAG,KAAK;IACvF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAmB,CAAC;IACzE,IAAI,KAAK,CAAC,aAAa,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IACpJ,MAAM,iBAAiB,GAAG,WAAW,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;IAC1E,IAAI,KAAK,CAAC,SAAS,KAAK,iBAAiB;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAC9G,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,CAAC,mBAAmB,IAAI,KAAK,CAAC,iBAAiB,KAAK,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,wHAAwH,CAAC,CAAC;IAC3M,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY,EAAE,MAAc,EAAE,KAAc,EAAE,OAAgC;IAC7G,MAAM,IAAI,GAAG,EAAE,aAAa,EAAE,CAAU,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAC7K,MAAM,KAAK,GAAmB,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IACrG,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;IAC/E,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrG,MAAM,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC9B,MAAM,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC"}
|
package/dist/trace.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type Redactor } from "./redact.js";
|
|
2
|
+
import type { RunResult, Target, TestSession } from "./types.js";
|
|
3
|
+
export type TraceEventType = "session.connect.start" | "session.connect.success" | "request" | "response" | "error" | "session.close" | "diagnostic";
|
|
4
|
+
export interface TraceEvent {
|
|
5
|
+
schemaVersion: 1;
|
|
6
|
+
sequence: number;
|
|
7
|
+
elapsedMs: number;
|
|
8
|
+
type: TraceEventType;
|
|
9
|
+
testId?: string;
|
|
10
|
+
step?: string;
|
|
11
|
+
requestId?: string;
|
|
12
|
+
method?: string;
|
|
13
|
+
data?: unknown;
|
|
14
|
+
}
|
|
15
|
+
export interface NormalizedTraceEvent {
|
|
16
|
+
schemaVersion: 1;
|
|
17
|
+
sequence: number;
|
|
18
|
+
type: TraceEventType;
|
|
19
|
+
testId?: string;
|
|
20
|
+
step?: string;
|
|
21
|
+
requestId?: string;
|
|
22
|
+
method?: string;
|
|
23
|
+
data?: unknown;
|
|
24
|
+
}
|
|
25
|
+
export interface EvidenceManifest {
|
|
26
|
+
schemaVersion: 1;
|
|
27
|
+
frameworkVersion: string;
|
|
28
|
+
createdAt: string;
|
|
29
|
+
suiteName: string;
|
|
30
|
+
status: RunResult["status"];
|
|
31
|
+
resultHash: string;
|
|
32
|
+
traceHash: string;
|
|
33
|
+
normalizedTraceHash: string;
|
|
34
|
+
files: Record<string, string>;
|
|
35
|
+
target: {
|
|
36
|
+
transport: Target["transport"];
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export declare class TraceRecorder {
|
|
40
|
+
private readonly redactor;
|
|
41
|
+
private readonly started;
|
|
42
|
+
private sequence;
|
|
43
|
+
private request;
|
|
44
|
+
readonly events: TraceEvent[];
|
|
45
|
+
constructor(redactor?: Redactor);
|
|
46
|
+
record(type: TraceEventType, fields?: Omit<TraceEvent, "schemaVersion" | "sequence" | "elapsedMs" | "type">): TraceEvent;
|
|
47
|
+
nextRequestId(): string;
|
|
48
|
+
normalized(): NormalizedTraceEvent[];
|
|
49
|
+
}
|
|
50
|
+
export declare function traceSession(session: TestSession, recorder: TraceRecorder, context: () => {
|
|
51
|
+
testId?: string;
|
|
52
|
+
step?: string;
|
|
53
|
+
}): TestSession;
|
|
54
|
+
export declare function writeEvidenceBundle(directory: string, result: RunResult, target: Target, recorder: TraceRecorder): Promise<EvidenceManifest>;
|
|
55
|
+
export declare function showEvidence(directory: string): Promise<string>;
|
|
56
|
+
export declare function compareEvidence(first: string, second: string): Promise<string>;
|
|
57
|
+
//# sourceMappingURL=trace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../src/trace.ts"],"names":[],"mappings":"AAGA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9E,MAAM,MAAM,cAAc,GAAG,uBAAuB,GAAG,yBAAyB,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,eAAe,GAAG,YAAY,CAAC;AACrJ,MAAM,WAAW,UAAU;IAAG,aAAa,EAAE,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE;AAChM,MAAM,WAAW,oBAAoB;IAAG,aAAa,EAAE,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE;AACvL,MAAM,WAAW,gBAAgB;IAAG,aAAa,EAAE,CAAC,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;KAAE,CAAA;CAAE;AAElS,qBAAa,aAAa;IAGZ,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAFrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IAAC,OAAO,CAAC,QAAQ,CAAK;IAAC,OAAO,CAAC,OAAO,CAAK;IACjF,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,CAAM;gBACN,QAAQ,GAAE,QAA2B;IAClE,MAAM,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,GAAE,IAAI,CAAC,UAAU,EAAE,eAAe,GAAG,UAAU,GAAG,WAAW,GAAG,MAAM,CAAM,GAAG,UAAU;IAG5H,aAAa,IAAI,MAAM;IACvB,UAAU,IAAI,oBAAoB,EAAE;CACrC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,CAc1I;AAED,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CASlJ;AAED,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIrE;AACD,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIpF"}
|
package/dist/trace.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { basename, join, resolve } from "node:path";
|
|
3
|
+
import { canonicalize, fingerprint } from "./canonical.js";
|
|
4
|
+
import { createRedactor } from "./redact.js";
|
|
5
|
+
export class TraceRecorder {
|
|
6
|
+
redactor;
|
|
7
|
+
started = Date.now();
|
|
8
|
+
sequence = 0;
|
|
9
|
+
request = 0;
|
|
10
|
+
events = [];
|
|
11
|
+
constructor(redactor = createRedactor()) {
|
|
12
|
+
this.redactor = redactor;
|
|
13
|
+
}
|
|
14
|
+
record(type, fields = {}) {
|
|
15
|
+
const event = this.redactor.value({ schemaVersion: 1, sequence: ++this.sequence, elapsedMs: Date.now() - this.started, type, ...fields });
|
|
16
|
+
this.events.push(event);
|
|
17
|
+
return event;
|
|
18
|
+
}
|
|
19
|
+
nextRequestId() { return `request-${++this.request}`; }
|
|
20
|
+
normalized() { return this.events.map(({ elapsedMs: _elapsed, ...event }) => canonicalize(normalizeVolatile(event))); }
|
|
21
|
+
}
|
|
22
|
+
export function traceSession(session, recorder, context) {
|
|
23
|
+
return {
|
|
24
|
+
async connect() { recorder.record("session.connect.start", context()); try {
|
|
25
|
+
const info = await session.connect();
|
|
26
|
+
recorder.record("session.connect.success", { ...context(), data: info });
|
|
27
|
+
return info;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
recorder.record("error", { ...context(), data: safeError(error) });
|
|
31
|
+
throw error;
|
|
32
|
+
} },
|
|
33
|
+
async request(method, params, timeoutMs) { const requestId = recorder.nextRequestId(); recorder.record("request", { ...context(), requestId, method, data: { params, timeoutMs } }); try {
|
|
34
|
+
const response = await session.request(method, params, timeoutMs);
|
|
35
|
+
recorder.record("response", { ...context(), requestId, method, data: response });
|
|
36
|
+
return response;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
recorder.record("error", { ...context(), requestId, method, data: safeError(error) });
|
|
40
|
+
throw error;
|
|
41
|
+
} },
|
|
42
|
+
async close() { try {
|
|
43
|
+
await session.close();
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
recorder.record("session.close", context());
|
|
47
|
+
for (const message of session.diagnostics())
|
|
48
|
+
recorder.record("diagnostic", { ...context(), data: message });
|
|
49
|
+
} },
|
|
50
|
+
nativeRequest: session.nativeRequest ? (method, params, options) => session.nativeRequest(method, params, options) : undefined,
|
|
51
|
+
events: session.events ? () => session.events() : undefined,
|
|
52
|
+
awaitEvent: session.awaitEvent ? (method, timeoutMs) => session.awaitEvent(method, timeoutMs) : undefined,
|
|
53
|
+
subscribe: session.subscribe ? (uri) => session.subscribe(uri) : undefined,
|
|
54
|
+
unsubscribe: session.unsubscribe ? (uri) => session.unsubscribe(uri) : undefined,
|
|
55
|
+
setLoggingLevel: session.setLoggingLevel ? (level) => session.setLoggingLevel(level) : undefined,
|
|
56
|
+
configureClient: session.configureClient ? (behavior) => session.configureClient(behavior) : undefined,
|
|
57
|
+
diagnostics: () => session.diagnostics(),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export async function writeEvidenceBundle(directory, result, target, recorder) {
|
|
61
|
+
const root = resolve(directory);
|
|
62
|
+
await mkdir(root, { recursive: true });
|
|
63
|
+
const raw = recorder.events.map((event) => JSON.stringify(event)).join("\n") + "\n";
|
|
64
|
+
const normalizedEvents = recorder.normalized();
|
|
65
|
+
const normalized = normalizedEvents.map((event) => JSON.stringify(event)).join("\n") + "\n";
|
|
66
|
+
const files = { result: "result.json", trace: "trace.jsonl", normalizedTrace: "trace.normalized.jsonl", manifest: "manifest.json" };
|
|
67
|
+
const manifestCore = { schemaVersion: 1, frameworkVersion: "1.0.0-rc.1", createdAt: new Date().toISOString(), suiteName: result.suiteName, status: result.status, resultHash: result.evidenceHash, traceHash: fingerprint(recorder.events), normalizedTraceHash: fingerprint(normalizedEvents), files, target: { transport: target.transport } };
|
|
68
|
+
const manifest = manifestCore;
|
|
69
|
+
await Promise.all([writeFile(join(root, files.result), JSON.stringify(result, null, 2) + "\n"), writeFile(join(root, files.trace), raw), writeFile(join(root, files.normalizedTrace), normalized), writeFile(join(root, files.manifest), JSON.stringify(manifest, null, 2) + "\n")]);
|
|
70
|
+
return manifest;
|
|
71
|
+
}
|
|
72
|
+
export async function showEvidence(directory) {
|
|
73
|
+
const manifest = JSON.parse(await readFile(join(resolve(directory), "manifest.json"), "utf8"));
|
|
74
|
+
const result = JSON.parse(await readFile(join(resolve(directory), manifest.files.result), "utf8"));
|
|
75
|
+
return [`Evidence: ${basename(resolve(directory))}`, `Suite: ${manifest.suiteName}`, `Status: ${manifest.status}`, `Tests: ${result.summary.passed} passed, ${result.summary.failed} failed, ${result.summary.blocked} blocked`, `Result: ${manifest.resultHash}`, `Normalized trace: ${manifest.normalizedTraceHash}`].join("\n");
|
|
76
|
+
}
|
|
77
|
+
export async function compareEvidence(first, second) {
|
|
78
|
+
const a = JSON.parse(await readFile(join(resolve(first), "manifest.json"), "utf8"));
|
|
79
|
+
const b = JSON.parse(await readFile(join(resolve(second), "manifest.json"), "utf8"));
|
|
80
|
+
if (a.normalizedTraceHash === b.normalizedTraceHash && a.resultHash === b.resultHash)
|
|
81
|
+
return "Evidence bundles are semantically identical.";
|
|
82
|
+
const lines = ["Evidence bundles differ:"];
|
|
83
|
+
if (a.resultHash !== b.resultHash)
|
|
84
|
+
lines.push(`- Result hash: ${a.resultHash} → ${b.resultHash}`);
|
|
85
|
+
if (a.normalizedTraceHash !== b.normalizedTraceHash)
|
|
86
|
+
lines.push(`- Trace hash: ${a.normalizedTraceHash} → ${b.normalizedTraceHash}`);
|
|
87
|
+
return lines.join("\n");
|
|
88
|
+
}
|
|
89
|
+
function normalizeVolatile(value) { if (Array.isArray(value))
|
|
90
|
+
return value.map(normalizeVolatile); if (!value || typeof value !== "object")
|
|
91
|
+
return typeof value === "string" ? value.replace(/\/var\/folders\/[^\s"']+/g, "<temp-path>").replace(/\/tmp\/[^\s"']+/g, "<temp-path>") : value; return Object.fromEntries(Object.entries(value).filter(([key]) => !/timestamp|createdAt|sessionId/i.test(key)).map(([key, item]) => [key, normalizeVolatile(item)])); }
|
|
92
|
+
function safeError(error) { if (!(error instanceof Error))
|
|
93
|
+
return { message: String(error) }; const candidate = error; return { name: error.name, message: error.message, code: candidate.code, data: candidate.data }; }
|
|
94
|
+
//# sourceMappingURL=trace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.js","sourceRoot":"","sources":["../src/trace.ts"],"names":[],"mappings":"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"}
|