Skip to content

chore: update publish#93

Merged
muratkeremozcan merged 2 commits intomainfrom
chore/update-publish-per-bmad-core
Apr 23, 2026
Merged

chore: update publish#93
muratkeremozcan merged 2 commits intomainfrom
chore/update-publish-per-bmad-core

Conversation

@muratkeremozcan
Copy link
Copy Markdown
Collaborator

@muratkeremozcan muratkeremozcan commented Apr 23, 2026

Summary

Aligns TEA’s release flow with the current BMAD-METHOD publish model. This replaces the old Manual Release workflow that
depended on NPM_TOKEN with the shared Publish workflow pattern using npm trusted publishing and app-based stable releases.

What Changed

  • Replaced .github/workflows/manual-release.yaml with .github/workflows/publish.yaml
  • Added support for:
    • automatic next publishes from main
    • manual latest releases with patch, minor, and major bumps
  • Kept version sync for .claude-plugin/marketplace.json as part of release
  • Updated package.json release scripts to target publish.yaml
  • Updated the maintainer release docs in README.md to reflect:
    • npm trusted publishing
    • RELEASE_APP_ID / RELEASE_APP_PRIVATE_KEY
    • the new next / latest channel flow

Notes

  • This PR removes the repo’s dependency on NPM_TOKEN
  • Stable releases now assume the release GitHub App is installed and allowed to push the version/tag
  • npm Trusted Publishing still needs to be configured on the npm package side for this workflow

@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Apr 23, 2026

🤖 Augment PR Summary

Summary: This PR replaces the old manual release automation with a new unified publish workflow for npm and GitHub releases.

Changes:

  • Removed the legacy Manual Release workflow and added a new Publish workflow.
  • Introduced two channels: automatic next prereleases on pushes to main, and manual stable publishes to the latest dist-tag via workflow_dispatch.
  • Adopted npm Trusted Publishing / provenance publishing (OIDC) to avoid requiring an NPM_TOKEN secret.
  • Kept marketplace metadata in sync by updating .claude-plugin/marketplace.json to match package.json version before publishing.
  • For stable releases, the workflow also commits the version bump, tags it, pushes back to main, and creates a GitHub Release from CHANGELOG.md when available.
  • Updated README.md publishing docs and adjusted package.json release scripts to trigger the new workflow.

Technical Notes: Stable releases use a GitHub App token for pushing commit/tag; prereleases don’t modify the repository state.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 3 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.


concurrency:
group: publish
cancel-in-progress: ${{ github.event_name == 'push' }}
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

concurrency.group: publish combined with cancel-in-progress for push runs means a new push can cancel an in-flight manual channel=latest release run, which can leave a partially completed release sequence.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: "npm"
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For npm Trusted Publishing, it’s common/expected to set registry-url: https://registry.npmjs.org in actions/setup-node; without it, publishes can fail depending on runner/npm configuration.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Comment thread .github/workflows/publish.yaml Outdated

- name: Publish stable release to npm
if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest'
run: npm publish --tag latest --provenance
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stable path publishes to npm before the version bump commit/tag is created and pushed; if the later git push/tag/release steps fail, npm can contain a version that isn’t represented in git and reruns may hit “version already exists”.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 23, 2026

📝 Walkthrough

Walkthrough

The PR replaces the manual release workflow with a new CI/CD pipeline supporting two release channels: prerelease (next) and stable (latest). The new workflow implements OIDC/Trusted Publishing for npm, conditionally bumps versions based on channel selection, syncs marketplace metadata, and creates GitHub Releases.

Changes

Cohort / File(s) Summary
GitHub Actions Workflows
.github/workflows/manual-release.yaml, .github/workflows/publish.yaml
Removed legacy token-based manual release workflow (216 lines). Added new workflow supporting conditional prerelease (next dist-tag) and stable (latest) channels with OIDC-based npm publishing, version synchronization to marketplace metadata, and GitHub Release creation.
Configuration & Documentation
package.json, README.md
Updated release npm scripts to invoke new publish.yaml workflow with channel and bump parameters instead of version_bump. Replaced release:alpha/release:beta with release:next. Updated maintainer release guide to reflect OIDC/Trusted Publishing, GitHub App setup for manual releases, and new workflow trigger patterns.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'chore: update publish' is vague and generic, using non-descriptive terms that don't convey meaningful information about the changeset. Use a more descriptive title that explains the specific change, such as 'chore: replace manual-release workflow with OIDC-based publish workflow' or 'chore: migrate release automation to trusted publishing'.
Description check ❓ Inconclusive No pull request description was provided, making it impossible to assess whether the author intended to document the changes or rationale. Add a description explaining the motivation for migrating from token-based to OIDC/Trusted Publishing, the new workflow structure, and impact on release processes.
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/update-publish-per-bmad-core

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/publish.yaml:
- Around line 131-145: The workflow publishes to npm before pushing the version
commit and tag, risking an irreversible publish without a corresponding
commit/tag on main; change the sequence so the steps "Commit version bump"
(creates v${VERSION}) and "Push version commit and tag" (git push origin main
--follow-tags) run before the "Publish stable release to npm" (npm publish --tag
latest --provenance), or alternatively add a guard step at the top that verifies
the runner/bot can push to main (e.g., attempt a dry-run git push or check
required permissions) and fail fast if push will be blocked; ensure the step
names "Commit version bump", "Push version commit and tag", and the npm publish
invocation are updated accordingly so publish is the last irreversible action.
- Around line 152-165: The awk matcher that builds BODY (the multi-line awk
block using VERSION) is too narrow and only matches "## [ver]" or "## vver";
update that awk pattern to accept common header variants (e.g., "## ver", "##
[ver]", "## vver" and headers with an optional date or suffix like " -
YYYY-MM-DD") so the block correctly sets found when encountering headers for
TAG/VERSION; change the regex inside the awk script that checks "^## \\[" ver
"\\]" || "^## v" ver to a single broader test that allows optional brackets,
optional leading "v", optional surrounding whitespace, and optional trailing
date/suffix, and keep using the same BODY, VERSION, TAG variables for subsequent
gh release create invocation.
- Around line 3-9: The push trigger for the publish workflow currently watches
package.json and package-lock.json and will retrigger when the release job
commits the version bump; update the workflow to skip release-commit pushes by
adding a guard: in the publish workflow's jobs add an `if` check that ignores
runs when the commit author or actor is the GitHub Actions bot (e.g.,
github.actor == 'github-actions[bot]') or when the head commit message contains
a skip token (e.g., "[skip ci]"); modify the release step that performs the
version bump (the job that pushes the new version) to either use a skip token in
its commit message or set the actor so the guard matches, ensuring the stable
release push does not re-enter the prerelease path.
- Around line 30-32: The current concurrency setup uses a single group named
"publish" with cancel-in-progress true for pushes, which allows a push run to
cancel an in-progress workflow_dispatch release; change the concurrency grouping
so runs are isolated by event/channel (e.g., include the event and
inputs.channel in concurrency.group) or disable cancel-in-progress for
workflow_dispatch releases so a manually-triggered "latest" publish isn't
cancelled by a push; update the concurrency.group and cancel-in-progress
expression (the concurrency.group and cancel-in-progress keys in the workflow)
to reflect this separation.
- Around line 80-100: Replace the semver comparison in the inline Node script
that computes BASE so it uses semver.gte instead of semver.gt; specifically, in
the Node block that defines next, latest and nextBase (the code that currently
does console.log(semver.gt(latest, nextBase) ? latest : next)), change that call
to semver.gte to ensure BASE becomes latest when latest === nextBase, then keep
the existing npm version "$BASE" and prerelease steps unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 09bacff4-4624-4b0a-abba-b5d8cc7f2b6c

📥 Commits

Reviewing files that changed from the base of the PR and between 3016dd0 and a7f006f.

📒 Files selected for processing (4)
  • .github/workflows/manual-release.yaml
  • .github/workflows/publish.yaml
  • README.md
  • package.json
💤 Files with no reviewable changes (1)
  • .github/workflows/manual-release.yaml

Comment on lines +3 to +9
on:
push:
branches: [main]
paths:
- "src/**"
- "package.json"
- "package-lock.json"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Stable release commit will re-trigger the workflow as a next prerelease.

The push trigger watches package.json and package-lock.json. After a latest run commits the version bump and pushes to main (line 145), the resulting push matches this filter and spawns a new run that goes down the prerelease path — immediately publishing e.g. 1.13.2-next.0 right after 1.13.2 stable. If that’s intentional (auto‑resume next track), consider documenting it; otherwise, guard the push trigger to skip release commits, e.g. by checking the commit author/message in the job if, or use [skip ci] in the commit message on line 140.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/publish.yaml around lines 3 - 9, The push trigger for the
publish workflow currently watches package.json and package-lock.json and will
retrigger when the release job commits the version bump; update the workflow to
skip release-commit pushes by adding a guard: in the publish workflow's jobs add
an `if` check that ignores runs when the commit author or actor is the GitHub
Actions bot (e.g., github.actor == 'github-actions[bot]') or when the head
commit message contains a skip token (e.g., "[skip ci]"); modify the release
step that performs the version bump (the job that pushes the new version) to
either use a skip token in its commit message or set the actor so the guard
matches, ensuring the stable release push does not re-enter the prerelease path.

Comment on lines +30 to +32
concurrency:
group: publish
cancel-in-progress: ${{ github.event_name == 'push' }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Push events can cancel an in-progress stable release.

concurrency.group is a single publish group and cancel-in-progress evaluates to true whenever the new run is a push. If a maintainer triggers a workflow_dispatch with channel=latest and, while it is running, any push to main that touches src/**, package.json, or package-lock.json lands (including the release commit from another branch or a concurrent merge), the incoming push run will cancel the in-progress stable release — potentially between npm publish --tag latest and the git push/gh release create steps, leaving npm and git out of sync.

Consider either separating the groups by channel or never cancelling when a latest release is in flight:

Suggested change
concurrency:
group: publish
cancel-in-progress: ${{ github.event_name == 'push' }}
concurrency:
group: publish-${{ github.event_name == 'workflow_dispatch' && inputs.channel || 'next' }}
cancel-in-progress: ${{ github.event_name == 'push' }}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/publish.yaml around lines 30 - 32, The current concurrency
setup uses a single group named "publish" with cancel-in-progress true for
pushes, which allows a push run to cancel an in-progress workflow_dispatch
release; change the concurrency grouping so runs are isolated by event/channel
(e.g., include the event and inputs.channel in concurrency.group) or disable
cancel-in-progress for workflow_dispatch releases so a manually-triggered
"latest" publish isn't cancelled by a push; update the concurrency.group and
cancel-in-progress expression (the concurrency.group and cancel-in-progress keys
in the workflow) to reflect this separation.

Comment on lines +80 to +100
- name: Derive next prerelease version
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.channel == 'next')
run: |
NEXT_VER=$(npm view bmad-method-test-architecture-enterprise@next version 2>/dev/null || echo "")
LATEST_VER=$(npm view bmad-method-test-architecture-enterprise@latest version 2>/dev/null || echo "")

BASE=$(node -e "
const semver = require('semver');
const next = process.argv[1] || null;
const latest = process.argv[2] || null;
if (!next && !latest) process.exit(0);
if (!next) { console.log(latest); process.exit(0); }
if (!latest) { console.log(next); process.exit(0); }
const nextBase = next.replace(/-next\.\d+$/, '');
console.log(semver.gt(latest, nextBase) ? latest : next);
" "$NEXT_VER" "$LATEST_VER")

if [ -n "$BASE" ]; then
npm version "$BASE" --no-git-tag-version --allow-same-version
fi
npm version prerelease --preid=next --no-git-tag-version
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Verify semver comparison logic
# Check if 1.13.1-next.6 < 1.13.1
python3 <<'EOF'
import subprocess
import json

# Test semver comparisons in Node.js
test_script = """
const semver = require('semver');

// Test 1: Is 1.13.1-next.6 less than 1.13.1?
console.log('1.13.1-next.6 < 1.13.1:', semver.lt('1.13.1-next.6', '1.13.1'));

// Test 2: Verify gt vs gte with equal versions
const latest = '1.13.1';
const nextBase = '1.13.1';
console.log('semver.gt("1.13.1", "1.13.1"):', semver.gt(latest, nextBase));
console.log('semver.gte("1.13.1", "1.13.1"):', semver.gte(latest, nextBase));

// Test 3: Verify the logic flow when latest equals nextBase
if (!semver.gt(latest, nextBase)) {
  console.log('With gt: BASE would be set to next (1.13.1-next.5)');
}
if (semver.gte(latest, nextBase)) {
  console.log('With gte: BASE would be set to latest (1.13.1)');
}

// Test 4: Check other comparisons
console.log('semver.gt("1.13.2", "1.13.1"):', semver.gt('1.13.2', '1.13.1'));
console.log('semver.lt("1.13.0", "1.13.1"):', semver.lt('1.13.0', '1.13.1'));
"""

console.log("=== Testing semver comparison logic ===")
print(test_script)
EOF

Repository: bmad-code-org/bmad-method-test-architecture-enterprise

Length of output: 212


🏁 Script executed:

#!/bin/bash

# Run the semver tests
node -e "
const semver = require('semver');

console.log('=== Semver Comparison Tests ===');
console.log('');

// Test 1: Is prerelease older than stable?
console.log('Test 1: Prerelease vs stable');
console.log('semver.lt(\"1.13.1-next.6\", \"1.13.1\"):', semver.lt('1.13.1-next.6', '1.13.1'));
console.log('');

// Test 2: gt vs gte with equal base versions
console.log('Test 2: gt vs gte comparison');
const latest = '1.13.1';
const nextBase = '1.13.1';
console.log('semver.gt(\"' + latest + '\", \"' + nextBase + '\"):', semver.gt(latest, nextBase));
console.log('semver.gte(\"' + latest + '\", \"' + nextBase + '\"):', semver.gte(latest, nextBase));
console.log('');

// Test 3: Impact on BASE selection
console.log('Test 3: Impact on BASE selection logic');
console.log('When latest=\"1.13.1\" and nextBase=\"1.13.1\":');
console.log('  gt(latest, nextBase) returns:', semver.gt(latest, nextBase), '-> BASE would be next');
console.log('  gte(latest, nextBase) returns:', semver.gte(latest, nextBase), '-> BASE would be latest');
"

Repository: bmad-code-org/bmad-method-test-architecture-enterprise

Length of output: 949


🏁 Script executed:

#!/bin/bash

# Test npm version prerelease behavior
# We'll create a test to understand the behavior
npm --version
node -e "console.log('Node:', process.version)"

# Create a temporary directory to test npm version behavior
TMPDIR=$(mktemp -d)
cd "$TMPDIR"

# Initialize a test package
npm init -y > /dev/null 2>&1

echo "=== Testing npm version prerelease behavior ==="
echo ""

# Test 1: Starting from a stable version
echo "Test 1: npm version prerelease --preid=next on a clean stable"
npm pkg set version="1.13.1"
npm version prerelease --preid=next --no-git-tag-version 2>&1 | grep -oP '(?<=>)[^<]+' || npm pkg get version

# Test 2: Starting from a prerelease
npm pkg set version="1.13.1-next.5"
echo ""
echo "Test 2: npm version prerelease --preid=next on 1.13.1-next.5"
npm version prerelease --preid=next --no-git-tag-version 2>&1 | grep -oP '(?<=>)[^<]+' || npm pkg get version

# Clean up
cd /
rm -rf "$TMPDIR"

Repository: bmad-code-org/bmad-method-test-architecture-enterprise

Length of output: 325


🏁 Script executed:

#!/bin/bash

# Simpler test for npm version behavior
TMPDIR=$(mktemp -d)
trap "rm -rf $TMPDIR" EXIT
cd "$TMPDIR"

npm init -y > /dev/null 2>&1

echo "=== npm version prerelease Tests ==="
echo ""

# Test 1: Clean stable to prerelease
echo "Test 1: From clean stable (1.13.1) to prerelease"
npm pkg set version="1.13.1"
echo "Before: $(npm pkg get version)"
npm version prerelease --preid=next --no-git-tag-version > /dev/null 2>&1
echo "After prerelease: $(npm pkg get version)"
echo ""

# Test 2: From prerelease to next prerelease  
npm pkg set version="1.13.1-next.5"
echo "Test 2: From prerelease (1.13.1-next.5) to next prerelease"
echo "Before: $(npm pkg get version)"
npm version prerelease --preid=next --no-git-tag-version > /dev/null 2>&1
echo "After prerelease: $(npm pkg get version)"
echo ""

# Test 3: From 1.13.2-next.0 (simulating after patch bump)
npm pkg set version="1.13.2-next.0"
echo "Test 3: From patch-bumped prerelease (1.13.2-next.0)"
echo "Before: $(npm pkg get version)"
npm version prerelease --preid=next --no-git-tag-version > /dev/null 2>&1
echo "After prerelease: $(npm pkg get version)"

Repository: bmad-code-org/bmad-method-test-architecture-enterprise

Length of output: 465


🏁 Script executed:

npm install semver --no-save && node -e "
const semver = require('semver');

console.log('=== Semver Comparison Verification ===');
console.log('');

// Core claim: prerelease is older than stable
console.log('Prerelease ordering:');
console.log('semver.lt(\"1.13.1-next.6\", \"1.13.1\"):', semver.lt('1.13.1-next.6', '1.13.1'));
console.log('');

// Test the specific condition: gt vs gte when versions are equal
console.log('Comparison when latest == nextBase:');
const latest = '1.13.1';
const nextBase = '1.13.1';
console.log('latest=\"' + latest + '\", nextBase=\"' + nextBase + '\"');
console.log('semver.gt(latest, nextBase):', semver.gt(latest, nextBase), '-> BASE would be: next');
console.log('semver.gte(latest, nextBase):', semver.gte(latest, nextBase), '-> BASE would be: latest');
console.log('');

// Show impact: what happens with each choice
console.log('Impact analysis:');
console.log('If BASE=next (gt returns false):');
console.log('  Starting: 1.13.1-next.5');
console.log('  After npm version prerelease --preid=next: 1.13.1-next.6');
console.log('  Semver comparison: 1.13.1-next.6 < 1.13.1:', semver.lt('1.13.1-next.6', '1.13.1'));
console.log('');
console.log('If BASE=latest (gte returns true):');
console.log('  Starting: 1.13.1');
console.log('  After npm version prerelease --preid=next: 1.13.2-next.0');
console.log('  Semver comparison: 1.13.2-next.0 >= 1.13.1:', semver.gte('1.13.2-next.0', '1.13.1'));
"

Repository: bmad-code-org/bmad-method-test-architecture-enterprise

Length of output: 3284


Change semver.gt to semver.gte to prevent prerelease regression after stable promotion.

When latest equals nextBase (the common case right after promoting a stable release), semver.gt(latest, nextBase) returns false, causing BASE=next (e.g., 1.13.1-next.5). Then npm version prerelease --preid=next yields 1.13.1-next.6, which semver considers older than the now-published stable 1.13.1. Consumers on @next who have @latest installed can end up pinned to an older build, and the next channel silently stops tracking forward progress.

Using gte ensures that when latest equals nextBase, BASE becomes latest, so npm version prerelease --preid=next on 1.13.1 produces 1.13.2-next.0, correctly advancing the prerelease.

Suggested change
Suggested change
- name: Derive next prerelease version
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.channel == 'next')
run: |
NEXT_VER=$(npm view bmad-method-test-architecture-enterprise@next version 2>/dev/null || echo "")
LATEST_VER=$(npm view bmad-method-test-architecture-enterprise@latest version 2>/dev/null || echo "")
BASE=$(node -e "
const semver = require('semver');
const next = process.argv[1] || null;
const latest = process.argv[2] || null;
if (!next && !latest) process.exit(0);
if (!next) { console.log(latest); process.exit(0); }
if (!latest) { console.log(next); process.exit(0); }
const nextBase = next.replace(/-next\.\d+$/, '');
console.log(semver.gt(latest, nextBase) ? latest : next);
" "$NEXT_VER" "$LATEST_VER")
if [ -n "$BASE" ]; then
npm version "$BASE" --no-git-tag-version --allow-same-version
fi
npm version prerelease --preid=next --no-git-tag-version
BASE=$(node -e "
const semver = require('semver');
const next = process.argv[1] || null;
const latest = process.argv[2] || null;
if (!next && !latest) process.exit(0);
if (!next) { console.log(latest); process.exit(0); }
if (!latest) { console.log(next); process.exit(0); }
const nextBase = next.replace(/-next\.\d+$/, '');
console.log(semver.gte(latest, nextBase) ? latest : next);
" "$NEXT_VER" "$LATEST_VER")
if [ -n "$BASE" ]; then
npm version "$BASE" --no-git-tag-version --allow-same-version
fi
npm version prerelease --preid=next --no-git-tag-version

Note: when BASE=latest (stable), npm version prerelease --preid=next on 1.13.1 produces 1.13.2-next.0 — please verify this matches your expectations for the first prerelease after a stable release.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/publish.yaml around lines 80 - 100, Replace the semver
comparison in the inline Node script that computes BASE so it uses semver.gte
instead of semver.gt; specifically, in the Node block that defines next, latest
and nextBase (the code that currently does console.log(semver.gt(latest,
nextBase) ? latest : next)), change that call to semver.gte to ensure BASE
becomes latest when latest === nextBase, then keep the existing npm version
"$BASE" and prerelease steps unchanged.

Comment thread .github/workflows/publish.yaml Outdated
Comment on lines +131 to +145
- name: Publish stable release to npm
if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest'
run: npm publish --tag latest --provenance

- name: Commit version bump
if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest'
run: |
VERSION=$(node -p 'require("./package.json").version')
git add package.json package-lock.json .claude-plugin/marketplace.json
git commit -m "release: bump to v${VERSION}"
git tag -a "v${VERSION}" -m "Release v${VERSION}"

- name: Push version commit and tag
if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest'
run: git push origin main --follow-tags
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Stable publish happens before the git push — failure leaves npm ahead of main.

For the latest channel, the order is:

  1. npm publish --tag latest --provenance (line 133)
  2. git commit + git tag (lines 140‑141)
  3. git push origin main --follow-tags (line 145)

If step 3 fails (branch protection, missing app permissions, race with another push, etc.), the version is already live on npm with no corresponding commit/tag on main. A subsequent run will re-bump from the stale package.json version and attempt to publish a version that’s already taken, and the v${VERSION} tag never exists.

Prefer committing, tagging, and pushing first, then publishing to npm. The npm publish step is the hardest to reverse (unpublish has a 72‑hour window and deprecation is permanent), so it should be the last irreversible action. Alternatively, keep the current order but add a guard at the top of the workflow that fails fast if the bot/app cannot push to main.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/publish.yaml around lines 131 - 145, The workflow
publishes to npm before pushing the version commit and tag, risking an
irreversible publish without a corresponding commit/tag on main; change the
sequence so the steps "Commit version bump" (creates v${VERSION}) and "Push
version commit and tag" (git push origin main --follow-tags) run before the
"Publish stable release to npm" (npm publish --tag latest --provenance), or
alternatively add a guard step at the top that verifies the runner/bot can push
to main (e.g., attempt a dry-run git push or check required permissions) and
fail fast if push will be blocked; ensure the step names "Commit version bump",
"Push version commit and tag", and the npm publish invocation are updated
accordingly so publish is the last irreversible action.

Comment on lines +152 to +165
BODY=$(awk -v ver="$VERSION" '
/^## / {
if (found) exit
if ($0 ~ "^## \\[" ver "\\]" || $0 ~ "^## v" ver) found=1
next
}
found { print }
' CHANGELOG.md)
if [ -z "$BODY" ]; then
echo "::warning::No CHANGELOG.md entry for $TAG — falling back to auto-generated notes"
gh release create "$TAG" --generate-notes
else
gh release create "$TAG" --notes "$BODY"
fi
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

CHANGELOG header matcher is narrow.

The awk pattern matches only ## [1.2.3] or ## v1.2.3. Common Keep-a-Changelog variants like ## 1.2.3 or ## [1.2.3] - 2026-04-23 with surrounding whitespace work for the second form but a bare ## 1.2.3 (no brackets, no v) silently falls through to the auto-generated notes path. If the project’s CHANGELOG.md style doesn’t include brackets/v, every release will use fallback notes without any warning that a matching entry actually existed in a slightly different format.

Consider broadening the pattern, or at minimum documenting the required header format in CHANGELOG.md / the release guide.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/publish.yaml around lines 152 - 165, The awk matcher that
builds BODY (the multi-line awk block using VERSION) is too narrow and only
matches "## [ver]" or "## vver"; update that awk pattern to accept common header
variants (e.g., "## ver", "## [ver]", "## vver" and headers with an optional
date or suffix like " - YYYY-MM-DD") so the block correctly sets found when
encountering headers for TAG/VERSION; change the regex inside the awk script
that checks "^## \\[" ver "\\]" || "^## v" ver to a single broader test that
allows optional brackets, optional leading "v", optional surrounding whitespace,
and optional trailing date/suffix, and keep using the same BODY, VERSION, TAG
variables for subsequent gh release create invocation.

@muratkeremozcan muratkeremozcan merged commit 615d08d into main Apr 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant