Release CUA packages #11
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release CUA CLI | |
| on: | |
| push: | |
| tags: | |
| - "cua-cli/v*" | |
| workflow_dispatch: | |
| inputs: | |
| dist_tag: | |
| description: "npm dist-tag to publish under (never 'latest'); also used as the prerelease id" | |
| required: true | |
| default: "ext" | |
| type: string | |
| permissions: | |
| contents: read | |
| id-token: write | |
| concurrency: | |
| group: release-cua-cli-${{ github.event_name }}-${{ github.ref_name }} | |
| cancel-in-progress: false | |
| jobs: | |
| publish: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| env: | |
| PTYWRIGHT_ZIG_VERSION: "0.15.2" | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Verify production release | |
| if: github.event_name == 'push' | |
| run: | | |
| git fetch origin main:refs/remotes/origin/main | |
| git merge-base --is-ancestor "$GITHUB_SHA" origin/main | |
| node --input-type=module <<'EOF' | |
| import { readFileSync } from "node:fs"; | |
| const tag = process.env.GITHUB_REF_NAME; | |
| const prefix = "cua-cli/v"; | |
| if (!tag?.startsWith(prefix)) { | |
| throw new Error(`Expected tag to start with ${prefix}, got ${tag}`); | |
| } | |
| const tagVersion = tag.slice(prefix.length); | |
| const pkg = JSON.parse(readFileSync("packages/cli/package.json", "utf8")); | |
| if (pkg.version !== tagVersion) { | |
| throw new Error(`Tag version ${tagVersion} does not match ${pkg.name} package.json version ${pkg.version}`); | |
| } | |
| console.log(`${pkg.name}@${pkg.version}`); | |
| EOF | |
| - uses: actions/setup-node@v5 | |
| with: | |
| node-version: 24 | |
| registry-url: https://registry.npmjs.org | |
| - name: Ensure npm supports trusted publishing | |
| run: npm install -g npm@^11.5.1 | |
| - run: npm ci | |
| - name: Compute prerelease version | |
| if: github.event_name == 'workflow_dispatch' | |
| id: prerelease | |
| env: | |
| DIST_TAG: ${{ inputs.dist_tag }} | |
| run: | | |
| if [[ ! "$DIST_TAG" =~ ^[a-z0-9][a-z0-9-]*$ ]]; then | |
| echo "dist_tag must be lowercase alphanumeric/hyphen, e.g. ext, next, pr-41 (got '$DIST_TAG')" >&2 | |
| exit 1 | |
| fi | |
| if [[ "$DIST_TAG" == "latest" ]]; then | |
| echo "refusing to publish a prerelease to the 'latest' dist-tag" >&2 | |
| exit 1 | |
| fi | |
| BASE=$(node -p "require('./packages/cli/package.json').version") | |
| VERSION="${BASE}-${DIST_TAG}.${GITHUB_RUN_NUMBER}" | |
| npm pkg set version="$VERSION" --workspace @onkernel/cua-cli | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "cua-cli prerelease version: $VERSION" | |
| - name: Cache Zig toolchain | |
| if: github.event_name == 'push' | |
| uses: actions/cache@v4 | |
| with: | |
| path: .dev/tools/zig-x86_64-linux-${{ env.PTYWRIGHT_ZIG_VERSION }} | |
| key: zig-${{ runner.os }}-${{ env.PTYWRIGHT_ZIG_VERSION }} | |
| - name: Install Zig ${{ env.PTYWRIGHT_ZIG_VERSION }} | |
| if: github.event_name == 'push' | |
| run: | | |
| set -euo pipefail | |
| ZIG_DIR=".dev/tools/zig-x86_64-linux-${PTYWRIGHT_ZIG_VERSION}" | |
| if [ ! -x "${ZIG_DIR}/zig" ]; then | |
| mkdir -p .dev/tools | |
| curl -fsSL "https://ziglang.org/download/${PTYWRIGHT_ZIG_VERSION}/zig-x86_64-linux-${PTYWRIGHT_ZIG_VERSION}.tar.xz" \ | |
| | tar -xJ -C .dev/tools | |
| fi | |
| "${ZIG_DIR}/zig" version | |
| echo "${GITHUB_WORKSPACE}/${ZIG_DIR}" >> "${GITHUB_PATH}" | |
| - name: Cache ptywright native artifacts | |
| if: github.event_name == 'push' | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| packages/ptywright/.cache | |
| packages/ptywright/native/build | |
| key: ptywright-${{ runner.os }}-${{ hashFiles('packages/ptywright/GHOSTTY_UPSTREAM', 'packages/ptywright/native/**', 'packages/ptywright/scripts/**') }} | |
| - run: npm run build --workspace @onkernel/cua-ai | |
| - run: npm run build --workspace @onkernel/cua-agent | |
| - name: Verify published production dependencies | |
| if: github.event_name == 'push' | |
| run: | | |
| node -p 'require("./packages/cli/package.json").dependencies["@onkernel/cua-ai"]' \ | |
| | xargs -I{} npm view @onkernel/cua-ai@{} version | |
| node -p 'require("./packages/cli/package.json").dependencies["@onkernel/cua-agent"]' \ | |
| | xargs -I{} npm view @onkernel/cua-agent@{} version | |
| - name: Build ptywright (native binding) | |
| if: github.event_name == 'push' | |
| run: npm run build --workspace @onkernel/ptywright | |
| - name: Build cua-cli | |
| run: npm run build --workspace @onkernel/cua-cli | |
| - name: CLI unit tests | |
| if: github.event_name == 'push' | |
| env: | |
| PTYWRIGHT_REQUIRED: "1" | |
| run: npm test --workspace @onkernel/cua-cli | |
| - name: Pack production tarball | |
| if: github.event_name == 'push' | |
| run: npm pack --workspace @onkernel/cua-cli --pack-destination "$RUNNER_TEMP" | |
| - name: Pack branch workspace dependencies | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| mkdir -p "$RUNNER_TEMP/workspace-packages" | |
| npm pack --workspace @onkernel/cua-ai --pack-destination "$RUNNER_TEMP/workspace-packages" | |
| npm pack --workspace @onkernel/cua-agent --pack-destination "$RUNNER_TEMP/workspace-packages" | |
| - name: Pack bundled CLI prerelease | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| export STAGE_DIR="$RUNNER_TEMP/cua-cli-prerelease" | |
| mkdir -p "$STAGE_DIR/node_modules/@onkernel" | |
| cp packages/cli/package.json packages/cli/README.md "$STAGE_DIR/" | |
| cp -R packages/cli/dist "$STAGE_DIR/" | |
| for package in cua-ai cua-agent; do | |
| tarball=$(find "$RUNNER_TEMP/workspace-packages" -name "onkernel-${package}-*.tgz" -print -quit) | |
| mkdir -p "$STAGE_DIR/node_modules/@onkernel/$package" | |
| tar -xzf "$tarball" --strip-components=1 -C "$STAGE_DIR/node_modules/@onkernel/$package" | |
| done | |
| node --input-type=module <<'EOF' | |
| import { readFileSync, writeFileSync } from "node:fs"; | |
| import { join } from "node:path"; | |
| const packagePath = join(process.env.STAGE_DIR, "package.json"); | |
| const pkg = JSON.parse(readFileSync(packagePath, "utf8")); | |
| const bundled = ["@onkernel/cua-ai", "@onkernel/cua-agent"]; | |
| for (const name of bundled) { | |
| const dependency = JSON.parse( | |
| readFileSync(join(process.env.STAGE_DIR, "node_modules", name, "package.json"), "utf8"), | |
| ); | |
| pkg.dependencies[name] = dependency.version; | |
| for (const [dependencyName, version] of Object.entries(dependency.dependencies ?? {})) { | |
| if (bundled.includes(dependencyName)) continue; | |
| const current = pkg.dependencies[dependencyName]; | |
| if (current && current !== version) { | |
| throw new Error(`Conflicting ${dependencyName} versions: ${current} and ${version}`); | |
| } | |
| pkg.dependencies[dependencyName] = version; | |
| } | |
| } | |
| pkg.bundledDependencies = bundled; | |
| writeFileSync(packagePath, `${JSON.stringify(pkg, null, 2)}\n`); | |
| EOF | |
| npm pack "$STAGE_DIR" --pack-destination "$RUNNER_TEMP" | |
| - name: CLI bin smoke test | |
| run: | | |
| SMOKE_DIR=$(mktemp -d) | |
| cd "$SMOKE_DIR" | |
| npm init -y > /dev/null | |
| npm install "$RUNNER_TEMP"/onkernel-cua-cli-*.tgz | |
| if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then | |
| test -f node_modules/@onkernel/cua-cli/node_modules/@onkernel/cua-ai/dist/index.js | |
| test -f node_modules/@onkernel/cua-cli/node_modules/@onkernel/cua-agent/dist/index.js | |
| fi | |
| OUTPUT=$(./node_modules/.bin/cua --help) | |
| echo "$OUTPUT" | |
| echo "$OUTPUT" | grep -q "Usage:" | |
| echo "$OUTPUT" | grep -q "cua \[options\] \[prompt\.\.\.\]" | |
| - name: Publish production release | |
| if: github.event_name == 'push' | |
| run: npm publish --workspace @onkernel/cua-cli --access public | |
| - name: Publish prerelease | |
| if: github.event_name == 'workflow_dispatch' | |
| env: | |
| DIST_TAG: ${{ inputs.dist_tag }} | |
| run: npm publish "$RUNNER_TEMP"/onkernel-cua-cli-*.tgz --access public --tag "$DIST_TAG" | |
| - name: Prerelease summary | |
| if: github.event_name == 'workflow_dispatch' | |
| env: | |
| DIST_TAG: ${{ inputs.dist_tag }} | |
| VERSION: ${{ steps.prerelease.outputs.version }} | |
| run: | | |
| { | |
| echo "### Prerelease published" | |
| echo "" | |
| echo "- version: \`$VERSION\`" | |
| echo "- dist-tag: \`$DIST_TAG\`" | |
| echo "- branch: \`$GITHUB_REF_NAME\` (\`$GITHUB_SHA\`)" | |
| echo "" | |
| echo "Install:" | |
| echo "" | |
| echo '```' | |
| echo "npm install -g @onkernel/cua-cli@$DIST_TAG" | |
| echo '```' | |
| } >> "$GITHUB_STEP_SUMMARY" |