mirror of
https://github.com/earendil-works/pi.git
synced 2026-06-18 15:54:04 +08:00
116 lines
3.8 KiB
JavaScript
116 lines
3.8 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { spawnSync } from "node:child_process";
|
|
import { existsSync, readFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
|
|
const packages = [
|
|
{ directory: "packages/ai", name: "@earendil-works/pi-ai" },
|
|
{ directory: "packages/agent", name: "@earendil-works/pi-agent-core" },
|
|
{ directory: "packages/tui", name: "@earendil-works/pi-tui" },
|
|
{ directory: "packages/coding-agent", name: "@earendil-works/pi-coding-agent" },
|
|
];
|
|
|
|
const dryRun = process.argv.includes("--dry-run");
|
|
const unknownArgs = process.argv.slice(2).filter((arg) => arg !== "--dry-run");
|
|
|
|
if (unknownArgs.length > 0) {
|
|
console.error(`Usage: node scripts/publish.mjs [--dry-run]`);
|
|
process.exit(1);
|
|
}
|
|
|
|
function commandForPlatform(command) {
|
|
return process.platform === "win32" ? `${command}.cmd` : command;
|
|
}
|
|
|
|
function run(command, args, options = {}) {
|
|
console.log(`$ ${[command, ...args].join(" ")}`);
|
|
const result = spawnSync(commandForPlatform(command), args, {
|
|
cwd: options.cwd,
|
|
encoding: "utf8",
|
|
stdio: options.capture ? ["inherit", "pipe", "pipe"] : "inherit",
|
|
});
|
|
|
|
if (result.status !== 0) {
|
|
const output = [result.stdout, result.stderr].filter(Boolean).join("\n");
|
|
throw new Error(output ? `Command failed: ${command} ${args.join(" ")}\n${output}` : `Command failed: ${command} ${args.join(" ")}`);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function readPackageJson(directory) {
|
|
return JSON.parse(readFileSync(join(directory, "package.json"), "utf8"));
|
|
}
|
|
|
|
function assertBuildOutputExists(directory) {
|
|
if (!existsSync(join(directory, "dist"))) {
|
|
throw new Error(`${directory}/dist does not exist. Run npm run build before publishing.`);
|
|
}
|
|
}
|
|
|
|
function validatePack(directory) {
|
|
const result = run("npm", ["pack", "--dry-run", "--ignore-scripts", "--json"], { capture: true, cwd: directory });
|
|
const packed = JSON.parse(result.stdout)[0];
|
|
console.log(` ${packed.filename}: ${packed.files.length} files, ${packed.size} bytes packed, ${packed.unpackedSize} bytes unpacked`);
|
|
}
|
|
|
|
function isPublished(name, version) {
|
|
const result = spawnSync(commandForPlatform("npm"), ["view", `${name}@${version}`, "version", "--json"], {
|
|
encoding: "utf8",
|
|
stdio: ["inherit", "pipe", "pipe"],
|
|
});
|
|
|
|
if (result.status === 0 && result.stdout.trim()) {
|
|
return true;
|
|
}
|
|
|
|
const output = [result.stdout, result.stderr].filter(Boolean).join("\n");
|
|
if (result.status !== 0 && (output.includes("E404") || output.includes("404 Not Found"))) {
|
|
return false;
|
|
}
|
|
|
|
throw new Error(output ? `Failed to query ${name}@${version}\n${output}` : `Failed to query ${name}@${version}`);
|
|
}
|
|
|
|
const packageVersions = new Map();
|
|
for (const pkg of packages) {
|
|
const packageJson = readPackageJson(pkg.directory);
|
|
if (packageJson.name !== pkg.name) {
|
|
throw new Error(`${pkg.directory}/package.json has name ${packageJson.name}, expected ${pkg.name}`);
|
|
}
|
|
packageVersions.set(pkg.name, packageJson.version);
|
|
}
|
|
|
|
const versions = [...new Set(packageVersions.values())];
|
|
if (versions.length !== 1) {
|
|
throw new Error(`Publish packages are not lockstep versioned: ${versions.join(", ")}`);
|
|
}
|
|
|
|
console.log(`Publishing pi packages at ${versions[0]}${dryRun ? " (dry run)" : ""}\n`);
|
|
|
|
for (const pkg of packages) {
|
|
const version = packageVersions.get(pkg.name);
|
|
assertBuildOutputExists(pkg.directory);
|
|
const published = isPublished(pkg.name, version);
|
|
|
|
if (dryRun) {
|
|
if (published) {
|
|
console.log(`${pkg.name}@${version} is already published; validating package contents only.`);
|
|
} else {
|
|
console.log(`${pkg.name}@${version} is not published; validating package contents before publish.`);
|
|
}
|
|
validatePack(pkg.directory);
|
|
console.log();
|
|
continue;
|
|
}
|
|
|
|
if (published) {
|
|
console.log(`Skipping ${pkg.name}@${version}: already published\n`);
|
|
continue;
|
|
}
|
|
|
|
run("npm", ["publish", "--access", "public", "--provenance", "--ignore-scripts"], { cwd: pkg.directory });
|
|
console.log();
|
|
}
|