build(deps): bump anthropics/claude-code-action from 1.0.178 to 1.0.183 #6222
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |