Skip to content

build(deps): bump anthropics/claude-code-action from 1.0.178 to 1.0.183 #6222

build(deps): bump anthropics/claude-code-action from 1.0.178 to 1.0.183

build(deps): bump anthropics/claude-code-action from 1.0.178 to 1.0.183 #6222

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
runs-on: ubuntu-latest
name: Lint
steps:
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version: 22
# Runs before `npm install` because npm 11 silently strips the `libc`
# field from optional-dependency lockfile entries (see #1160). If the
# check ran post-install we'd flag every CI run instead of the PRs that
# actually introduce the regression.
- name: Verify lockfile libc discriminators
run: node scripts/verify-lockfile-libc.mjs
- name: Install dependencies
timeout-minutes: 20
shell: bash
run: |
git config --global url."https://github.com/".insteadOf "ssh://git@github.com/"
git config --global --add url."https://github.com/".insteadOf "git@github.com:"
for attempt in 1 2 3; do
npm install && break
if [ "$attempt" -lt 3 ]; then
echo "::warning::npm install attempt $attempt failed, retrying in 15s..."
sleep 15
else
echo "::error::npm install failed after 3 attempts"
exit 1
fi
done
- name: Run Biome
run: npx @biomejs/biome check src/ tests/
detect-changes:
name: Detect native-relevant changes
runs-on: ubuntu-latest
outputs:
native_changed: ${{ steps.check.outputs.native_changed }}
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Check for native-relevant changes since the last published release
id: check
run: |
# When this job says "unchanged", test/parity/pre-publish-benchmark
# fall back to the published npm platform packages (pinned exactly
# to package.json's version). Those packages only get rebuilt by an
# on-demand release (workflow_dispatch) — native-relevant commits
# routinely land on main between releases without republishing (this
# repo has shipped 60+ crates/ fixes since the last tag at the time
# of writing). Diffing against the PR base or the previous push SHA
# only answers "did *this* change touch native code" — it says
# nothing about whether the published binary this job's skip relies
# on has already drifted from HEAD. The only baseline that actually
# answers "is the published fallback binary still trustworthy" is
# the tag for the version package.json currently declares.
#
# This deliberately does NOT use "the most recent vX.Y.Z tag" —
# a release tag is created by the GitHub Release that kicks off
# publish.yml, but publish itself (and the package.json version
# bump that comes with it) can still fail afterwards, e.g. the
# pre-publish benchmark gate. That leaves a tag on origin with no
# matching publish, which made this job wrongly report "unchanged"
# against a fallback binary that was actually several releases
# stale (#2127).
CURRENT_VERSION=$(node -p "require('./package.json').version")
LAST_TAG="v$CURRENT_VERSION"
if [ -z "$CURRENT_VERSION" ] || ! git cat-file -e "$LAST_TAG" 2>/dev/null; then
echo "No usable release tag ($LAST_TAG) to diff against — assuming native changed"
echo "native_changed=true" >> "$GITHUB_OUTPUT"
exit 0
fi
if git diff --name-only "$LAST_TAG" HEAD | grep -qE '^(crates/|Cargo\.toml$|Cargo\.lock$|src/infrastructure/native\.ts$)'; then
echo "Native-relevant paths changed since $LAST_TAG (last published release)"
echo "native_changed=true" >> "$GITHUB_OUTPUT"
else
echo "No native-relevant paths changed since $LAST_TAG (last published release)"
echo "native_changed=false" >> "$GITHUB_OUTPUT"
fi
native-host-build:
needs: detect-changes
# Fail open: only skip when detect-changes positively confirmed nothing
# native-relevant changed. Any other outcome (failure, skip) still builds,
# so a broken change-detector can't silently hide a real Rust regression.
if: needs.detect-changes.result != 'success' || needs.detect-changes.outputs.native_changed == 'true'
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-2022] # pinned: node-gyp cannot detect VS2026 on windows-latest; revert once node-gyp supports VS ≥ 18
runs-on: ${{ matrix.os }}
name: Native host build (${{ matrix.os }})
steps:
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version: 22
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: crates/codegraph-core
- name: Install napi-rs CLI
timeout-minutes: 5
run: npm install -g @napi-rs/cli@3
- name: Build native addon
working-directory: crates/codegraph-core
run: napi build --release
# Runs `cargo test`, which exercises the grammar-ABI regression test
# added in #1054. Without this step a future tree-sitter / grammar
# version drift would only surface as a runtime "files dropped"
# warning during benchmarks, not as a test failure on the PR.
- name: Run Rust tests
working-directory: crates/codegraph-core
run: cargo test --release
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: native-host-${{ matrix.os }}
path: crates/codegraph-core/*.node
if-no-files-found: error
test:
needs: native-host-build
# native-host-build may have been legitimately skipped (no native-relevant
# changes) — that's not a failure, so keep running against the published
# binary rather than cascading a skip.
if: |
always() &&
needs.native-host-build.result != 'failure' &&
needs.native-host-build.result != 'cancelled'
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-2022] # pinned: node-gyp cannot detect VS2026 on windows-latest; revert once node-gyp supports VS ≥ 18
node-version: [22]
runs-on: ${{ matrix.os }}
name: Test Node ${{ matrix.node-version }} (${{ matrix.os }})
steps:
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
timeout-minutes: 20
shell: bash
run: |
git config --global url."https://github.com/".insteadOf "ssh://git@github.com/"
git config --global --add url."https://github.com/".insteadOf "git@github.com:"
for attempt in 1 2 3; do
npm install && break
if [ "$attempt" -lt 3 ]; then
echo "::warning::npm install attempt $attempt failed, retrying in 15s..."
sleep 15
else
echo "::error::npm install failed after 3 attempts"
exit 1
fi
done
- name: Download PR-built native addon
if: needs.native-host-build.result == 'success'
uses: actions/download-artifact@v8
with:
name: native-host-${{ matrix.os }}
path: crates/codegraph-core
- name: Install native addon over published binary
if: needs.native-host-build.result == 'success'
shell: bash
run: node scripts/ci-install-native.mjs
- name: Run tests
run: npm test
typecheck:
runs-on: ubuntu-latest
name: TypeScript type check
steps:
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version: 22
- name: Install dependencies
timeout-minutes: 20
shell: bash
run: |
git config --global url."https://github.com/".insteadOf "ssh://git@github.com/"
git config --global --add url."https://github.com/".insteadOf "git@github.com:"
for attempt in 1 2 3; do
npm install && break
if [ "$attempt" -lt 3 ]; then
echo "::warning::npm install attempt $attempt failed, retrying in 15s..."
sleep 15
else
echo "::error::npm install failed after 3 attempts"
exit 1
fi
done
- name: Type check
run: npm run typecheck
audit:
runs-on: ubuntu-latest
name: Security audit
steps:
- uses: actions/checkout@v7
- name: Audit production dependencies
# --package-lock-only reads the lock file directly — no npm install needed.
# This avoids flaky binary downloads (e.g. onnxruntime-node) that would
# abort the audit before it can report real vulnerabilities.
run: npm audit --omit=dev --audit-level=high --package-lock-only
- name: Audit dev dependencies (critical only)
# Catches malware/critical advisories in devDependencies (e.g. GHSA-rphw-c8qj-jv84).
# Scoped to critical only — high/moderate in devDeps are acceptable noise since
# they never reach production. --package-lock-only avoids installing packages.
run: npm audit --audit-level=critical --package-lock-only
verify-imports:
runs-on: ubuntu-latest
name: Verify dynamic imports
steps:
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version: 22
- name: Verify all dynamic imports resolve
run: |
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
node $STRIP_FLAG scripts/verify-imports.ts
grammar-version-parity:
runs-on: ubuntu-latest
name: Grammar version parity
steps:
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version: 22
- name: Check grammar major-version parity (npm vs Cargo)
run: node scripts/check-grammar-versions.mjs
parity:
needs: native-host-build
if: |
always() &&
needs.native-host-build.result != 'failure' &&
needs.native-host-build.result != 'cancelled'
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-2022] # pinned: node-gyp cannot detect VS2026 on windows-latest; revert once node-gyp supports VS ≥ 18
runs-on: ${{ matrix.os }}
name: Engine parity (${{ matrix.os }})
steps:
- uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version: 22
- name: Install dependencies
timeout-minutes: 20
shell: bash
run: |
git config --global url."https://github.com/".insteadOf "ssh://git@github.com/"
git config --global --add url."https://github.com/".insteadOf "git@github.com:"
for attempt in 1 2 3; do
npm install && break
if [ "$attempt" -lt 3 ]; then
echo "::warning::npm install attempt $attempt failed, retrying in 15s..."
sleep 15
else
echo "::error::npm install failed after 3 attempts"
exit 1
fi
done
- name: Download PR-built native addon
if: needs.native-host-build.result == 'success'
uses: actions/download-artifact@v8
with:
name: native-host-${{ matrix.os }}
path: crates/codegraph-core
- name: Install native addon over published binary
if: needs.native-host-build.result == 'success'
shell: bash
run: node scripts/ci-install-native.mjs
- name: Verify native addon is available
shell: bash
run: |
node -e "
const { createRequire } = require('node:module');
const r = createRequire(require.resolve('./package.json'));
const os = require('os');
const fs = require('fs');
const plat = os.platform();
const arch = os.arch();
let libc = '';
if (plat === 'linux') {
try {
const files = fs.readdirSync('/lib');
libc = files.some(f => f.startsWith('ld-musl-') && f.endsWith('.so.1')) ? 'musl' : 'gnu';
} catch { libc = 'gnu'; }
}
const pkgs = {
'linux-x64-gnu': '@optave/codegraph-linux-x64-gnu',
'linux-x64-musl': '@optave/codegraph-linux-x64-musl',
'linux-arm64-gnu': '@optave/codegraph-linux-arm64-gnu',
'linux-arm64-musl': '@optave/codegraph-linux-arm64-musl',
'darwin-arm64': '@optave/codegraph-darwin-arm64',
'darwin-x64': '@optave/codegraph-darwin-x64',
'win32-x64': '@optave/codegraph-win32-x64-msvc',
};
const key = libc ? plat + '-' + arch + '-' + libc : plat + '-' + arch;
const pkg = pkgs[key];
if (!pkg) { console.error('No native package for ' + key); process.exit(1); }
try { r(pkg); console.log('Native addon loaded: ' + pkg); }
catch (e) { console.error('Failed to load ' + pkg + ': ' + e.message); process.exit(1); }
"
- name: Run parity tests
shell: bash
env:
CODEGRAPH_PARITY: '1'
run: npx vitest run tests/engines/ tests/integration/build-parity.test.ts --reporter=verbose
# Isolated regression canary for #1147 — runs only the dropped-language-gap
# suite so a failure surfaces under a clear step name and can't be masked
# by pollution from neighbouring tests in the larger `test` job. The gap
# repair path (#1083) is load-bearing for engine parity but easy to break
# silently — the bug shape is "node row never re-inserted", which only
# this test exercises directly.
- name: Dropped-language gap regression guard (#1147)
shell: bash
env:
CODEGRAPH_PARITY: '1'
run: npx vitest run tests/integration/dropped-language-gap.test.ts --reporter=verbose
rust-check:
runs-on: ubuntu-latest
name: Rust compile check
steps:
- uses: actions/checkout@v7
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: crates/codegraph-core
- name: Check compilation
run: cargo check --workspace
# ── Pre-publish benchmark gate ──
#
# Mirrors the gate in publish.yml so every PR catches regressions before
# merge instead of at release time. Measures the PR-built native artifact
# against the local source as version "dev", appends to the benchmark
# history files (in-job only — never committed from CI), and runs the
# regression guard against the most recent release baseline.
#
# Long-running but parallel with the rest of CI, so it does not extend
# the critical path for fast-failing checks (lint/typecheck/test).
pre-publish-benchmark:
name: Pre-publish benchmark gate
# Only run on PRs — push-to-main re-runs the same benchmarks the merged
# PR already gated on, doubling CI minutes per landed change with no new
# signal. Mirrors the `if: github.event_name != 'push'` skip in
# publish.yml's equivalent gate. Also tolerates native-host-build being
# legitimately skipped (no native-relevant changes) — benchmarks still
# need to run against the published binary since most regressions are
# TS-side, not Rust-side.
if: |
always() &&
github.event_name == 'pull_request' &&
needs.native-host-build.result != 'failure' &&
needs.native-host-build.result != 'cancelled'
needs: native-host-build
runs-on: ubuntu-latest
env:
# Surface why detectNoChanges returns false on each fast-skip pre-flight
# so we can pinpoint the cause of the ~2s incremental-rebuild regression
# observed in CI but not locally (#1066). Remove once root cause is fixed.
CODEGRAPH_FAST_SKIP_DIAG: "1"
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-node@v7
with:
node-version: "22"
cache: "npm"
- name: Setup Python (for resolution benchmark + tracer validation)
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Setup Go (for resolution benchmark + tracer validation)
uses: actions/setup-go@v7
with:
go-version: "stable"
cache: false
- name: Download PR-built native addon
if: needs.native-host-build.result == 'success'
uses: actions/download-artifact@v8
with:
name: native-host-ubuntu-latest
path: crates/codegraph-core/
- name: Install dependencies
timeout-minutes: 20
shell: bash
run: |
git config --global url."https://github.com/".insteadOf "ssh://git@github.com/"
git config --global --add url."https://github.com/".insteadOf "git@github.com:"
for attempt in 1 2 3; do
npm install && break
if [ "$attempt" -lt 3 ]; then
echo "::warning::npm install attempt $attempt failed, retrying in 15s..."
sleep 15
else
echo "::error::npm install failed after 3 attempts"
exit 1
fi
done
- name: Install native addon over published binary
if: needs.native-host-build.result == 'success'
run: node scripts/ci-install-native.mjs
# Build dist/ so benchmarks load the same compiled JS that ships to npm.
# Historical baselines (v3.9.6 and earlier) were measured against dist/
# via the post-publish --npm path; running against src/ with --strip-types
# changes the load path and introduces version-to-version noise unrelated
# to the code under test (#1055).
- name: Build TypeScript
run: npm run build
- name: Run build benchmark
timeout-minutes: 20
run: |
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
node $STRIP_FLAG --import ./scripts/ts-resolve-loader.js scripts/benchmark.ts --version dev --dist > benchmark-result.json
- name: Run resolution benchmark
timeout-minutes: 20
run: |
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
node $STRIP_FLAG --import ./scripts/ts-resolve-loader.js scripts/resolution-benchmark.ts --version dev --dist > resolution-result.json
- name: Gate on resolution thresholds
timeout-minutes: 30
run: npx vitest run tests/benchmarks/resolution/resolution-benchmark.test.ts --reporter=verbose
- name: Run tracer validation (same-file edge recall)
timeout-minutes: 10
run: npx vitest run tests/benchmarks/resolution/tracer/tracer-validation.test.ts --reporter=verbose
- name: Merge resolution into build result
run: |
node -e "
const fs = require('fs');
const build = JSON.parse(fs.readFileSync('benchmark-result.json', 'utf8'));
const resolution = JSON.parse(fs.readFileSync('resolution-result.json', 'utf8'));
build.resolution = resolution;
fs.writeFileSync('benchmark-result.json', JSON.stringify(build, null, 2));
"
- name: Run query benchmark
timeout-minutes: 20
run: |
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
node $STRIP_FLAG --import ./scripts/ts-resolve-loader.js scripts/query-benchmark.ts --version dev --dist > query-benchmark-result.json
- name: Run incremental benchmark
timeout-minutes: 20
run: |
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
node $STRIP_FLAG --import ./scripts/ts-resolve-loader.js scripts/incremental-benchmark.ts --version dev --dist > incremental-benchmark-result.json
- name: Update build report
run: |
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
node $STRIP_FLAG scripts/update-benchmark-report.ts benchmark-result.json
- name: Update query report
run: |
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
node $STRIP_FLAG scripts/update-query-report.ts query-benchmark-result.json
- name: Update incremental report
run: |
STRIP_FLAG=$(node -e "const [M]=process.versions.node.split('.').map(Number); console.log(M>=23?'--strip-types':'--experimental-strip-types')")
node $STRIP_FLAG scripts/update-incremental-report.ts incremental-benchmark-result.json
- name: Regression guard
env:
RUN_REGRESSION_GUARD: "1"
run: npm run test:regression-guard
# Always upload raw JSON so a failed regression guard is debuggable
# without re-running the full benchmark suite locally.
- name: Upload benchmark JSON results
if: always()
uses: actions/upload-artifact@v7
with:
name: benchmark-results-json
path: |
benchmark-result.json
query-benchmark-result.json
incremental-benchmark-result.json
if-no-files-found: warn
ci-pipeline:
if: always()
needs: [lint, native-host-build, test, typecheck, audit, verify-imports, grammar-version-parity, rust-check, parity, pre-publish-benchmark]
runs-on: ubuntu-latest
name: CI Testing Pipeline
steps:
- name: Check results
run: |
if [[ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" == "true" ]]; then
echo "One or more CI jobs failed or were cancelled."
exit 1
fi