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, 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); const manifest = join(root, "manifest.json").replaceAll("\\", "/"); const map = join(root, "app.js.map"); await writeFile(manifest, JSON.stringify(fixture.manifest)); 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: { source: { script_index: 0 }, 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, );