Skip to content

release

release #13

Workflow file for this run

name: release
# Tag-driven publishing for @leadbay/mcp (npm) and @leadbay/leadclaw (npm + ClawHub).
#
# Tag scheme:
# - mcp-v<ver> → publishes @leadbay/mcp only
# - leadclaw-v<ver> → publishes @leadbay/leadclaw to npm, then ClawHub
# - v<ver> → legacy alias for mcp-v<ver> (from the original release-mcp workflow)
#
# One-time setup (done in repo settings):
# - NPM_TOKEN → npm automation token, scope-owner on @leadbay
# - CLAWHUB_TOKEN → ClawHub publish token with rights to @leadbay/leadclaw
#
# No auto-version-bump, no auto-changelog. Bump `package.json` (and
# `openclaw.plugin.json` for leadclaw) in a normal PR. Tagging is automatic:
# `auto-tag.yml` watches main, sees the bumped version, and pushes the
# corresponding tag, which triggers this workflow. Manual `git tag` is only
# needed for emergency re-publish of a version already on main.
on:
push:
tags:
- "mcp-v*.*.*"
- "leadclaw-v*.*.*"
- "v*.*.*"
workflow_dispatch:
inputs:
package:
description: "Which package to publish (mcp | leadclaw)"
required: true
default: "mcp"
type: choice
options: [mcp, leadclaw]
dry_run:
description: "If true, npm half uses --dry-run (ClawHub has no dry-run; skipped on dry runs)"
required: false
default: "false"
jobs:
preflight-npm:
name: Preflight — verify npm auth + @leadbay scope
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: "https://registry.npmjs.org"
always-auth: true
- name: whoami + scope probe
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -euo pipefail
echo "Logged in as: $(npm whoami --registry=https://registry.npmjs.org)"
# Scope-empty on first publish is OK; fall through. Fatal errors (401/403)
# come from npm whoami above.
npm access list packages @leadbay 2>&1 || echo "scope empty or no packages yet — first publish will create"
publish-mcp:
name: Publish @leadbay/mcp to npm
needs: preflight-npm
if: |
startsWith(github.ref, 'refs/tags/mcp-v') ||
startsWith(github.ref, 'refs/tags/v') ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.package == 'mcp')
runs-on: ubuntu-latest
permissions:
contents: write # gh release create/upload for the .dxt bundle
id-token: write # npm provenance
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: "https://registry.npmjs.org"
always-auth: true
- name: Install
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm -r build
- name: Test
run: pnpm -r test
- name: Verify tag matches packages/mcp/package.json version
# Runs whenever the workflow is keyed off a tag ref — both real
# tag-push events and auto-tag's workflow_dispatch on a tag ref.
if: startsWith(github.ref, 'refs/tags/')
run: |
set -euo pipefail
REF="${GITHUB_REF#refs/tags/}"
# Strip either "mcp-v" or plain "v" prefix.
TAG="${REF#mcp-v}"
TAG="${TAG#v}"
PKG_VERSION=$(node -p "require('./packages/mcp/package.json').version")
if [ "$TAG" != "$PKG_VERSION" ]; then
echo "Tag $REF → version $TAG does not match packages/mcp/package.json $PKG_VERSION"
exit 1
fi
echo "Aligned: $REF = $PKG_VERSION"
- name: Publish
working-directory: packages/mcp
run: |
set -euo pipefail
VERSION=$(node -p "require('./package.json').version")
# Idempotent: if @leadbay/mcp@$VERSION is already on npm, skip.
if npm view "@leadbay/mcp@$VERSION" version --silent 2>/dev/null; then
echo "@leadbay/mcp@$VERSION already on npm — skipping"
exit 0
fi
if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then
npm publish --access public --provenance --dry-run
else
npm publish --access public --provenance
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Build .dxt bundle
# Same gate as the tag-verify step: runs on any tag ref, including
# auto-tag's workflow_dispatch. Skipped when running off main.
if: startsWith(github.ref, 'refs/tags/') && github.event.inputs.dry_run != 'true'
run: pnpm --filter @leadbay/dxt build
- name: Upload .dxt to GitHub Release
if: startsWith(github.ref, 'refs/tags/') && github.event.inputs.dry_run != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
TAG="${GITHUB_REF#refs/tags/}"
# gh release upload needs a release to exist. Create it if the tag
# wasn't already promoted to a release (auto-tag.yml only pushes tags).
if ! gh release view "$TAG" >/dev/null 2>&1; then
gh release create "$TAG" \
--title "$TAG" \
--notes "Automated release for $TAG — see CHANGELOG.md"
fi
gh release upload "$TAG" packages/dxt/dist/*.dxt --clobber
echo "Uploaded .dxt to release $TAG"
publish-leadclaw:
name: Publish @leadbay/leadclaw to npm + ClawHub
needs: preflight-npm
if: |
startsWith(github.ref, 'refs/tags/leadclaw-v') ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.package == 'leadclaw')
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: "https://registry.npmjs.org"
always-auth: true
- name: Install
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm -r build
- name: Test
run: pnpm -r test
- name: Verify tag ↔ package.json ↔ openclaw.plugin.json version agreement
if: startsWith(github.ref, 'refs/tags/')
run: |
set -euo pipefail
TAG="${GITHUB_REF#refs/tags/leadclaw-v}"
PKG=$(node -p "require('./packages/leadclaw/package.json').version")
MAN=$(node -p "require('./packages/leadclaw/openclaw.plugin.json').version")
if [ "$TAG" != "$PKG" ] || [ "$PKG" != "$MAN" ]; then
echo "Version drift: tag=$TAG pkg=$PKG manifest=$MAN — bump all three to match"
exit 1
fi
echo "Aligned: $TAG = $PKG = $MAN"
- name: Publish to npm
working-directory: packages/leadclaw
run: |
set -euo pipefail
VERSION=$(node -p "require('./package.json').version")
# Idempotent: if @leadbay/leadclaw@$VERSION is already on npm, skip.
# Handles the retry-after-ClawHub-failure case without manual intervention.
if npm view "@leadbay/leadclaw@$VERSION" version --silent 2>/dev/null; then
echo "@leadbay/leadclaw@$VERSION already on npm — skipping npm publish"
exit 0
fi
if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then
npm publish --access public --provenance --dry-run
else
npm publish --access public --provenance
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Install ClawHub CLI
if: github.event.inputs.dry_run != 'true'
run: npm i -g clawhub@^0.9
- name: Authenticate ClawHub
if: github.event.inputs.dry_run != 'true'
env:
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
run: clawhub login --token "$CLAWHUB_TOKEN" --no-browser
- name: Publish to ClawHub
if: github.event.inputs.dry_run != 'true'
run: |
set -euo pipefail
VERSION=$(node -p "require('./packages/leadclaw/package.json').version")
clawhub package publish packages/leadclaw \
--version "$VERSION" \
--source-repo "$GITHUB_REPOSITORY" \
--source-commit "$GITHUB_SHA" \
--source-ref "${GITHUB_REF_NAME}" \
--source-path packages/leadclaw \
--tags latest