diff --git a/.github/workflows/prerelease-cua-cli.yml b/.github/workflows/prerelease-cua-cli.yml deleted file mode 100644 index 4f95774..0000000 --- a/.github/workflows/prerelease-cua-cli.yml +++ /dev/null @@ -1,117 +0,0 @@ -name: Prerelease CUA CLI - -# Manually publish a prerelease of @onkernel/cua-cli from any branch under an -# npm dist-tag (never `latest`). Unlike release-cua-cli.yml there is no -# "tag is on main" gate — this exists to try unmerged work via -# `npm install -g @onkernel/cua-cli@`. The published version is -# `-.`, unique per run, and only reachable -# through the chosen dist-tag, so normal installs are unaffected. - -on: - 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: prerelease-cua-cli-${{ github.ref_name }} - cancel-in-progress: false - -jobs: - publish: - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v5 - - - 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 - - - name: Validate dist-tag - 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 - - - run: npm ci - - - name: Compute prerelease version - id: version - env: - DIST_TAG: ${{ inputs.dist_tag }} - run: | - 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: Verify runtime dependencies are published - 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 - - - run: npm run build --workspace @onkernel/cua-ai - - run: npm run build --workspace @onkernel/cua-agent - - - name: Build cua-cli - run: npm run build --workspace @onkernel/cua-cli - - - name: Pack tarball - run: npm pack --workspace @onkernel/cua-cli --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 - OUTPUT=$(./node_modules/.bin/cua --help) - echo "$OUTPUT" - echo "$OUTPUT" | grep -q "Usage:" - echo "$OUTPUT" | grep -q "cua \[options\] \[prompt\.\.\.\]" - - - name: Publish to npm - env: - DIST_TAG: ${{ inputs.dist_tag }} - run: npm publish --workspace @onkernel/cua-cli --access public --tag "$DIST_TAG" - - - name: Job summary - env: - DIST_TAG: ${{ inputs.dist_tag }} - VERSION: ${{ steps.version.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" diff --git a/.github/workflows/release-cua-cli.yml b/.github/workflows/release-cua-cli.yml index 46de0c6..371b14f 100644 --- a/.github/workflows/release-cua-cli.yml +++ b/.github/workflows/release-cua-cli.yml @@ -4,13 +4,20 @@ 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.ref_name }} + group: release-cua-cli-${{ github.event_name }}-${{ github.ref_name }} cancel-in-progress: false jobs: @@ -24,23 +31,12 @@ jobs: with: fetch-depth: 0 - - name: Verify tag is on main + - 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 - - 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: Verify package version matches tag - run: | node --input-type=module <<'EOF' import { readFileSync } from "node:fs"; @@ -59,13 +55,46 @@ jobs: 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}" @@ -78,6 +107,7 @@ jobs: echo "${GITHUB_WORKSPACE}/${ZIG_DIR}" >> "${GITHUB_PATH}" - name: Cache ptywright native artifacts + if: github.event_name == 'push' uses: actions/cache@v4 with: path: | @@ -88,37 +118,122 @@ jobs: - run: npm run build --workspace @onkernel/cua-ai - run: npm run build --workspace @onkernel/cua-agent - - name: Build ptywright (native binding) - run: npm run build --workspace @onkernel/ptywright - - - name: Build cua-cli - run: npm run build --workspace @onkernel/cua-cli - - - name: Verify runtime dependencies are published + - 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 tarball + - 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 to npm + - 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"