fix: keep ecc release surfaces version-synced

This commit is contained in:
Affaan Mustafa
2026-04-12 02:25:14 -07:00
parent 125d5e6199
commit 6fd1358d04
2 changed files with 57 additions and 2 deletions

View File

@@ -8,7 +8,9 @@ VERSION="${1:-}"
ROOT_PACKAGE_JSON="package.json" ROOT_PACKAGE_JSON="package.json"
PLUGIN_JSON=".claude-plugin/plugin.json" PLUGIN_JSON=".claude-plugin/plugin.json"
MARKETPLACE_JSON=".claude-plugin/marketplace.json" MARKETPLACE_JSON=".claude-plugin/marketplace.json"
CODEX_PLUGIN_JSON=".codex-plugin/plugin.json"
OPENCODE_PACKAGE_JSON=".opencode/package.json" OPENCODE_PACKAGE_JSON=".opencode/package.json"
README_FILE="README.md"
# Function to show usage # Function to show usage
usage() { usage() {
@@ -43,7 +45,7 @@ if ! git diff --quiet || ! git diff --cached --quiet; then
fi fi
# Verify versioned manifests exist # 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 if [[ ! -f "$FILE" ]]; then
echo "Error: $FILE not found" echo "Error: $FILE not found"
exit 1 exit 1
@@ -75,14 +77,34 @@ update_version() {
fi 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 all shipped package/plugin manifests
update_version "$ROOT_PACKAGE_JSON" "s|\"version\": *\"[^\"]*\"|\"version\": \"$VERSION\"|" update_version "$ROOT_PACKAGE_JSON" "s|\"version\": *\"[^\"]*\"|\"version\": \"$VERSION\"|"
update_version "$PLUGIN_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 "$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_version "$OPENCODE_PACKAGE_JSON" "s|\"version\": *\"[^\"]*\"|\"version\": \"$VERSION\"|"
update_readme_version_row
# Stage, commit, tag, and push # 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 commit -m "chore: bump plugin version to $VERSION"
git tag "v$VERSION" git tag "v$VERSION"
git push origin main "v$VERSION" git push origin main "v$VERSION"

View File

@@ -20,6 +20,8 @@ const path = require('path');
const repoRoot = path.resolve(__dirname, '..'); const repoRoot = path.resolve(__dirname, '..');
const repoRootWithSep = `${repoRoot}${path.sep}`; const repoRootWithSep = `${repoRoot}${path.sep}`;
const packageJsonPath = path.join(repoRoot, 'package.json');
const opencodePackageJsonPath = path.join(repoRoot, '.opencode', 'package.json');
let passed = 0; let passed = 0;
let failed = 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 ──────────────────────────────────────────────────── // ── Claude plugin manifest ────────────────────────────────────────────────────
console.log('\n=== .claude-plugin/plugin.json ===\n'); 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'); 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', () => { test('claude plugin.json uses short plugin slug', () => {
assert.strictEqual(claudePlugin.name, 'ecc'); 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'); 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 ───────────────────────────────────────────────────── // ── Codex plugin manifest ─────────────────────────────────────────────────────
// Per official docs: https://platform.openai.com/docs/codex/plugins // Per official docs: https://platform.openai.com/docs/codex/plugins
// - .codex-plugin/plugin.json is the required manifest // - .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'); 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', () => { test('codex plugin.json skills is a string (not array) per official spec', () => {
assert.strictEqual( assert.strictEqual(
typeof codexPlugin.skills, typeof codexPlugin.skills,
@@ -268,6 +289,7 @@ test('marketplace.json exists at .agents/plugins/', () => {
}); });
const marketplace = loadJsonObject(marketplacePath, '.agents/plugins/marketplace.json'); const marketplace = loadJsonObject(marketplacePath, '.agents/plugins/marketplace.json');
const opencodePackage = loadJsonObject(opencodePackageJsonPath, '.opencode/package.json');
test('marketplace.json has name field', () => { test('marketplace.json has name field', () => {
assert.ok(marketplace.name, 'Expected 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 ─────────────────────────────────────────────────────────────────── // ── Summary ───────────────────────────────────────────────────────────────────
console.log(`\nPassed: ${passed}`); console.log(`\nPassed: ${passed}`);
console.log(`Failed: ${failed}`); console.log(`Failed: ${failed}`);