chore: import upstream snapshot with attribution
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Windows) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:30:36 +08:00
commit f99010fae1
1834 changed files with 662985 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
name: Bench Gate
# Compares hot-path benchmarks between the PR head and its merge
# base, so performance regressions in the sync engine and DB write
# paths fail the PR instead of shipping. The gated regression classes
# have all shipped before:
#
# - discovery/skip work scaling with archive size instead of new
# data (#912, the providerSourceUnchangedInDB gap)
# - O(session history) work per incremental append (#954)
# - bulk ingest throughput (#411)
# - per-row query-shape regressions in usage aggregation (#309)
#
# Both sides run `make bench-gate` — the Makefile is the single
# source of truth for the gated package list, sample count, and
# iteration count — and cmd/benchgate compares the outputs. It gates
# on allocs/op and B/op (deterministic on a given machine, tight
# thresholds) and on ns/op with a loose 2x threshold that only
# catches algorithmic blowups; both sides run on the same runner
# within one job, so the comparison is apples to apples.
#
# Benchmarks that only exist on one side are reported but never fail
# the gate: a benchmark added by a PR has no baseline and is reported
# without gating, then gates automatically once merged. Because each
# side benchmarks its own Makefile's package list, a PR that adds a
# package to the gate cannot break the base run. A partially failing
# base run degrades to a partial baseline (whatever benchmarks it
# produced still gate) rather than silently disabling the whole gate.
on:
pull_request:
# Docs/frontend-only PRs cannot change the gated Go paths. If
# this check is ever made required on branch protection, pair it
# with a no-op sibling workflow on the inverse paths.
paths:
- "**.go"
- "go.mod"
- "go.sum"
- "Makefile"
- ".github/workflows/bench.yml"
concurrency:
group: bench-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
bench-gate:
name: Benchmark Gate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- name: Run benchmarks (PR head)
run: |
set -euo pipefail
make -s bench-gate | tee /tmp/bench-new.txt
- name: Run benchmarks (merge base)
env:
BASE_REF: ${{ github.base_ref }}
# A failing merge-base run keeps whatever benchmark output it
# produced: go test emits results per package, so one broken
# package (or a base predating the bench-gate target) leaves
# a partial or empty baseline and benchgate gates only what
# exists on both sides. The warning makes the degraded run
# visible instead of a silently green vacuous pass.
#
# The sample count and fixed iteration count are evaluated
# from the PR head's Makefile and passed into the base run:
# two benchmarks grow their fixture per iteration, so a PR
# that changes BENCH_GATE_COUNT/TIME must not compare against
# a baseline measured with the old values. The package list
# intentionally stays per-side, so growing the gate cannot
# break the base run.
run: |
set -euo pipefail
eval "$(make -s bench-gate-config)"
base=$(git merge-base HEAD "origin/$BASE_REF")
git worktree add /tmp/bench-base "$base"
if ! make -s -C /tmp/bench-base bench-gate \
BENCH_GATE_COUNT="$BENCH_GATE_COUNT" \
BENCH_GATE_TIME="$BENCH_GATE_TIME" > /tmp/bench-old.txt; then
echo "::warning title=Bench Gate::merge-base benchmark run exited non-zero; gating against its partial output"
fi
- name: Compare against merge base
run: go run ./cmd/benchgate -old /tmp/bench-old.txt -new /tmp/bench-new.txt
+364
View File
@@ -0,0 +1,364 @@
name: CI
on:
push:
branches: [main]
# Run on every pull request regardless of base branch so stacked PRs that
# target another feature branch (not just main) still get the full test,
# lint, and e2e suite. The expensive desktop/tauri bundle builds are gated
# to main separately in desktop-artifacts.yml.
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- name: Install lint tools
run: |
make lint-tools
echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"
- name: Run Go linters
run: make lint-ci
frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24"
- name: Install frontend dependencies
run: npm ci
working-directory: frontend
- name: Type-check (svelte-check)
run: npm run check
working-directory: frontend
- name: Design-system conformance (kit-ui-check)
# Full rule set over all of src; legitimate exceptions carry inline
# kit-ui-check-ignore markers with reasons (e.g. the app token
# definitions in app.css).
run: npm run check:kit-ui
working-directory: frontend
- name: Run frontend tests
run: npm test
working-directory: frontend
frontend-node-25:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "25"
- name: Install frontend dependencies
run: npm ci
working-directory: frontend
- name: Run frontend tests
run: npm test
working-directory: frontend
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
- name: Set up uv
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
- name: Install docs check tools
run: |
sudo apt-get update
sudo apt-get install -y ripgrep
- name: Run docs check
run: make docs-check
scripts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Run shell script tests
run: |
bash scripts/install_test.sh
bash scripts/retry_test.sh
bash scripts/check_desktop_release_health_test.sh
bash scripts/check_desktop_release_health_from_event_test.sh
bash desktop/scripts/test-repair-appimage-diricon.sh
test:
name: Go Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- name: Setup MinGW (Windows)
if: runner.os == 'Windows'
id: setup_mingw
continue-on-error: true
uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
with:
msystem: MINGW64
update: false
install: mingw-w64-x86_64-gcc
path-type: inherit
- name: Setup MinGW (Windows, retry on transient failure)
if: runner.os == 'Windows' && steps.setup_mingw.outcome == 'failure'
uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
with:
msystem: MINGW64
update: false
install: mingw-w64-x86_64-gcc
path-type: inherit
- name: Restore pricing snapshot
run: go run ./internal/pricing/cmd/litellm-snapshot -restore
- name: Run Go tests
run: go test -tags "fts5" ./... -v -count=1 -timeout=20m
env:
CGO_ENABLED: "1"
- name: Run eval-ingest build-tag tests
if: runner.os == 'Linux'
run: make test-evalingest
- name: Run Go tests (race detector)
if: runner.os == 'Linux'
run: |
go test -tags "fts5" ./internal/duckdb -count=1
go test -tags "fts5" -race $(go list ./... | grep -v '/internal/duckdb$') -count=1
env:
CGO_ENABLED: "1"
desktop-windows-unit:
name: Desktop Unit Tests (Windows)
runs-on: windows-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Prepare placeholder sidecar resource
shell: pwsh
run: |
$hostTriple = (rustc -vV | Select-String '^host: ').ToString() -replace '^host:\s+', ''
if (-not $hostTriple) {
throw "could not determine Rust host triple"
}
New-Item -ItemType Directory -Force desktop/src-tauri/binaries | Out-Null
New-Item -ItemType File -Force "desktop/src-tauri/binaries/agentsview-$hostTriple.exe" | Out-Null
- name: Fetch Windows desktop Rust dependencies
shell: pwsh
run: |
for ($attempt = 1; $attempt -le 3; $attempt++) {
cargo fetch --locked --manifest-path desktop/src-tauri/Cargo.toml
if ($LASTEXITCODE -eq 0) {
break
}
if ($attempt -eq 3) {
exit $LASTEXITCODE
}
Start-Sleep -Seconds (10 * $attempt)
}
- name: Run Windows desktop update tests
run: cargo test --locked --manifest-path desktop/src-tauri/Cargo.toml --lib install_downloaded_update
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- name: Restore pricing snapshot
run: go run ./internal/pricing/cmd/litellm-snapshot -restore
- name: Test with coverage
run: go test -tags "fts5" -coverprofile=coverage.out ./...
env:
CGO_ENABLED: "1"
- name: Upload coverage
id: codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
files: coverage.out
continue-on-error: true
- name: Warn on coverage upload failure
if: steps.codecov.outcome == 'failure'
run: echo "::warning::Codecov upload failed"
integration:
runs-on: ubuntu-latest
services:
postgres:
image: pgvector/pgvector:pg18
env:
POSTGRES_USER: agentsview_test
POSTGRES_PASSWORD: agentsview_test_password
POSTGRES_DB: agentsview_test
ports:
- 5433:5432
options: >-
--health-cmd "pg_isready -U agentsview_test -d agentsview_test"
--health-interval 2s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- name: Restore pricing snapshot
run: go run ./internal/pricing/cmd/litellm-snapshot -restore
- name: Run PostgreSQL integration tests
run: make test-postgres-ci
env:
CGO_ENABLED: "1"
TEST_PG_URL: postgres://agentsview_test:agentsview_test_password@localhost:5433/agentsview_test?sslmode=disable
- name: Build SSH test container
run: bash scripts/retry.sh 3 10 docker build -t agentsview-sshd -f testdata/ssh/Dockerfile .
- name: Start SSH test container
run: |
docker run -d --name sshd-test -p 2222:22 agentsview-sshd
for i in $(seq 1 10); do nc -z localhost 2222 && break || sleep 1; done
docker cp sshd-test:/tmp/test_ssh_key testdata/ssh/test_key
chmod 600 testdata/ssh/test_key
- name: Verify SSH connectivity
run: |
echo "=== Key file ==="
ls -la testdata/ssh/test_key
head -1 testdata/ssh/test_key
echo "=== Container sshd_config ==="
docker exec sshd-test cat /etc/ssh/sshd_config
echo "=== Container authorized_keys ==="
docker exec sshd-test cat /home/testuser/.ssh/authorized_keys
echo "=== Test SSH connection ==="
ssh -v -i testdata/ssh/test_key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 testuser@localhost echo "SSH works" 2>&1 || true
- name: Run SSH integration tests
run: make test-ssh-ci
env:
CGO_ENABLED: "1"
TEST_SSH_HOST: localhost
TEST_SSH_PORT: "2222"
TEST_SSH_USER: testuser
TEST_SSH_KEY: ${{ github.workspace }}/testdata/ssh/test_key
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24"
- name: Install frontend dependencies
run: npm ci
working-directory: frontend
- name: Build frontend
run: npm run build
working-directory: frontend
- name: Embed frontend in Go source tree
run: |
rm -rf internal/web/dist
cp -r frontend/dist internal/web/dist
- name: Restore pricing snapshot
run: go run ./internal/pricing/cmd/litellm-snapshot -restore
- name: Pre-build Go binaries
run: |
CGO_ENABLED=1 go build -tags "fts5,kit_posthog_disabled" \
-o /tmp/testfixture ./cmd/testfixture
CGO_ENABLED=1 go build -tags "fts5,kit_posthog_disabled" \
-o /tmp/agentsview ./cmd/agentsview
env:
CGO_ENABLED: "1"
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium webkit
working-directory: frontend
- name: Run E2E tests
run: npx playwright test --reporter=list
working-directory: frontend
env:
E2E_PREBUILT_FIXTURE: /tmp/testfixture
E2E_PREBUILT_SERVER: /tmp/agentsview
+68
View File
@@ -0,0 +1,68 @@
name: Desktop Artifacts
on:
# Keep this workflow GitHub-hosted so pull requests cannot select a
# persistent runner. macOS builds live in desktop-macos-main.yml.
push:
branches: [main]
paths:
- 'desktop/**'
- 'frontend/**'
- 'go.mod'
- 'go.sum'
- '.github/workflows/desktop-artifacts.yml'
- '.github/actions/build-desktop-artifact/**'
pull_request:
branches: [main]
paths:
- 'desktop/**'
- 'frontend/**'
- 'go.mod'
- 'go.sum'
- '.github/workflows/desktop-artifacts.yml'
- '.github/actions/build-desktop-artifact/**'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
build:
name: Desktop Build (${{ matrix.name }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: Windows
os: windows-latest
bundle: nsis
target_triple: ""
artifact_name: agentsview-desktop-windows
artifact_dir: desktop/src-tauri/target/release/bundle/nsis/
- name: Linux
os: ubuntu-22.04
bundle: appimage
target_triple: ""
artifact_name: agentsview-desktop-linux
artifact_dir: desktop/src-tauri/target/release/bundle/appimage/
- name: Linux (arm64)
os: ubuntu-22.04-arm
bundle: appimage
target_triple: aarch64-unknown-linux-gnu
artifact_name: agentsview-desktop-linux-arm64
artifact_dir: desktop/src-tauri/target/aarch64-unknown-linux-gnu/release/bundle/appimage/
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: ./.github/actions/build-desktop-artifact
with:
bundle: ${{ matrix.bundle }}
target_triple: ${{ matrix.target_triple }}
artifact_name: ${{ matrix.artifact_name }}
artifact_dir: ${{ matrix.artifact_dir }}
+55
View File
@@ -0,0 +1,55 @@
name: Desktop Artifacts (macOS)
on:
# This workflow is the only workflow allowed to use the ci-runners group.
# The organization runner-group policy must pin access to this path on main.
push:
branches: [main]
paths:
- 'desktop/**'
- 'frontend/**'
- 'go.mod'
- 'go.sum'
- '.github/workflows/desktop-macos-main.yml'
- '.github/actions/build-desktop-artifact/**'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: Desktop Build (${{ matrix.name }})
runs-on:
group: ci-runners
labels: [self-hosted, macOS, "${{ matrix.runner_arch }}"]
strategy:
fail-fast: false
matrix:
include:
- name: macOS (aarch64)
runner_arch: ARM64
bundle: app
target_triple: aarch64-apple-darwin
artifact_name: agentsview-desktop-macos-aarch64
artifact_dir: desktop/src-tauri/target/aarch64-apple-darwin/release/bundle/macos/
- name: macOS (x86_64)
runner_arch: X64
bundle: app
target_triple: x86_64-apple-darwin
artifact_name: agentsview-desktop-macos-x86_64
artifact_dir: desktop/src-tauri/target/x86_64-apple-darwin/release/bundle/macos/
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: ./.github/actions/build-desktop-artifact
with:
bundle: ${{ matrix.bundle }}
target_triple: ${{ matrix.target_triple }}
artifact_name: ${{ matrix.artifact_name }}
artifact_dir: ${{ matrix.artifact_dir }}
@@ -0,0 +1,33 @@
name: Desktop Release Health
on:
workflow_run:
workflows:
- Desktop Release
types:
- completed
workflow_dispatch:
inputs:
tag:
description: Release tag to check, for example v0.34.5
required: true
type: string
permissions:
contents: read
jobs:
check:
name: Check Desktop Updater State
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.workflow_run.event == 'push' &&
startsWith(github.event.workflow_run.head_branch, 'v'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Check desktop release health
run: bash scripts/check_desktop_release_health_from_event.sh
+475
View File
@@ -0,0 +1,475 @@
name: Desktop Release
on:
push:
tags:
- 'v*'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-macos:
name: Desktop Build (macOS ${{ matrix.arch }})
runs-on: macos-15
env:
AGENTSVIEW_TARGET_TRIPLE: ${{ matrix.target_triple }}
CARGO_BUILD_TARGET: ${{ matrix.target_triple }}
strategy:
fail-fast: false
matrix:
include:
- arch: aarch64
target_triple: aarch64-apple-darwin
- arch: x86_64
target_triple: x86_64-apple-darwin
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24"
- name: Install Rust target
run: rustup target add "$AGENTSVIEW_TARGET_TRIPLE"
- name: Install desktop dependencies
run: npm ci
working-directory: desktop
- name: Prepare sidecar
env:
AGENTSVIEW_VERSION: ${{ github.ref_name }}
run: |
export TAURI_ENV_TARGET_TRIPLE="$AGENTSVIEW_TARGET_TRIPLE"
npm run prepare-sidecar
working-directory: desktop
- name: Patch updater config for current repository
env:
AGENTSVIEW_UPDATER_PUBKEY: ${{ secrets.AGENTSVIEW_UPDATER_PUBKEY }}
run: |
sed -i.bak \
-e "s|wesm/agentsview|${GITHUB_REPOSITORY}|g" \
-e "s|NOT_SET|${AGENTSVIEW_UPDATER_PUBKEY}|g" \
desktop/src-tauri/tauri.conf.json
rm -f desktop/src-tauri/tauri.conf.json.bak
- name: Import signing certificate
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
run: |
KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain"
KEYCHAIN_PASS="$(openssl rand -base64 32)"
security create-keychain -p "$KEYCHAIN_PASS" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 3600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASS" "$KEYCHAIN_PATH"
CERT_PATH="$RUNNER_TEMP/certificate.p12"
echo "$APPLE_CERTIFICATE" | base64 -d > "$CERT_PATH"
security import "$CERT_PATH" \
-k "$KEYCHAIN_PATH" \
-P "$APPLE_CERTIFICATE_PASSWORD" \
-T /usr/bin/codesign \
-T /usr/bin/security
rm -f "$CERT_PATH"
security set-key-partition-list \
-S apple-tool:,apple: \
-k "$KEYCHAIN_PASS" "$KEYCHAIN_PATH"
security list-keychains -d user -s "$KEYCHAIN_PATH" login.keychain
- name: Write API key
env:
APPLE_API_KEY_CONTENT: ${{ secrets.APPLE_API_KEY_CONTENT }}
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
run: |
KEY_DIR="$RUNNER_TEMP/apple-keys"
mkdir -p "$KEY_DIR"
echo "$APPLE_API_KEY_CONTENT" | base64 -d \
> "$KEY_DIR/AuthKey_${APPLE_API_KEY}.p8"
echo "APPLE_API_KEY_PATH=$KEY_DIR/AuthKey_${APPLE_API_KEY}.p8" \
>> "$GITHUB_ENV"
- name: Build DMG and updater bundle
env:
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
AGENTSVIEW_UPDATER_PUBKEY: ${{ secrets.AGENTSVIEW_UPDATER_PUBKEY }}
run: npx tauri build --target "$AGENTSVIEW_TARGET_TRIPLE"
working-directory: desktop
- name: Collect build artifacts
run: |
bundle_dir="desktop/src-tauri/target/${AGENTSVIEW_TARGET_TRIPLE}/release/bundle"
mkdir -p staging
cp "$bundle_dir"/dmg/*.dmg staging/
app_bundle="$(find "$bundle_dir"/macos -maxdepth 1 -name '*.app.tar.gz' -print -quit)"
app_sig="$(find "$bundle_dir"/macos -maxdepth 1 -name '*.app.tar.gz.sig' -print -quit)"
app_name="$(basename "$app_bundle")"
app_sig_name="$(basename "$app_sig")"
cp "$app_bundle" "staging/${app_name%.app.tar.gz}_${{ matrix.arch }}.app.tar.gz"
cp "$app_sig" "staging/${app_sig_name%.app.tar.gz.sig}_${{ matrix.arch }}.app.tar.gz.sig"
ls -la staging/
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: agentsview-desktop-macos-${{ matrix.arch }}
path: staging/*
if-no-files-found: error
- name: Cleanup signing secrets
if: always()
run: |
KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain"
security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true
rm -rf "$RUNNER_TEMP/apple-keys" 2>/dev/null || true
build-windows:
name: Desktop Build (Windows)
runs-on: windows-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24"
- name: Setup MinGW
id: setup_mingw
continue-on-error: true
uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
with:
msystem: MINGW64
update: false
install: mingw-w64-x86_64-gcc
path-type: inherit
- name: Setup MinGW (retry on transient failure)
if: steps.setup_mingw.outcome == 'failure'
uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
with:
msystem: MINGW64
update: false
install: mingw-w64-x86_64-gcc
path-type: inherit
- name: Install desktop dependencies
run: npm ci
working-directory: desktop
- name: Prepare sidecar
shell: bash
env:
AGENTSVIEW_VERSION: ${{ github.ref_name }}
run: npm run prepare-sidecar
working-directory: desktop
- name: Patch updater config for current repository
shell: bash
env:
AGENTSVIEW_UPDATER_PUBKEY: ${{ secrets.AGENTSVIEW_UPDATER_PUBKEY }}
run: |
sed -i.bak \
-e "s|wesm/agentsview|${GITHUB_REPOSITORY}|g" \
-e "s|NOT_SET|${AGENTSVIEW_UPDATER_PUBKEY}|g" \
desktop/src-tauri/tauri.conf.json
rm -f desktop/src-tauri/tauri.conf.json.bak
- name: Build NSIS installer and updater bundle
shell: bash
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
AGENTSVIEW_UPDATER_PUBKEY: ${{ secrets.AGENTSVIEW_UPDATER_PUBKEY }}
run: npx tauri build --bundles nsis
working-directory: desktop
- name: Collect build artifacts
shell: bash
run: |
mkdir -p staging
cp desktop/src-tauri/target/release/bundle/nsis/*.exe staging/
cp desktop/src-tauri/target/release/bundle/nsis/*.nsis.zip staging/
cp desktop/src-tauri/target/release/bundle/nsis/*.nsis.zip.sig staging/
ls -la staging/
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: agentsview-desktop-windows
path: staging/*
if-no-files-found: error
build-linux:
name: Desktop Build (Linux ${{ matrix.arch }})
runs-on: ${{ matrix.os }}
env:
AGENTSVIEW_TARGET_TRIPLE: ${{ matrix.target_triple }}
strategy:
fail-fast: false
matrix:
include:
- arch: x86_64
os: ubuntu-22.04
target_triple: ""
artifact_name: agentsview-desktop-linux
artifact_dir: desktop/src-tauri/target/release/bundle/appimage/
create_updater_artifacts: "true"
- arch: arm64
os: ubuntu-22.04-arm
target_triple: aarch64-unknown-linux-gnu
artifact_name: agentsview-desktop-linux-arm64
artifact_dir: desktop/src-tauri/target/aarch64-unknown-linux-gnu/release/bundle/appimage/
create_updater_artifacts: "false"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24"
- name: Install Rust target
if: env.AGENTSVIEW_TARGET_TRIPLE != ''
run: rustup target add "$AGENTSVIEW_TARGET_TRIPLE"
- name: Install Linux system dependencies
run: |
sudo apt-get update -q
sudo apt-get install -y \
libwebkit2gtk-4.1-dev libgtk-3-dev \
libappindicator3-dev librsvg2-dev \
patchelf squashfs-tools xdg-utils
- name: Install desktop dependencies
run: npm ci
working-directory: desktop
- name: Prepare sidecar
env:
AGENTSVIEW_VERSION: ${{ github.ref_name }}
run: |
export TAURI_ENV_TARGET_TRIPLE="$AGENTSVIEW_TARGET_TRIPLE"
npm run prepare-sidecar
working-directory: desktop
- name: Patch updater config for current repository
env:
AGENTSVIEW_UPDATER_PUBKEY: ${{ secrets.AGENTSVIEW_UPDATER_PUBKEY }}
run: |
sed -i.bak \
-e "s|wesm/agentsview|${GITHUB_REPOSITORY}|g" \
-e "s|NOT_SET|${AGENTSVIEW_UPDATER_PUBKEY}|g" \
desktop/src-tauri/tauri.conf.json
rm -f desktop/src-tauri/tauri.conf.json.bak
- name: Build AppImage and updater bundle
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
AGENTSVIEW_UPDATER_PUBKEY: ${{ secrets.AGENTSVIEW_UPDATER_PUBKEY }}
run: |
build_cmd=(npx tauri build --bundles appimage)
if [ -n "$AGENTSVIEW_TARGET_TRIPLE" ]; then
build_cmd+=(--target "$AGENTSVIEW_TARGET_TRIPLE")
fi
if [ "${{ matrix.create_updater_artifacts }}" = "false" ]; then
build_cmd+=(--config '{"bundle":{"createUpdaterArtifacts":false}}')
fi
"${build_cmd[@]}"
bash scripts/repair-appimage-diricon.sh \
"../${{ matrix.artifact_dir }}"/*.AppImage
working-directory: desktop
- name: Collect build artifacts
run: |
mkdir -p staging
cp "${{ matrix.artifact_dir }}"/*.AppImage staging/
if [ "${{ matrix.create_updater_artifacts }}" = "true" ]; then
cp "${{ matrix.artifact_dir }}"/*.AppImage.tar.gz staging/
cp "${{ matrix.artifact_dir }}"/*.AppImage.tar.gz.sig staging/
fi
ls -la staging/
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.artifact_name }}
path: staging/*
if-no-files-found: error
release:
name: Upload Desktop Installers
needs: [build-macos, build-windows, build-linux]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: artifacts
pattern: agentsview-desktop-*
merge-multiple: true
- name: Generate checksums
run: |
cd artifacts
sha256sum *.dmg *.exe *.AppImage *.tar.gz *.nsis.zip > SHA256SUMS-desktop 2>/dev/null || true
cat SHA256SUMS-desktop
- name: Generate updater manifest
run: |
set -euo pipefail
VERSION="${GITHUB_REF_NAME#v}"
DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
TAG="updater"
MACOS_AARCH64_SIG=""
MACOS_AARCH64_URL=""
MACOS_X86_64_SIG=""
MACOS_X86_64_URL=""
WINDOWS_SIG=""
WINDOWS_URL=""
LINUX_SIG=""
LINUX_URL=""
for f in artifacts/*_aarch64.app.tar.gz.sig; do
if [ -f "$f" ]; then
MACOS_AARCH64_SIG="$(cat "$f")"
MACOS_AARCH64_TARBALL="$(basename "${f%.sig}")"
MACOS_AARCH64_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/${MACOS_AARCH64_TARBALL}"
fi
done
for f in artifacts/*_x86_64.app.tar.gz.sig; do
if [ -f "$f" ]; then
MACOS_X86_64_SIG="$(cat "$f")"
MACOS_X86_64_TARBALL="$(basename "${f%.sig}")"
MACOS_X86_64_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/${MACOS_X86_64_TARBALL}"
fi
done
for f in artifacts/*.nsis.zip.sig; do
if [ -f "$f" ]; then
WINDOWS_SIG="$(cat "$f")"
NSIS_ZIP="$(basename "${f%.sig}")"
WINDOWS_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/${NSIS_ZIP}"
fi
done
for f in artifacts/*.AppImage.tar.gz.sig; do
if [ -f "$f" ]; then
LINUX_SIG="$(cat "$f")"
LINUX_TARBALL="$(basename "${f%.sig}")"
LINUX_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/${LINUX_TARBALL}"
fi
done
if [ -z "$MACOS_AARCH64_SIG" ] || [ -z "$MACOS_AARCH64_URL" ]; then
echo "error: missing macOS aarch64 updater signature or URL" >&2
exit 1
fi
if [ -z "$MACOS_X86_64_SIG" ] || [ -z "$MACOS_X86_64_URL" ]; then
echo "error: missing macOS x86_64 updater signature or URL" >&2
exit 1
fi
if [ -z "$WINDOWS_SIG" ] || [ -z "$WINDOWS_URL" ]; then
echo "error: missing Windows updater signature or URL" >&2
exit 1
fi
if [ -z "$LINUX_SIG" ] || [ -z "$LINUX_URL" ]; then
echo "error: missing Linux updater signature or URL" >&2
exit 1
fi
cat > artifacts/latest.json << MANIFEST
{
"version": "${VERSION}",
"pub_date": "${DATE}",
"platforms": {
"darwin-aarch64": {
"url": "${MACOS_AARCH64_URL}",
"signature": "${MACOS_AARCH64_SIG}"
},
"darwin-x86_64": {
"url": "${MACOS_X86_64_URL}",
"signature": "${MACOS_X86_64_SIG}"
},
"windows-x86_64": {
"url": "${WINDOWS_URL}",
"signature": "${WINDOWS_SIG}"
},
"linux-x86_64": {
"url": "${LINUX_URL}",
"signature": "${LINUX_SIG}"
}
}
}
MANIFEST
echo "Generated latest.json:"
cat artifacts/latest.json
- name: Upload installers to versioned release
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
with:
files: |
artifacts/*.dmg
artifacts/*.exe
artifacts/*.AppImage
artifacts/SHA256SUMS-desktop
- name: Upload updater artifacts
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
# Create or update the permanent 'updater' release
if ! gh release view updater --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
gh release create updater \
--repo "$GITHUB_REPOSITORY" \
--title "Auto-Updater Artifacts" \
--notes "Internal release used by the desktop auto-updater. Do not delete." \
--prerelease
fi
# Overwrite existing assets
gh release upload updater \
--repo "$GITHUB_REPOSITORY" \
--clobber \
artifacts/*.app.tar.gz \
artifacts/*.app.tar.gz.sig \
artifacts/*.nsis.zip \
artifacts/*.nsis.zip.sig \
artifacts/*.AppImage.tar.gz \
artifacts/*.AppImage.tar.gz.sig \
artifacts/latest.json
+83
View File
@@ -0,0 +1,83 @@
name: Docker
on:
push:
branches: [main]
tags:
- 'v*'
workflow_dispatch:
permissions:
contents: read
packages: write
env:
REGISTRY: ghcr.io
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- name: Restore pricing snapshot
run: go run ./internal/pricing/cmd/litellm-snapshot -restore
- name: Compute image build metadata
id: vars
shell: bash
run: |
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
VERSION="${GITHUB_REF#refs/tags/}"
else
VERSION="dev"
fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "commit=${GITHUB_SHA::8}" >> "$GITHUB_OUTPUT"
echo "build_date=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> "$GITHUB_OUTPUT"
echo "image=${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT"
- uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
- uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
id: meta
with:
images: ${{ env.REGISTRY }}/${{ steps.vars.outputs.image }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=stable,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=semver,pattern={{version}}
labels: |
org.opencontainers.image.title=agentsview
org.opencontainers.image.description=Local web viewer for AI agent sessions
- name: Build and push Docker image
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VERSION=${{ steps.vars.outputs.version }}
COMMIT=${{ steps.vars.outputs.commit }}
BUILD_DATE=${{ steps.vars.outputs.build_date }}
cache-from: type=gha
cache-to: type=gha,mode=max
+61
View File
@@ -0,0 +1,61 @@
name: Fuzz
# Long-running fuzz exploration of the Antigravity wire-walk
# (GitHub #648). Every CI run already executes the committed seed
# corpus via plain `go test`; this workflow spends real fuzz time
# searching for new invariant violations on a schedule. A found
# failure is written to testdata/fuzz/ by the fuzz engine and
# uploaded as an artifact so it can be committed as a regression
# case.
on:
schedule:
- cron: "17 5 * * 1" # weekly, Monday 05:17 UTC
workflow_dispatch:
inputs:
fuzztime:
description: "Fuzz time per target (Go duration)"
required: false
default: "10m"
jobs:
fuzz:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- FuzzAgProtoParse
- FuzzAgProtoLooksLikePrefix
- FuzzDecodeAntigravityStep
- FuzzExtractModelName
- FuzzExtractTokenUsage
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
# The dispatch input goes through an env var, never directly
# into the run script, so it cannot inject shell commands.
- name: Fuzz ${{ matrix.target }}
run: >
go test -tags "fts5"
-fuzz "^${TARGET}$"
-fuzztime "$FUZZTIME"
./internal/parser/
env:
CGO_ENABLED: "1"
TARGET: ${{ matrix.target }}
FUZZTIME: ${{ github.event.inputs.fuzztime || '10m' }}
- name: Upload failing inputs
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fuzz-failures-${{ matrix.target }}
path: internal/parser/testdata/fuzz/
if-no-files-found: ignore
+45
View File
@@ -0,0 +1,45 @@
name: MSYS2 Update Check
# Periodically run Windows CI with MSYS2 updates enabled to catch
# toolchain drift, security fixes, and package metadata changes.
# If this workflow fails, update the pinned SHA and packages in ci.yml.
on:
schedule:
- cron: "0 9 * * 1" # Every Monday at 09:00 UTC
workflow_dispatch:
jobs:
windows-update-check:
runs-on: windows-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- name: Restore pricing snapshot
run: go run ./internal/pricing/cmd/litellm-snapshot -restore
- name: Setup MinGW (with updates)
uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
with:
msystem: MINGW64
update: true
install: mingw-w64-x86_64-gcc
path-type: inherit
- name: Stub frontend embed dir
shell: pwsh
run: |
New-Item -ItemType Directory -Force internal/web/dist | Out-Null
Set-Content -Path internal/web/dist/stub.html -Value ok
- name: Run Go tests
run: go test -tags "fts5" ./... -v -count=1
env:
CGO_ENABLED: "1"
+344
View File
@@ -0,0 +1,344 @@
name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: read
jobs:
build-linux:
strategy:
fail-fast: false
matrix:
include:
- goarch: amd64
runner: ubuntu-latest
container: quay.io/pypa/manylinux_2_28_x86_64@sha256:853663dc8253b62be437bb52a5caecffd020792af4442f55d927d22e0ea795ae
- goarch: arm64
runner: ubuntu-24.04-arm
container: quay.io/pypa/manylinux_2_28_aarch64@sha256:ca1f9d96910e129d38f999644a1f211a6cdb4147da9f19157a49d72c5092453a
runs-on: ${{ matrix.runner }}
container: ${{ matrix.container }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false
- name: Trust git checkout
shell: bash
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git status --short >/dev/null
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24"
- name: Build frontend
run: npm ci && npm run build
working-directory: frontend
- name: Embed frontend
shell: bash
run: |
rm -rf internal/web/dist
cp -r frontend/dist internal/web/dist
- name: Restore pricing snapshot
run: go run ./internal/pricing/cmd/litellm-snapshot -restore
- name: Build
shell: bash
env:
GOOS: linux
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: "1"
run: |
VERSION=${GITHUB_REF#refs/tags/v}
COMMIT=${GITHUB_SHA::8}
BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# sqlite-vec's cgo bindings #include "sqlite3.h". The manylinux
# image has no SQLite headers, and AlmaLinux 8's sqlite-devel
# (3.26) is old enough that sqlite-vec would silently compile out
# its vtab_in support. Use the header of the exact amalgamation
# bundled and statically linked by mattn/go-sqlite3.
# "-O2 -g" restates Go's built-in default, which setting
# CGO_CFLAGS would otherwise replace, leaving the SQLite
# amalgamation unoptimized (2-3x slower queries).
go mod download github.com/mattn/go-sqlite3
mkdir -p .sqlite-include
cp "$(go list -m -f '{{.Dir}}' github.com/mattn/go-sqlite3)/sqlite3-binding.h" .sqlite-include/sqlite3.h
export CGO_CFLAGS="-O2 -g -I${PWD}/.sqlite-include"
mkdir -p dist
LDFLAGS="-s -w -X main.version=v${VERSION} -X main.commit=${COMMIT} -X main.buildDate=${BUILD_DATE}"
go build -tags fts5 -buildvcs=false -ldflags="$LDFLAGS" -trimpath \
-o dist/agentsview ./cmd/agentsview
# Smoke test (native builds — no cross-compilation)
./dist/agentsview --version
# Verify glibc compatibility
MAX_GLIBC="GLIBC_2.28"
HIGHEST=$(objdump -T dist/agentsview | grep -oP 'GLIBC_\d+\.\d+' | sort -t. -k1,1n -k2,2n | tail -1)
echo "Highest glibc symbol: $HIGHEST (max allowed: $MAX_GLIBC)"
if [ "$(printf '%s\n%s' "$MAX_GLIBC" "$HIGHEST" | sort -t. -k1,1n -k2,2n | tail -1)" != "$MAX_GLIBC" ]; then
echo "ERROR: Binary requires $HIGHEST but wheel claims $MAX_GLIBC"
exit 1
fi
cd dist
ARCHIVE="agentsview_${VERSION}_linux_${{ matrix.goarch }}.tar.gz"
tar czf "$ARCHIVE" agentsview
rm agentsview
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: agentsview-linux-${{ matrix.goarch }}
path: dist/*.tar.gz
build:
strategy:
fail-fast: false
matrix:
include:
- os: macos-15
goos: darwin
goarch: amd64
- os: macos-15
goos: darwin
goarch: arm64
- os: windows-latest
goos: windows
goarch: amd64
- os: windows-11-arm
goos: windows
goarch: arm64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24"
- name: Build frontend
run: npm ci && npm run build
working-directory: frontend
- name: Embed frontend
shell: bash
run: |
rm -rf internal/web/dist
cp -r frontend/dist internal/web/dist
- name: Restore pricing snapshot
run: go run ./internal/pricing/cmd/litellm-snapshot -restore
- name: Setup MinGW (Windows amd64)
if: matrix.goos == 'windows' && matrix.goarch == 'amd64'
uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
with:
msystem: MINGW64
update: false
install: mingw-w64-x86_64-gcc
path-type: inherit
- name: Setup llvm-mingw (Windows arm64)
if: matrix.goos == 'windows' && matrix.goarch == 'arm64'
shell: pwsh
env:
# Self-contained aarch64 mingw clang toolchain (clang + runtime +
# lld). cgo (mattn/go-sqlite3) needs a C compiler; no Visual
# Studio / Windows SDK required. Pinned to a version + SHA256 for
# reproducibility and supply-chain integrity.
LLVM_MINGW_VERSION: "20260602"
LLVM_MINGW_NAME: llvm-mingw-20260602-ucrt-aarch64
LLVM_MINGW_SHA256: cb5c20fbe1808e31ada5cbe4efd9daa2fee19c91dac6ec5ca1ac46a9c7247e37
run: |
$ErrorActionPreference = 'Stop'
$zip = Join-Path $env:RUNNER_TEMP 'llvm-mingw.zip'
$url = "https://github.com/mstorsjo/llvm-mingw/releases/download/$env:LLVM_MINGW_VERSION/$env:LLVM_MINGW_NAME.zip"
Write-Host "Downloading $url"
Invoke-WebRequest -Uri $url -OutFile $zip
# Verify the archive against the pinned SHA256 before extracting or
# executing any of it, so a swapped or compromised upstream asset
# fails the build instead of producing a trojaned binary.
$actual = (Get-FileHash -Path $zip -Algorithm SHA256).Hash
if ($actual -ne $env:LLVM_MINGW_SHA256) {
throw "Checksum mismatch for $url`n expected $env:LLVM_MINGW_SHA256`n actual $actual"
}
# 7-Zip is preinstalled on the runner image and extracts faster
# than Expand-Archive for this many files.
7z x $zip -o"$env:RUNNER_TEMP" | Out-Null
$bin = Join-Path $env:RUNNER_TEMP "$env:LLVM_MINGW_NAME\bin"
$cc = Join-Path $bin 'aarch64-w64-mingw32-clang.exe'
if (-not (Test-Path $cc)) { throw "CC not found at $cc" }
Add-Content -Path $env:GITHUB_PATH -Value $bin
Add-Content -Path $env:GITHUB_ENV -Value "CC=$cc"
- name: Build
shell: bash
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: "1"
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.goos == 'darwin' && '11.0' || '' }}
run: |
VERSION=${GITHUB_REF#refs/tags/v}
COMMIT=${GITHUB_SHA::8}
BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
EXT=""
if [ "$GOOS" = "windows" ]; then EXT=".exe"; fi
mkdir -p dist
LDFLAGS="-s -w -X main.version=v${VERSION} -X main.commit=${COMMIT} -X main.buildDate=${BUILD_DATE}"
go build -tags fts5 -ldflags="$LDFLAGS" -trimpath \
-o dist/agentsview${EXT} ./cmd/agentsview
# Smoke test (skip cross-compiled darwin/amd64 on ARM runner)
if [ "$GOARCH" = "$(go env GOHOSTARCH)" ]; then
./dist/agentsview${EXT} --version
fi
# Verify macOS deployment target
if [ "$GOOS" = "darwin" ]; then
MINOS=$(otool -l dist/agentsview | grep -A3 LC_BUILD_VERSION | grep minos | awk '{print $2}')
echo "Minimum macOS version: $MINOS"
if [ "$MINOS" != "11.0" ]; then
echo "ERROR: Expected minos 11.0, got $MINOS"
exit 1
fi
fi
cd dist
if [ "$GOOS" = "windows" ]; then
ARCHIVE="agentsview_${VERSION}_${{ matrix.goos }}_${{ matrix.goarch }}.zip"
7z a "$ARCHIVE" agentsview${EXT}
else
ARCHIVE="agentsview_${VERSION}_${{ matrix.goos }}_${{ matrix.goarch }}.tar.gz"
tar czf "$ARCHIVE" agentsview${EXT}
fi
rm agentsview${EXT}
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: agentsview-${{ matrix.goos }}-${{ matrix.goarch }}
path: |
dist/*.tar.gz
dist/*.zip
release:
needs: [build-linux, build]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: artifacts
merge-multiple: true
- name: Generate checksums
run: |
cd artifacts
sha256sum *.tar.gz *.zip > SHA256SUMS
cat SHA256SUMS
- name: Get tag message
id: tag_message
run: |
TAG_NAME="${GITHUB_REF#refs/tags/}"
TAG_TYPE=$(git cat-file -t "$TAG_NAME")
if [ "$TAG_TYPE" != "tag" ]; then
echo "Warning: $TAG_NAME is a lightweight tag, using auto-generated notes"
echo "has_body=false" >> $GITHUB_OUTPUT
exit 0
fi
TAG_MSG=$(git tag -l --format='%(contents:body)' "$TAG_NAME")
if [ -n "$TAG_MSG" ]; then
DELIM="TAGMSG_$(date +%s%N)"
echo "body<<$DELIM" >> $GITHUB_OUTPUT
echo "$TAG_MSG" >> $GITHUB_OUTPUT
echo "$DELIM" >> $GITHUB_OUTPUT
echo "has_body=true" >> $GITHUB_OUTPUT
else
echo "has_body=false" >> $GITHUB_OUTPUT
fi
- name: Create Release
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
with:
files: |
artifacts/*.tar.gz
artifacts/*.zip
artifacts/SHA256SUMS
body: ${{ steps.tag_message.outputs.has_body == 'true' && steps.tag_message.outputs.body || '' }}
generate_release_notes: ${{ steps.tag_message.outputs.has_body != 'true' }}
pypi:
needs: [build-linux, build, release]
runs-on: ubuntu-latest
environment: pypi
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: artifacts
merge-multiple: true
- name: Build wheels
run: |
VERSION=${GITHUB_REF#refs/tags/v}
python scripts/build_wheels.py \
--version "$VERSION" \
--input-dir artifacts \
--output-dir wheels \
--readme README.md \
--require-all
- name: Smoke test wheel
run: |
VERSION=${GITHUB_REF#refs/tags/v}
pip install wheels/agentsview-${VERSION}-py3-none-manylinux_2_28_x86_64.whl
agentsview --version
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
with:
packages-dir: wheels/