Skip to content

fix(virtual-display): reserve owned display numbers across acquires #154

fix(virtual-display): reserve owned display numbers across acquires

fix(virtual-display): reserve owned display numbers across acquires #154

Workflow file for this run

name: CI
on:
push:
branches:
- main
- "feature/**"
pull_request:
branches:
- main
# Cancel in-flight runs for the same branch when a new commit is pushed.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check:
name: check (${{ matrix.os }})
strategy:
# Never fail-fast — we always want to see both Linux and Windows
# results, even if one platform regresses. Masking a Windows-only
# break with a Linux pass (or vice versa) would defeat the whole
# point of having this matrix.
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Install Linux system dependencies
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libwebkit2gtk-4.1-dev \
build-essential \
libssl-dev \
libgtk-3-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
patchelf \
file \
ripgrep
# This matches the package list installed in release.yml so the CI
# toolchain is a strict subset of what the release pipeline uses.
# libfuse2 is excluded — it is only needed by `tauri build`'s
# AppImage packager, not by `cargo check` or `cargo test`.
# ripgrep is required by `commands::files::tests::grep_count_pattern_*`,
# which shells out to `rg` to count CODEMUX_DEBUG markers.
- name: Install Windows system dependencies
if: matrix.os == 'windows-latest'
# Chocolatey is pre-installed on windows-latest runners. ripgrep
# is needed for the same `grep_count_pattern_*` tests as Linux.
run: choco install ripgrep -y --no-progress
shell: pwsh
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri -> target
# Scope the cache per OS so Linux and Windows artifacts never
# collide in the same cache key.
key: ${{ matrix.os }}
- name: Setup Node
uses: actions/setup-node@v5
with:
# Node 22 for the project's npm scripts. The action itself is on
# @v5 (Node 24 runtime) so it won't trip GitHub's Node-20-actions
# deprecation that takes effect 2026-06-02.
# See: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
node-version: 22
cache: npm
- name: Install npm dependencies
run: npm ci
- name: Setup Bun
# Needed to build the claude-agent sidecar below. Installed here
# so the stage step can produce the per-target binary before
# `cargo check` fails tauri-build's externalBin validation.
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Stage claude-agent sidecar binary
shell: bash
run: |
# Like the agent-browser step below, tauri-build validates
# `externalBin` at compile time, so the sidecar binary has to
# be present before `cargo check` / `cargo test`. Full build
# via Bun; fall back to a zero-byte placeholder if Bun fails
# (e.g. transient registry hiccup) — CI is checking types and
# running tests, not producing distributables.
TARGET="${CARGO_BUILD_TARGET:-$(rustc -vV | grep host | cut -d' ' -f2)}"
mkdir -p src-tauri/binaries
case "$TARGET" in
*windows*) DEST="src-tauri/binaries/codemux-claude-sidecar-$TARGET.exe" ;;
*) DEST="src-tauri/binaries/codemux-claude-sidecar-$TARGET" ;;
esac
if bash scripts/build-claude-sidecar.sh; then
if [ ! -s "$DEST" ]; then
echo "[ci] build-claude-sidecar.sh reported success but $DEST is missing — placeholder"
touch "$DEST"
chmod +x "$DEST" 2>/dev/null || true
fi
else
echo "[ci] sidecar build failed — creating placeholder at $DEST"
touch "$DEST"
chmod +x "$DEST" 2>/dev/null || true
fi
- name: Stage agent-browser sidecar binary
shell: bash
run: |
# tauri-build validates `externalBin` at compile time, so even
# `cargo check` fails if src-tauri/binaries/agent-browser-<target>
# does not exist. Our existing copy-agent-browser.sh maps the host
# target triple to the upstream npm package's pre-built binary.
#
# Git Bash is preinstalled on windows-latest, so `shell: bash`
# works on both platforms without needing a second .ps1 script.
bash scripts/copy-agent-browser.sh || true
# Fallback: if the copy script couldn't find the upstream binary
# (e.g. agent-browser's postinstall was skipped on a particular
# platform — see upstream issue #549), drop a zero-byte placeholder
# at the expected path so tauri-build's externalBin check passes.
# CI's job is to verify type-correctness and run unit tests, not
# to produce a distributable installer — an empty placeholder is
# sufficient for `cargo check` / `cargo test`.
TARGET="${CARGO_BUILD_TARGET:-$(rustc -vV | grep host | cut -d' ' -f2)}"
mkdir -p src-tauri/binaries
case "$TARGET" in
*windows*) DEST="src-tauri/binaries/agent-browser-$TARGET.exe" ;;
*) DEST="src-tauri/binaries/agent-browser-$TARGET" ;;
esac
if [ ! -f "$DEST" ]; then
echo "[ci] Real agent-browser binary not found at $DEST — creating placeholder"
touch "$DEST"
chmod +x "$DEST" 2>/dev/null || true
fi
- name: Sidecar ToS boundary check
# Static check that forbids the sidecar from reading Claude
# credential files, hitting Anthropic URLs directly, spawning
# the `claude` binary outside the auth-probe allowlist, or
# peeking at ANTHROPIC_* / CLAUDE_CODE_OAUTH_TOKEN env vars.
# This is a hard CI gate so a violation can never slip in.
shell: bash
run: cd sidecar/claude-agent && bun run check-tos
- name: Sidecar unit tests
shell: bash
run: cd sidecar/claude-agent && bun install --frozen-lockfile && bun test
- name: Build frontend
# `frontendDist: "../dist"` in tauri.conf.json means tauri-build
# wants `dist/` to exist at compile time — build the frontend first.
run: npm run build
- name: TypeScript typecheck
run: npm run check
- name: Frontend tests
run: npm run test
- name: Cargo check
run: cargo check --manifest-path src-tauri/Cargo.toml
- name: Configure git identity and line endings for tests
# Several tests in src-tauri/src/git.rs spin up a fixture repo and
# shell out to `git commit`. GitHub runners have git installed but
# no default user.email/user.name, so `git commit` refuses to run
# unless we provide a throwaway identity here.
#
# The `core.autocrlf false` + `core.eol lf` pair disables Git for
# Windows's default `autocrlf=true` behavior — without this, git on
# Windows rewrites `\n` to `\r\n` on checkout, and tests that write
# a file with `\n` then read it back after a git operation fail
# with `left: "...\r\n"` vs `right: "...\n"` assertion mismatches.
# Linux git already defaults to autocrlf=false, so these lines are
# no-ops there.
#
# Works on both Linux and Windows runners — git --global reads from
# $HOME on Linux and %USERPROFILE% on Windows.
shell: bash
run: |
git config --global user.email "ci@codemux.dev"
git config --global user.name "Codemux CI"
git config --global core.autocrlf false
git config --global core.eol lf
- name: Cargo test
run: cargo test --manifest-path src-tauri/Cargo.toml