Files
2026-07-13 12:52:40 +08:00

156 lines
4.2 KiB
TypeScript

#!/usr/bin/env bun
import { mkdtemp, readdir, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
const root = join(import.meta.dir, "..");
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
async function runCommand(
cmd: string[],
options: {
cwd: string;
env?: Record<string, string | undefined>;
captureStdout?: boolean;
timeoutMs?: number;
},
): Promise<string> {
const captureStdout = options.captureStdout === true;
let timedOut = false;
const proc = Bun.spawn(cmd, {
cwd: options.cwd,
env: {
...process.env,
...options.env,
},
stdout: captureStdout ? "pipe" : "inherit",
stderr: "inherit",
});
const stdoutPromise =
captureStdout && proc.stdout
? new Response(proc.stdout).text()
: Promise.resolve("");
const timeout = setTimeout(
() => {
timedOut = true;
proc.kill();
},
options.timeoutMs ?? 5 * 60_000,
);
timeout.unref();
const exitCode = await proc.exited.finally(() => clearTimeout(timeout));
const stdout = await stdoutPromise;
if (exitCode !== 0) {
if (timedOut) {
throw new Error(
`${cmd.join(" ")} timed out after ${options.timeoutMs ?? 5 * 60_000}ms`,
);
}
throw new Error(`${cmd.join(" ")} exited with code ${exitCode}`);
}
return stdout.trim();
}
async function packWorkspace(
workspace: "core" | "agents" | "llms" | "shared",
packDir: string,
): Promise<string> {
const destination = await mkdtemp(join(packDir, `${workspace}-`));
await runCommand(["bun", "pm", "pack", "--destination", destination], {
cwd: join(root, `packages/${workspace}`),
timeoutMs: 2 * 60_000,
});
const files = (await readdir(destination)).filter((file) =>
file.endsWith(".tgz"),
);
if (files.length !== 1) {
throw new Error(
`Expected one tarball for ${workspace}, found ${files.length}`,
);
}
return join(destination, files[0]);
}
async function main(): Promise<void> {
const packDir = await mkdtemp(join(tmpdir(), "cline-node-smoke-packs-"));
const smokeDir = await mkdtemp(join(tmpdir(), "cline-node-smoke-"));
const sessionsDir = await mkdtemp(join(tmpdir(), "cline-node-sessions-"));
const npmCacheDir = await mkdtemp(join(tmpdir(), "cline-node-npm-cache-"));
const npmEnv = { npm_config_cache: npmCacheDir };
try {
console.log("Packing smoke-test tarballs with Bun...");
const tarballs = {
core: await packWorkspace("core", packDir),
agents: await packWorkspace("agents", packDir),
llms: await packWorkspace("llms", packDir),
shared: await packWorkspace("shared", packDir),
};
await writeFile(
join(smokeDir, "package.json"),
`${JSON.stringify(
{
name: "cline-node-smoke",
private: true,
type: "module",
dependencies: {
"@cline/core": `file:${tarballs.core}`,
"@cline/agents": `file:${tarballs.agents}`,
"@cline/llms": `file:${tarballs.llms}`,
"@cline/shared": `file:${tarballs.shared}`,
},
},
null,
2,
)}\n`,
);
console.log("Installing smoke-test dependencies...");
await runCommand([npmCommand, "install"], {
cwd: smokeDir,
env: npmEnv,
timeoutMs: 10 * 60_000,
});
const nodeMajor = Number(process.versions.node.split(".")[0] || "0");
const smokeSource =
nodeMajor >= 24
? `
const { SqliteSessionStore } = await import("@cline/core");
const store = new SqliteSessionStore({ sessionsDir: process.env.CLINE_DATA_DIR });
try {
store.init();
console.log("SQLite smoke test passed");
} finally {
store.close();
}
`
: `
const { resolveSessionBackend } = await import("@cline/core");
await resolveSessionBackend({ backendMode: "local" });
console.log("Node compatibility smoke test passed");
`;
const smokeFile = join(smokeDir, "smoke.mjs");
await writeFile(smokeFile, `${smokeSource.trim()}\n`);
console.log("Running smoke test...");
await runCommand(["node", smokeFile], {
cwd: smokeDir,
env: {
...npmEnv,
CLINE_DATA_DIR: sessionsDir,
},
timeoutMs: 2 * 60_000,
});
} finally {
await rm(packDir, { recursive: true, force: true });
await rm(smokeDir, { recursive: true, force: true });
await rm(sessionsDir, { recursive: true, force: true });
await rm(npmCacheDir, { recursive: true, force: true });
}
}
await main();