mirror of
https://github.com/morluto/rea.git
synced 2026-10-12 02:19:24 +00:00
* fix(build): emit no runtime imports for type-only bindings
Under verbatimModuleSyntax, an import whose specifiers all carry inline
`type` modifiers compiles to `import {} from "..."`, a side-effect import
that still resolves and evaluates the module. 78 compiled modules carried
one, including `import {} from "playwright-core"` in the browser scenario
session, which loaded Playwright's module graph at MCP startup.
Use top-level `import type` for these bindings and enable oxlint's
typescript/no-import-type-side-effects rule so the pattern cannot return.
Refs #1685
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* perf(mcp): load Playwright when a scenario launches, not at startup
The browser scenario and Electron active providers are constructed before
the stdio server serves, and both bound Playwright's launchers at module
load. Resolve `chromium` and `_electron` from playwright-core when a
capture opens instead, as the web module resolver already does.
MCP startup now resolves 1,312 modules (4,902 resolutions) instead of
1,598 (6,076) before reading the first request, and no longer loads
playwright-core. Provider construction, the tool catalog, and capability
inventory are unchanged.
A boundary test spawns the stdio server, initializes, lists tools, and
asserts playwright-core and isomorphic-git were not resolved; the CLI
probe now exercises the real launch path to prove detection.
Closes #1685
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
127 lines
4.0 KiB
TypeScript
127 lines
4.0 KiB
TypeScript
import { lstat, open, rename, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { buffer } from "node:stream/consumers";
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import type { ArtifactEntry } from "../../../src/artifacts/ArtifactReader.js";
|
|
import { DirectoryArtifactReader } from "../../../src/artifacts/DirectoryArtifactReader.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
|
|
const sampleEntry = async (
|
|
reader: DirectoryArtifactReader,
|
|
): Promise<ArtifactEntry> => {
|
|
for await (const entry of reader.entries()) {
|
|
if (entry.path === "sample.txt") return entry;
|
|
}
|
|
throw new Error("Fixture omitted sample.txt");
|
|
};
|
|
|
|
const fixture = async () => {
|
|
const root = await createTestTempDirectory("rea-dir-reader-open-");
|
|
const path = join(root, "sample.txt");
|
|
await writeFile(path, "test payload\n");
|
|
return { path, reader: new DirectoryArtifactReader(root) };
|
|
};
|
|
|
|
describe("DirectoryArtifactReader.open", () => {
|
|
it("preserves native path and handle identity while streaming an unchanged file", async () => {
|
|
const { path, reader } = await fixture();
|
|
try {
|
|
const entry = await sampleEntry(reader);
|
|
const metadata = await lstat(path);
|
|
const handle = await open(path, "r");
|
|
try {
|
|
const observed = await handle.stat();
|
|
expect(entry.sourceIdentity).toEqual({
|
|
device: metadata.dev,
|
|
inode: metadata.ino,
|
|
});
|
|
expect({ device: observed.dev, inode: observed.ino }).toEqual(
|
|
entry.sourceIdentity,
|
|
);
|
|
console.info(
|
|
JSON.stringify({
|
|
platform: process.platform,
|
|
node: process.version,
|
|
pathDevice: metadata.dev,
|
|
handleDevice: observed.dev,
|
|
pathInode: metadata.ino,
|
|
handleInode: observed.ino,
|
|
}),
|
|
);
|
|
} finally {
|
|
await handle.close();
|
|
}
|
|
expect((await buffer(await reader.open(entry))).toString("utf8")).toBe(
|
|
"test payload\n",
|
|
);
|
|
} finally {
|
|
await reader.close();
|
|
}
|
|
});
|
|
|
|
it("rejects an actual file replacement after enumeration", async () => {
|
|
const { path, reader } = await fixture();
|
|
try {
|
|
const entry = await sampleEntry(reader);
|
|
await rename(path, `${path}.original`);
|
|
await writeFile(path, "replacement payload\n");
|
|
await expect(reader.open(entry)).rejects.toMatchObject({
|
|
reason: "integrity",
|
|
});
|
|
} finally {
|
|
await reader.close();
|
|
}
|
|
});
|
|
|
|
it.each(["zero", "another"] as const)(
|
|
"requires the enumerated %s device to match the opened file",
|
|
async (kind) => {
|
|
const { reader } = await fixture();
|
|
try {
|
|
const entry = await sampleEntry(reader);
|
|
const identity = entry.sourceIdentity;
|
|
if (identity === undefined)
|
|
throw new Error("Fixture omitted source identity");
|
|
if (kind === "zero" && identity.device === 0) {
|
|
expect(
|
|
(await buffer(await reader.open(entry))).toString("utf8"),
|
|
).toBe("test payload\n");
|
|
return;
|
|
}
|
|
const device = kind === "zero" ? 0 : identity.device === 1 ? 2 : 1;
|
|
await expect(
|
|
reader.open({ ...entry, sourceIdentity: { ...identity, device } }),
|
|
).rejects.toMatchObject({ reason: "integrity" });
|
|
} finally {
|
|
await reader.close();
|
|
}
|
|
},
|
|
);
|
|
|
|
it("rejects a file without enumerated source identity", async () => {
|
|
const { reader } = await fixture();
|
|
try {
|
|
const { sourceIdentity: _identity, ...entry } = await sampleEntry(reader);
|
|
await expect(reader.open(entry)).rejects.toMatchObject({
|
|
reason: "integrity",
|
|
});
|
|
} finally {
|
|
await reader.close();
|
|
}
|
|
});
|
|
|
|
it("rejects entries that are not files", async () => {
|
|
const { reader } = await fixture();
|
|
try {
|
|
const entry = await sampleEntry(reader);
|
|
await expect(
|
|
reader.open({ ...entry, kind: "directory" }),
|
|
).rejects.toMatchObject({ reason: "format" });
|
|
} finally {
|
|
await reader.close();
|
|
}
|
|
});
|
|
});
|