Files
reverse-engineering-anything/experiments/analysis-efficiency/web-bundle-paging.mjs
T

342 lines
11 KiB
JavaScript

import assert from "node:assert/strict";
import { createServer } from "node:http";
import { readFile, writeFile, mkdir, mkdtemp, rm } from "node:fs/promises";
import { join, resolve } from "node:path";
import { tmpdir } from "node:os";
import { createRequire } from "node:module";
import { pathToFileURL } from "node:url";
import { execFile } from "node:child_process";
import { promisify, parseArgs } from "node:util";
import { performance } from "node:perf_hooks";
// Public CLI capture and same-session retained MCP queries. All assets and output
// paths are explicitly supplied; this verifier installs no browser or application.
const { values } = parseArgs({
options: {
repository: { type: "string" },
mode: { type: "string" },
output: { type: "string" },
parent: { type: "string" },
application: { type: "string" },
browser: { type: "string" },
task: { type: "string", default: "all" },
"verify-cli": { type: "boolean", default: false },
},
});
assert.ok(values.repository && values.mode && values.output);
const repo = resolve(values.repository),
mode = values.mode,
out = resolve(values.output),
bundle = values.parent && resolve(values.parent);
assert.ok(["capture", "complete", "selected"].includes(mode));
assert.ok(["all", "first-candidate"].includes(values.task));
assert.ok(mode === "capture" ? values.application && values.browser : bundle);
await mkdir(out);
const require = createRequire(join(repo, "package.json"));
const { Client } = await import(
pathToFileURL(require.resolve("@modelcontextprotocol/client"))
);
const { StdioClientTransport } = await import(
pathToFileURL(require.resolve("@modelcontextprotocol/client/stdio"))
);
const env = {
PATH: process.env.PATH,
NODE_OPTIONS: "--max-old-space-size=3072",
UV_THREADPOOL_SIZE: "2",
REA_LOG_LEVEL: "silent",
REA_MCP_INPUT_SCHEMA_PROFILE: "compact",
REA_MCP_TOOL_FAMILIES: "application,session",
};
if (mode === "capture") {
const { chromium } = require("playwright-core");
const assets = resolve(values.application);
const allowed = new Set(
await (await import("node:fs/promises")).readdir(assets),
);
const server = createServer(async (req, res) => {
try {
const name =
new URL(req.url, "http://127.0.0.1").pathname.slice(1) || "index.html";
assert.ok(allowed.has(name));
const data = await readFile(join(assets, name));
res.setHeader(
"Content-Type",
name.endsWith(".js")
? "text/javascript"
: name.endsWith(".css")
? "text/css"
: name.endsWith(".json")
? "application/json"
: "text/html",
);
res.setHeader(
"Content-Type",
res.getHeader("Content-Type") + "; charset=utf-8",
);
res.end(data);
} catch {
res.writeHead(404);
res.end();
}
});
await new Promise((r) => server.listen(0, "127.0.0.1", r));
const origin = `http://127.0.0.1:${server.address().port}`;
const userData = await mkdtemp(join(tmpdir(), "rea-6198-chrome-"));
let context;
try {
context = await chromium.launchPersistentContext(userData, {
executablePath: resolve(values.browser),
headless: true,
args: ["--remote-debugging-port=0", "--no-sandbox"],
});
context
.pages()[0]
.on("pageerror", (e) => console.error("PAGE ERROR", e.message));
context
.pages()[0]
.on("response", (r) => console.error("RESPONSE", r.status(), r.url()));
await context.pages()[0].goto(origin, { waitUntil: "networkidle" });
const port = (
await readFile(join(userData, "DevToolsActivePort"), "utf8")
).split("\n")[0];
const endpoint = `http://127.0.0.1:${port}`;
const targets = await (await fetch(`${endpoint}/json/list`)).json();
const target = targets.find(
(t) => t.type === "page" && t.url === origin + "/",
);
assert.ok(target);
const started = performance.now();
const { stdout, stderr } = await promisify(execFile)(
process.execPath,
[
join(repo, "scripts/rea.mjs"),
"analyze-web-bundle",
endpoint,
target.id,
"--observation-ms",
"1000",
"--max-heap-mb",
"1024",
"--analysis-timeout-ms",
"60000",
"--total-analysis-timeout-ms",
"90000",
"--format",
"json",
],
{ cwd: repo, env, maxBuffer: 64 * 1024 ** 2, timeout: 120000 },
);
await writeFile(join(out, "stderr.txt"), stderr);
const evidence = JSON.parse(stdout);
assert.equal(evidence.operation, "analyze_web_bundle");
assert.ok(evidence.normalized_result.observations);
await writeFile(join(out, "parent.json"), JSON.stringify(evidence));
// Public export/import format comes from the CLI's complete Evidence publication.
console.log(
JSON.stringify({
capture_ms: performance.now() - started,
evidence_id: evidence.evidence_id,
counts: {
endpoints: evidence.normalized_result.observations.endpoints.length,
inferences: evidence.normalized_result.inferences.length,
},
completeness: evidence.normalized_result.completeness,
}),
);
} finally {
await context?.close();
await new Promise((r) => server.close(r));
await rm(userData, { recursive: true, force: true });
}
process.exit(0);
}
const parent = JSON.parse(await readFile(bundle, "utf8"));
const report = parent.normalized_result;
const { createEvidenceBundle } = await import(
pathToFileURL(join(repo, "dist/domain/evidenceBundle.js"))
);
const bundleFile = join(out, "input-bundle.json");
await writeFile(bundleFile, JSON.stringify(createEvidenceBundle([parent])));
const transport = new StdioClientTransport({
command: process.execPath,
args: [join(repo, "scripts/rea.mjs"), "mcp"],
cwd: repo,
env,
stderr: "pipe",
});
transport.stderr?.resume();
const client = new Client({
name: "rea-web-bundle-paging-verifier",
version: "1",
});
const calls = [];
let catalog;
async function invoke(name, args) {
const toolDefinition = catalog.tools.find((t) => t.name === name);
assert.ok(toolDefinition);
const start = performance.now();
const result = await client.callTool(
{ name, arguments: args },
{ toolDefinition, timeout: 90000 },
);
calls.push({
name,
arguments: args,
result,
elapsed_ms: performance.now() - start,
});
assert.notEqual(result.isError, true, JSON.stringify(result));
return result.structuredContent;
}
try {
await client.connect(transport);
catalog = await client.listTools();
await writeFile(join(out, "catalog.json"), JSON.stringify(catalog));
const runs = [];
for (const temperature of ["cold", "warm"]) {
const start = performance.now();
const callStart = calls.length;
if (temperature === "cold")
await invoke("import_evidence_bundle", { path: bundleFile });
if (mode === "complete") {
const full = await invoke("get_evidence_bundle", {});
const actual = full.result.records.find(
(r) => r.evidence_id === parent.evidence_id,
);
assert.deepEqual(actual, parent);
runs.push({
temperature,
elapsed_ms: performance.now() - start,
calls: calls.length - callStart,
});
continue;
}
const source = {
kind: "retained-evidence",
evidence_id: parent.evidence_id,
};
if (values.task === "all") {
const summary = await invoke("inspect_analysis_view", {
source,
view: { kind: "web-bundle", collection: "summary" },
});
assert.equal(
summary.normalized_result.summary.counts.endpoints,
report.observations.endpoints.length,
);
}
if (values.task === "first-candidate") {
const value = await invoke("inspect_analysis_view", {
source,
view: {
kind: "web-bundle",
collection: "inferences",
kinds: ["endpoint_candidate"],
limit: 1,
},
});
const index = report.inferences.findIndex(
(row) => row.kind === "endpoint_candidate",
);
assert.equal(
value.normalized_result.coverage.total,
report.inferences.filter((row) => row.kind === "endpoint_candidate")
.length,
);
assert.deepEqual(
value.normalized_result.items,
index < 0 ? [] : [{ source_index: index, ...report.inferences[index] }],
);
assert.deepEqual(
value.normalized_result.source_unknowns,
report.unknowns,
);
} else
for (const collection of ["endpoints", "inferences"]) {
const expected =
collection === "endpoints"
? report.observations.endpoints
: report.inferences;
const rows = [];
let offset = 0;
do {
const value = await invoke("inspect_analysis_view", {
source,
view: { kind: "web-bundle", collection, offset, limit: 32 },
});
const page = value.normalized_result;
assert.deepEqual(page.source_unknowns, report.unknowns);
assert.deepEqual(page.completeness, report.completeness);
assert.equal(page.coverage.total, expected.length);
for (const row of page.items) {
assert.deepEqual(row, {
source_index: rows.length,
...expected[rows.length],
});
rows.push(row);
}
if (page.coverage.exhausted) break;
assert.ok(page.coverage.next_offset > offset);
offset = page.coverage.next_offset;
} while (true);
assert.equal(rows.length, expected.length);
}
runs.push({
temperature,
elapsed_ms: performance.now() - start,
calls: calls.length - callStart,
});
}
if (mode === "selected" && values["verify-cli"]) {
const input = JSON.stringify({
source: { kind: "evidence-file", path: bundle },
view: {
kind: "web-bundle",
collection: "endpoints",
fields: ["value", "location"],
limit: 32,
},
});
const { stdout } = await promisify(execFile)(
process.execPath,
[
join(repo, "scripts/rea.mjs"),
"inspect-analysis-view",
input,
"--format",
"json",
],
{ cwd: repo, env, maxBuffer: 64 * 1024 ** 2, timeout: 90000 },
);
const cli = JSON.parse(stdout);
assert.deepEqual(
cli.normalized_result.items,
report.observations.endpoints.slice(0, 32).map((r, source_index) => ({
source_index,
value: r.value,
location: r.location,
})),
);
await writeFile(join(out, "cli.json"), stdout);
}
await writeFile(join(out, "calls.json"), JSON.stringify(calls));
await writeFile(
join(out, "metrics.json"),
JSON.stringify(
{
mode,
task: values.task,
runs,
counts: {
endpoints: report.observations.endpoints.length,
inferences: report.inferences.length,
},
},
null,
2,
),
);
console.log(JSON.stringify({ mode, task: values.task, runs }));
} finally {
await client.close();
}