Skip to content

Releases: kepptic/ghax

v0.4.2

20 Apr 04:44

Choose a tag to compare

What's new in ghax 0.4.2

Fixed

  • BUG-001 — auto-bootstrap daemon's Playwright runtime on fresh
    attach. Release archives ship dist/ghax-daemon.mjs without a
    sibling node_modules/, so the first ghax attach against a
    fresh install used to fail with Cannot find package 'playwright'.
    attach.rs now detects the missing-module sentinel and runs
    scripts/bootstrap-daemon-runtime.sh (npm install playwright +
    source-map) before the second attempt. Version literals
    (PLAYWRIGHT_VERSION, SOURCE_MAP_VERSION) live at module level
    and can be overridden by a sibling package.json if one is
    present — so release archives can ship a real package.json and
    skip the constants entirely.

Docs

  • Reproducible cross-tool benchmark — test/benchmark.ts now reads
    GHAX_BIN env var so the same 7-step workflow (launch → goto →
    text → js → screenshot → snapshot → close) runs against any
    binary. First published baseline: ghax 65ms/cmd, gstack 56ms/cmd,
    agent-browser 178ms/cmd, playwright-cli 476ms/cmd.

Install ghax 0.4.2

Install prebuilt binaries via shell script

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/kepptic/ghax/releases/download/v0.4.2/ghax-installer.sh | sh

Install prebuilt binaries via powershell script

powershell -ExecutionPolicy Bypass -c "irm https://github.com/kepptic/ghax/releases/download/v0.4.2/ghax-installer.ps1 | iex"

Download ghax 0.4.2

File Platform Checksum
ghax-aarch64-apple-darwin.tar.xz Apple Silicon macOS checksum
ghax-x86_64-apple-darwin.tar.xz Intel macOS checksum
ghax-x86_64-pc-windows-msvc.zip x64 Windows checksum
ghax-aarch64-unknown-linux-gnu.tar.xz ARM64 Linux checksum
ghax-x86_64-unknown-linux-gnu.tar.xz x64 Linux checksum

v0.4.1

20 Apr 03:29

Choose a tag to compare

What's new in ghax 0.4.1

First public release. The Rust CLI rewrite — ghax is now a ~2.6 MB
Rust binary that talks to the unchanged Node daemon over HTTP. ~3×
faster cold start (P50 ~20 ms vs ~70 ms), ~20× smaller download,
distributed as platform-specific binaries via cargo-dist for 5 target
triples (macOS x64/ARM, Linux x64/ARM, Windows x64).

Breaking

  • Two error-surface tightenings fell out of the evalInTarget helper
    consolidation. Both are behavior improvements but worth flagging for
    anyone with scripted error handling:
    • ext storage used to return { ok: true } when the underlying JS
      expression threw. It now throws a DaemonError (exit code 4) with
      the exception details, so a failed chrome.storage.*.set no longer
      silently looks successful.
    • ext message used to return null when the cross-extension
      chrome.runtime.sendMessage threw outside its inner try/catch. It
      now throws a DaemonError as well.

Added

  • 5-target release matrix via cargo-dist (macOS x64/ARM, Linux x64/ARM,
    Windows x64).
  • Shell + PowerShell installer scripts that download from this repo's
    GitHub Releases. All distribution stays inside kepptic/ghax — no
    Homebrew tap, no crates.io publish, no npm publish required.
  • Daemon discovery precedence in attach.rs: (1) $GHAX_DAEMON_BUNDLE
    env var, (2) sibling of CLI binary, (3) dev fallback at
    <repo root>/dist/ghax-daemon.mjs.
  • Smoke suite (test/smoke.ts) reads GHAX_BIN env var so the same 80
    checks run against any binary. 80/80 against the Rust binary in 31.3s.
  • console --since <epoch-ms> and network --since <epoch-ms> filter
    buffer entries server-side, so callers (notably qa and canary)
    don't have to ship hundreds of irrelevant entries across the HTTP
    RPC just to discard them locally. console also accepts errors: true via RPC opts so the daemon drops non-error levels before
    serialising; the Rust CLI uses this on the hot path.
  • ghax xpath <expression> [--limit N] — query the page's DOM with an
    XPath expression, return every matching element with its tag, text
    preview, and bounding box. XPath is also usable via Playwright's
    xpath=... prefix in every selector-accepting command (click,
    fill, screenshot, is, etc.).
  • ghax box <@ref|selector> — return {x, y, width, height} of the
    first matching element. Resolves snapshot refs (@e3, @c1) or any
    selector form.
  • ghax attach --capture-bodies[=<url-glob>] — opt-in response-body
    capture. Without a pattern, captures every JSON/text-like response
    (application/json, text/*, javascript, xml, html, css, graphql)
    up to 32KB each. With a glob (e.g. '*/api/*'), restricts to
    matching URLs so browsing doesn't blow memory on images or chunks.
    Bodies past 32KB truncate with a [truncated N bytes] marker.
    Included in HAR export when the content is available.
  • ghax console --source-maps — resolve bundled stack frames back to
    their original source locations via the page's source maps. Each
    captured pageerror already parses its stack; with --source-maps,
    every frame is run through the daemon's source-map cache. Silent
    fallback to the bundled frame on any failure. Adds ~60KB to the
    daemon bundle for the source-map library; zero cost when the flag
    isn't used.
  • ghax shell — interactive REPL. Reads commands from stdin, tokenises
    with shell-ish quoting, re-enters the main dispatcher per line. One
    process for the whole session, so the per-command Bun spawn cost goes
    away. Measured 1.8× faster for 10-command batches (138ms/cmd vs
    247ms/cmd for separate invocations). Works as a pipe or TTY prompt.
  • Disconnect recovery. The daemon now listens for
    browser.on('disconnected') and self-shuts cleanly when the user's
    browser quits or a scratch browser crashes. State file gets cleared,
    next ghax attach is fresh. CLI-side, Playwright "browser has been
    closed" / "Target page has been closed" errors get rewritten to
    "browser has disconnected — run ghax attach to reconnect".
  • ghax try [<js>] [--css <rules>] [--selector <sel>] [--measure <expr>] [--shot <path>] — live-injection fix-preview. Composable wrapper over
    page.evaluate + page.screenshot for the "mutate the live page,
    measure, maybe screenshot" loop. Revert = reload the page.
  • ghax perf [--wait <ms>] — Core Web Vitals + navigation timing. Reads
    LCP (with size + URL), FCP, FP, CLS, TTFB, INP, long-task count, plus
    full navTiming breakdown. LCP/CLS/longtask come via a buffered
    PerformanceObserver.
  • ghax find <url-substring> — list tabs whose URL contains the
    substring. Returns [{id, url, title}].
  • ghax new-window [url] — open a new OS-level window via
    Target.createTarget({ newWindow: true, background: true }). Same
    profile, so auth + extensions carry over. Does NOT steal focus.
  • ghax tab <id> --quiet — skip bringToFront. Lets an agent lock onto
    a tab without raising the window or stealing focus.
  • ghax attach ergonomics: auto-port fallback (scans :9222-9230 and
    picks the first free one on --launch), multi-CDP picker, --headless
    flag (scratch-profile only), and a clearer kind-mismatch error when
    --browser chrome is asked for but only Edge is running.
  • ghax console --dedup — groups repeated entries by (level, text)
    into [{level, text, count, firstAt, lastAt, url, source, stack}]
    sorted by count desc. On capture, pageerror events now include a
    parsed stack [{fn, url, line, col}] via a new V8 stack-trace parser.
  • ghax network --status <code|family|range> filter — --status 404
    (exact), --status 4xx (family), --status 400-499 (range).
  • ghax network --har <path> — export captured entries as HAR 1.2 JSON
    consumable by Charles, har-analyzer, WebPageTest, and the Chrome
    DevTools network panel.
  • Request + response headers captured on every network entry (not
    just URL + status). Response statusText and duration also
    captured.
  • test/cross-browser.ts + bun run test:cross-browser — iterates every
    Chromium-family browser detectBrowsers() finds, launches each
    headless in a disposable scratch profile, runs the full smoke suite
    against it, tabulates pass/fail + timing per browser. First baseline:
    Edge 64/64 in 24.3s, Chrome 64/64 in 26.5s.
  • test/benchmark.ts + bun run test:benchmark — headless CLI benchmark
    against gstack-browse, playwright-cli, and agent-browser on a
    6-step workflow.
  • ghax profile [--duration sec] [--heap] [--extension <id>] — CDP
    Performance.getMetrics snapshot for the active tab or an
    extension service worker. Optional duration-based delta capture and
    heap snapshot (writes a .heapsnapshot loadable in DevTools).
  • ghax console --follow / ghax network --follow / ghax ext sw <id> logs --follow — live Server-Sent-Events streaming. Daemon exposes
    /sse/console, /sse/network, /sse/ext-sw-logs/<ext-id>; CLI
    consumes and prints each event as JSON. Ctrl-C exits 0.
  • ghax ext sw <id> logs [--last N] [--errors] — dedicated SW
    console buffer (subscribes to Runtime.consoleAPICalled +
    Runtime.exceptionThrown on first call). Persists across reads,
    auto-resubscribes after hot-reload.
  • ghax ext popup <id> eval <js> + ghax ext options <id> eval <js>
    — same shape as ext panel, for the popup and options pages.
  • ghax diff-state <before.json> <after.json> — structural JSON
    diff. Emits RFC-6901-style paths with + / - / ~ prefixes.
  • ghax ship [--message "..."] [--no-check] [--no-build] [--no-pr] [--dry-run] — opinionated commit + push + PR workflow.
  • ghax canary <url> [--interval sec] [--max sec] [--out r.json] [--fail-fast] — periodic prod health check. Goto + snapshot +
    capture console errors + HTTP >=400 responses per cycle.
  • ghax review [--base origin/main] [--diff] — emits a Claude-ready
    review prompt wrapping the branch's diff against a base.
  • ghax pair status — v0 SSH-tunnel setup instructions.
  • ghax qa — orchestrated QA pass over a URL list.
  • ghax qa --crawl <root> — auto URL discovery via <root>/sitemap.xml,
    falls back to same-origin <a href> scraping up to --depth N hops.
  • ghax is <visible|hidden|enabled|disabled|checked|editable> <@ref|selector> — assertion command. Exit 0 if condition holds, 1
    otherwise.
  • ghax storage [local|session] [get|set|remove|clear|keys] [key] [value] — page-level localStorage / sessionStorage.
  • ghax ext message <ext-id> <json-payload>chrome.runtime.sendMessage
    wrapper.
  • ghax gesture dblclick <x,y> + ghax gesture scroll <dir> [amount]
    real CDP Input.dispatch* gestures.
  • ghax attach --launch --load-extension <path> [--data-dir <path>]
    pass-through for Chrome's --load-extension + scratch profile.
  • Invariant enforcement: ctx.refs is now cleared when the active
    tab changes (via tab <id> or new-window). Previously the
    "refs survive only until next snapshot" rule held within a tab but
    broke across tab switches — @e3 from tab A could silently resolve
    against tab B's DOM. A new smoke check (refs cleared on tab switch)
    asserts the invariant.
  • test/smoke.ts — 80-check harness against a live browser.
  • test/hot-reload-smoke.ts — fully scripted hot-reload verification.
  • test/fixtures/test-extension/ — minimal MV3 fixture.

Changed

  • ghax CLI: TypeScript/Bun → Rust 2021 edition. Single source of truth.
  • Distribution: 61 MB Bun-compiled universal blob → ~2.6 MB stripped Rust
    binary on Apple Silicon (~10 MB on Linux x64) per platform.
  • Cold start: ~70 ms (P50) → ~20 ms (P50). P99 ~600 ms → ~20 ms.
  • Build: now requires Rust toolchain (1.80+). Bun stays as a dev tool for
    the daemon bundle (bun build --target=node) and the test runner.
  • Daemon DRY pass: three new helpers collapse repeated shapes.
    evalInTarget() centralises nine Runtime.evaluate sites with
    consistent exceptionDetails handling. getSwTarget() owns the...
Read more

Version 0.4.1-rc.3

20 Apr 03:04

Choose a tag to compare

Version 0.4.1-rc.3 Pre-release
Pre-release

Release Notes

Added

  • ghax xpath <expression> [--limit N] — query the page's DOM with an
    XPath expression, return every matching element with its tag, text
    preview, and bounding box. XPath is also usable via Playwright's
    xpath=... prefix in every selector-accepting command (click,
    fill, screenshot, is, etc.).

  • ghax box <@ref|selector> — return {x, y, width, height} of the
    first matching element. Resolves snapshot refs (@e3, @c1) or any
    selector form.

  • ghax attach --capture-bodies[=<url-glob>] — opt-in response-body
    capture. Without a pattern, captures every JSON/text-like response
    (application/json, text/*, javascript, xml, html, css, graphql)
    up to 32KB each. With a glob (e.g. '*/api/*'), restricts to
    matching URLs so browsing doesn't blow memory on images or chunks.
    Bodies past 32KB truncate with a [truncated N bytes] marker.
    Included in HAR export when the content is available.

  • ghax console --source-maps — resolve bundled stack frames back to their
    original source locations via the page's source maps. Each captured
    pageerror already parses its stack; with --source-maps, every frame
    is run through the daemon's source-map cache: fetch the script, read
    its sourceMappingURL comment (or data: URI), parse the map, look up
    the original position. Result includes the resolved {url, line, col}
    plus {bundledUrl, bundledLine, bundledCol} for correlation. Silent
    fallback to the bundled frame on any failure (script unreachable, no
    map comment, parse error, position out of range). Adds ~60KB to the
    daemon bundle for the source-map library; zero cost when the flag
    isn't used.

  • ghax shell — interactive REPL. Reads commands from stdin, tokenises
    with shell-ish quoting (single/double quotes, backslash escapes),
    re-enters the main dispatcher per line. One process for the whole
    session, so the per-command Bun spawn cost goes away. Measured 1.8x
    faster for 10-command batches (138ms/cmd vs 247ms/cmd for separate
    invocations). Works as a pipe (cat script.txt | ghax shell) or
    interactively (TTY prompt, history, Ctrl-D to exit). exit/quit
    stop the loop; # lines are comments.

  • Disconnect recovery. The daemon now listens for
    browser.on('disconnected') and self-shuts cleanly when the user's
    browser quits or a scratch browser crashes. State file gets cleared,
    next ghax attach is fresh. CLI-side, "browser has been closed" /
    "Target page has been closed" errors get rewritten to
    "browser has disconnected — run ghax attach to reconnect" instead
    of surfacing as a raw Playwright stack trace.

  • ghax try [<js>] [--css <rules>] [--selector <sel>] [--measure <expr>] [--shot <path>] — live-injection fix-preview. Composable wrapper over
    page.evaluate + page.screenshot for the "mutate the live page,
    measure, maybe screenshot" loop. CSS appends <style class="ghax-try">;
    JS is IIFE-wrapped with optional el binding; --measure runs
    post-mutation. Revert = reload the page.

  • ghax perf [--wait <ms>] — Core Web Vitals + navigation timing. Reads
    LCP (with size and URL), FCP, FP, CLS, TTFB, INP, long-task count,
    plus full navTiming breakdown (DNS, TCP, TLS, TTFB, response,
    DOMInteractive, DOMContentLoaded, load, transfer/encoded/decoded
    sizes). LCP/CLS/longtask come via a buffered PerformanceObserver — they
    don't live in the default timeline buffer.

  • ghax find <url-substring> — list tabs whose URL contains the
    substring. Returns [{id, url, title}]. Pipe the id into ghax tab
    to attach to a matching tab, or fall through to new-window.

  • ghax new-window [url] — open a new OS-level window via
    Target.createTarget({ newWindow: true, background: true }). Same
    profile, so auth + extensions carry over. Does NOT steal focus.
    Auto-locks the new tab as the daemon's active tab so subsequent
    commands land in the fresh window without an extra tab step.

  • ghax tab <id> --quiet — skip bringToFront. Lets an agent lock onto
    a tab without raising the window or stealing focus from whatever
    the user is actively doing.

  • ghax attach ergonomics: auto-port fallback (--launch without
    --port scans :9222-9230 and picks the first free one, prints the
    chosen port on fallback), multi-CDP picker (plain ghax attach with
    multiple live CDPs shows a numbered selector), --headless flag
    (scratch-profile only — spawns with --headless=new so extensions
    still work), and a clearer kind-mismatch error when --browser chrome
    is asked for but only Edge is running.

  • ghax console --dedup — groups repeated entries by (level, text)
    into [{level, text, count, firstAt, lastAt, url, source, stack}]
    sorted by count desc. Turns "500 identical errors" into one row with
    count=500. On capture, pageerror events now include a parsed stack
    [{fn, url, line, col}] via a new V8 stack-trace parser in
    buffers.ts.

  • ghax network --status <code|family|range> filter — --status 404
    (exact), --status 4xx (family), --status 400-499 (range).

  • ghax network --har <path> — export captured entries as HAR 1.2 JSON
    consumable by Charles, har-analyzer, WebPageTest, and the Chrome
    DevTools network panel.

  • Request + response headers captured on every network entry (not
    just URL + status). Response statusText and duration also
    captured. Bodies are still not captured by default (memory cost too
    high for a 5k rolling buffer).

  • test/cross-browser.ts + bun run test:cross-browser — iterates every
    Chromium-family browser detectBrowsers() finds, launches each
    headless in a disposable scratch profile, runs the full smoke suite
    against it, tabulates pass/fail + timing per browser. Arc is filtered
    out (no CDP). First baseline: Edge 64/64 in 24.3s, Chrome 64/64 in
    26.5s.

  • test/benchmark.ts + bun run test:benchmark — headless CLI benchmark
    against gstack-browse, playwright-cli, and agent-browser on a
    6-step workflow (launch → goto → text → js → screenshot → snapshot →
    close). Reports cold (end-to-end) and warm (per-command, session
    reused) numbers. First baseline: ghax 65ms/cmd, gstack 56ms/cmd,
    agent-browser 178ms/cmd, playwright-cli 476ms/cmd.

  • ghax profile [--duration sec] [--heap] [--extension <id>] — CDP
    Performance.getMetrics snapshot for the active tab or an
    extension service worker. Optional duration-based delta capture and
    heap snapshot (writes a .heapsnapshot loadable in DevTools).
    Report written to .ghax/profiles/<ts>.json.

  • ghax console --follow / ghax network --follow / ghax ext sw <id> logs --follow — live Server-Sent-Events streaming. Daemon exposes
    /sse/console, /sse/network, /sse/ext-sw-logs/<ext-id>;
    CLI consumes and prints each event as JSON. Ctrl-C exits 0.

  • ghax ext sw <id> logs [--last N] [--errors] — dedicated SW
    console buffer (subscribes to Runtime.consoleAPICalled +
    Runtime.exceptionThrown on first call). Persists across reads,
    auto-resubscribes after hot-reload.

  • ghax ext popup <id> eval <js> + ghax ext options <id> eval <js>
    — same shape as ext panel, for the popup and options pages. URL
    pattern matching against /popup.html, /options.html, etc.

  • ghax diff-state <before.json> <after.json> — structural JSON
    diff. Emits RFC-6901-style paths (/a/b/0) with + / - / ~
    prefixes. Supports --json for machine output.

  • ghax ship [--message "..."] [--no-check] [--no-build] [--no-pr] [--dry-run] — opinionated commit + push + PR workflow. Runs
    typecheck + build first; on a non-main branch, fires
    gh pr create --fill or reports the existing PR URL.

  • ghax canary <url> [--interval sec] [--max sec] [--out r.json] [--fail-fast] — periodic prod health check. Goto + snapshot +
    capture console errors + HTTP >=400 responses per cycle. Appends
    a rolling log to .ghax/canary-<host>.log; writes a structured
    JSON report on exit.

  • ghax review [--base origin/main] [--diff] — emits a Claude-ready
    review prompt wrapping the branch's diff against a base. No API
    calls — stdout only, user pipes to claude or pastes.

  • ghax pair status — v0 SSH-tunnel setup instructions. A proper
    token-auth multi-tenant mode is deferred to v0.5.

  • ghax qa — orchestrated QA pass over a URL list. Flow: attach →
    goto each URL → snapshot -i → record console errors + HTTP >=400
    responses → write qa-report.json. Flags: --url (repeatable),
    --urls a,b,c, positional URLs, or stdin JSON array. --out,
    --screenshots, --annotate, --gif.

  • ghax qa --crawl <root> — auto URL discovery. Tries
    <root>/sitemap.xml first; falls back to same-origin <a href>
    scraping up to --depth N hops (default 1), capped by --limit N
    (default 20).

  • ghax is <visible|hidden|enabled|disabled|checked|editable> <@ref|selector>
    — assertion command. Exit 0 if condition holds, 1 otherwise.

  • ghax storage [local|session] [get|set|remove|clear|keys] [key] [value]
    — page-level localStorage / sessionStorage.

  • ghax ext message <ext-id> <json-payload>chrome.runtime.sendMessage
    wrapper.

  • ghax gesture dblclick <x,y> + ghax gesture scroll <dir> [amount]
    real CDP Input.dispatch* gestures.

  • ghax attach --launch --load-extension <path> [--data-dir <path>]
    pass-through for Chrome's --load-extension + scratch profile.

  • test/smoke.ts — 64-check harness against a live browser (grew from
    24 as the v0.4 + debugging-tier-1 surface landed).

  • test/hot-reload-smoke.ts — fully scripted hot-reload verification.

  • test/fixtures/test-extension/ — minimal MV3 fixture.

Changed

  • ghax ext list enriches each entry with manifest-derived name,
    version, and enabled fields.
  • ghax attach defaults changed: no --port now scans :9222-9230 for
    existing CDPs (multiple → picker, one → attach). With --launch and
    no --port, auto-picks the first free port in the same range. Pass
    --port <n> explicitly to opt ...
Read more