mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
bd1b2c74ae
Resolve the filesystem-selected manifest parent once before deriving script paths and reuse the shared containment rule. Preserve selected manifest spelling and capture metadata while retaining source integrity, symlink refusal and cleanup. Cover differing and identical lexical siblings through both artifact consumers and public CLI/MCP parity.
322 lines
11 KiB
TypeScript
322 lines
11 KiB
TypeScript
import { connectLocalToolsMcp } from "../fixtures/localToolsMcp.js";
|
|
import { parseMcpToolError } from "../fixtures/mcpToolError.js";
|
|
import { expect, onTestFinished } from "vitest";
|
|
import { Client } from "@modelcontextprotocol/client";
|
|
import {
|
|
StdioClientTransport,
|
|
getDefaultEnvironment,
|
|
} from "@modelcontextprotocol/client/stdio";
|
|
import { fileURLToPath } from "node:url";
|
|
import { mkdir, symlink, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { webSourceLocationFixture } from "../fixtures/webSourceLocation.js";
|
|
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
|
|
import { cliTest } from "../support/cli/cliFixture.js";
|
|
|
|
cliTest(
|
|
"accepts numeric UTF-16 coordinates and runs the actual owned source-map codec without a browser",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-source-map-cli-");
|
|
const fixture = webSourceLocationFixture();
|
|
await mkdir(join(root, "files", "modules"), { recursive: true });
|
|
await writeFile(join(root, "files", "modules", "main.js"), fixture.source);
|
|
let manifest = join(root, "manifest.json").replaceAll("\\", "/");
|
|
const map = join(root, "app.js.map");
|
|
await writeFile(manifest, JSON.stringify(fixture.manifest));
|
|
if (process.platform !== "win32") {
|
|
await mkdir(join(root, "lexical"));
|
|
await mkdir(join(root, "nested"));
|
|
await symlink(join(root, "nested"), join(root, "lexical", "link"));
|
|
manifest = `${root}/lexical/link/../manifest.json`;
|
|
}
|
|
await writeFile(map, fixture.sourceMap.text);
|
|
const response = await cli.run({
|
|
arguments: [
|
|
"trace-web-source-location",
|
|
manifest,
|
|
"0",
|
|
map,
|
|
fixture.sourceMap.url,
|
|
"1",
|
|
"0",
|
|
"--json",
|
|
],
|
|
environment: {
|
|
REA_LOG_LEVEL: "silent",
|
|
REA_BROWSER_EXECUTABLE: "relative-unconfigured-browser",
|
|
CLANG_MODULE_CACHE_PATH: map,
|
|
},
|
|
timeoutMs: 45000,
|
|
});
|
|
expect(response.exitCode, response.stdout + response.stderr).toBe(0);
|
|
expect(response.json).toMatchObject({
|
|
normalized_result: {
|
|
manifest: {
|
|
path: manifest,
|
|
reported_output_directory: fixture.manifest.output_directory,
|
|
},
|
|
source: {
|
|
script_index: 0,
|
|
path: join(root, "files", "modules", "main.js"),
|
|
},
|
|
source_map: { association: "caller-selected" },
|
|
generated_offset: 0,
|
|
execution: "unknown",
|
|
matches: [{ content: { text: "original" } }],
|
|
runtime: {
|
|
id: process.versions.bun === undefined ? "node-v8" : "bun",
|
|
},
|
|
},
|
|
});
|
|
const transport = new StdioClientTransport({
|
|
command: process.execPath,
|
|
args: [
|
|
fileURLToPath(new URL("../../scripts/rea.mjs", import.meta.url)),
|
|
"mcp",
|
|
],
|
|
env: {
|
|
...getDefaultEnvironment(),
|
|
REA_LOG_LEVEL: "silent",
|
|
CLANG_MODULE_CACHE_PATH: map,
|
|
},
|
|
stderr: "pipe",
|
|
});
|
|
const client = new Client({
|
|
name: "source-location-cli-parity",
|
|
version: "1",
|
|
});
|
|
onTestFinished(async () => {
|
|
try {
|
|
await client.close();
|
|
} finally {
|
|
await transport.close();
|
|
}
|
|
});
|
|
await client.connect(transport);
|
|
const mcpResponse = await client.callTool({
|
|
name: "trace_web_source_location",
|
|
arguments: {
|
|
manifest_path: manifest,
|
|
script_index: 0,
|
|
source_map: { path: map, url: fixture.sourceMap.url },
|
|
generated_position: { line: 1, column: 0 },
|
|
},
|
|
});
|
|
expect(mcpResponse.isError, JSON.stringify(mcpResponse)).not.toBe(true);
|
|
expect(mcpResponse.structuredContent).toEqual(response.json);
|
|
const invalid = await cli.run({
|
|
arguments: [
|
|
"trace-web-source-location",
|
|
manifest,
|
|
"0",
|
|
map,
|
|
fixture.sourceMap.url,
|
|
"2",
|
|
"0",
|
|
"--json",
|
|
],
|
|
environment: { REA_LOG_LEVEL: "silent" },
|
|
timeoutMs: 45000,
|
|
});
|
|
expect(invalid.exitCode).toBe(1);
|
|
expect(invalid.json).toMatchObject({
|
|
code: "invalid_request",
|
|
details: { issues: [{ path: ["generated_position"] }] },
|
|
});
|
|
},
|
|
// Allow cold CLI and MCP ownership preparation across the full parity sequence.
|
|
180_000,
|
|
);
|
|
|
|
cliTest(
|
|
"applies the shared version constraint to nested indexed maps through CLI and stdio MCP",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-indexed-map-version-");
|
|
const fixture = webSourceLocationFixture();
|
|
await mkdir(join(root, "files", "modules"), { recursive: true });
|
|
await writeFile(join(root, "files", "modules", "main.js"), fixture.source);
|
|
const manifest = join(root, "manifest.json").replaceAll("\\", "/");
|
|
await writeFile(manifest, JSON.stringify(fixture.manifest));
|
|
const { call } = await connectLocalToolsMcp({
|
|
REA_BROWSER_EXECUTABLE: "relative-unconfigured-browser",
|
|
});
|
|
const leaf: unknown = JSON.parse(fixture.sourceMap.text);
|
|
for (const [index, version] of [3, 2, null, undefined, "3"].entries()) {
|
|
const text = JSON.stringify({
|
|
version: 3,
|
|
sections: [
|
|
{
|
|
offset: { line: 0, column: 0 },
|
|
map: {
|
|
version,
|
|
sections: [{ offset: { line: 0, column: 0 }, map: leaf }],
|
|
},
|
|
},
|
|
],
|
|
});
|
|
const path = join(root, `nested-${index}.map`);
|
|
await writeFile(path, text);
|
|
const result = await cli.run({
|
|
arguments: [
|
|
"trace-web-source-location",
|
|
manifest,
|
|
"0",
|
|
path,
|
|
fixture.sourceMap.url,
|
|
"1",
|
|
"0",
|
|
"--json",
|
|
],
|
|
environment: {
|
|
REA_LOG_LEVEL: "silent",
|
|
REA_BROWSER_EXECUTABLE: "relative-unconfigured-browser",
|
|
},
|
|
timeoutMs: 45_000,
|
|
});
|
|
const response = await call("trace_web_source_location", {
|
|
manifest_path: manifest,
|
|
script_index: 0,
|
|
source_map: { path, url: fixture.sourceMap.url },
|
|
generated_position: { line: 1, column: 0 },
|
|
});
|
|
if (version === 3) {
|
|
expect(result.exitCode, result.stderr).toBe(0);
|
|
expect(result.json).toMatchObject({
|
|
normalized_result: {
|
|
matches: [
|
|
{
|
|
state: "mapped",
|
|
section_path: [0, 0],
|
|
content: { text: "original" },
|
|
},
|
|
],
|
|
},
|
|
});
|
|
expect(response.isError, JSON.stringify(response)).not.toBe(true);
|
|
expect(response.structuredContent).toEqual(result.json);
|
|
} else {
|
|
const failure = {
|
|
code: "invalid_request",
|
|
details: {
|
|
issues: [
|
|
{
|
|
path: ["source_map", "path"],
|
|
reason: "invalid_format",
|
|
message: expect.stringContaining(
|
|
"not a version 3 map. Section path: [0].",
|
|
),
|
|
},
|
|
],
|
|
},
|
|
};
|
|
expect(result.exitCode).toBe(1);
|
|
expect(result.json).toMatchObject(failure);
|
|
expect(result.json).not.toHaveProperty("normalized_result");
|
|
expect(parseMcpToolError(response).error).toMatchObject(failure);
|
|
expect(response.structuredContent).toBeUndefined();
|
|
}
|
|
}
|
|
},
|
|
180_000,
|
|
);
|
|
|
|
cliTest(
|
|
"traces empty equal-offset sections while rejecting decreasing offsets and represented overlaps",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-empty-indexed-map-");
|
|
const fixture = webSourceLocationFixture();
|
|
await mkdir(join(root, "files", "modules"), { recursive: true });
|
|
await writeFile(join(root, "files", "modules", "main.js"), fixture.source);
|
|
const manifest = join(root, "manifest.json").replaceAll("\\", "/");
|
|
await writeFile(manifest, JSON.stringify(fixture.manifest));
|
|
const { call } = await connectLocalToolsMcp();
|
|
const leaf: unknown = JSON.parse(fixture.sourceMap.text);
|
|
const empty = { version: 3, sources: [], names: [], mappings: "" };
|
|
const nestedEmpty = {
|
|
version: 3,
|
|
sections: [{ offset: { line: 0, column: 0 }, map: empty }],
|
|
};
|
|
for (const [index, sample] of [
|
|
{ first: empty, firstColumn: 0, nextColumn: 0, succeeds: true },
|
|
{ first: nestedEmpty, firstColumn: 0, nextColumn: 0, succeeds: true },
|
|
{ first: empty, firstColumn: 0, nextColumn: 1, succeeds: true },
|
|
{ first: leaf, firstColumn: 0, nextColumn: 0, succeeds: false },
|
|
{ first: empty, firstColumn: 1, nextColumn: 0, succeeds: false },
|
|
].entries()) {
|
|
const path = join(root, `empty-${index}.map`);
|
|
await writeFile(
|
|
path,
|
|
JSON.stringify({
|
|
version: 3,
|
|
sections: [
|
|
{
|
|
offset: { line: 0, column: sample.firstColumn },
|
|
map: sample.first,
|
|
},
|
|
{ offset: { line: 0, column: sample.nextColumn }, map: leaf },
|
|
],
|
|
}),
|
|
);
|
|
const result = await cli.run({
|
|
arguments: [
|
|
"trace-web-source-location",
|
|
manifest,
|
|
"0",
|
|
path,
|
|
fixture.sourceMap.url,
|
|
"1",
|
|
String(sample.nextColumn),
|
|
"--json",
|
|
],
|
|
environment: { REA_LOG_LEVEL: "silent" },
|
|
timeoutMs: 45_000,
|
|
});
|
|
const response = await call("trace_web_source_location", {
|
|
manifest_path: manifest,
|
|
script_index: 0,
|
|
source_map: { path, url: fixture.sourceMap.url },
|
|
generated_position: { line: 1, column: sample.nextColumn },
|
|
});
|
|
if (sample.succeeds) {
|
|
expect(result.exitCode, result.stderr).toBe(0);
|
|
expect(result.json).toMatchObject({
|
|
normalized_result: {
|
|
lookup: {
|
|
matched_generated_position: {
|
|
line: 1,
|
|
column: sample.nextColumn,
|
|
},
|
|
},
|
|
matches: [
|
|
{
|
|
state: "mapped",
|
|
section_path: [1],
|
|
content: { text: "original" },
|
|
},
|
|
],
|
|
},
|
|
});
|
|
expect(response.isError, JSON.stringify(response)).not.toBe(true);
|
|
expect(response.structuredContent).toEqual(result.json);
|
|
} else {
|
|
const failure = {
|
|
code: "invalid_request",
|
|
details: {
|
|
issues: [
|
|
{
|
|
path: ["source_map", "path"],
|
|
reason: "invalid_format",
|
|
message: expect.stringMatching(/overlap|nondecreasing/u),
|
|
},
|
|
],
|
|
},
|
|
};
|
|
expect(result.exitCode).toBe(1);
|
|
expect(result.json).toMatchObject(failure);
|
|
expect(parseMcpToolError(response).error).toMatchObject(failure);
|
|
}
|
|
}
|
|
},
|
|
180_000,
|
|
);
|