From 8552da341985436e1d785961d359006b26ed6f93 Mon Sep 17 00:00:00 2001 From: Pedro Valerio Date: Sat, 11 Jul 2026 13:43:33 -0300 Subject: [PATCH] =?UTF-8?q?chore(release):=20unblock=205.3.0=20=E2=80=94?= =?UTF-8?q?=20version=20lockstep=20sync=20+=20npm-publish=20chaining?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every semantic-release run was blocked at the prepublishOnly safety gate: validate-publish.js (Check 5) requires .aiox-core/package.json to match the root version, but semantic-release only bumps the root manifest. Fixes: - scripts/sync-version-lockstep.js: syncs .aiox-core/package.json and compat/aiox-core/package.json (version + @aiox-squads/core dependency pin) to the target version. Idempotent, standalone-usable. - .releaserc.json: @semantic-release/exec prepare step runs the sync with ${nextRelease.version} — the gate now passes inside the release run. - semantic-release.yml: after a non-dry-run release, explicitly dispatch npm-publish.yml (stable, all) via gh workflow run — the GITHUB_TOKEN tag/ release events do not chain workflows (anti-recursion); workflow_dispatch is the documented exception (same pattern as release.yml trigger-npm-publish). Requires the new actions:write permission. - Version bump 5.2.9 -> 5.3.0 committed across the three manifests (repo convention: chore(release) bump PRs), so the chained npm-publish.yml can publish the legacy aiox-core wrapper at 5.3.0 from the committed tree. Context: docs/handoffs (aiox-cockpit) 2026-07-11-env-normalization- consolidation.md, Fase 4. The orphan v5.3.0 tag from the failed attempt was deleted; baseline tag for semantic-release remains v5.2.8 (next: 5.3.0, minor, driven by the feat commits in #800/#801). Co-Authored-By: Claude Fable 5 --- .aiox-core/install-manifest.yaml | 6 +- .aiox-core/package.json | 2 +- .github/workflows/semantic-release.yml | 16 ++ .releaserc.json | 3 + compat/aiox-core/package.json | 4 +- package-lock.json | 219 ++++++++++++++++++++++++- package.json | 3 +- scripts/sync-version-lockstep.js | 84 ++++++++++ 8 files changed, 328 insertions(+), 9 deletions(-) create mode 100644 scripts/sync-version-lockstep.js diff --git a/.aiox-core/install-manifest.yaml b/.aiox-core/install-manifest.yaml index 3d0a3ea5f5..8729395071 100644 --- a/.aiox-core/install-manifest.yaml +++ b/.aiox-core/install-manifest.yaml @@ -7,8 +7,8 @@ # - SHA256 hashes for change detection # - File types for categorization # -version: 5.2.9 -generated_at: "2026-07-10T16:41:41.241Z" +version: 5.3.0 +generated_at: "2026-07-11T16:43:33.419Z" generator: scripts/generate-install-manifest.js file_count: 1164 files: @@ -3837,7 +3837,7 @@ files: type: monitor size: 818 - path: package.json - hash: sha256:d8dbe037240a366d545ca4259d2059e705b709706dcf2a18a5a52d9b543b7ed9 + hash: sha256:b9b72ceb7aff3d535f0fbd573eb0f1e37872b115cf91ac5fae17188fea115a2c type: other size: 1445 - path: product/checklists/accessibility-wcag-checklist.md diff --git a/.aiox-core/package.json b/.aiox-core/package.json index 9243688b98..d70ec1e7ab 100644 --- a/.aiox-core/package.json +++ b/.aiox-core/package.json @@ -1,6 +1,6 @@ { "name": "@aiox-squads/core-internal", - "version": "5.2.9", + "version": "5.3.0", "description": "Internal package manifest for AIOX framework — declares runtime dependencies consumed by scripts under .aiox-core/. This is NOT published independently; it ships inside @aiox-squads/core (the top-level package). Kept name-distinct from the parent (`-internal` suffix) to avoid npm registry confusion. Version follows the parent package.", "private": true, "main": "index.js", diff --git a/.github/workflows/semantic-release.yml b/.github/workflows/semantic-release.yml index 6453ea0232..3978d34b48 100644 --- a/.github/workflows/semantic-release.yml +++ b/.github/workflows/semantic-release.yml @@ -46,6 +46,7 @@ permissions: issues: write pull-requests: write id-token: write + actions: write # chain npm-publish.yml via workflow_dispatch (legacy wrapper + workspace packages) jobs: # Release job - CI validation handled by branch protection rules @@ -172,6 +173,21 @@ jobs: npx semantic-release fi + - name: Chain npm-publish (legacy wrapper + workspace packages) + if: inputs.dry_run != true + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # The tag/release created by semantic-release uses GITHUB_TOKEN, which does + # NOT trigger npm-publish.yml's push/release triggers (GitHub Actions + # anti-recursion). workflow_dispatch via API is the documented exception — + # same pattern release.yml relies on in its trigger-npm-publish job. + # npm-publish.yml is idempotent (should_publish skips versions already in + # the registry), so dispatching after a no-release run is a safe no-op. + gh workflow run npm-publish.yml --ref main -f publish_mode=stable -f packages=all + echo "✅ npm-publish.yml dispatched (stable, all packages)" + echo "### 🔗 Chained npm-publish.yml (stable, all)" >> $GITHUB_STEP_SUMMARY + - name: Release Summary if: success() run: | diff --git a/.releaserc.json b/.releaserc.json index c4458650c4..1b37a975bc 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -34,6 +34,9 @@ ["@semantic-release/npm", { "npmPublish": true }], + ["@semantic-release/exec", { + "prepareCmd": "node scripts/sync-version-lockstep.js ${nextRelease.version}" + }], "@semantic-release/github" ] } diff --git a/compat/aiox-core/package.json b/compat/aiox-core/package.json index 60e44f10f8..f6710d4b9c 100644 --- a/compat/aiox-core/package.json +++ b/compat/aiox-core/package.json @@ -1,6 +1,6 @@ { "name": "aiox-core", - "version": "5.2.9", + "version": "5.3.0", "description": "Compatibility wrapper for @aiox-squads/core.", "license": "MIT", "bin": { @@ -15,7 +15,7 @@ "README.md" ], "dependencies": { - "@aiox-squads/core": "5.2.9" + "@aiox-squads/core": "5.3.0" }, "engines": { "node": ">=18" diff --git a/package-lock.json b/package-lock.json index 1281b8f837..1fa3f9c9f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@aiox-squads/core", - "version": "5.2.9", + "version": "5.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@aiox-squads/core", - "version": "5.2.9", + "version": "5.3.0", "license": "MIT", "workspaces": [ "packages/*" @@ -45,6 +45,7 @@ }, "devDependencies": { "@semantic-release/changelog": "^6.0.3", + "@semantic-release/exec": "^7.1.0", "@semantic-release/git": "^10.0.1", "@types/jest": "^30.0.0", "@typescript-eslint/eslint-plugin": "^8.46.2", @@ -1995,6 +1996,220 @@ "node": ">=14.17" } }, + "node_modules/@semantic-release/exec": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@semantic-release/exec/-/exec-7.1.0.tgz", + "integrity": "sha512-4ycZ2atgEUutspPZ2hxO6z8JoQt4+y/kkHvfZ1cZxgl9WKJId1xPj+UadwInj+gMn2Gsv+fLnbrZ4s+6tK2TFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "execa": "^9.0.0", + "lodash-es": "^4.17.21", + "parse-json": "^8.0.0" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=24.1.0" + } + }, + "node_modules/@semantic-release/exec/node_modules/@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@semantic-release/exec/node_modules/execa": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@semantic-release/exec/node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/exec/node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/exec/node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@semantic-release/exec/node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/exec/node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/exec/node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/exec/node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/exec/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/exec/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@semantic-release/exec/node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/exec/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@semantic-release/git": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/@semantic-release/git/-/git-10.0.1.tgz", diff --git a/package.json b/package.json index 4390508dd0..f5d4f54d65 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aiox-squads/core", - "version": "5.2.9", + "version": "5.3.0", "description": "Synkra AIOX: AI-Orchestrated System for Full Stack Development - Core Framework", "bin": { "aiox": "bin/aiox.js", @@ -171,6 +171,7 @@ }, "devDependencies": { "@semantic-release/changelog": "^6.0.3", + "@semantic-release/exec": "^7.1.0", "@semantic-release/git": "^10.0.1", "@types/jest": "^30.0.0", "@typescript-eslint/eslint-plugin": "^8.46.2", diff --git a/scripts/sync-version-lockstep.js b/scripts/sync-version-lockstep.js new file mode 100644 index 0000000000..4c0d23b0b1 --- /dev/null +++ b/scripts/sync-version-lockstep.js @@ -0,0 +1,84 @@ +#!/usr/bin/env node +/** + * Version Lockstep Sync + * + * The publish safety gate (bin/utils/validate-publish.js → Check 5 / + * scripts/validate-aiox-core-namespace.js) requires `.aiox-core/package.json` + * to match the root package.json version. semantic-release only bumps the + * root manifest (in the release working tree), so every release was blocked + * at prepublishOnly with version drift. This script is the missing `prepare` + * step: it syncs the internal manifest AND the legacy compat wrapper + * (`compat/aiox-core/`) — version + its `@aiox-squads/core` dependency pin — + * to the target version. + * + * Wired into .releaserc.json via @semantic-release/exec: + * prepareCmd: node scripts/sync-version-lockstep.js ${nextRelease.version} + * + * Also usable standalone (release-bump PRs, e.g. chore(release) commits): + * node scripts/sync-version-lockstep.js # target = root version + * node scripts/sync-version-lockstep.js 5.3.0 # explicit target + * + * Exit codes: 0 = synced (or already in sync), 1 = invalid input / IO error + */ + +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const ROOT = path.resolve(__dirname, '..'); +const SEMVER_RE = /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/; + +function readJson(filePath) { + return JSON.parse(fs.readFileSync(filePath, 'utf8')); +} + +function writeJson(filePath, obj) { + fs.writeFileSync(filePath, `${JSON.stringify(obj, null, 2)}\n`); +} + +function main() { + const rootPkg = readJson(path.join(ROOT, 'package.json')); + const version = process.argv[2] || rootPkg.version; + + if (!SEMVER_RE.test(version)) { + console.error(`FAIL: invalid semver target "${version}"`); + process.exit(1); + } + + // 1. .aiox-core/package.json — version lockstep with root + // (validate-aiox-core-namespace.js rule 4: root is SOT) + const internalPath = path.join(ROOT, '.aiox-core', 'package.json'); + const internal = readJson(internalPath); + if (internal.version !== version) { + internal.version = version; + writeJson(internalPath, internal); + console.log(`synced: .aiox-core/package.json -> ${version}`); + } else { + console.log(`ok: .aiox-core/package.json already ${version}`); + } + + // 2. compat/aiox-core/package.json — legacy wrapper version + exact + // dependency pin on the scoped package (published by npm-publish.yml) + const compatPath = path.join(ROOT, 'compat', 'aiox-core', 'package.json'); + const compat = readJson(compatPath); + let compatChanged = false; + if (compat.version !== version) { + compat.version = version; + compatChanged = true; + } + if (compat.dependencies && compat.dependencies['@aiox-squads/core'] !== version) { + compat.dependencies['@aiox-squads/core'] = version; + compatChanged = true; + } + if (compatChanged) { + writeJson(compatPath, compat); + console.log(`synced: compat/aiox-core/package.json -> ${version} (version + dependency pin)`); + } else { + console.log(`ok: compat/aiox-core/package.json already ${version}`); + } + + console.log(`PASS: version lockstep at ${version}`); +} + +main();