Title
Hello link world.
+- one
- two
| Name | Stars |
|---|---|
| a | 100 |
| b | 5 |
diff --git a/.github/scripts/smoke.sh b/.github/scripts/smoke.sh new file mode 100755 index 0000000..b583cf1 --- /dev/null +++ b/.github/scripts/smoke.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +# The compiled binary must behave exactly like the same sources under bun. +# +# A --version check would exercise almost none of the compiled surface: the +# binary embeds a JavaScript engine for linkedom and fetch, and the port had to +# hand-roll argument parsing, DOM traversal, the TSV renderer and the --where +# evaluator. So every output mode is compared byte-for-byte against the bun +# entry point, which the test suite already covers. +set -uo pipefail + +AX=${AX:-./ax} +pass=0 +fail=0 + +work=$(mktemp -d) +trap 'rm -rf "$work"' EXIT + +cat >"$work/page.html" <<'HTML' +
Hello link world.
+| Name | Stars |
|---|---|
| a | 100 |
| b | 5 |
| H | |
|---|---|
| a | b |
hi
' | "$AX" - '.x' --text 2>&1) +want=$(printf 'hi
' | bun src/index.ts - '.x' --text 2>&1) +if [ "$got" = "$want" ]; then + pass=$((pass + 1)) + echo "ok stdin" +else + fail=$((fail + 1)) + echo "FAIL stdin" + diff <(printf '%s\n' "$want") <(printf '%s\n' "$got") || true +fi + +echo +echo "pass=$pass fail=$fail" +[ "$fail" -eq 0 ] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49c6921..5b709b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,12 +2,16 @@ name: CI on: push: - branches: [main] pull_request: permissions: contents: read +# A push to a branch with an open PR would otherwise run this twice. +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: test: runs-on: ubuntu-latest @@ -19,7 +23,78 @@ jobs: - run: bun install --frozen-lockfile - name: nix/bun.nix must be in sync with bun.lock run: git diff --exit-code nix/bun.nix + - name: src/agent-context.gen.ts must be in sync with agent-context.txt + run: bun run gen && git diff --exit-code src/agent-context.gen.ts - run: bunx tsc --noEmit - run: bunx oxfmt --check . - run: bun test - - run: bun build src/index.ts --compile --outfile ax && ./ax --version + + # A job per OS: a scriptc --dynamic binary is host-native (the embedded engine + # archive is built per target, and cross-compiling one is not supported), so + # each platform needs its own runner. The first build on a runner compiles + # that engine from source, which takes minutes and needs a C toolchain the + # `test` job has no other use for. + build: + name: compile (${{ matrix.target }}, ${{ matrix.builder }}) + runs-on: ${{ matrix.os }} + timeout-minutes: 40 + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-latest, target: linux-x64, builder: scriptc } + - { os: ubuntu-24.04-arm, target: linux-arm64, builder: scriptc } + - { os: macos-latest, target: darwin-arm64, builder: scriptc } + - { os: macos-15-intel, target: darwin-x64, builder: scriptc } + # Windows builds with bun instead: scriptc has not ported the socket + # stack (net/http/https/tls), which is where ax's fetch lives. The + # sources are the same, and the bun path keeps the full-fidelity + # lib/platform.ts (TextDecoder labels, the stdout drain) that the + # compiled builds trade away. + - { os: windows-latest, target: windows-x64, builder: bun, ext: .exe } + defaults: + run: + # One script for every OS; Windows runners ship Git Bash. + shell: bash + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: 1.3.14 + # scriptc's compiler runs on Node, not Bun: typescript@7's synchronous RPC + # channel reads `stdout._handle.fd` off a spawned child. + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + if: matrix.builder == 'scriptc' + with: + node-version: 22 + - run: bun install --frozen-lockfile + + - name: Install the C toolchain scriptc drives (Linux) + if: matrix.builder == 'scriptc' && runner.os == 'Linux' + run: sudo apt-get update && sudo apt-get install -y clang cmake + + - name: Install the C toolchain scriptc drives (macOS) + if: matrix.builder == 'scriptc' && runner.os == 'macOS' + run: brew install cmake + + - name: Compile (scriptc) + if: matrix.builder == 'scriptc' + run: bun run build ax${{ matrix.ext }} + + - name: Compile (bun) + if: matrix.builder == 'bun' + run: bun build src/index.ts --compile --outfile ax${{ matrix.ext }} + + - name: Smoke test — output must match the bun entry point + env: + AX: ./ax${{ matrix.ext }} + run: bash .github/scripts/smoke.sh + + - name: Report binary size + run: ls -l ax${{ matrix.ext }} | awk '{print $5, $9}' + + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: ax-${{ matrix.target }} + path: ax${{ matrix.ext }} + if-no-files-found: error diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index c240d3f..0d1a2ea 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -6,7 +6,6 @@ name: Nix flake on: push: - branches: [main] paths: - '**.nix' - 'flake.lock' @@ -39,7 +38,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.os }} - timeout-minutes: 20 + timeout-minutes: 45 steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 @@ -60,8 +59,17 @@ jobs: - name: nix flake check --all-systems run: nix flake check --all-systems --no-build + # Compiles the embedded JavaScript engine from the vendored sources, so + # this is minutes rather than seconds. - name: nix build .#default run: nix build .#default --print-build-logs - name: nix run .#default -- --version run: nix run .#default -- --version + + - name: nix run .#default -- --md + run: | + printf 'Hello