mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
p2 (Pi Mobile on Chord v2) moves from pi-private into pi as one commit. Root scripts that loop all workspaces use --if-present; npm test, ./test.sh and the release script cover packages/* only (p2: cd apps/p2 && npm test); sync-versions also updates apps' workspace pins.
98 lines
4 KiB
JavaScript
98 lines
4 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Validates lockstep versions for published packages, then synchronizes
|
|
* exact internal dependency versions in all workspace packages, including private ones,
|
|
* and in the apps next to the packages directory (`apps/*`, never published).
|
|
*/
|
|
|
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
import { dirname, join } from "node:path";
|
|
import { findPackageDirectories } from "./package-workspaces.mjs";
|
|
|
|
const GENERATED_PACKAGE_SUFFIXES = [join("coding-agent", "install-lock")];
|
|
|
|
function readManifests(directories) {
|
|
return directories.map((directory) => {
|
|
const path = join(directory, "package.json");
|
|
return { data: JSON.parse(readFileSync(path, "utf8")), path };
|
|
});
|
|
}
|
|
|
|
const packageRoot = process.argv[2] ?? "packages";
|
|
const workspacePackages = readManifests(
|
|
findPackageDirectories(packageRoot).filter(
|
|
(directory) => !GENERATED_PACKAGE_SUFFIXES.some((suffix) => directory.endsWith(suffix)),
|
|
),
|
|
);
|
|
// Apps pin the workspace packages exactly too; stale pins would make npm install them from the registry.
|
|
const appRoot = join(dirname(packageRoot), "apps");
|
|
const appPackages = existsSync(appRoot) ? readManifests(findPackageDirectories(appRoot)) : [];
|
|
const publishedPackages = workspacePackages.filter((pkg) => pkg.data.private !== true);
|
|
const versionMap = new Map(workspacePackages.map((pkg) => [pkg.data.name, pkg.data.version]));
|
|
|
|
console.log("Current versions:");
|
|
for (const pkg of [...publishedPackages].sort((a, b) => a.data.name.localeCompare(b.data.name))) {
|
|
console.log(` ${pkg.data.name}: ${pkg.data.version}`);
|
|
}
|
|
|
|
const versions = new Set(publishedPackages.map((pkg) => pkg.data.version));
|
|
if (versions.size > 1) {
|
|
console.error("\nERROR: Not all non-private packages have the same version.");
|
|
console.error("Expected lockstep versioning. Run one of:");
|
|
console.error(" npm run version:patch");
|
|
console.error(" npm run version:minor");
|
|
console.error(" npm run version:major");
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log("\nAll non-private packages are at the same version (lockstep).");
|
|
|
|
let totalUpdates = 0;
|
|
const updatedPackages = new Set();
|
|
for (const pkg of [...workspacePackages, ...appPackages]) {
|
|
for (const dependencyType of ["dependencies", "devDependencies", "optionalDependencies"]) {
|
|
const dependencies = pkg.data[dependencyType];
|
|
if (!dependencies) {
|
|
continue;
|
|
}
|
|
|
|
for (const [dependencyName, currentSpecifier] of Object.entries(dependencies)) {
|
|
// Registry aliases such as `npm:@earendil-works/pi-ai@0.1.2` are never workspace-linked,
|
|
// so lockstep bumping them would point at a version that is not published yet.
|
|
const newSpecifier = versionMap.get(dependencyName);
|
|
if (!newSpecifier || currentSpecifier === newSpecifier) {
|
|
continue;
|
|
}
|
|
|
|
console.log(`\n${pkg.data.name}:`);
|
|
console.log(
|
|
` ${dependencyName}: ${currentSpecifier} → ${newSpecifier}${dependencyType === "dependencies" ? "" : ` (${dependencyType})`}`,
|
|
);
|
|
dependencies[dependencyName] = newSpecifier;
|
|
updatedPackages.add(pkg);
|
|
totalUpdates++;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const pkg of updatedPackages) {
|
|
writeFileSync(pkg.path, `${JSON.stringify(pkg.data, null, "\t")}\n`);
|
|
}
|
|
|
|
if (totalUpdates === 0) {
|
|
console.log("\nAll inter-package dependencies are already in sync.");
|
|
} else {
|
|
console.log(`\nUpdated ${totalUpdates} dependency version(s).`);
|
|
}
|
|
|
|
// pi-ai reports its version in the User-Agent without reading package.json, which browsers cannot do.
|
|
const aiPackage = workspacePackages.find((pkg) => pkg.data.name === "@earendil-works/pi-ai");
|
|
const aiVersionPath = aiPackage && join(dirname(aiPackage.path), "src", "utils", "version.ts");
|
|
if (aiVersionPath && existsSync(aiVersionPath)) {
|
|
const content = `// The @earendil-works/pi-ai package version. scripts/sync-versions.js keeps it in sync with package.json.\nexport const PI_AI_VERSION = ${JSON.stringify(aiPackage.data.version)};\n`;
|
|
if (readFileSync(aiVersionPath, "utf8") !== content) {
|
|
writeFileSync(aiVersionPath, content);
|
|
console.log(`\nUpdated ${aiVersionPath} to ${aiPackage.data.version}.`);
|
|
}
|
|
}
|