Skip to content

v0.3.0

v0.3.0 #22

Workflow file for this run

# cli-box - Release Workflow
# Builds Rust binaries + Electron app, packages skill tarball, uploads to GitHub Release.
#
# Triggers:
# 1. GitHub Release published (automatic)
# 2. Manual: Actions → Release → Run workflow → enter tag (e.g. v0.2.0)
#
# Artifacts:
# - cli-box CLI binary (macOS aarch64)
# - cli-box-daemon Daemon binary (macOS aarch64)
# - CLI Box.app.zip Electron desktop app (compressed)
# - CLI Box_*_aarch64.dmg macOS installer
# - cli-box-skill.tar.gz Skill package (SKILL.md + binaries + install.sh)
name: Release
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: 'Release tag (e.g. v0.2.0)'
required: true
permissions:
contents: write
env:
NODE_VERSION: '22'
PNPM_VERSION: '10'
RUST_VERSION: '1.88'
jobs:
build-and-release:
name: Build and Release
runs-on: macos-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', github.event.inputs.tag) || github.ref }}
- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Install Rust ${{ env.RUST_VERSION }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_VERSION }}
- name: Rust cache
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Frontend dependencies cache
uses: actions/cache@v4
with:
path: |
~/.pnpm-store
electron-app/node_modules
key: ${{ runner.os }}-pnpm-${{ hashFiles('electron-app/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install frontend dependencies
working-directory: electron-app
run: pnpm install --frozen-lockfile
- name: Build CLI + daemon binaries (release)
run: cargo build --release -p cli-box-cli -p cli-box-daemon
- name: Build Electron app
working-directory: electron-app
run: |
pnpm build
ELECTRON_MIRROR="${ELECTRON_MIRROR:-}" pnpm run pack
- name: Collect release artifacts
run: |
mkdir -p release
# CLI binary
cp target/release/cli-box release/
chmod +x release/cli-box
codesign --force --sign - release/cli-box 2>/dev/null || true
# Daemon binary
cp target/release/cli-box-daemon release/
chmod +x release/cli-box-daemon
codesign --force --sign - release/cli-box-daemon 2>/dev/null || true
# Electron .app bundle
APP_BUNDLE=""
for dir in \
electron-app/dist/electron/mac-arm64/CLI\ Box.app \
electron-app/dist/electron/mac/CLI\ Box.app \
dist/electron/mac-arm64/CLI\ Box.app \
dist/electron/mac/CLI\ Box.app; do
if [ -d "$dir" ]; then
APP_BUNDLE="$dir"
break
fi
done
if [ -n "$APP_BUNDLE" ]; then
cp -R "$APP_BUNDLE" "release/CLI Box.app"
cd release && zip -r "CLI Box.app.zip" "CLI Box.app" && cd ..
# Also create tarball for backward compatibility
cd release && tar czf "CLI-Box-app-macos-arm64.tar.gz" "CLI Box.app" && cd ..
fi
# DMG
find electron-app/dist/electron -name "*.dmg" -maxdepth 2 -exec cp {} release/ \; 2>/dev/null || true
find dist/electron -name "*.dmg" -maxdepth 2 -exec cp {} release/ \; 2>/dev/null || true
# Skill tarball
mkdir -p skill-pkg/bin
cp packages/cli-box-skill/skill/SKILL.md skill-pkg/
cp packages/cli-box-skill/skill/install.sh skill-pkg/
chmod +x skill-pkg/install.sh
cp target/release/cli-box skill-pkg/bin/
cp target/release/cli-box-daemon skill-pkg/bin/
chmod +x skill-pkg/bin/*
cd skill-pkg && tar czf ../release/cli-box-skill.tar.gz . && cd ..
echo "## Release Artifacts" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
ls -lh release/ | tail -n +2 | awk '{printf "| %s | %s |\n", $NF, $5}' >> "$GITHUB_STEP_SUMMARY"
- name: Upload to GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.ref_name }}
files: release/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Package npm platform packages
run: |
# Copy Rust binaries to platform package
mkdir -p packages/cli-box-darwin-arm64/bin
cp target/release/cli-box packages/cli-box-darwin-arm64/bin/
cp target/release/cli-box-daemon packages/cli-box-darwin-arm64/bin/
chmod +x packages/cli-box-darwin-arm64/bin/*
# Copy Electron .app to platform package
mkdir -p packages/cli-box-electron-darwin-arm64/app
if [ -d "release/CLI Box.app" ]; then
cp -R "release/CLI Box.app" packages/cli-box-electron-darwin-arm64/app/
fi
- name: Publish npm packages
if: github.event_name == 'release'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc
# Set version from git tag
VERSION="${GITHUB_REF_NAME#v}"
# Update package.json versions using node (more reliable than sed)
node -e "
const fs = require('fs');
const version = '$VERSION';
const files = [
'packages/cli-box-darwin-arm64/package.json',
'packages/cli-box-electron-darwin-arm64/package.json',
'packages/cli-box-skill/package.json'
];
for (const file of files) {
const pkg = JSON.parse(fs.readFileSync(file, 'utf8'));
pkg.version = version;
if (pkg.optionalDependencies) {
for (const dep of Object.keys(pkg.optionalDependencies)) {
pkg.optionalDependencies[dep] = version;
}
}
fs.writeFileSync(file, JSON.stringify(pkg, null, 2) + '\n');
console.log('Updated', file, 'to version', version);
}
"
# Publish platform packages first, then main package
# Note: must use ./ prefix to prevent npm from treating path as git reference
npm publish ./packages/cli-box-darwin-arm64 --access public
npm publish ./packages/cli-box-electron-darwin-arm64 --access public
npm publish ./packages/cli-box-skill --access public
- name: Commit version changes
if: github.event_name == 'release'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add packages/cli-box-darwin-arm64/package.json \
packages/cli-box-electron-darwin-arm64/package.json \
packages/cli-box-skill/package.json
git diff --cached --quiet || git commit -m "chore(npm): bump package versions to ${GITHUB_REF_NAME#v}"
git push