Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,20 @@ jobs:
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Install Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- name: Install pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4
with:
bun-version: latest
version: 11

- name: Install Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
with:
node-version: 22
cache: pnpm
cache-dependency-path: plugins/trace-codex/pnpm-lock.yaml

- name: Install dependencies
run: bun install --frozen-lockfile
run: pnpm install --frozen-lockfile
working-directory: plugins/trace-codex

- name: Run tests
Expand Down
24 changes: 18 additions & 6 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ jobs:
# Phase 2: publish once the version bump lands on main via the merged PR.
publish:
if: github.event_name == 'push'
runs-on: ubuntu-24.04
# Build on macOS: pkg code-signs the darwin binaries via the `codesign`
# utility (which only exists on macOS), and an unsigned arm64 binary is
# killed on launch by Apple Silicon. A macOS host cross-compiles the Linux
# targets too, so one job still produces all four binaries.
runs-on: macos-15
outputs:
version: ${{ steps.vars.outputs.version }}
published: ${{ steps.vars.outputs.published }}
Expand Down Expand Up @@ -134,19 +138,27 @@ jobs:
echo "published=true" >> "$GITHUB_OUTPUT"
fi

- name: Install Bun
- name: Install pnpm
if: steps.vars.outputs.published == 'true'
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4
with:
version: 11

- name: Install Node.js
if: steps.vars.outputs.published == 'true'
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
with:
bun-version: latest
node-version: 22
cache: pnpm
cache-dependency-path: ${{ env.PLUGIN_DIR }}/pnpm-lock.yaml

- name: Build release binaries
if: steps.vars.outputs.published == 'true'
working-directory: ${{ env.PLUGIN_DIR }}
run: |
bun install --frozen-lockfile
pnpm install --frozen-lockfile
# Cross-compiles every target (darwin/linux x arm64/x64) into bin/.
bun run build
pnpm run build
ls -la bin/

- name: Create and push tag
Expand Down
15 changes: 11 additions & 4 deletions .github/workflows/smoke.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,21 @@ jobs:
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Install Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- name: Install pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4
with:
bun-version: latest
version: 11

- name: Install Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
with:
node-version: 22
cache: pnpm
cache-dependency-path: ${{ env.PLUGIN_DIR }}/pnpm-lock.yaml

- name: Install plugin dependencies
working-directory: ${{ env.PLUGIN_DIR }}
run: bun install --frozen-lockfile
run: pnpm install --frozen-lockfile

- name: Install Codex CLI
run: npm install -g @openai/codex
Expand Down
12 changes: 6 additions & 6 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ read_json_field() {
grep -o "\"$2\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" "$1" | head -1 | sed 's/.*"\([^"]*\)"$/\1/'
}

# Build a plugin's compiled assets if it has a Bun build (build-on-install).
# Build a plugin's compiled assets if it has a build (build-on-install).
build_plugin() {
plugin_src="$1"
if [ ! -f "$plugin_src/package.json" ]; then
Expand All @@ -87,13 +87,13 @@ build_plugin() {
if ! grep -q '"build"' "$plugin_src/package.json"; then
return 0
fi
if ! command -v bun >/dev/null 2>&1; then
echo "Error: '$folder' needs Bun to build, but 'bun' was not found." >&2
echo " Install Bun from https://bun.sh and re-run ./install.sh" >&2
if ! command -v pnpm >/dev/null 2>&1; then
echo "Error: '$folder' needs pnpm to build, but 'pnpm' was not found." >&2
echo " Install pnpm from https://pnpm.io/installation and re-run ./install.sh" >&2
exit 1
fi
echo " building (bun)..."
( cd "$plugin_src" && bun install --silent && BUILD_HOST_ONLY=1 bun run build )
echo " building (pnpm)..."
( cd "$plugin_src" && pnpm install --reporter=silent && BUILD_HOST_ONLY=1 pnpm run build )
}

for folder in "${PLUGINS[@]}"; do
Expand Down
2 changes: 2 additions & 0 deletions plugins/trace-codex/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
node_modules/
# tsup's intermediate bundle (input to pkg); regenerated by `pnpm run build`.
dist/
# Built binaries are downloaded at runtime / built locally, never committed.
# The launcher scripts (bin/codex-hook.sh, bin/codex-hook.cmd) are tracked.
bin/codex-hook
Expand Down
35 changes: 24 additions & 11 deletions plugins/trace-codex/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,28 @@ Keep this boundary clean: nothing under `src/server/`, `src/processor/`, or
eventually be extracted into its own package, so treat any Codex-specific leak
into the generic layers as a bug, not a shortcut.

### 2. Bun-compiled, cross-platform binaries
### 2. Node-compiled, cross-platform binaries

The hook command in `hooks.json` is a fixed, platform-agnostic string that
invokes `bin/codex-hook.sh` (or `.cmd` on Windows), **not** the binary directly.
That launcher resolves and runs the real, platform-specific `codex-hook` binary.

- `scripts/build.ts` compiles `src/index.ts` with `bun build --compile` for each
target (`darwin-arm64/x64`, `linux-x64/arm64`; Windows slots in but isn't
built yet). `BUILD_HOST_ONLY=1` builds just the host target (used by the
repo-root `install.sh` for local dev installs).
- `scripts/build.ts` runs a two-step build: `tsup` bundles `src/index.ts` into a
single self-contained CommonJS file (`dist/codex-hook.cjs`, inlining the
`braintrust` dependency), then `@yao-pkg/pkg` wraps that bundle plus a Node
runtime into a standalone executable per target (`darwin-arm64/x64`,
`linux-x64/arm64`; Windows slots in but isn't built yet). `BUILD_HOST_ONLY=1`
builds just the host target (used by the repo-root `install.sh` for local dev
installs).
- **Build the release on macOS.** pkg code-signs the darwin binaries via the
`codesign` utility (macOS-only), and Apple Silicon kills an unsigned arm64
binary on launch. A macOS host cross-compiles the Linux targets too, so one
job produces all four signed/valid binaries (see `release.yaml`).
- **Re-exec caveat (pkg):** the hook spawns the server by re-executing
`process.execPath` with `serve`. pkg's child_process patch would otherwise make
the child act like `node` and treat `serve` as a script path, so
`spawn-server.ts` pre-sets `PKG_EXECPATH` to a non-exec-path sentinel to force
packaged-app mode. See the comment there.
- The compiled binaries are **large and not committed**. The launcher downloads
the matching binary from the plugin's GitHub release on first use and caches
it at `$PLUGIN_ROOT/bin/codex-hook`. Codex wipes `$PLUGIN_ROOT` on every
Expand Down Expand Up @@ -184,12 +196,13 @@ Invariants to preserve when changing this:

Run from `plugins/trace-codex/`:

- `bun test` — run the test suite (tests live next to sources as `*.test.ts`).
- `bun run typecheck` — `tsc --noEmit`.
- `bun run lint` / `bun run check` — Biome lint / lint+format.
- `bun run build` — compile all target binaries (`BUILD_HOST_ONLY=1` for host
only).
- `bun run dev` — run the server in watch mode.
- `pnpm test` — run the test suite with vitest (tests live next to sources as
`*.test.ts`).
- `pnpm run typecheck` — `tsc --noEmit`.
- `pnpm run lint` / `pnpm run check` — Biome lint / lint+format.
- `pnpm run build` — build all target binaries via tsup + pkg
(`BUILD_HOST_ONLY=1` for host only).
- `pnpm run dev` — run the server in watch mode (tsx).

Add or update tests alongside any behavior change; keep typecheck and lint
clean.
14 changes: 7 additions & 7 deletions plugins/trace-codex/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
# integration check.
# make lint Run the Biome linter/formatter check (no writes).
# make typecheck Run the TypeScript type checker.
# make unit Run only the bun unit tests.
# make unit Run only the unit tests (vitest).
# make build Compile the host binary (and per-platform binaries).
# make integration Build, boot the server via the hook binary, health-check,
# assert the version, then shut it down.
# make smoke End-to-end: run a real `codex exec` session with the
# installed plugin, traced to a local mock collector, and
# assert >=1 trace row. Requires codex, bun, and
# assert >=1 trace row. Requires codex, node, pnpm, and
# OPENAI_API_KEY; optionally SMOKE_VERSION to pin a release.
# make token-proxy Run the token-counting proxy (debugging aid) that sits
# between Codex and OpenAI and prints each call's token usage
Expand All @@ -38,19 +38,19 @@ test: lint typecheck unit integration

lint:
@echo "==> Linting (biome)"
bun run check
pnpm run check

typecheck:
@echo "==> Typechecking (tsc)"
bun run typecheck
pnpm run typecheck

unit:
@echo "==> Running unit tests"
bun test
pnpm test

build:
@echo "==> Building binaries"
BUILD_HOST_ONLY=1 bun run build
BUILD_HOST_ONLY=1 pnpm run build

integration: build
@echo "==> Integration test (port $(TEST_PORT), expecting version $(EXPECTED_VERSION))"
Expand Down Expand Up @@ -101,7 +101,7 @@ smoke:
# point Codex at it via a custom model_provider (see scripts/token-proxy.ts).
token-proxy:
@echo "==> Token proxy (Ctrl-C for the session total)"
bun run scripts/token-proxy.ts
pnpm exec tsx scripts/token-proxy.ts

clean:
@echo "==> Cleaning"
Expand Down
Loading
Loading