com um clique
generate-release-cx
// Create a new release, bump version up to the .999 patch threshold, generate a complete CHANGELOG (with PR co-authors + every commit since the last tag), and manage Pull Requests
// Create a new release, bump version up to the .999 patch threshold, generate a complete CHANGELOG (with PR co-authors + every commit since the last tag), and manage Pull Requests
| name | generate-release-cx |
| description | Create a new release, bump version up to the .999 patch threshold, generate a complete CHANGELOG (with PR co-authors + every commit since the last tag), and manage Pull Requests |
Bump version, build a complete CHANGELOG from every commit since the last tag (with PR back-reference and contributor attribution), commit, open a PR to main and wait for user confirmation before tagging, publishing, and deploying.
// turbo / // turbo-all as instructions to use multi_tool_use.parallel for independent reads, checks, and GitHub calls.notify_user or BlockedOnUser: true, present the report/status in the final response and stop. Do not continue into the next phase until the user explicitly approves.VERSION RULE: Always use PATCH bumps (3.x.y → 3.x.y+1) NEVER use
npm version minorornpm version major. Always use:npm version patch --no-git-tag-versionThe threshold rule: whenyreaches 1000, bump to3.(x+1).0— e.g.3.8.999→3.9.0.
🔴 INTEGRATION BRANCH RULE: The
release/vX.Y.Zbranch is the integration target for the entire release cycle. Bug fixes and feature implementations land here via per-issue PRs from short-livedfix/<ISSUE>-<short>orfeat/<ISSUE>-<short>worktrees (see/resolve-issues,/implement-features). Contributor PRs from/review-prslikewise merge into this branch. The release branch is then merged tomainvia a single release PR at the end of the cycle.
Phase 0 → security audit (npm + CodeQL + Dependabot)
Phase 1 → bump → full quality gate → changelog from commits → commit → push → open PR
↕ 🛑 STOP (BlockedOnUser: true): notify user, wait for PR merge
Phase 2 → deploy main to Local VPS for homologation
↕ 🛑 STOP (BlockedOnUser: true): notify user, wait for OK
Phase 3 → tag → GitHub release → Docker → npm → Akamai
Phase 4 → monitor CI pipelines and validate artifacts
NEVER push directly to main or create tags before the user confirms the PR.
// turbo
# 1. Local dependency audit
npm audit --production --audit-level=high
# 2. GitHub CodeQL alerts (open + high severity)
gh api '/repos/diegosouzapw/OmniRoute/code-scanning/alerts?state=open&severity=high' \
--jq '.[] | {rule: .rule.id, path: .most_recent_instance.location.path, msg: .most_recent_instance.message.text}' \
2>/dev/null || echo "(no CodeQL access or no alerts)"
# 3. Dependabot alerts (open + high/critical)
gh api '/repos/diegosouzapw/OmniRoute/dependabot/alerts?state=open' \
--jq '.[] | select(.security_advisory.severity == "high" or .security_advisory.severity == "critical") | {pkg: .dependency.package.name, sev: .security_advisory.severity, summary: .security_advisory.summary}' \
2>/dev/null || echo "(no Dependabot access or no alerts)"
Fix or justify (with vulnerability-scanner skill, or dismissal comment per Hard Rule #14) any high/critical findings before proceeding.
# To create a new release branch (MUST always be created from main):
git checkout main
git pull origin main
git checkout -b release/v3.9.0
# If continuing the current cycle, just verify:
git branch --show-current
grep '"version"' package.json
🔴 BRANCH-VERSION PARITY GATE — auto-checked before any work:
// turbo
BRANCH=$(git branch --show-current)
BRANCH_VER=${BRANCH#release/v}
PKG_VER=$(node -p "require('./package.json').version")
if [[ "$BRANCH" != release/v* ]]; then
echo "❌ Not on a release/v* branch (current: $BRANCH). Aborting."; exit 1
fi
echo "Branch target: $BRANCH_VER"
echo "package.json: $PKG_VER"
⚠️ ATOMIC COMMIT RULE — bump and feature/fix code MUST land in the same commit so that
git show vX.Y.Zalways contains both. NEVER commit features first and bump in a separate commit.
npm version patch --no-git-tag-version
npm install
Skipping causes @swc/helpers lock mismatch and CI failures.
🎯 Goal: produce a complete CHANGELOG section following the format of PR #2617 — emoji-grouped sections, PR back-reference, and
— thanks @userattribution. Nothing must slip through.
🔴 NO MIXUPS RULE: do not mix backlog of the previous version. The new section must contain ONLY commits whose merge/landing happened after the previous tag.
// turbo
LAST_TAG=$(git describe --tags --abbrev=0)
NEW_VERSION=$(node -p "require('./package.json').version")
TODAY=$(date -u +%F)
echo "Range: $LAST_TAG..HEAD → v$NEW_VERSION ($TODAY)"
# Full commit list (oneline)
git log --no-merges "$LAST_TAG..HEAD" --pretty=format:'%h %s' > /tmp/release_commits.txt
wc -l /tmp/release_commits.txt
# Merge commits (preserve PR numbers + authors)
git log --merges "$LAST_TAG..HEAD" --pretty=format:'%h %s%n author=%an <%ae>' > /tmp/release_merges.txt
# Per-commit detailed list (PR refs, co-authors, body)
git log "$LAST_TAG..HEAD" --pretty=format:'---%n%h | %s%n author=%an <%ae>%n body=%b' > /tmp/release_detailed.txt
For each commit referencing a PR (e.g. (#2617) or merge commit Merge pull request #N), fetch the PR author and any additional contributors. Use multi_tool_use.parallel to fan out the gh pr view calls.
// turbo
# Extract all PR numbers referenced in the range
grep -oE '#[0-9]+' /tmp/release_commits.txt | sort -u > /tmp/release_prs.txt
echo "PRs in range:"; cat /tmp/release_prs.txt
# Fetch author + co-author info for every PR
> /tmp/release_pr_meta.json
while read -r PR; do
N=${PR#\#}
gh pr view "$N" --repo diegosouzapw/OmniRoute \
--json number,title,author,mergeCommit,body \
>> /tmp/release_pr_meta.json 2>/dev/null || echo "(skip $PR — not found)"
echo "" >> /tmp/release_pr_meta.json
done < /tmp/release_prs.txt
Using /tmp/release_commits.txt + /tmp/release_pr_meta.json + /tmp/release_detailed.txt, build a new entry that:
### ✨ New Features — feat(*)### 🔧 Bug Fixes — fix(*)### 📝 Maintenance — chore(*), refactor(*), docs(*), test(*), ci(*), build(*)### 🔒 Security — security-flagged commits (only if any)- **type(scope):** human-friendly description — extra context if useful. ([#PR](https://github.com/diegosouzapw/OmniRoute/pull/PR) — thanks @author / @coauthor1 / @coauthor2)
(thanks @author).thanks @originalAuthor / @diegosouzapw.Co-Authored-By: lines that pre-date Hard Rule #16) and from PR participants who supplied commits./tmp/release_commits.txt. Any unlisted commit must either be explicitly added or consolidated under a roll-up bullet (e.g. "various lint and test alignments"). Do NOT silently drop commits.Place the new section in CHANGELOG.md right below ## [Unreleased], separated by ---:
## [Unreleased]
---
## [3.9.0] — 2026-05-27
### ✨ New Features
- **feat(scope):** description ([#1234](https://github.com/diegosouzapw/OmniRoute/pull/1234) — thanks @author)
- ...
### 🔧 Bug Fixes
- **fix(scope):** description ([#1235](https://github.com/diegosouzapw/OmniRoute/pull/1235) — thanks @author / @diegosouzapw)
- ...
### 📝 Maintenance
- **chore(scope):** description (thanks @diegosouzapw)
- ...
### 🏆 Hall of Contributors
A special thanks to everyone who contributed code, reviews, and tests for this release:
@user1, @user2, @user3
---
## [3.8.999] — 2026-05-20
🔴 HALL OF CONTRIBUTORS RULE: After drafting all section bullets, parse every
@usernamemention from the bullets (PR authors AND co-authors), deduplicate, sort, and append them as a### 🏆 Hall of Contributorsblock at the end of the new release section (before the trailing---).
// turbo
NEW_VERSION=$(node -p "require('./package.json').version")
# Count commits in range
COMMITS=$(wc -l < /tmp/release_commits.txt)
# Count bullets under the new section
BULLETS=$(awk "/^## \\[$NEW_VERSION\\]/{flag=1;next} /^## \\[/{flag=0} flag" CHANGELOG.md | grep -c '^- ')
echo "Commits in range: $COMMITS"
echo "Changelog bullets: $BULLETS"
if [ "$BULLETS" -lt $(( COMMITS / 3 )) ]; then
echo "⚠️ Bullet count looks low (< commits/3). Re-review /tmp/release_commits.txt for missed entries."
fi
If a commit cannot be matched to a bullet, EITHER add it or explicitly justify the omission in this session before continuing.
CI will fail if
docs/reference/openapi.yamlversion ≠package.jsonversion (check:docs-syncenforces this).
// turbo
VERSION=$(node -p "require('./package.json').version")
sed -i "s/ version: .*/ version: $VERSION/" docs/reference/openapi.yaml
echo "✓ openapi.yaml → $VERSION"
for dir in electron open-sse; do
if [ -d "$dir" ] && [ -f "$dir/package.json" ]; then
(cd "$dir" && npm version "$VERSION" --no-git-tag-version --allow-same-version > /dev/null)
echo "✓ $dir/package.json → $VERSION"
fi
done
# Re-run install so workspace lockfile picks up the bumps
npm install
There is no /update-docs workflow (deprecated in v3.8). Updates must happen manually OR via parallel agents.
Recommended automation — fan out via multi_tool_use.parallel:
README.md first (feature table row + "What's new in vX.Y.Z" section).git diff README.md > /tmp/readme.patch.docs/i18n/*/README.md, translating the diff into the target language.docs/<AREA>.md if architecture/counts changed (e.g. docs/frameworks/MCP-SERVER.md when MCP tools change).npm run check:docs-sync && npm run check:docs-all.npm test)Precedent: the v3.8.2 cycle landed with 49 broken tests because only
npm testwas running. Lint + typecheck + cycles caught zero of those regressions.
// turbo
set -e
npm run lint
npm run typecheck:core
npm run check:cycles
npm run check:docs-all
npm test
All five must pass before opening the PR. If any fail, fix and re-run.
// turbo-all
VERSION=$(node -p "require('./package.json').version")
git add -A
git commit -m "chore(release): v$VERSION — $(date -u +%F)"
git push origin "release/v$VERSION"
NEVER include
Co-Authored-By:trailers in the release commit (Hard Rule #16). Co-author attribution lives inside the CHANGELOG entries and the Hall of Contributors block.
// turbo
VERSION=$(node -p "require('./package.json').version")
# Extract the exact changelog entry for this version
awk "/^## \\[$VERSION\\]/{flag=1; print; next} /^---/{if(flag) {flag=0; exit}} flag" CHANGELOG.md > /tmp/changelog_body.txt
# Append PR-only metadata (test status + reviewer instructions)
{
echo ""
echo "---"
echo ""
echo "### Quality Gate"
echo "- lint: pass"
echo "- typecheck:core: pass"
echo "- check:cycles: pass"
echo "- check:docs-all: pass"
echo "- tests: pass"
echo ""
echo "### Coverage of commits since previous tag"
LAST_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "(no previous tag)")
COMMITS=$(git rev-list --no-merges "$LAST_TAG..HEAD" | wc -l)
echo "- Range: \`$LAST_TAG..HEAD\`"
echo "- Commits inspected: $COMMITS"
echo ""
echo "### ⚠️ After merging: run Phase 2 (Local VPS homologation) before tagging."
} >> /tmp/changelog_body.txt
gh pr create \
--repo diegosouzapw/OmniRoute \
--base main \
--head "release/v$VERSION" \
--title "Release v$VERSION" \
--body-file /tmp/changelog_body.txt
BlockedOnUser: true)Present in the final response and stop. Do not continue to Phase 2 until the user explicitly approves.
Provide:
git diff --stat $LAST_TAG..HEAD)DO NOT proceed to Phase 2 until the user confirms the PR looks good and merges it.
Run only AFTER the user has merged the PR into
mainand all CI jobs pass.
main to the Local VPSDelegate to the deploy-vps-local-cx skill (single source of truth for the deploy procedure — do NOT duplicate SCP/SSH commands here):
/deploy-vps-local-cx
The skill handles: checkout main, npm pack, scp to 192.168.0.15, install, pm2 restart, and HTTP probe.
BlockedOnUser: true)Inform the user that main is running on 192.168.0.15:20128. Provide a smoke-test checklist:
GET / returns 200/dashboard)/v1/chat/completions with default provider returns a streampm2 logs omniroute --lines 100Wait for user OK before Phase 3.
Run only AFTER the user gives the final OK from Phase 2.
// turbo
git checkout main
git pull origin main
VERSION=$(node -p "require('./package.json').version")
# Extract release notes section from CHANGELOG
NOTES=$(awk "/^## \\[$VERSION\\]/{flag=1; next} /^---/{if(flag) {flag=0; exit}} flag" CHANGELOG.md | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
[ -z "$NOTES" ] && NOTES="OmniRoute v$VERSION Release"
git tag -a "v$VERSION" -m "Release v$VERSION"
git push origin "v$VERSION"
gh release create "v$VERSION" \
--repo diegosouzapw/OmniRoute \
--title "v$VERSION" \
--notes "$NOTES" \
--target main \
|| gh release edit "v$VERSION" \
--repo diegosouzapw/OmniRoute \
--title "v$VERSION" \
--notes "$NOTES"
CRITICAL: Docker Hub and npm MUST publish the same version.
VERSION=$(node -p "require('./package.json').version")
gh run list --repo diegosouzapw/OmniRoute --workflow docker-publish.yml --limit 3
gh run watch --repo diegosouzapw/OmniRoute
prepublishOnly runs npm run build:cli. Manual fallback:
npm publish
npm info omniroute version # verify
Delegate to the deploy-vps-akamai-cx skill if present, or run the inline equivalent of deploy-vps-local-cx against 69.164.221.35. Do NOT duplicate the procedure here.
If a fatal regression surfaces after the tag is pushed:
VERSION=$(node -p "require('./package.json').version")
PREV=$(git describe --tags --abbrev=0 "v$VERSION^")
# 1. Mark GitHub release as pre-release (do not delete history)
gh release edit "v$VERSION" --repo diegosouzapw/OmniRoute --prerelease
# 2. Re-deploy previous version to Akamai
git checkout "$PREV" && /deploy-vps-akamai-cx
# 3. Deprecate the broken npm version
npm deprecate "omniroute@$VERSION" "broken release — use $PREV"
# 4. Open follow-up issue and start a new patch cycle from main
Actively monitor the CI pipelines until all artifacts succeed. If any fail, stop and fix before continuing.
Verify successful completion of:
gh run list --repo diegosouzapw/OmniRoute --workflow docker-publish.yml --limit 1
gh run list --repo diegosouzapw/OmniRoute --workflow electron-release.yml --limit 1
gh run watch <RUN_ID>
npm info omniroute version
gh run view <RUN_ID> --log-failed
# Fix on main, then re-trigger:
VERSION=$(node -p "require('./package.json').version")
gh workflow run <workflow.yml> --repo diegosouzapw/OmniRoute --ref "v$VERSION"
Branch is kept for historical purposes. Do not delete.
docs/* are current BEFORE this workflow — run npm run check:docs-all first.prepublishOnly script runs npm run build:cli automatically during npm publish.npm info omniroute version.npm install after version bump.gh auth switch -u diegosouzapw if git push fails with the wrong account.deploy-vps-local-cx, deploy-vps-akamai-cx if present) — never inline the SCP/SSH commands here, to avoid drift.| CI failure | Cause | Fix |
|---|---|---|
[docs-sync] FAIL - OpenAPI version differs from package.json | Skipped step 5 — docs/reference/openapi.yaml version not updated | Run step 5 (sed -i ...) and commit |
[docs-sync] FAIL - CHANGELOG.md first section must be "## [Unreleased]" | ## [Unreleased] missing or not at top of CHANGELOG | Add ## [Unreleased]\n\n---\n before the first versioned ## [x.y.z] |
Electron Linux .deb build fails (FpmTarget error) | fpm Ruby gem not installed on ubuntu-latest runner | Already fixed in electron-release.yml (gem install fpm step) |
Docker Hub 502 error writing layer blob | Transient Docker Hub network error during ARM64 push | Re-run the Docker publish workflow; no code change needed |
| Coverage gate fails (statements/lines < 75% or branches < 70%) | Production code changed without tests | Add tests, re-run npm run test:coverage (see CLAUDE.md hard rule #9) |
Create a new release, bump version up to the .999 patch threshold, generate a complete CHANGELOG (with PR co-authors + every commit since the last tag), and manage Pull Requests
Create a new release, bump version up to the .999 patch threshold, generate a complete CHANGELOG (with PR co-authors + every commit since the last tag), and manage Pull Requests
Automatically run a browser-automation agent to visually validate all new UI features from the current release and capture evidence WebP recordings of the changes.
Automatically run a browser-automation agent to visually validate all new UI features from the current release and capture evidence WebP recordings of the changes.
Deploy the latest OmniRoute code to the Akamai VPS (69.164.221.35)
Deploy the latest OmniRoute code to BOTH the Akamai VPS and the Local VPS