playbook/outfitter-agents/scripts/sync-versions.ts

105 lines
2.9 KiB
TypeScript

#!/usr/bin/env bun
/**
* Syncs package.json versions to marketplace.json after `changeset version` runs.
*
* - Reads each plugin's package.json version
* - Updates corresponding entry in marketplace.json
* - Updates metadata.version to match highest plugin version
* - Skips external plugins (those with object source)
*/
import { readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
const ROOT = import.meta.dirname ? join(import.meta.dirname, "..") : process.cwd();
const MARKETPLACE_PATH = join(ROOT, ".claude-plugin/marketplace.json");
// Local plugins tracked by changesets
const LOCAL_PLUGINS = ["outfitter", "but", "gt", "cli-dev", "outfitter-stack"];
interface Plugin {
name: string;
source: string | object;
version?: string;
[key: string]: unknown;
}
interface Marketplace {
metadata: { version: string; [key: string]: unknown };
plugins: Plugin[];
[key: string]: unknown;
}
function readJson<T>(path: string): T {
return JSON.parse(readFileSync(path, "utf-8"));
}
function writeJson(path: string, data: unknown): void {
writeFileSync(path, JSON.stringify(data, null, "\t") + "\n");
}
function main() {
const marketplace = readJson<Marketplace>(MARKETPLACE_PATH);
let highestVersion = "0.0.0";
for (const pluginName of LOCAL_PLUGINS) {
const pkgPath = join(ROOT, "plugins", pluginName, "package.json");
let pkg: { version: string };
try {
pkg = readJson<{ version: string }>(pkgPath);
} catch {
console.warn(`⚠ Skipping ${pluginName}: no package.json found`);
continue;
}
const version = pkg.version;
if (!version) {
console.warn(`⚠ Skipping ${pluginName}: no version in package.json`);
continue;
}
// Update plugin version in marketplace.json
const plugin = marketplace.plugins.find((p) => p.name === pluginName);
if (plugin && typeof plugin.source === "string") {
const oldVersion = plugin.version;
plugin.version = version;
if (oldVersion !== version) {
console.log(`${pluginName}: ${oldVersion}${version}`);
}
}
// Track highest version for metadata
if (compareVersions(version, highestVersion) > 0) {
highestVersion = version;
}
}
// Update metadata.version to highest
const oldMetaVersion = marketplace.metadata.version;
if (oldMetaVersion !== highestVersion) {
marketplace.metadata.version = highestVersion;
console.log(`✓ metadata.version: ${oldMetaVersion}${highestVersion}`);
}
writeJson(MARKETPLACE_PATH, marketplace);
console.log("✓ marketplace.json synced");
}
/**
* Compare semver versions. Returns:
* - positive if a > b
* - negative if a < b
* - 0 if equal
*/
function compareVersions(a: string, b: string): number {
const [aMajor, aMinor, aPatch] = a.split(".").map(Number);
const [bMajor, bMinor, bPatch] = b.split(".").map(Number);
if (aMajor !== bMajor) return aMajor - bMajor;
if (aMinor !== bMinor) return aMinor - bMinor;
return aPatch - bPatch;
}
main();