From b5938a651e92b74ee9276db9eb7f4fcf658601e5 Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Tue, 7 Apr 2026 22:09:46 -0700 Subject: [PATCH] bump: update plugin version to 1.0.3 --- .claude-plugin/marketplace.json | 4 +- package-lock.json | 4 +- package.json | 4 +- plugins/codex/.claude-plugin/plugin.json | 2 +- scripts/bump-version.mjs | 227 +++++++++++++++++++++++ tests/bump-version.test.mjs | 88 +++++++++ 6 files changed, 323 insertions(+), 6 deletions(-) create mode 100644 scripts/bump-version.mjs create mode 100644 tests/bump-version.test.mjs diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 21024a0..d7f7c4a 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -5,13 +5,13 @@ }, "metadata": { "description": "Codex plugins to use in Claude Code for delegation and code review.", - "version": "1.0.2" + "version": "1.0.3" }, "plugins": [ { "name": "codex", "description": "Use Codex from Claude Code to review code or delegate tasks.", - "version": "1.0.2", + "version": "1.0.3", "author": { "name": "OpenAI" }, diff --git a/package-lock.json b/package-lock.json index 36ad570..4600691 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@openai/codex-plugin-cc", - "version": "1.0.2", + "version": "1.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@openai/codex-plugin-cc", - "version": "1.0.2", + "version": "1.0.3", "license": "Apache-2.0", "devDependencies": { "@types/node": "^25.5.0", diff --git a/package.json b/package.json index 5ace406..2f8efc9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@openai/codex-plugin-cc", - "version": "1.0.2", + "version": "1.0.3", "private": true, "type": "module", "description": "Use Codex from Claude Code to review code or delegate tasks.", @@ -9,6 +9,8 @@ "node": ">=18.18.0" }, "scripts": { + "bump-version": "node scripts/bump-version.mjs", + "check-version": "node scripts/bump-version.mjs --check", "prebuild": "mkdir -p plugins/codex/.generated/app-server-types && codex app-server generate-ts --out plugins/codex/.generated/app-server-types", "build": "tsc -p tsconfig.app-server.json", "test": "node --test tests/*.test.mjs" diff --git a/plugins/codex/.claude-plugin/plugin.json b/plugins/codex/.claude-plugin/plugin.json index 8d04c2a..db3b22d 100644 --- a/plugins/codex/.claude-plugin/plugin.json +++ b/plugins/codex/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "codex", - "version": "1.0.2", + "version": "1.0.3", "description": "Use Codex from Claude Code to review code or delegate tasks.", "author": { "name": "OpenAI" diff --git a/scripts/bump-version.mjs b/scripts/bump-version.mjs new file mode 100644 index 0000000..19b9888 --- /dev/null +++ b/scripts/bump-version.mjs @@ -0,0 +1,227 @@ +#!/usr/bin/env node +import fs from "node:fs"; +import path from "node:path"; +import process from "node:process"; + +const VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/; + +const TARGETS = [ + { + file: "package.json", + values: [ + { + label: "version", + get: (json) => json.version, + set: (json, version) => { + json.version = version; + } + } + ] + }, + { + file: "package-lock.json", + values: [ + { + label: "version", + get: (json) => json.version, + set: (json, version) => { + json.version = version; + } + }, + { + label: "packages[\"\"].version", + get: (json) => json.packages?.[""]?.version, + set: (json, version) => { + requireObject(json.packages?.[""], "package-lock.json packages[\"\"]"); + json.packages[""].version = version; + } + } + ] + }, + { + file: "plugins/codex/.claude-plugin/plugin.json", + values: [ + { + label: "version", + get: (json) => json.version, + set: (json, version) => { + json.version = version; + } + } + ] + }, + { + file: ".claude-plugin/marketplace.json", + values: [ + { + label: "metadata.version", + get: (json) => json.metadata?.version, + set: (json, version) => { + requireObject(json.metadata, ".claude-plugin/marketplace.json metadata"); + json.metadata.version = version; + } + }, + { + label: "plugins[codex].version", + get: (json) => findMarketplacePlugin(json).version, + set: (json, version) => { + findMarketplacePlugin(json).version = version; + } + } + ] + } +]; + +function usage() { + return [ + "Usage:", + " node scripts/bump-version.mjs ", + " node scripts/bump-version.mjs --check [version]", + "", + "Options:", + " --check Verify manifest versions. Uses package.json when version is omitted.", + " --root Run against a different repository root.", + " --help Print this help." + ].join("\n"); +} + +function parseArgs(argv) { + const options = { + check: false, + root: process.cwd(), + version: null + }; + + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + + if (arg === "--check") { + options.check = true; + } else if (arg === "--root") { + const root = argv[i + 1]; + if (!root) { + throw new Error("--root requires a directory."); + } + options.root = root; + i += 1; + } else if (arg === "--help" || arg === "-h") { + options.help = true; + } else if (arg.startsWith("-")) { + throw new Error(`Unknown option: ${arg}`); + } else if (options.version) { + throw new Error(`Unexpected extra argument: ${arg}`); + } else { + options.version = arg; + } + } + + options.root = path.resolve(options.root); + return options; +} + +function validateVersion(version) { + if (!VERSION_PATTERN.test(version)) { + throw new Error(`Expected a semver-like version such as 1.0.3, got: ${version}`); + } +} + +function requireObject(value, label) { + if (!value || typeof value !== "object" || Array.isArray(value)) { + throw new Error(`Expected ${label} to be an object.`); + } +} + +function findMarketplacePlugin(json) { + const plugin = json.plugins?.find((entry) => entry?.name === "codex"); + requireObject(plugin, ".claude-plugin/marketplace.json plugins[codex]"); + return plugin; +} + +function readJson(root, file) { + const filePath = path.join(root, file); + return JSON.parse(fs.readFileSync(filePath, "utf8")); +} + +function writeJson(root, file, json) { + const filePath = path.join(root, file); + fs.writeFileSync(filePath, `${JSON.stringify(json, null, 2)}\n`); +} + +function readPackageVersion(root) { + const packageJson = readJson(root, "package.json"); + if (typeof packageJson.version !== "string") { + throw new Error("package.json version must be a string."); + } + validateVersion(packageJson.version); + return packageJson.version; +} + +function checkVersions(root, expectedVersion) { + const mismatches = []; + + for (const target of TARGETS) { + const json = readJson(root, target.file); + for (const value of target.values) { + const actual = value.get(json); + if (actual !== expectedVersion) { + mismatches.push(`${target.file} ${value.label}: expected ${expectedVersion}, found ${actual ?? ""}`); + } + } + } + + return mismatches; +} + +function bumpVersion(root, version) { + const changedFiles = []; + + for (const target of TARGETS) { + const json = readJson(root, target.file); + const before = JSON.stringify(json); + + for (const value of target.values) { + value.set(json, version); + } + + if (JSON.stringify(json) !== before) { + writeJson(root, target.file, json); + changedFiles.push(target.file); + } + } + + return changedFiles; +} + +function main() { + const options = parseArgs(process.argv.slice(2)); + if (options.help) { + console.log(usage()); + return; + } + + const version = options.version ?? (options.check ? readPackageVersion(options.root) : null); + if (!version) { + throw new Error(`Missing version.\n\n${usage()}`); + } + validateVersion(version); + + if (options.check) { + const mismatches = checkVersions(options.root, version); + if (mismatches.length > 0) { + throw new Error(`Version metadata is out of sync:\n${mismatches.join("\n")}`); + } + console.log(`All version metadata matches ${version}.`); + return; + } + + const changedFiles = bumpVersion(options.root, version); + const touched = changedFiles.length > 0 ? changedFiles.join(", ") : "no files changed"; + console.log(`Set version metadata to ${version}: ${touched}.`); +} + +try { + main(); +} catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; +} diff --git a/tests/bump-version.test.mjs b/tests/bump-version.test.mjs new file mode 100644 index 0000000..205b0e9 --- /dev/null +++ b/tests/bump-version.test.mjs @@ -0,0 +1,88 @@ +import fs from "node:fs"; +import path from "node:path"; +import test from "node:test"; +import assert from "node:assert/strict"; +import { fileURLToPath } from "node:url"; + +import { makeTempDir, run } from "./helpers.mjs"; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const SCRIPT = path.join(ROOT, "scripts", "bump-version.mjs"); + +function writeJson(filePath, json) { + fs.mkdirSync(path.dirname(filePath), { recursive: true }); + fs.writeFileSync(filePath, `${JSON.stringify(json, null, 2)}\n`); +} + +function readJson(filePath) { + return JSON.parse(fs.readFileSync(filePath, "utf8")); +} + +function makeVersionFixture() { + const root = makeTempDir(); + + writeJson(path.join(root, "package.json"), { + name: "@openai/codex-plugin-cc", + version: "1.0.2" + }); + writeJson(path.join(root, "package-lock.json"), { + name: "@openai/codex-plugin-cc", + version: "1.0.2", + lockfileVersion: 3, + packages: { + "": { + name: "@openai/codex-plugin-cc", + version: "1.0.2" + } + } + }); + writeJson(path.join(root, "plugins", "codex", ".claude-plugin", "plugin.json"), { + name: "codex", + version: "1.0.2" + }); + writeJson(path.join(root, ".claude-plugin", "marketplace.json"), { + metadata: { + version: "1.0.2" + }, + plugins: [ + { + name: "codex", + version: "1.0.2" + } + ] + }); + + return root; +} + +test("bump-version updates every release manifest", () => { + const root = makeVersionFixture(); + + const result = run("node", [SCRIPT, "--root", root, "1.2.3"], { + cwd: ROOT + }); + + assert.equal(result.status, 0, result.stderr); + assert.equal(readJson(path.join(root, "package.json")).version, "1.2.3"); + assert.equal(readJson(path.join(root, "package-lock.json")).version, "1.2.3"); + assert.equal(readJson(path.join(root, "package-lock.json")).packages[""].version, "1.2.3"); + assert.equal(readJson(path.join(root, "plugins", "codex", ".claude-plugin", "plugin.json")).version, "1.2.3"); + assert.equal(readJson(path.join(root, ".claude-plugin", "marketplace.json")).metadata.version, "1.2.3"); + assert.equal(readJson(path.join(root, ".claude-plugin", "marketplace.json")).plugins[0].version, "1.2.3"); +}); + +test("bump-version check mode reports stale metadata", () => { + const root = makeVersionFixture(); + writeJson(path.join(root, "package.json"), { + name: "@openai/codex-plugin-cc", + version: "1.0.3" + }); + + const result = run("node", [SCRIPT, "--root", root, "--check"], { + cwd: ROOT + }); + + assert.notEqual(result.status, 0); + assert.match(result.stderr, /plugins\/codex\/\.claude-plugin\/plugin\.json version/); + assert.match(result.stderr, /\.claude-plugin\/marketplace\.json metadata\.version/); +});