263 lines
9.4 KiB
JavaScript
263 lines
9.4 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { after, before, test } from "node:test";
|
|
import { fileURLToPath } from "node:url";
|
|
import { Client } from "@modelcontextprotocol/client";
|
|
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
|
|
import { CodeModeBridge, connectUpstream, json } from "./bridge.mjs";
|
|
|
|
const entrypoint = fileURLToPath(
|
|
new URL("../../scripts/rea.mjs", import.meta.url),
|
|
);
|
|
const fixture = fileURLToPath(
|
|
new URL("../../tests/conformance/readiness/javascript-cli", import.meta.url),
|
|
);
|
|
const analysisArgs = {
|
|
input_path: fixture,
|
|
detail: "summary",
|
|
max_heap_mb: 128,
|
|
};
|
|
let upstream;
|
|
let bridge;
|
|
before(async () => {
|
|
upstream = await connectUpstream({
|
|
command: process.execPath,
|
|
args: [entrypoint, "mcp"],
|
|
env: { ...process.env, REA_LOG_LEVEL: "silent" },
|
|
});
|
|
bridge = new CodeModeBridge(upstream);
|
|
});
|
|
after(async () => {
|
|
await upstream?.close();
|
|
});
|
|
|
|
test("discovery preserves exact current REA schemas and names", async () => {
|
|
const result = await bridge.search({
|
|
names: ["binary_session"],
|
|
output_schemas: true,
|
|
});
|
|
assert.equal(result.total_tools, upstream.catalog.length);
|
|
const original = upstream.catalog.find(
|
|
(tool) => tool.name === "binary_session",
|
|
);
|
|
const { typescript, output_typescript, ...discovered } = result.tools[0];
|
|
assert.deepEqual(discovered, original);
|
|
assert.match(typescript, /export interface BinarySession_Input/);
|
|
assert.match(output_typescript, /export interface BinarySession_Output/);
|
|
const inputOnly = await bridge.search({ names: ["binary_session"] });
|
|
assert.deepEqual(inputOnly.tools[0].inputSchema, original.inputSchema);
|
|
assert.equal(inputOnly.tools[0].outputSchema, undefined);
|
|
assert.equal(inputOnly.tools[0].output_typescript, output_typescript);
|
|
const all = await bridge.search({ schemas: false });
|
|
assert.deepEqual(
|
|
all.tools.map((tool) => tool.name),
|
|
upstream.catalog.map((tool) => tool.name),
|
|
);
|
|
const query = await bridge.search({ query: "android" });
|
|
assert.ok(query.tools.length > 0);
|
|
assert.ok(query.tools.every((tool) => tool.inputSchema === undefined));
|
|
const querySchemas = await bridge.search({ query: "android", schemas: true });
|
|
assert.ok(querySchemas.tools.every((tool) => tool.inputSchema !== undefined));
|
|
const outputRequested = await bridge.search({
|
|
query: "android",
|
|
output_schemas: true,
|
|
});
|
|
assert.ok(
|
|
outputRequested.tools.every((tool) => tool.outputSchema !== undefined),
|
|
);
|
|
const missed = await bridge.search({
|
|
query: "android impossible_query_word",
|
|
});
|
|
assert.equal(missed.matched_tools, 0);
|
|
assert.ok(
|
|
missed.suggestions.some((tool) => tool.name === "inspect_android_package"),
|
|
);
|
|
assert.ok(missed.suggestions.every((tool) => tool.inputSchema === undefined));
|
|
});
|
|
|
|
test("raw original result and parsed result survive a real MCP call", async () => {
|
|
const result = await bridge.execute({
|
|
code: "const r = await tools.binary_session({}); return {raw:r, parsed:json(r)};",
|
|
});
|
|
assert.equal(result.bridge_error, undefined);
|
|
assert.deepEqual(json(result.value.raw), result.value.parsed);
|
|
assert.equal(result.calls[0].name, "binary_session");
|
|
assert.match(result.calls[0].result_sha256, /^[a-f0-9]{64}$/);
|
|
assert.equal(result.calls[0].is_error, false);
|
|
});
|
|
|
|
test("Promise.all calls settle in order without losing pending work", async () => {
|
|
const result = await bridge.execute({
|
|
code: "return await Promise.all([tools.binary_session({}), tools.binary_session({}), tools.binary_session({})]);",
|
|
});
|
|
assert.equal(result.bridge_error, undefined);
|
|
assert.equal(result.value.length, 3);
|
|
assert.equal(result.calls.length, 3);
|
|
assert.ok(result.calls.every((call) => call.result_sha256));
|
|
});
|
|
|
|
test("upstream invalid-input result remains an original MCP error envelope", async () => {
|
|
const args = {
|
|
input_path: "/nonexistent/rea-codemode-artifact",
|
|
detail: "summary",
|
|
};
|
|
const direct = await upstream.call("analyze_javascript_application", args);
|
|
const result = await bridge.execute({
|
|
code: `return await tools.analyze_javascript_application(${JSON.stringify(args)});`,
|
|
});
|
|
assert.equal(result.bridge_error, undefined);
|
|
assert.equal(result.value.isError, true);
|
|
assert.deepEqual(json(result.value).error, json(direct).error);
|
|
assert.equal(result.calls[0].is_error, true);
|
|
});
|
|
|
|
test("guest has no Node, filesystem, fetch or module-loading capabilities", async () => {
|
|
const result = await bridge.execute({
|
|
code: "return [typeof process,typeof require,typeof fetch,typeof Deno,Function('return typeof process')()];",
|
|
});
|
|
assert.deepEqual(result.value, Array(5).fill("undefined"));
|
|
const imported = await bridge.execute({
|
|
code: "return await import('node:fs');",
|
|
});
|
|
assert.ok(imported.bridge_error);
|
|
});
|
|
|
|
test("CPU deadline interrupts runaway code and the next execution works", async () => {
|
|
const result = await bridge.execute({
|
|
code: "while(true) {}",
|
|
timeout_ms: 20,
|
|
});
|
|
assert.ok(result.bridge_error);
|
|
assert.deepEqual(result.calls, []);
|
|
assert.equal((await bridge.execute({ code: "return 42;" })).value, 42);
|
|
});
|
|
|
|
test("error after successful call preserves original Evidence reference", async () => {
|
|
const result = await bridge.execute({
|
|
code: `await tools.analyze_javascript_application(${JSON.stringify(analysisArgs)}); throw new Error('after-call');`,
|
|
});
|
|
assert.match(result.bridge_error.message, /after-call/);
|
|
assert.ok(result.calls[0].evidence_id);
|
|
assert.ok(result.calls[0].evidence_links.length > 0);
|
|
const readback = await upstream.call("get_evidence_bundle", {
|
|
detail: "summary",
|
|
});
|
|
assert.equal(readback.isError, undefined);
|
|
assert.ok(
|
|
JSON.stringify(json(readback)).includes(result.calls[0].evidence_id),
|
|
);
|
|
for (const evidence_id of result.calls[0].evidence_links) {
|
|
const view = json(
|
|
await upstream.call("inspect_analysis_view", {
|
|
source: { kind: "retained-evidence", evidence_id },
|
|
view: { kind: "summary" },
|
|
}),
|
|
);
|
|
assert.equal(view.normalized_result.parent_evidence_id, evidence_id);
|
|
}
|
|
});
|
|
|
|
test("provider timeout retains its actual partial Evidence reference", async () => {
|
|
const result = await bridge.execute({
|
|
code: `const reply = await tools.analyze_javascript_application(${JSON.stringify({ ...analysisArgs, analysis_timeout_ms: 1 })}); return json(reply);`,
|
|
});
|
|
const partial = result.value.error.details.partial_observation;
|
|
assert.equal(partial.kind, "retained-evidence");
|
|
assert.equal(result.calls[0].is_error, true);
|
|
assert.equal(result.calls[0].partial_evidence_id, partial.evidence_id);
|
|
const view = json(
|
|
await upstream.call("inspect_analysis_view", {
|
|
source: partial,
|
|
view: { kind: "summary" },
|
|
}),
|
|
);
|
|
assert.equal(view.normalized_result.parent_evidence_id, partial.evidence_id);
|
|
});
|
|
|
|
test("cancelling queued calls releases deferred handles and permits reuse", async () => {
|
|
let callStarted;
|
|
const started = new Promise((resolve) => {
|
|
callStarted = resolve;
|
|
});
|
|
const cancelled = new AbortController();
|
|
const controlled = new CodeModeBridge({
|
|
catalog: upstream.catalog,
|
|
async call(name, args, options) {
|
|
const reply = await upstream.call(name, args, options);
|
|
callStarted();
|
|
// A controlled delivery delay after a real result makes the queued
|
|
// cancellation deterministic, without simulating provider behavior.
|
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
return reply;
|
|
},
|
|
});
|
|
const execution = controlled.execute(
|
|
{
|
|
code: "return await Promise.all([tools.binary_session({}), tools.binary_session({})]);",
|
|
},
|
|
{ signal: cancelled.signal },
|
|
);
|
|
await started;
|
|
cancelled.abort(new Error("controlled queued cancellation"));
|
|
const result = await execution;
|
|
assert.ok(result.bridge_error);
|
|
assert.equal(result.calls.length, 2);
|
|
assert.match(
|
|
result.calls[1].transport_error,
|
|
/controlled queued cancellation/,
|
|
);
|
|
assert.equal((await controlled.execute({ code: "return 42;" })).value, 42);
|
|
});
|
|
|
|
test("a guest promise without any producer fails without hanging", async () => {
|
|
const result = await bridge.execute({
|
|
code: "return await new Promise(() => {});",
|
|
});
|
|
assert.match(result.bridge_error.message, /cannot progress/);
|
|
});
|
|
|
|
test("bridge's two tools are usable through actual downstream stdio MCP", async () => {
|
|
const transport = new StdioClientTransport({
|
|
command: process.execPath,
|
|
args: [
|
|
fileURLToPath(new URL("./bridge.mjs", import.meta.url)),
|
|
process.execPath,
|
|
entrypoint,
|
|
"mcp",
|
|
],
|
|
env: { ...process.env, REA_LOG_LEVEL: "silent" },
|
|
stderr: "inherit",
|
|
});
|
|
const client = new Client({ name: "codemode-boundary-test", version: "1" });
|
|
try {
|
|
await client.connect(transport);
|
|
const catalog = await client.listTools();
|
|
assert.deepEqual(
|
|
catalog.tools.map((tool) => tool.name),
|
|
["rea_search", "rea_execute"],
|
|
);
|
|
const found = json(
|
|
await client.callTool({
|
|
name: "rea_search",
|
|
arguments: { names: ["binary_session"] },
|
|
}),
|
|
);
|
|
assert.equal(found.matched_tools, 1);
|
|
const result = json(
|
|
await client.callTool({
|
|
name: "rea_execute",
|
|
arguments: {
|
|
code: "return json(await tools.binary_session({}));",
|
|
},
|
|
}),
|
|
);
|
|
assert.equal(result.value.result.open, false);
|
|
const invalid = await client.callTool({
|
|
name: "rea_execute",
|
|
arguments: { code: 7 },
|
|
});
|
|
assert.equal(invalid.isError, true);
|
|
} finally {
|
|
await client.close();
|
|
}
|
|
});
|