From 54ba8da47d409ce9f4c8dd7f6395acc66811f9c5 Mon Sep 17 00:00:00 2001 From: smakosh Date: Wed, 1 Jul 2026 23:59:35 +0200 Subject: [PATCH 1/2] feat: make DevPass Code installable via npm, brew, curl, and Docker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework the inherited opencode release pipeline so it publishes DevPass Code artifacts under this fork's identity: - build: compile binaries as bin/devpass-code (user agent devpass-code/) - npm: publish wrapper package `devpass-code` (name is free — no -ai suffix needed) plus devpass-code-{os}-{arch} platform packages; postinstall + dev shim resolve the new names - brew: generate devpass-code.rb (class DevpassCode) and push to theopenco/homebrew-tap; formula installs the devpass-code binary - curl: rebrand the install script — installs to ~/.devpass-code/bin from theopenco/devpass-code releases, new wordmark + outro - docker: ghcr.io/theopenco/devpass-code, devpass-code entrypoint - AUR: devpass-code-bin, only pushed when AUR_KEY is configured - workflow: run on theopenco/devpass-code with GitHub-hosted runners, drop the GitHub-App committer (RELEASE_TOKEN || github.token), gate Windows signing and desktop builds on their secrets so a bare repo can still release CLI artifacts, add NODE_AUTH_TOKEN for npm, stop building/publishing the @opencode-ai-scoped packages upstream owns - versioning: bump from the devpass-code npm package, falling back to the repo version for the first release; changelog is best-effort - self-upgrade: devpass-code upgrade now points every method (curl, npm/bun/pnpm, brew tap, choco, scoop, GitHub releases) at the fork - GitHub Action: install devpass-code from this repo's releases - README: real install instructions Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01FQXtaZmzWzXTrEikFpfCpK --- .github/workflows/publish.yml | 188 ++++++++---------- README.md | 26 ++- github/action.yml | 28 +-- install | 65 +++--- packages/devpass-code/Dockerfile | 8 +- packages/devpass-code/bin/devpass-code | 10 +- packages/devpass-code/package.json | 2 +- packages/devpass-code/script/build.ts | 6 +- packages/devpass-code/script/postinstall.mjs | 10 +- packages/devpass-code/script/publish.ts | 146 +++++++------- .../devpass-code/src/installation/index.ts | 66 +++--- .../test/installation/installation.test.ts | 21 +- packages/script/src/index.ts | 11 +- script/publish.ts | 23 +-- script/version.ts | 4 +- 15 files changed, 306 insertions(+), 308 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c15444e5..2be169fa 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -7,7 +7,6 @@ on: - ci - dev - beta - - fix/npm-native-binary-install - snapshot-* workflow_dispatch: inputs: @@ -33,8 +32,8 @@ permissions: jobs: version: - runs-on: blacksmith-4vcpu-ubuntu-2404 - if: github.repository == 'anomalyco/opencode' + runs-on: ubuntu-latest + if: github.repository == 'theopenco/devpass-code' steps: - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: @@ -42,14 +41,21 @@ jobs: - uses: ./.github/actions/setup-bun - - name: Setup git committer - id: committer - uses: ./.github/actions/setup-git-committer - with: - opencode-app-id: ${{ vars.OPENCODE_APP_ID }} - opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }} + - name: Configure git user + run: | + git config --global user.name "devpass-code-release" + git config --global user.email "devpass-code-release@users.noreply.github.com" - - name: Install OpenCode + # optional capabilities: jobs below are skipped when their secrets are absent + - id: capabilities + env: + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} + run: | + echo "sign_windows=$([[ -n "$AZURE_CLIENT_ID" ]] && echo true || echo false)" >> "$GITHUB_OUTPUT" + echo "desktop=$([[ -n "$APPLE_CERTIFICATE" && -n "$AZURE_CLIENT_ID" ]] && echo true || echo false)" >> "$GITHUB_OUTPUT" + + - name: Install OpenCode (changelog generation) if: inputs.bump || inputs.version run: bun i -g opencode-ai @@ -57,21 +63,23 @@ jobs: run: | ./script/version.ts env: - GH_TOKEN: ${{ steps.committer.outputs.token }} + GH_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }} OPENCODE_BUMP: ${{ inputs.bump }} OPENCODE_VERSION: ${{ inputs.version }} OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - GH_REPO: ${{ (github.ref_name == 'beta' && 'anomalyco/opencode-beta') || github.repository }} + GH_REPO: ${{ github.repository }} outputs: version: ${{ steps.version.outputs.version }} release: ${{ steps.version.outputs.release }} tag: ${{ steps.version.outputs.tag }} repo: ${{ steps.version.outputs.repo }} + sign_windows: ${{ steps.capabilities.outputs.sign_windows }} + desktop: ${{ steps.capabilities.outputs.desktop }} build-cli: needs: version - runs-on: blacksmith-4vcpu-ubuntu-2404 - if: github.repository == 'anomalyco/opencode' + runs-on: ubuntu-latest + if: github.repository == 'theopenco/devpass-code' steps: - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: @@ -79,40 +87,27 @@ jobs: - uses: ./.github/actions/setup-bun - - name: Setup git committer - id: committer - uses: ./.github/actions/setup-git-committer - with: - opencode-app-id: ${{ vars.OPENCODE_APP_ID }} - opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }} - - name: Build id: build run: | ./packages/devpass-code/script/build.ts ${{ (github.ref_name == 'beta' && '--sourcemaps') || '' }} - ./packages/cli/script/build.ts ${{ (github.ref_name == 'beta' && '--sourcemaps') || '' }} env: OPENCODE_VERSION: ${{ needs.version.outputs.version }} OPENCODE_RELEASE: ${{ needs.version.outputs.release }} GH_REPO: ${{ needs.version.outputs.repo }} - GH_TOKEN: ${{ steps.committer.outputs.token }} + GH_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: - name: opencode-cli + name: devpass-code-cli path: | - packages/devpass-code/dist/opencode-darwin* - packages/devpass-code/dist/opencode-linux* + packages/devpass-code/dist/devpass-code-darwin* + packages/devpass-code/dist/devpass-code-linux* - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: - name: opencode-cli-windows - path: packages/devpass-code/dist/opencode-windows* - - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: opencode-preview-cli - path: packages/cli/dist/cli-* + name: devpass-code-cli-windows + path: packages/devpass-code/dist/devpass-code-windows* outputs: version: ${{ needs.version.outputs.version }} @@ -121,8 +116,8 @@ jobs: needs: - build-cli - version - runs-on: blacksmith-4vcpu-windows-2025 - if: github.repository == 'anomalyco/opencode' + runs-on: windows-2025 + if: github.repository == 'theopenco/devpass-code' && needs.version.outputs.sign_windows == 'true' env: AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} @@ -135,16 +130,9 @@ jobs: - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: - name: opencode-cli-windows + name: devpass-code-cli-windows path: packages/devpass-code/dist - - name: Setup git committer - id: committer - uses: ./.github/actions/setup-git-committer - with: - opencode-app-id: ${{ vars.OPENCODE_APP_ID }} - opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }} - - name: Azure login uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0 with: @@ -158,9 +146,9 @@ jobs: signing-account-name: ${{ env.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }} certificate-profile-name: ${{ env.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE }} files: | - ${{ github.workspace }}\packages\opencode\dist\opencode-windows-arm64\bin\opencode.exe - ${{ github.workspace }}\packages\opencode\dist\opencode-windows-x64\bin\opencode.exe - ${{ github.workspace }}\packages\opencode\dist\opencode-windows-x64-baseline\bin\opencode.exe + ${{ github.workspace }}\packages\devpass-code\dist\devpass-code-windows-arm64\bin\devpass-code.exe + ${{ github.workspace }}\packages\devpass-code\dist\devpass-code-windows-x64\bin\devpass-code.exe + ${{ github.workspace }}\packages\devpass-code\dist\devpass-code-windows-x64-baseline\bin\devpass-code.exe exclude-environment-credential: true exclude-workload-identity-credential: true exclude-managed-identity-credential: true @@ -176,9 +164,9 @@ jobs: shell: pwsh run: | $files = @( - "${{ github.workspace }}\packages\opencode\dist\opencode-windows-arm64\bin\opencode.exe", - "${{ github.workspace }}\packages\opencode\dist\opencode-windows-x64\bin\opencode.exe", - "${{ github.workspace }}\packages\opencode\dist\opencode-windows-x64-baseline\bin\opencode.exe" + "${{ github.workspace }}\packages\devpass-code\dist\devpass-code-windows-arm64\bin\devpass-code.exe", + "${{ github.workspace }}\packages\devpass-code\dist\devpass-code-windows-x64\bin\devpass-code.exe", + "${{ github.workspace }}\packages\devpass-code\dist\devpass-code-windows-x64-baseline\bin\devpass-code.exe" ) foreach ($file in $files) { @@ -192,36 +180,36 @@ jobs: working-directory: packages/devpass-code/dist shell: pwsh run: | - Compress-Archive -Path "opencode-windows-arm64\bin\*" -DestinationPath "opencode-windows-arm64.zip" -Force - Compress-Archive -Path "opencode-windows-x64\bin\*" -DestinationPath "opencode-windows-x64.zip" -Force - Compress-Archive -Path "opencode-windows-x64-baseline\bin\*" -DestinationPath "opencode-windows-x64-baseline.zip" -Force + Compress-Archive -Path "devpass-code-windows-arm64\bin\*" -DestinationPath "devpass-code-windows-arm64.zip" -Force + Compress-Archive -Path "devpass-code-windows-x64\bin\*" -DestinationPath "devpass-code-windows-x64.zip" -Force + Compress-Archive -Path "devpass-code-windows-x64-baseline\bin\*" -DestinationPath "devpass-code-windows-x64-baseline.zip" -Force - name: Upload signed Windows CLI release assets if: needs.version.outputs.release != '' shell: pwsh env: - GH_TOKEN: ${{ steps.committer.outputs.token }} + GH_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }} run: | gh release upload "v${{ needs.version.outputs.version }}" ` - "${{ github.workspace }}\packages\opencode\dist\opencode-windows-arm64.zip" ` - "${{ github.workspace }}\packages\opencode\dist\opencode-windows-x64.zip" ` - "${{ github.workspace }}\packages\opencode\dist\opencode-windows-x64-baseline.zip" ` + "${{ github.workspace }}\packages\devpass-code\dist\devpass-code-windows-arm64.zip" ` + "${{ github.workspace }}\packages\devpass-code\dist\devpass-code-windows-x64.zip" ` + "${{ github.workspace }}\packages\devpass-code\dist\devpass-code-windows-x64-baseline.zip" ` --clobber ` --repo "${{ needs.version.outputs.repo }}" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: - name: opencode-cli-signed-windows + name: devpass-code-cli-signed-windows path: | - packages/devpass-code/dist/opencode-windows-arm64 - packages/devpass-code/dist/opencode-windows-x64 - packages/devpass-code/dist/opencode-windows-x64-baseline + packages/devpass-code/dist/devpass-code-windows-arm64 + packages/devpass-code/dist/devpass-code-windows-x64 + packages/devpass-code/dist/devpass-code-windows-x64-baseline build-electron: needs: - build-cli - version - if: github.repository == 'anomalyco/opencode' + if: github.repository == 'theopenco/devpass-code' && needs.version.outputs.desktop == 'true' continue-on-error: false env: AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} @@ -242,17 +230,16 @@ jobs: target: aarch64-apple-darwin platform_flag: --mac --arm64 bun_install_flags: --os=darwin --cpu=arm64 - # github-hosted: blacksmith lacks ARM64 MSVC cross-compilation toolchain - host: "windows-2025" target: aarch64-pc-windows-msvc platform_flag: --win --arm64 - - host: "blacksmith-4vcpu-windows-2025" + - host: "windows-2025" target: x86_64-pc-windows-msvc platform_flag: --win - - host: "blacksmith-4vcpu-ubuntu-2404" + - host: "ubuntu-latest" target: x86_64-unknown-linux-gnu platform_flag: --linux - - host: "blacksmith-4vcpu-ubuntu-2404-arm" + - host: "ubuntu-24.04-arm" target: aarch64-unknown-linux-gnu platform_flag: --linux --arm64 runs-on: ${{ matrix.settings.host }} @@ -303,12 +290,10 @@ jobs: sudo apt-get install -y --no-install-recommends -o dir::cache::archives="$HOME/apt-cache" rpm sudo chmod -R a+rw ~/apt-cache - - name: Setup git committer - id: committer - uses: ./.github/actions/setup-git-committer - with: - opencode-app-id: ${{ vars.OPENCODE_APP_ID }} - opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }} + - name: Configure git user + run: | + git config --global user.name "devpass-code-release" + git config --global user.email "devpass-code-release@users.noreply.github.com" - name: Prepare run: bun ./scripts/prepare.ts @@ -316,7 +301,7 @@ jobs: env: OPENCODE_VERSION: ${{ needs.version.outputs.version }} OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }} - OPENCODE_CLI_ARTIFACT: ${{ (runner.os == 'Windows' && 'opencode-cli-windows') || 'opencode-cli' }} + OPENCODE_CLI_ARTIFACT: ${{ (runner.os == 'Windows' && 'devpass-code-cli-windows') || 'devpass-code-cli' }} RUST_TARGET: ${{ matrix.settings.target }} GH_TOKEN: ${{ github.token }} GITHUB_RUN_ID: ${{ github.run_id }} @@ -342,7 +327,7 @@ jobs: timeout-minutes: 60 env: OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }} - GH_TOKEN: ${{ steps.committer.outputs.token }} + GH_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }} CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }} CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_API_KEY: ${{ runner.temp }}/apple-api-key.p8 @@ -363,10 +348,10 @@ jobs: run: | if [[ "${{ matrix.settings.target }}" == "x86_64-apple-darwin" ]]; then APP_DIR="mac" - OUT_NAME="opencode-desktop-mac-x64.app.tar.gz" + OUT_NAME="devpass-code-desktop-mac-x64.app.tar.gz" elif [[ "${{ matrix.settings.target }}" == "aarch64-apple-darwin" ]]; then APP_DIR="mac-arm64" - OUT_NAME="opencode-desktop-mac-arm64.app.tar.gz" + OUT_NAME="devpass-code-desktop-mac-arm64.app.tar.gz" else echo "Unknown macOS target: ${{ matrix.settings.target }}" exit 1 @@ -385,7 +370,6 @@ jobs: $files = @() $files += Get-ChildItem "${{ github.workspace }}\packages\desktop\dist\*.exe" | Select-Object -ExpandProperty FullName $files += Get-ChildItem "${{ github.workspace }}\packages\desktop\dist\*unpacked\*.exe" | Select-Object -ExpandProperty FullName - $files += Get-ChildItem "${{ github.workspace }}\packages\desktop\dist\*unpacked\resources\opencode-cli.exe" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName foreach ($file in $files | Select-Object -Unique) { $sig = Get-AuthenticodeSignature $file @@ -396,7 +380,7 @@ jobs: - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: - name: opencode-desktop-${{ matrix.settings.target }} + name: devpass-code-desktop-${{ matrix.settings.target }} path: packages/desktop/dist/* - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 @@ -412,7 +396,7 @@ jobs: - sign-cli-windows - build-electron if: always() && !failure() && !cancelled() - runs-on: blacksmith-4vcpu-ubuntu-2404 + runs-on: ubuntu-latest steps: - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 @@ -438,67 +422,52 @@ jobs: - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: - name: opencode-cli + name: devpass-code-cli path: packages/devpass-code/dist - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: - name: opencode-cli-windows + name: devpass-code-cli-windows path: packages/devpass-code/dist - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + if: needs.version.outputs.sign_windows == 'true' with: - name: opencode-cli-signed-windows + name: devpass-code-cli-signed-windows path: packages/devpass-code/dist - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: opencode-preview-cli - path: packages/cli/dist - - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - if: needs.version.outputs.release + if: needs.version.outputs.release && needs.version.outputs.desktop == 'true' with: pattern: latest-yml-* path: /tmp/latest-yml - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - if: needs.version.outputs.release + if: needs.version.outputs.release && needs.version.outputs.desktop == 'true' with: - pattern: opencode-desktop-* + pattern: devpass-code-desktop-* path: /tmp/desktop merge-multiple: true - - name: Setup git committer - id: committer - uses: ./.github/actions/setup-git-committer - with: - opencode-app-id: ${{ vars.OPENCODE_APP_ID }} - opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }} - - - name: Cache apt packages (AUR) - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: /var/cache/apt/archives - key: ${{ runner.os }}-apt-aur-${{ hashFiles('.github/workflows/publish.yml') }} - restore-keys: | - ${{ runner.os }}-apt-aur- + - name: Configure git user + run: | + git config --global user.name "devpass-code-release" + git config --global user.email "devpass-code-release@users.noreply.github.com" - name: Setup SSH for AUR + if: ${{ secrets.AUR_KEY != '' }} run: | sudo apt-get update sudo apt-get install -y pacman-package-manager mkdir -p ~/.ssh echo "${{ secrets.AUR_KEY }}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa - git config --global user.email "opencode@sst.dev" - git config --global user.name "opencode" ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts || true - name: Upload desktop release assets - if: needs.version.outputs.release + if: needs.version.outputs.release && needs.version.outputs.desktop == 'true' env: - GH_TOKEN: ${{ steps.committer.outputs.token }} + GH_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }} run: | shopt -s nullglob files=(/tmp/desktop/*.{exe,blockmap,dmg,zip,AppImage,deb,rpm} /tmp/desktop/*.app.tar.gz) @@ -513,9 +482,8 @@ jobs: OPENCODE_VERSION: ${{ needs.version.outputs.version }} OPENCODE_RELEASE: ${{ needs.version.outputs.release }} AUR_KEY: ${{ secrets.AUR_KEY }} - GITHUB_TOKEN: ${{ steps.committer.outputs.token }} + GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }} GH_REPO: ${{ needs.version.outputs.repo }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NPM_CONFIG_PROVENANCE: false LATEST_YML_DIR: /tmp/latest-yml - TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} - TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} diff --git a/README.md b/README.md index 0226ec8c..b20bab79 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,31 @@ Both route to `https://api.llmgateway.io/v1` and send an `x-source: devpass-code` header so DevPass usage is attributed correctly. -### Install & run (from source) +### Install + +```bash +curl -fsSL https://raw.githubusercontent.com/theopenco/devpass-code/main/install | bash +``` + +Or with a package manager: + +```bash +npm i -g devpass-code # or: bun / pnpm / yarn +brew install theopenco/tap/devpass-code # macOS & Linux +paru -S devpass-code-bin # Arch Linux (AUR) +``` + +Run it with Docker: + +```bash +docker run -it --rm ghcr.io/theopenco/devpass-code +``` + +Windows binaries (`devpass-code-windows-*.zip`) are attached to every [GitHub release](https://github.com/theopenco/devpass-code/releases); `npm i -g devpass-code` works there too. + +Already installed? Upgrade in place with `devpass-code upgrade`. + +### Run from source ```bash bun install diff --git a/github/action.yml b/github/action.yml index 3d983a16..5a36275e 100644 --- a/github/action.yml +++ b/github/action.yml @@ -1,5 +1,5 @@ -name: "opencode GitHub Action" -description: "Run opencode in GitHub Actions workflows" +name: "DevPass Code GitHub Action" +description: "Run DevPass Code in GitHub Actions workflows" branding: icon: "code" color: "orange" @@ -41,33 +41,33 @@ inputs: runs: using: "composite" steps: - - name: Get opencode version + - name: Get devpass-code version id: version shell: bash run: | - VERSION=$(curl -sf https://api.github.com/repos/anomalyco/opencode/releases/latest | grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4) + VERSION=$(curl -sf https://api.github.com/repos/theopenco/devpass-code/releases/latest | grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4) echo "version=${VERSION:-latest}" >> $GITHUB_OUTPUT - - name: Cache opencode + - name: Cache devpass-code id: cache uses: actions/cache@v4 with: - path: ~/.opencode/bin - key: opencode-${{ runner.os }}-${{ runner.arch }}-${{ steps.version.outputs.version }} + path: ~/.devpass-code/bin + key: devpass-code-${{ runner.os }}-${{ runner.arch }}-${{ steps.version.outputs.version }} - - name: Install opencode + - name: Install devpass-code if: steps.cache.outputs.cache-hit != 'true' shell: bash - run: curl -fsSL https://opencode.ai/install | bash + run: curl -fsSL https://raw.githubusercontent.com/theopenco/devpass-code/main/install | bash - - name: Add opencode to PATH + - name: Add devpass-code to PATH shell: bash - run: echo "$HOME/.opencode/bin" >> $GITHUB_PATH + run: echo "$HOME/.devpass-code/bin" >> $GITHUB_PATH - - name: Run opencode + - name: Run devpass-code shell: bash - id: run_opencode - run: opencode github run + id: run_devpass_code + run: devpass-code github run env: MODEL: ${{ inputs.model }} AGENT: ${{ inputs.agent }} diff --git a/install b/install index b0716d53..526686f8 100755 --- a/install +++ b/install @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -euo pipefail -APP=opencode +APP=devpass-code MUTED='\033[0;2m' RED='\033[0;31m' @@ -9,7 +9,7 @@ NC='\033[0m' # No Color usage() { cat </dev/null 2>&1; then - opencode_path=$(which opencode) + if command -v devpass-code >/dev/null 2>&1; then + devpass_code_path=$(which devpass-code) ## Check the installed version - installed_version=$(opencode --version 2>/dev/null || echo "") + installed_version=$(devpass-code --version 2>/dev/null || echo "") if [[ "$installed_version" != "$specific_version" ]]; then print_message info "${MUTED}Installed version: ${NC}$installed_version." @@ -275,7 +275,7 @@ download_with_progress() { fi local tmp_dir=${TMPDIR:-/tmp} - local basename="${tmp_dir}/opencode_install_$$" + local basename="${tmp_dir}/devpass-code_install_$$" local tracefile="${basename}.trace" rm -f "$tracefile" @@ -325,8 +325,8 @@ download_with_progress() { } download_and_install() { - print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}version: ${NC}$specific_version" - local tmp_dir="${TMPDIR:-/tmp}/opencode_install_$$" + print_message info "\n${MUTED}Installing ${NC}devpass-code ${MUTED}version: ${NC}$specific_version" + local tmp_dir="${TMPDIR:-/tmp}/devpass-code_install_$$" mkdir -p "$tmp_dir" if [[ "$os" == "windows" ]] || ! [ -t 2 ] || ! download_with_progress "$url" "$tmp_dir/$filename"; then @@ -340,15 +340,15 @@ download_and_install() { unzip -q "$tmp_dir/$filename" -d "$tmp_dir" fi - mv "$tmp_dir/opencode" "$INSTALL_DIR" - chmod 755 "${INSTALL_DIR}/opencode" + mv "$tmp_dir/devpass-code" "$INSTALL_DIR" + chmod 755 "${INSTALL_DIR}/devpass-code" rm -rf "$tmp_dir" } install_from_binary() { - print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}from: ${NC}$binary_path" - cp "$binary_path" "${INSTALL_DIR}/opencode" - chmod 755 "${INSTALL_DIR}/opencode" + print_message info "\n${MUTED}Installing ${NC}devpass-code ${MUTED}from: ${NC}$binary_path" + cp "$binary_path" "${INSTALL_DIR}/devpass-code" + chmod 755 "${INSTALL_DIR}/devpass-code" } if [ -n "$binary_path" ]; then @@ -366,9 +366,9 @@ add_to_path() { if grep -Fxq "$command" "$config_file"; then print_message info "Command already exists in $config_file, skipping write." elif [[ -w $config_file ]]; then - echo -e "\n# opencode" >> "$config_file" + echo -e "\n# devpass-code" >> "$config_file" echo "$command" >> "$config_file" - print_message info "${MUTED}Successfully added ${NC}opencode ${MUTED}to \$PATH in ${NC}$config_file" + print_message info "${MUTED}Successfully added ${NC}devpass-code ${MUTED}to \$PATH in ${NC}$config_file" else print_message warning "Manually add the directory to $config_file (or similar):" print_message info " $command" @@ -444,17 +444,18 @@ if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then fi echo -e "" -echo -e "${MUTED}  ${NC} ▄ " -echo -e "${MUTED}█▀▀█ █▀▀█ █▀▀█ █▀▀▄ ${NC}█▀▀▀ █▀▀█ █▀▀█ █▀▀█" -echo -e "${MUTED}█░░█ █░░█ █▀▀▀ █░░█ ${NC}█░░░ █░░█ █░░█ █▀▀▀" -echo -e "${MUTED}▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀ ${NC}▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀" +echo -e "${MUTED} ▄ ${NC} ▄ " +echo -e "${MUTED}█▀▀█ █▀▀█ █░░█ █▀▀█ █▀▀█ █▀▀▀ █▀▀▀ ${NC}█▀▀▀ █▀▀█ █▀▀█ █▀▀█" +echo -e "${MUTED}█░░█ █▀▀▀ █░░█ █░░█ █▀▀█ ▀▀▀█ ▀▀▀█ ${NC}█░░░ █░░█ █░░█ █▀▀▀" +echo -e "${MUTED}▀▀▀▀ ▀▀▀▀ ▀▀ █▀▀▀ █░░█ ▀▀▀▀ ▀▀▀▀ ${NC}▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀" echo -e "" echo -e "" -echo -e "${MUTED}OpenCode includes free models, to start:${NC}" +echo -e "${MUTED}DevPass Code runs on LLM Gateway, to start:${NC}" echo -e "" -echo -e "cd ${MUTED}# Open directory${NC}" -echo -e "opencode ${MUTED}# Run command${NC}" +echo -e "cd ${MUTED}# Open directory${NC}" +echo -e "devpass-code auth login ${MUTED}# Connect to LLM Gateway${NC}" +echo -e "devpass-code ${MUTED}# Run command${NC}" echo -e "" -echo -e "${MUTED}For more information visit ${NC}https://opencode.ai/docs" +echo -e "${MUTED}For more information visit ${NC}https://llmgateway.io" echo -e "" echo -e "" diff --git a/packages/devpass-code/Dockerfile b/packages/devpass-code/Dockerfile index f92b48a6..c435b15e 100644 --- a/packages/devpass-code/Dockerfile +++ b/packages/devpass-code/Dockerfile @@ -7,12 +7,12 @@ ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} RUN apk add libgcc libstdc++ ripgrep FROM base AS build-amd64 -COPY dist/opencode-linux-x64-baseline-musl/bin/opencode /usr/local/bin/opencode +COPY dist/devpass-code-linux-x64-baseline-musl/bin/devpass-code /usr/local/bin/devpass-code FROM base AS build-arm64 -COPY dist/opencode-linux-arm64-musl/bin/opencode /usr/local/bin/opencode +COPY dist/devpass-code-linux-arm64-musl/bin/devpass-code /usr/local/bin/devpass-code ARG TARGETARCH FROM build-${TARGETARCH} -RUN opencode --version -ENTRYPOINT ["opencode"] +RUN devpass-code --version +ENTRYPOINT ["devpass-code"] diff --git a/packages/devpass-code/bin/devpass-code b/packages/devpass-code/bin/devpass-code index a7101f42..3ff92433 100755 --- a/packages/devpass-code/bin/devpass-code +++ b/packages/devpass-code/bin/devpass-code @@ -43,13 +43,13 @@ function run(target) { }) } -const envPath = process.env.OPENCODE_BIN_PATH +const envPath = process.env.DEVPASS_CODE_BIN_PATH || process.env.OPENCODE_BIN_PATH const scriptPath = fs.realpathSync(__filename) const scriptDir = path.dirname(scriptPath) // -const cached = path.join(scriptDir, ".opencode") +const cached = path.join(scriptDir, ".devpass-code") const platformMap = { darwin: "darwin", @@ -70,8 +70,8 @@ let arch = archMap[os.arch()] if (!arch) { arch = os.arch() } -const base = "opencode-" + platform + "-" + arch -const binary = platform === "windows" ? "opencode.exe" : "opencode" +const base = "devpass-code-" + platform + "-" + arch +const binary = platform === "windows" ? "devpass-code.exe" : "devpass-code" function supportsAvx2() { if (arch !== "x64") return false @@ -189,7 +189,7 @@ function findBinary(startDir) { const resolved = envPath || (fs.existsSync(cached) ? cached : findBinary(scriptDir)) if (!resolved) { console.error( - "It seems that your package manager failed to install the right version of the opencode CLI for your platform. You can try manually installing " + + "It seems that your package manager failed to install the right version of the devpass-code CLI for your platform. You can try manually installing " + names.map((n) => `\"${n}\"`).join(" or ") + " package", ) diff --git a/packages/devpass-code/package.json b/packages/devpass-code/package.json index 37640684..08204708 100644 --- a/packages/devpass-code/package.json +++ b/packages/devpass-code/package.json @@ -16,7 +16,7 @@ "dev:temporary": "bun run --conditions=browser ./src/temporary.ts" }, "bin": { - "devpass-code": "./bin/opencode" + "devpass-code": "./bin/devpass-code" }, "exports": { "./*": "./src/*.ts" diff --git a/packages/devpass-code/script/build.ts b/packages/devpass-code/script/build.ts index 236838db..bd3c39cf 100755 --- a/packages/devpass-code/script/build.ts +++ b/packages/devpass-code/script/build.ts @@ -180,8 +180,8 @@ for (const item of targets) { autoloadTsconfig: true, autoloadPackageJson: true, target: name.replace(pkg.name, "bun") as any, - outfile: `dist/${name}/bin/opencode`, - execArgv: [`--user-agent=opencode/${Script.version}`, "--use-system-ca", "--"], + outfile: `dist/${name}/bin/${pkg.name}`, + execArgv: [`--user-agent=${pkg.name}/${Script.version}`, "--use-system-ca", "--"], windows: {}, }, files: embeddedFileMap ? { "opencode-web-ui.gen.ts": embeddedFileMap } : {}, @@ -200,7 +200,7 @@ for (const item of targets) { // Smoke test: only run if binary is for current platform if (item.os === process.platform && item.arch === process.arch && !item.abi) { - const binaryPath = `dist/${name}/bin/opencode` + const binaryPath = `dist/${name}/bin/${pkg.name}` console.log(`Running smoke test: ${binaryPath} --version`) try { const versionOutput = await $`${binaryPath} --version`.text() diff --git a/packages/devpass-code/script/postinstall.mjs b/packages/devpass-code/script/postinstall.mjs index fa303b74..6e734a7a 100644 --- a/packages/devpass-code/script/postinstall.mjs +++ b/packages/devpass-code/script/postinstall.mjs @@ -24,9 +24,9 @@ const archMap = { const platform = platformMap[os.platform()] ?? os.platform() const arch = archMap[os.arch()] ?? os.arch() -const base = `opencode-${platform}-${arch}` -const sourceBinary = platform === "windows" ? "opencode.exe" : "opencode" -const targetBinary = path.join(__dirname, "bin", "opencode.exe") +const base = `devpass-code-${platform}-${arch}` +const sourceBinary = platform === "windows" ? "devpass-code.exe" : "devpass-code" +const targetBinary = path.join(__dirname, "bin", "devpass-code.exe") function supportsAvx2() { if (arch !== "x64") return false @@ -127,7 +127,7 @@ function installPackage(name) { const version = packageJson.optionalDependencies?.[name] if (!version) return - const temp = fs.mkdtempSync(path.join(os.tmpdir(), "opencode-install-")) + const temp = fs.mkdtempSync(path.join(os.tmpdir(), "devpass-code-install-")) try { const result = childProcess.spawnSync( "npm", @@ -175,7 +175,7 @@ function main() { } throw new Error( - `It seems your package manager failed to install the right opencode CLI package. Try manually installing ${packageNames() + `It seems your package manager failed to install the right devpass-code CLI package. Try manually installing ${packageNames() .map((name) => JSON.stringify(name)) .join(" or ")}.`, ) diff --git a/packages/devpass-code/script/publish.ts b/packages/devpass-code/script/publish.ts index ac1cafff..ba2133fc 100755 --- a/packages/devpass-code/script/publish.ts +++ b/packages/devpass-code/script/publish.ts @@ -7,6 +7,8 @@ import { fileURLToPath } from "url" const dir = fileURLToPath(new URL("..", import.meta.url)) process.chdir(dir) +const REPO = "theopenco/devpass-code" + async function published(name: string, version: string) { return (await $`npm view ${name}@${version} version`.nothrow()).exitCode === 0 } @@ -37,15 +39,15 @@ await $`cp ./script/postinstall.mjs ./dist/${pkg.name}/postinstall.mjs` await Bun.file(`./dist/${pkg.name}/LICENSE`).write(await Bun.file("../../LICENSE").text()) await Bun.file(`./dist/${pkg.name}/bin/${pkg.name}.exe`).write( [ - `echo "Error: ${pkg.name}-ai's postinstall script was not run." >&2`, + `echo "Error: ${pkg.name}'s postinstall script was not run." >&2`, 'echo "" >&2', 'echo "This occurs when using --ignore-scripts during installation, or when using a" >&2', 'echo "package manager like pnpm that does not run postinstall scripts by default." >&2', 'echo "" >&2', 'echo "To fix this, run the postinstall script manually:" >&2', - `echo " cd node_modules/${pkg.name}-ai && node postinstall.mjs" >&2`, + `echo " cd node_modules/${pkg.name} && node postinstall.mjs" >&2`, 'echo "" >&2', - `echo "Or reinstall ${pkg.name}-ai without the --ignore-scripts flag." >&2`, + `echo "Or reinstall ${pkg.name} without the --ignore-scripts flag." >&2`, "exit 1", "", ].join("\n"), @@ -54,7 +56,8 @@ await Bun.file(`./dist/${pkg.name}/bin/${pkg.name}.exe`).write( await Bun.file(`./dist/${pkg.name}/package.json`).write( JSON.stringify( { - name: pkg.name + "-ai", + name: pkg.name, + description: "DevPass Code — the LLM Gateway coding agent for the terminal", bin: { [pkg.name]: `./bin/${pkg.name}.exe`, }, @@ -63,6 +66,10 @@ await Bun.file(`./dist/${pkg.name}/package.json`).write( }, version: version, license: pkg.license, + repository: { + type: "git", + url: `git+https://github.com/${REPO}.git`, + }, os: ["darwin", "linux", "win32"], cpu: ["arm64", "x64"], optionalDependencies: binaries, @@ -76,9 +83,9 @@ const tasks = Object.entries(binaries).map(async ([name]) => { await publish(`./dist/${name}`, name, binaries[name]) }) await Promise.all(tasks) -await publish(`./dist/${pkg.name}`, `${pkg.name}-ai`, version) +await publish(`./dist/${pkg.name}`, pkg.name, version) -const image = "ghcr.io/anomalyco/opencode" +const image = `ghcr.io/${REPO}` const platforms = "linux/amd64,linux/arm64" const tags = [`${image}:${version}`, `${image}:${Script.channel}`] const tagFlags = tags.flatMap((t) => ["-t", t]) @@ -87,58 +94,61 @@ const tagFlags = tags.flatMap((t) => ["-t", t]) if (!Script.preview) { await $`docker buildx build --platform ${platforms} ${tagFlags} --push .` // Calculate SHA values - const arm64Sha = await $`sha256sum ./dist/opencode-linux-arm64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim()) - const x64Sha = await $`sha256sum ./dist/opencode-linux-x64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim()) - const macX64Sha = await $`sha256sum ./dist/opencode-darwin-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) - const macArm64Sha = await $`sha256sum ./dist/opencode-darwin-arm64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) + const arm64Sha = await $`sha256sum ./dist/${pkg.name}-linux-arm64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim()) + const x64Sha = await $`sha256sum ./dist/${pkg.name}-linux-x64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim()) + const macX64Sha = await $`sha256sum ./dist/${pkg.name}-darwin-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) + const macArm64Sha = await $`sha256sum ./dist/${pkg.name}-darwin-arm64.zip | cut -d' ' -f1` + .text() + .then((x) => x.trim()) const [pkgver, _subver = ""] = Script.version.split(/(-.*)/, 2) - // arch - const binaryPkgbuild = [ - "# Maintainer: dax", - "# Maintainer: adam", - "", - "pkgname='opencode-bin'", - `pkgver=${pkgver}`, - `_subver=${_subver}`, - "options=('!debug' '!strip')", - "pkgrel=1", - "pkgdesc='The AI coding agent built for the terminal.'", - "url='https://github.com/anomalyco/opencode'", - "arch=('aarch64' 'x86_64')", - "license=('MIT')", - "provides=('opencode')", - "conflicts=('opencode')", - "depends=('ripgrep')", - "", - `source_aarch64=("\${pkgname}_\${pkgver}_aarch64.tar.gz::https://github.com/anomalyco/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-arm64.tar.gz")`, - `sha256sums_aarch64=('${arm64Sha}')`, + // arch (AUR pushes need the AUR SSH key; skip when it is not configured) + if (process.env.AUR_KEY) { + const binaryPkgbuild = [ + "# Maintainer: devpass", + "", + `pkgname='${pkg.name}-bin'`, + `pkgver=${pkgver}`, + `_subver=${_subver}`, + "options=('!debug' '!strip')", + "pkgrel=1", + "pkgdesc='DevPass Code — the LLM Gateway coding agent for the terminal.'", + `url='https://github.com/${REPO}'`, + "arch=('aarch64' 'x86_64')", + "license=('MIT')", + `provides=('${pkg.name}')`, + `conflicts=('${pkg.name}')`, + "depends=('ripgrep')", + "", + `source_aarch64=("\${pkgname}_\${pkgver}_aarch64.tar.gz::https://github.com/${REPO}/releases/download/v\${pkgver}\${_subver}/${pkg.name}-linux-arm64.tar.gz")`, + `sha256sums_aarch64=('${arm64Sha}')`, - `source_x86_64=("\${pkgname}_\${pkgver}_x86_64.tar.gz::https://github.com/anomalyco/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-x64.tar.gz")`, - `sha256sums_x86_64=('${x64Sha}')`, - "", - "package() {", - ' install -Dm755 ./opencode "${pkgdir}/usr/bin/opencode"', - "}", - "", - ].join("\n") + `source_x86_64=("\${pkgname}_\${pkgver}_x86_64.tar.gz::https://github.com/${REPO}/releases/download/v\${pkgver}\${_subver}/${pkg.name}-linux-x64.tar.gz")`, + `sha256sums_x86_64=('${x64Sha}')`, + "", + "package() {", + ` install -Dm755 ./${pkg.name} "\${pkgdir}/usr/bin/${pkg.name}"`, + "}", + "", + ].join("\n") - for (const [pkg, pkgbuild] of [["opencode-bin", binaryPkgbuild]]) { - for (let i = 0; i < 30; i++) { - try { - await $`rm -rf ./dist/aur-${pkg}` - await $`git clone ssh://aur@aur.archlinux.org/${pkg}.git ./dist/aur-${pkg}` - await $`cd ./dist/aur-${pkg} && git checkout master` - await Bun.file(`./dist/aur-${pkg}/PKGBUILD`).write(pkgbuild) - await $`cd ./dist/aur-${pkg} && makepkg --printsrcinfo > .SRCINFO` - await $`cd ./dist/aur-${pkg} && git add PKGBUILD .SRCINFO` - if ((await $`cd ./dist/aur-${pkg} && git diff --cached --quiet`.nothrow()).exitCode === 0) break - await $`cd ./dist/aur-${pkg} && git commit -m "Update to v${Script.version}"` - await $`cd ./dist/aur-${pkg} && git push` - break - } catch { - continue + for (const [aurPkg, pkgbuild] of [[`${pkg.name}-bin`, binaryPkgbuild]]) { + for (let i = 0; i < 30; i++) { + try { + await $`rm -rf ./dist/aur-${aurPkg}` + await $`git clone ssh://aur@aur.archlinux.org/${aurPkg}.git ./dist/aur-${aurPkg}` + await $`cd ./dist/aur-${aurPkg} && git checkout master` + await Bun.file(`./dist/aur-${aurPkg}/PKGBUILD`).write(pkgbuild) + await $`cd ./dist/aur-${aurPkg} && makepkg --printsrcinfo > .SRCINFO` + await $`cd ./dist/aur-${aurPkg} && git add PKGBUILD .SRCINFO` + if ((await $`cd ./dist/aur-${aurPkg} && git diff --cached --quiet`.nothrow()).exitCode === 0) break + await $`cd ./dist/aur-${aurPkg} && git commit -m "Update to v${Script.version}"` + await $`cd ./dist/aur-${aurPkg} && git push` + break + } catch { + continue + } } } } @@ -148,46 +158,46 @@ if (!Script.preview) { "# typed: false", "# frozen_string_literal: true", "", - "# This file was generated by GoReleaser. DO NOT EDIT.", - "class Opencode < Formula", - ` desc "The AI coding agent built for the terminal."`, - ` homepage "https://github.com/anomalyco/opencode"`, + "# This file was generated by the devpass-code release pipeline. DO NOT EDIT.", + "class DevpassCode < Formula", + ` desc "DevPass Code — the LLM Gateway coding agent for the terminal."`, + ` homepage "https://github.com/${REPO}"`, ` version "${Script.version.split("-")[0]}"`, "", ` depends_on "ripgrep"`, "", " on_macos do", " if Hardware::CPU.intel?", - ` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-darwin-x64.zip"`, + ` url "https://github.com/${REPO}/releases/download/v${Script.version}/${pkg.name}-darwin-x64.zip"`, ` sha256 "${macX64Sha}"`, "", " def install", - ' bin.install "opencode"', + ` bin.install "${pkg.name}"`, " end", " end", " if Hardware::CPU.arm?", - ` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-darwin-arm64.zip"`, + ` url "https://github.com/${REPO}/releases/download/v${Script.version}/${pkg.name}-darwin-arm64.zip"`, ` sha256 "${macArm64Sha}"`, "", " def install", - ' bin.install "opencode"', + ` bin.install "${pkg.name}"`, " end", " end", " end", "", " on_linux do", " if Hardware::CPU.intel? and Hardware::CPU.is_64_bit?", - ` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-linux-x64.tar.gz"`, + ` url "https://github.com/${REPO}/releases/download/v${Script.version}/${pkg.name}-linux-x64.tar.gz"`, ` sha256 "${x64Sha}"`, " def install", - ' bin.install "opencode"', + ` bin.install "${pkg.name}"`, " end", " end", " if Hardware::CPU.arm? and Hardware::CPU.is_64_bit?", - ` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-linux-arm64.tar.gz"`, + ` url "https://github.com/${REPO}/releases/download/v${Script.version}/${pkg.name}-linux-arm64.tar.gz"`, ` sha256 "${arm64Sha}"`, " def install", - ' bin.install "opencode"', + ` bin.install "${pkg.name}"`, " end", " end", " end", @@ -201,11 +211,11 @@ if (!Script.preview) { console.error("GITHUB_TOKEN is required to update homebrew tap") process.exit(1) } - const tap = `https://x-access-token:${token}@github.com/anomalyco/homebrew-tap.git` + const tap = `https://x-access-token:${token}@github.com/theopenco/homebrew-tap.git` await $`rm -rf ./dist/homebrew-tap` await $`git clone ${tap} ./dist/homebrew-tap` - await Bun.file("./dist/homebrew-tap/opencode.rb").write(homebrewFormula) - await $`cd ./dist/homebrew-tap && git add opencode.rb` + await Bun.file(`./dist/homebrew-tap/${pkg.name}.rb`).write(homebrewFormula) + await $`cd ./dist/homebrew-tap && git add ${pkg.name}.rb` if ((await $`cd ./dist/homebrew-tap && git diff --cached --quiet`.nothrow()).exitCode !== 0) { await $`cd ./dist/homebrew-tap && git commit -m "Update to v${Script.version}"` await $`cd ./dist/homebrew-tap && git push` diff --git a/packages/devpass-code/src/installation/index.ts b/packages/devpass-code/src/installation/index.ts index 43002202..2222e0a3 100644 --- a/packages/devpass-code/src/installation/index.ts +++ b/packages/devpass-code/src/installation/index.ts @@ -39,7 +39,7 @@ export const Info = Schema.Struct({ export type Info = Schema.Schema.Type export function userAgent(client = "cli") { - return `opencode/${InstallationChannel}/${InstallationVersion}/${client}` + return `devpass-code/${InstallationChannel}/${InstallationVersion}/${client}` } export const USER_AGENT = userAgent() @@ -63,7 +63,6 @@ export class UpgradeFailedError extends Schema.TaggedErrorClass { @@ -144,7 +143,9 @@ const layer: Layer.Layer text(["yarn", "global", "list"]) }, { name: "pnpm", command: () => text(["pnpm", "list", "-g", "--depth=0"]) }, { name: "bun", command: () => text(["bun", "pm", "ls", "-g"]) }, - { name: "brew", command: () => text(["brew", "list", "--formula", "opencode"]) }, - { name: "scoop", command: () => text(["scoop", "list", "opencode"]) }, - { name: "choco", command: () => text(["choco", "list", "--limit-output", "opencode"]) }, + { name: "brew", command: () => text(["brew", "list", "--formula", "devpass-code"]) }, + { name: "scoop", command: () => text(["scoop", "list", "devpass-code"]) }, + { name: "choco", command: () => text(["choco", "list", "--limit-output", "devpass-code"]) }, ] checks.sort((a, b) => { @@ -196,9 +197,7 @@ const layer: Layer.Layer { Effect.gen(function* () { const result = yield* Installation.use.latest("npm") expect(result).toBe("1.5.0") - expect(npmCalls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`) + expect(npmCalls).toContain(`https://registry.npmjs.org/devpass-code/${InstallationChannel}`) }), ) @@ -110,7 +110,7 @@ describe("installation", () => { Effect.gen(function* () { const result = yield* Installation.use.latest("bun") expect(result).toBe("1.6.0") - expect(bunCalls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`) + expect(bunCalls).toContain(`https://registry.npmjs.org/devpass-code/${InstallationChannel}`) }), ) @@ -124,7 +124,7 @@ describe("installation", () => { Effect.gen(function* () { const result = yield* Installation.use.latest("pnpm") expect(result).toBe("1.7.0") - expect(pnpmCalls).toContain(`https://registry.npmjs.org/opencode-ai/${InstallationChannel}`) + expect(pnpmCalls).toContain(`https://registry.npmjs.org/devpass-code/${InstallationChannel}`) }), ) @@ -146,15 +146,17 @@ describe("installation", () => { testEffect( testLayer( - () => jsonResponse({ versions: { stable: "2.0.0" } }), + () => jsonResponse({}), // HTTP not used for brew (cmd, args) => { - // getBrewFormula: return core formula (no tap) - if (cmd === "brew" && args.includes("--formula") && args.includes("anomalyco/tap/opencode")) return "" - if (cmd === "brew" && args.includes("--formula") && args.includes("opencode")) return "opencode" + // getBrewFormula: return plain formula (no tap) + if (cmd === "brew" && args.includes("--formula") && args.includes("theopenco/tap/devpass-code")) return "" + if (cmd === "brew" && args.includes("--formula") && args.includes("devpass-code")) return "devpass-code" + if (cmd === "brew" && args.includes("--json=v2")) + return JSON.stringify({ formulae: [{ versions: { stable: "2.0.0" } }] }) return "" }, ), - ).effect("reads brew formulae API versions", () => + ).effect("reads brew plain formula versions via CLI", () => Effect.gen(function* () { const result = yield* Installation.use.latest("brew") expect(result).toBe("2.0.0") @@ -168,7 +170,8 @@ describe("installation", () => { testLayer( () => jsonResponse({}), // HTTP not used for tap formula (cmd, args) => { - if (cmd === "brew" && args.includes("anomalyco/tap/opencode") && args.includes("--formula")) return "opencode" + if (cmd === "brew" && args.includes("theopenco/tap/devpass-code") && args.includes("--formula")) + return "devpass-code" if (cmd === "brew" && args.includes("--json=v2")) return brewInfoJson return "" }, diff --git a/packages/script/src/index.ts b/packages/script/src/index.ts index d148ce0d..9b283c91 100644 --- a/packages/script/src/index.ts +++ b/packages/script/src/index.ts @@ -34,12 +34,17 @@ const IS_PREVIEW = CHANNEL !== "latest" const VERSION = await (async () => { if (env.OPENCODE_VERSION) return env.OPENCODE_VERSION if (IS_PREVIEW) return `0.0.0-${CHANNEL}-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}` - const version = await fetch("https://registry.npmjs.org/opencode-ai/latest") + const version = await fetch("https://registry.npmjs.org/devpass-code/latest") .then((res) => { + // not published yet: bump from the version checked into the repo + if (res.status === 404) return null if (!res.ok) throw new Error(res.statusText) - return res.json() + return res.json().then((data: any) => data.version) }) - .then((data: any) => data.version) + .then( + async (published: string | null) => + published ?? (await Bun.file(path.resolve(import.meta.dir, "../../devpass-code/package.json")).json()).version, + ) const [major, minor, patch] = version.split(".").map((x: string) => Number(x) || 0) const t = env.OPENCODE_BUMP?.toLowerCase() if (t === "major") return `${major + 1}.0.0` diff --git a/script/publish.ts b/script/publish.ts index f27958dd..7bb74646 100755 --- a/script/publish.ts +++ b/script/publish.ts @@ -2,6 +2,7 @@ import { Script } from "@opencode-ai/script" import { $ } from "bun" +import { existsSync } from "fs" import { fileURLToPath } from "url" console.log("=== publishing ===\n") @@ -9,6 +10,7 @@ console.log("=== publishing ===\n") const dir = fileURLToPath(new URL("..", import.meta.url)) process.chdir(dir) const tag = `v${Script.version}` +const syncBranch = process.env.GITHUB_REF_NAME || "main" const pkgjsons = await Array.fromAsync( new Bun.Glob("**/package.json").scan({ @@ -38,19 +40,12 @@ await prepareReleaseFiles() console.log("\n=== cli ===\n") await $`bun ./packages/devpass-code/script/publish.ts` -console.log("\n=== preview cli ===\n") -await $`bun ./packages/cli/script/publish.ts` +// The preview cli, sdk, plugin, and ui packages are published under the +// @opencode-ai npm scope, which belongs to upstream. Skip them until this +// fork has its own scope for them. -console.log("\n=== sdk ===\n") -await $`bun ./packages/sdk/js/script/publish.ts` - -console.log("\n=== plugin ===\n") -await $`bun ./packages/plugin/script/publish.ts` - -console.log("\n=== ui ===\n") -await $`bun ./packages/ui/script/publish.ts` - -if (Script.release) { +if (Script.release && process.env.LATEST_YML_DIR && existsSync(process.env.LATEST_YML_DIR)) { + console.log("\n=== desktop ===\n") await $`bun ./packages/desktop/scripts/finalize-latest-json.ts` await $`bun ./packages/desktop/scripts/finalize-latest-yml.ts` } @@ -62,10 +57,10 @@ if (Script.release && !Script.preview) { await $`git push origin refs/tags/${tag} --force-with-lease --no-verify` await new Promise((resolve) => setTimeout(resolve, 5_000)) await $`git fetch origin` - await $`git checkout -B dev origin/dev` + await $`git checkout -B ${syncBranch} origin/${syncBranch}` await prepareReleaseFiles() await $`git commit -am "sync release versions for ${tag}"` - await $`git push origin HEAD:dev --no-verify` + await $`git push origin HEAD:${syncBranch} --no-verify` } if (Script.release) { diff --git a/script/version.ts b/script/version.ts index 0582f49a..7100c32a 100755 --- a/script/version.ts +++ b/script/version.ts @@ -7,7 +7,9 @@ const output = [`version=${Script.version}`] const sha = process.env.GITHUB_SHA ?? (await $`git rev-parse HEAD`.text()).trim() if (!Script.preview) { - await $`bun script/changelog.ts --to ${sha}`.cwd(process.cwd()) + // best-effort: changelog generation needs the opencode CLI plus an API key, + // and the release-notes read below falls back to "No notable changes" + await $`bun script/changelog.ts --to ${sha}`.cwd(process.cwd()).nothrow() const file = `${process.cwd()}/UPCOMING_CHANGELOG.md` const body = await Bun.file(file) .text() From 5de30d3ae15f66bf7edae084b3b3890edc309905 Mon Sep 17 00:00:00 2001 From: Luca Steeb Date: Thu, 2 Jul 2026 19:53:59 +0100 Subject: [PATCH 2/2] ci(publish): enable npm provenance attestations for OIDC releases Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2be169fa..0dd5ea6f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -485,5 +485,5 @@ jobs: GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }} GH_REPO: ${{ needs.version.outputs.repo }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - NPM_CONFIG_PROVENANCE: false + NPM_CONFIG_PROVENANCE: true LATEST_YML_DIR: /tmp/latest-yml