From 6fd1358d046225ee905619e8a0fdf4b899b30d9a Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Sun, 12 Apr 2026 02:25:14 -0700 Subject: [PATCH] fix: keep ecc release surfaces version-synced --- scripts/release.sh | 26 ++++++++++++++++++++++++-- tests/plugin-manifest.test.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/scripts/release.sh b/scripts/release.sh index f9c1ebb7..7e93acf4 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -8,7 +8,9 @@ VERSION="${1:-}" ROOT_PACKAGE_JSON="package.json" PLUGIN_JSON=".claude-plugin/plugin.json" MARKETPLACE_JSON=".claude-plugin/marketplace.json" +CODEX_PLUGIN_JSON=".codex-plugin/plugin.json" OPENCODE_PACKAGE_JSON=".opencode/package.json" +README_FILE="README.md" # Function to show usage usage() { @@ -43,7 +45,7 @@ if ! git diff --quiet || ! git diff --cached --quiet; then fi # Verify versioned manifests exist -for FILE in "$ROOT_PACKAGE_JSON" "$PLUGIN_JSON" "$MARKETPLACE_JSON" "$OPENCODE_PACKAGE_JSON"; do +for FILE in "$ROOT_PACKAGE_JSON" "$PLUGIN_JSON" "$MARKETPLACE_JSON" "$CODEX_PLUGIN_JSON" "$OPENCODE_PACKAGE_JSON" "$README_FILE"; do if [[ ! -f "$FILE" ]]; then echo "Error: $FILE not found" exit 1 @@ -75,14 +77,34 @@ update_version() { fi } +update_readme_version_row() { + node -e ' + const fs = require("fs"); + const file = process.argv[1]; + const version = process.argv[2]; + const current = fs.readFileSync(file, "utf8"); + const updated = current.replace( + /^\| \*\*Version\*\* \| Plugin \| Plugin \| Reference config \| [0-9][0-9.]* \|$/m, + `| **Version** | Plugin | Plugin | Reference config | ${version} |` + ); + if (updated === current) { + console.error(`Error: could not update README version row in ${file}`); + process.exit(1); + } + fs.writeFileSync(file, updated); + ' "$README_FILE" "$VERSION" +} + # Update all shipped package/plugin manifests update_version "$ROOT_PACKAGE_JSON" "s|\"version\": *\"[^\"]*\"|\"version\": \"$VERSION\"|" update_version "$PLUGIN_JSON" "s|\"version\": *\"[^\"]*\"|\"version\": \"$VERSION\"|" update_version "$MARKETPLACE_JSON" "0,/\"version\": *\"[^\"]*\"/s|\"version\": *\"[^\"]*\"|\"version\": \"$VERSION\"|" +update_version "$CODEX_PLUGIN_JSON" "s|\"version\": *\"[^\"]*\"|\"version\": \"$VERSION\"|" update_version "$OPENCODE_PACKAGE_JSON" "s|\"version\": *\"[^\"]*\"|\"version\": \"$VERSION\"|" +update_readme_version_row # Stage, commit, tag, and push -git add "$ROOT_PACKAGE_JSON" "$PLUGIN_JSON" "$MARKETPLACE_JSON" "$OPENCODE_PACKAGE_JSON" +git add "$ROOT_PACKAGE_JSON" "$PLUGIN_JSON" "$MARKETPLACE_JSON" "$CODEX_PLUGIN_JSON" "$OPENCODE_PACKAGE_JSON" "$README_FILE" git commit -m "chore: bump plugin version to $VERSION" git tag "v$VERSION" git push origin main "v$VERSION" diff --git a/tests/plugin-manifest.test.js b/tests/plugin-manifest.test.js index 0fa99946..1f7c3ad0 100644 --- a/tests/plugin-manifest.test.js +++ b/tests/plugin-manifest.test.js @@ -20,6 +20,8 @@ const path = require('path'); const repoRoot = path.resolve(__dirname, '..'); const repoRootWithSep = `${repoRoot}${path.sep}`; +const packageJsonPath = path.join(repoRoot, 'package.json'); +const opencodePackageJsonPath = path.join(repoRoot, '.opencode', 'package.json'); let passed = 0; let failed = 0; @@ -64,6 +66,13 @@ function assertSafeRepoRelativePath(relativePath, label) { ); } +const rootPackage = loadJsonObject(packageJsonPath, 'package.json'); +const expectedVersion = rootPackage.version; + +test('package.json has version field', () => { + assert.ok(expectedVersion, 'Expected package.json version field'); +}); + // ── Claude plugin manifest ──────────────────────────────────────────────────── console.log('\n=== .claude-plugin/plugin.json ===\n'); @@ -80,6 +89,10 @@ test('claude plugin.json has version field', () => { assert.ok(claudePlugin.version, 'Expected version field'); }); +test('claude plugin.json version matches package.json', () => { + assert.strictEqual(claudePlugin.version, expectedVersion); +}); + test('claude plugin.json uses short plugin slug', () => { assert.strictEqual(claudePlugin.name, 'ecc'); }); @@ -156,6 +169,10 @@ test('claude marketplace.json has plugins array with a short ecc plugin entry', assert.strictEqual(claudeMarketplace.plugins[0].name, 'ecc'); }); +test('claude marketplace.json plugin version matches package.json', () => { + assert.strictEqual(claudeMarketplace.plugins[0].version, expectedVersion); +}); + // ── Codex plugin manifest ───────────────────────────────────────────────────── // Per official docs: https://platform.openai.com/docs/codex/plugins // - .codex-plugin/plugin.json is the required manifest @@ -183,6 +200,10 @@ test('codex plugin.json has version field', () => { assert.ok(codexPlugin.version, 'Expected version field'); }); +test('codex plugin.json version matches package.json', () => { + assert.strictEqual(codexPlugin.version, expectedVersion); +}); + test('codex plugin.json skills is a string (not array) per official spec', () => { assert.strictEqual( typeof codexPlugin.skills, @@ -268,6 +289,7 @@ test('marketplace.json exists at .agents/plugins/', () => { }); const marketplace = loadJsonObject(marketplacePath, '.agents/plugins/marketplace.json'); +const opencodePackage = loadJsonObject(opencodePackageJsonPath, '.opencode/package.json'); test('marketplace.json has name field', () => { assert.ok(marketplace.name, 'Expected name field'); @@ -317,6 +339,17 @@ test('marketplace local plugin path resolves to the repo-root Codex bundle', () } }); +test('.opencode/package.json version matches package.json', () => { + assert.strictEqual(opencodePackage.version, expectedVersion); +}); + +test('README version row matches package.json', () => { + const readme = fs.readFileSync(path.join(repoRoot, 'README.md'), 'utf8'); + const match = readme.match(/^\| \*\*Version\*\* \| Plugin \| Plugin \| Reference config \| ([0-9][0-9.]*) \|$/m); + assert.ok(match, 'Expected README version summary row'); + assert.strictEqual(match[1], expectedVersion); +}); + // ── Summary ─────────────────────────────────────────────────────────────────── console.log(`\nPassed: ${passed}`); console.log(`Failed: ${failed}`);