Skip to content

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[0.9.3] - 2026-09-06

More reliable CLI automation, independent log collectors, and safer incident bundles. This release includes the changes since v0.9.2 plus fixes found during release review. Existing commands are retained; malformed numeric arguments and conflicting options now fail explicitly. The bridge protocol remains v0.8.0, and no bridge update is required for these CLI fixes.

Fixed

  • Reliable evaluation and condition checks. eval, wait, and check await promises and preserve JavaScript truthiness before the bridge serializes values. false, 0, null, and undefined no longer look truthy just because they arrived as strings; the string "false" remains truthy. Thrown expressions fail, literal ERROR: strings remain ordinary results, and escaped selectors survive transport. Evaluation runs in the webview’s global context without shadowing app globals named value, kind, or encoded.
  • Bounded waiting and one-time clicks. Poll requests and sleeps share the same overall timeout budget. click --wait polls from the CLI before dispatching one click instead of leaving a delayed click running inside the webview after a request times out.
  • Collector cleanup and interruption reporting. Signal handling spans observer setup through cleanup. Console, IPC, and mutation monitors take a final sample even when the duration is shorter than the polling interval. Interrupted check --no-errors assertions fail instead of reporting success after observing only part of the requested duration; interrupted captures preserve available evidence and record warnings and partial: true. Lost setup replies, collection failures, and cleanup errors are handled explicitly.
  • Independent monitoring sessions. Concurrent console, IPC, and mutation collectors no longer drain or restore each other’s sessions. Buffers are limited to 1,000 entries with overflow warnings. Serialization handles circular references and BigInts, bounds large payloads, and avoids invoking object getters. IPC instrumentation excludes internal bridge callbacks and preserves application results and exceptions, including calls settling after a collector closes.
  • Image comparison errors. diff checks both image dimensions, accepts ImageMagick’s scientific-notation metrics, and treats only comparison exit code 1 as a valid difference. Missing tools, malformed images, dimension mismatches, and unwritable diff outputs fail instead of becoming misleading pixel counts. X11 window searches distinguish no matches from actual tool/display errors.
  • Configuration and offline diagnostics. Config and capability loading uses JSON5 instead of stripping comments with regex, preserving URLs and comment-like text inside strings. diagnose --no-bridge now skips bridge enrichment even with an explicit target.

Added

  • eval --json returns { "result": value }. Fatal errors for JSON-enabled invocations use { "error": { "code", "message", "hint" } } on stderr with a nonzero exit status; command results remain on stdout. Failed assertions and diff thresholds retain their structured stdout results.
  • Selected-target details in probe. JSON output includes the target PID, port, and window label, with a note when automatic discovery chooses among multiple bridges.
  • Capture completeness metadata. Capture manifests include optional partial and warnings fields. Missing screenshot tools no longer prevent collection of DOM, state, storage, and logs.
  • Release checks. Package validation checks package/lockfile/skill version agreement, required shipped files, and exclusion of Rust build outputs. Import-boundary validation is now part of lint.

Changed

  • logs, rust-logs, and capture use independent non-draining cursors on bridge v0.8+, replaying the retained backlog and reporting dropped entries. Older bridges emit a warning and fall back to destructive drain reads. logs --follow requires a bridge and rejects --no-bridge.
  • Bundles stage privately before publication. Text, structured storage credentials, and summaries are redacted and checked for remaining secrets before the new directory or archive is published. Redaction failure prevents publication. Archives contain only artifacts from the current run, unrelated existing output files are preserved, and artifact symlinks are rejected. Missing sources mark phases incomplete; archive failure preserves sanitized directory evidence and reports archive: null. Images remain unredacted and are listed as warnings for review.
  • Platform dependencies are checked per operation. Window listing, info, and title waits do not require ImageMagick. Full-window PNG capture on macOS/Wayland uses native tools; crop/resize/JPEG/diff and X11 capture require ImageMagick. Title matching is documented as regex on X11 and substring matching on macOS/Sway/Hyprland.
  • Integer, port, and percentage options receive stricter validation. wait requires exactly one condition, check requires an assertion, and conflicting evaluation sources, click types, scroll actions, and replay destinations are rejected. Sidecar replay examples quote the complete --to-exec value and document its whitespace-splitting limitation.
  • CI now covers Node 20/24 on Ubuntu, Node 24 on macOS, and locked Rust bridge builds/tests on both platforms. The example’s Cargo lockfile is tracked; local Rust target and generated gen directories are excluded from npm. CI and release jobs install ImageMagick for real image-comparison tests.
  • Updated READMEs, command references, architecture, troubleshooting, contributor/security guidance, and all three shipped skills. The documentation changelog mirrors this file; older design documents are marked as historical.

[0.9.2] - 2026-08-24

type and select now reach framework-controlled inputs and verify their writes. Additive and backwards-compatible — no flag changed meaning, all result-schema additions are optional-only, and no bridge change is required.

Fixed

  • type and select no longer report success while React ignores the value (#10, reported by @papercupai). Values are written through the element's native prototype value setter (HTMLInputElement/HTMLTextAreaElement/HTMLSelectElement.prototype; custom elements are resolved up their prototype chain) instead of el.value = …, which react-dom's instance-level value tracker turns into a no-op — the command read back its own write and reported success while React state never changed and the DOM reverted on the next render. Both the --clear write and the final write use the native setter. select --toggle now performs a native click() (React only observes click for checkbox/radio) instead of assigning el.checked and firing a synthetic change, which never reached React either.
  • type/select scripts are wrapped in try/catch and always return JSON; a bridge ERROR: … payload or non-JSON result now surfaces as an actionable error instead of a SyntaxError from JSON.parse. el.select() is guarded (absent on <select> and custom elements), and select values are JSON-escaped, so values containing newlines no longer produce a script syntax error.

Added

  • Write verification for type and select — after dispatching input/change the element is re-read synchronously and then polled (50 ms, default deadline 500 ms). The outcome is reported in new optional result fields verified, verification (matched | transformed | reverted), requestedValue, previousValue (previousChecked for --toggle), options, and hint. A write the app rolls back (reverted) fails with Value reverted: … (Checked state reverted: … for --toggle) plus a hint on stderr, and the failure object is printed to stdout (type --json; select always prints JSON) — verification: "reverted" is the stable signal for scripts; a value the app reformats (masks, formatters) is a success with verification: "transformed" and verified: false. The reverted baseline is taken after focus()/--clear have settled, so an app that accepts the clear (or reformats the value on focus) but rejects the real write is still reported as reverted. A value the browser sanitizes to empty (e.g. abc into type=number) fails with Browser discarded the value: … and the field is restored to what it held right before the write (after --clear, to the pre-clear value, with an input event so the app sees the restore); a value the browser clamps or sanitizes back onto the field's current value (e.g. 50 into a type=range already at its max of 10) fails with Browser did not take the value: … with no events dispatched — a clamp that lands on a different value (50 into a range at 5 → 10) is a matched success carrying the normalized value and the original requestedValue; a field the app empties after a non-empty write fails with Value cleared: …; an element that leaves the document (or is re-mounted) after focus/--clear is re-resolved by selector before the write, and one that disappears after the write (for --toggle, after the click) fails explicitly instead of being verified against a stale node. Custom elements that reflect value asynchronously are verified against the requested value. --verify-timeout <ms> (0–4000; 0 = single synchronous check) tunes the deadline for apps that apply values on a transition/async render. Detection is React-specific by construction (React restores controlled values synchronously inside dispatchEvent); frameworks that leave a rejected value in the DOM are reported as matched.
  • type and select fail fast when the target is a <select> with no <option> matching the value, listing the available values in the options field and the hint (previously reported success with value: "").
  • Shared helpers in src/commands/interact/shared.ts (buildSetValueScript(), the NATIVE_VALUE_WRITER_SNIPPET/VERIFY_POLL_SNIPPET/SETTLE_SNIPPET/SELECT_OPTIONS_SNIPPET script fragments, the verify-timeout constants and option wiring, parseInteractResult()) and WriteVerificationSchema in src/schemas/interact.ts.
  • Regression fixture tests/integration/react-controlled-forms.test.ts runs the generated scripts against a real React 19 tree in jsdom (controlled input/textarea/select/checkbox/radio, reject and transform paths, transition-fed values, custom elements, and negative controls using the pre-fix scripts). react, react-dom, and jsdom are added as devDependencies only.

Changed

  • type and select (value mode) refuse <input type=checkbox|radio> (hint: select --toggle), <input type=file>, and elements with no value setter such as contenteditable <div>s (previously both set an expando property — or the checkbox/radio value attribute — and reported success). type's human output appends a note when the app transformed or the browser normalized the requested value.
  • On failure, type --json and select print the failure result object (error, hint, and any verification/options/previousValue fields) to stdout before exiting 1; previously only the error message reached stderr.
  • select --toggle refuses non-checkable, disabled (including <fieldset disabled> descendants), and already-checked radio elements; because it now clicks, the element's click handlers run, as they would for a user click.
  • select value mode dispatches input before change (native order; previously change then input).
  • Only a matched write resolves immediately; reverted and transformed outcomes wait out the full --verify-timeout (default 500 ms) before being classified.

[0.9.1] - 2026-07-21

Window targeting by platform id: the window-consuming commands can now skip the title-regex path entirely. Additive and backwards-compatible — no flag changed meaning and all output additions are optional-only.

Added

  • -w, --window-id <id> on screenshot, info, snapshot, and capture (#9, reported by @papercupai) — target a window by its platform id (from list-windows) instead of a --title regex. Skips findWindow() entirely, so there is no shell-quoting risk (ids have no spaces) and windows a title regex can't uniquely or reliably match (e.g. unmapped/headless windows under xdotool search) become addressable. The id passes through unvalidated at the CLI layer — its format is adapter-specific (X11/macOS/Sway numeric, Hyprland hex 0x…); adapters that shell-interpolate ids keep their existing validateWindowId() guards. screenshot --window-id full-window capture needs no bridge at all. Unrelated to --window-label (Tauri webview label, a bridge concept).
  • Shared resolveWindowId() export from src/commands/shared.ts (windowId > title > bridge document.title precedence), replacing three duplicated per-command resolution helpers. CaptureToDirOptions gains an optional windowId field, and screenshot --json output now includes the resolved windowId (both additive).

Changed

  • info --title is no longer a required option — one of --title or --window-id suffices.
  • --title help text on window-targeting commands now notes that titles containing spaces must be shell-quoted (an unquoted title splits at the shell and can substring-match the wrong window).

[0.9.0] - 2026-07-15

Fork-uplift release: bug fixes and features generalized from the contextful_debugger fork. Everything is additive and backwards-compatible; schema additions are optional-only, and the bridge protocol change is opt-in by request shape.

Added

  • logs --follow (+ --interval <ms>) — tail live bridge logs until interrupted. Against a v0.8 bridge this uses non-draining cursor long-polls (seeded at cursor 0 to replay the buffered backlog) so multiple log consumers can coexist; evicted entries surface as a dropped-count warning. Against a pre-0.8 bridge it emits a one-time note: and degrades to drain polling every --interval ms.
  • sidecar replay --tap-format / --dir in|out — unwrap {dir,ts,line} tap wrapper rows (the common shape for bidirectional IPC tap recordings) before replaying, optionally filtered by direction. Malformed wrapper rows fail with a line-numbered error.
  • captureToDir() library API — capture's pipeline is now an exported function (src/commands/capture.ts) returning the CaptureManifest, so other tooling can snapshot evidence programmatically. CLI behavior unchanged.
  • BridgeClient.fetchLogs() cursor overload — passing {cursor, waitMs, limit, timeoutMs} returns {entries, cursor?, dropped?} via the non-draining v0.8 /logs cursor mode. A pre-0.8 bridge answers without a cursor field, so callers feature-detect by response shape with no extra round-trips (this is how logs --follow decides to degrade to drain polling). The legacy fetchLogs(timeout?) drain call is unchanged; log-entry/response schemas gain optional id, cursor, and dropped fields.
  • scripts/check-bridge-parity.mjs (npm check:bridge-parity, part of npm run lint) — lint gate that regex-parses BRIDGE_VERSION + the endpoint list from dev_bridge.rs and ENDPOINT_MIN_VERSION from client.ts, failing on missing/extra entries or a min-version above BRIDGE_VERSION (semver compare, so legacy entries survive protocol bumps).

Changed

  • Stronger artifact redaction — bundle now redacts via the shared src/util/redactText.ts engine: Bearer/JWT/query-param/env-var secrets, AWS keys, emails, IPs, phone numbers, and home paths (including base64-encoded ones); .json/.ndjson artifacts are re-serialized so they stay parseable after masking. The redact phase reports {redactions, warnings, failures}, fails on write-back failures, and flags unredacted images as warnings. A scanResidualSecrets() helper (known token prefixes + Shannon-entropy gate with a configurable artifact-name allowlist) is available for downstream gates. Clock times and ISO timestamps (which share the IPv6 colon-group shape) and bare ~ prose (~10s) survive redaction unchanged.
  • probe reports instead of throwing when no bridge exists — with nothing discoverable and no explicit --port/--token/--pid, probe now emits a complete result (JSON and human forms) with target.alive=false and an actionable note, so agents can branch on structured output.
  • BRIDGE_VERSION bumped from "0.7.0" to "0.8.0".
  • Cursor-mode /logs: a request carrying {cursor, waitMs ≤ 25000, limit 1..1000} returns {entries, cursor, dropped} without draining the ring buffer; requests with waitMs > 0 long-poll on a worker thread (the accept loop is serial). LogEntry gains a monotonic id. Bare {token} requests keep the legacy drain semantics unchanged, so pre-0.8 CLIs are unaffected.
  • Integrators can re-copy examples/tauri-bridge/src/dev_bridge.rs as a drop-in — no main.rs signature changes this time. Without the re-copy, logs --follow degrades gracefully to drain polling.

Fixed

  • Integer CLI flags now parse reliably. Every .option(..., parseInt, <default>) coercion passed the option default to parseInt as its radix, so explicitly-passed values were ignored (--interval 1000 → NaN → silent fallback to the default) or misparsed (dom --depth 12, default 3, parsed in base 3 as 5). All 24 numeric flag coercions now share a base-10 parseIntArg() helper in commands/shared.ts.
  • Bridge discovery now prefers the newest live bridge. Token files are sorted by mtime (newest first, filename tie-break) instead of readdir order, so running several bridge-enabled apps no longer attaches the CLI to a stale instance.
  • sidecar tap no longer drops or reorders envelopes under bursty output. Async chunk handling is serialized through a promise chain and close waits for it to drain before flushing the trailing line.

[0.8.0] - 2026-06-19

Real-world observability hardening. Everything in this release is additive and backwards-compatible: no command was removed or renamed, no flag changed meaning, no default output changed, and all schema additions are optional-only. The existing test suite passes unchanged; new behavior is opt-in or only affects paths that previously errored.

Added

  • logs — merge a Tauri app's scattered logs into one timestamp-ordered stream. Discovers and normalizes the on-disk tauri-plugin-log LogDir files (auto-resolved from tauri.conf.json, an --identifier, or --log-dir/--log-file) and the live bridge /logs ring buffer, then emits NDJSON (--pretty for humans). Timezone-less timestamps are normalized to UTC so ordering is host-independent. Filters: --level, --source, --filter; --correlate infers run_id/requestId-style correlation ids. Works with no bridge.
  • bundle — collect a shareable incident bundle (merged logs + deep process-tree + app-paths + forensics, plus an optional UI capture) into one directory and a .tar.gz. Secrets (token/api_key/password/…) are redacted from text artifacts on write. Best-effort: each phase degrades cleanly.
  • process-tree --deep — walk the real OS process descendant tree (sidecar children, MCP servers, ML workers — including grandchildren the bridge never registered) via ps. Needs no bridge with an explicit --pid. New optional JSON fields: ppid, children, source, descendants.
  • ipc-monitor --slow <ms> / --stats — flag IPC calls that completed but took ≥ N ms, and print a per-command latency summary (count, max, avg, errors) on exit.
  • --strict flag (shared) — for the v0.7-endpoint commands, fail with the actionable upgrade error instead of degrading.

Changed

  • Graceful degradation against older/vendored bridges. health, capabilities audit, and webview attach now feature-detect via GET /version and emit a clear note: instead of throwing when the bridge predates v0.7 (default behavior; --strict restores the hard error). process-tree without --deep degrades to the OS walk when the bridge lacks /process and the app PID is resolvable, otherwise it still surfaces the actionable upgrade error. This fixes a latent regression where these commands hard-failed against any bridge older than v0.7.0.
  • BridgeClient gained a non-throwing hasEndpoint() capability check (shares the /version cache with requireEndpoint).
  • Agent skills (tauri-agent-tools, tauri-debug-quickstart, tauri-bridge-setup) updated to document the new commands and the degrade-by-default behavior; the now-inaccurate "emits an error against older bridges" guidance was corrected.

Fixed

  • macOS window listing on recent macOS. JXA's ObjC.deepUnwrap on CGWindowListCopyWindowInfo began returning a non-array, so .map threw "list.map is not a function" and broke every macOS window command (screenshot, info, list-windows, snapshot, capture). The adapter now reads the CFArray element-by-element via CFArrayGetCount / CFArrayGetValueAtIndex / castRefToObject, keeping the macOS adapter dependency-free on the built-in osascript (no PyObjC / pip). Thanks to @ethan-krich (#8).

[0.7.1] - 2026-05-18

Fixed

  • Bridge auto-discovery now scans both os.tmpdir() and /tmp, fixing macOS where the Rust dev bridge writes token files to /tmp but Node's os.tmpdir() resolves to /var/folders/.../T/. Closes #5.
  • Dev bridge eval callbacks now use Tauri 2's window.__TAURI_INTERNALS__.invoke path first, so apps no longer need app.withGlobalTauri: true for bridge-backed commands (dom, click, eval, page-state, screenshot --selector, etc.). Closes #7.
  • Documented the missing libc = "0.2" Cargo dependency in rust-bridge/README.md and docs/getting-started/bridge-setup.md. The bridge's /process and /health endpoints depend on libc::kill() for sidecar liveness probing on Unix. Closes #6.

[0.7.0] - 2026-05-13

Added — Agent UX (Tier 3)

  • diagnose — best-effort super-command. Composes forensics (Tier 1) with live bridge data (Tier 2) into one bundle. Always runs the forensics half; layers /process, /capabilities, /devtools, /health on top when a bridge is reachable. Each bridge endpoint is best-effort with per-endpoint error recording — partial bridge availability still produces a useful bundle. Output: <out-dir>/{summary.md, summary.json, bridge.json, forensics/...}. Use --no-bridge to skip the bridge phase entirely.
  • New agent skill: tauri-debug-quickstart — first-30-seconds triage skill (.agents/skills/tauri-debug-quickstart/SKILL.md). Symptom → command table, decision flowchart, and an explicit "when this skill is wrong" section calling out Tauri 1, Windows, and release-build caveats.
  • MkDocs troubleshooting page — docs/troubleshooting/decision-tree.md with a mermaid flowchart mirroring the skill's symptom-table for human readers. Wired into mkdocs.yml nav.

Added — Bridge-extending diagnostics (Tier 2)

Four CLI commands that talk to new dev-bridge endpoints. Each calls GET /version first to feature-detect; against a pre-v0.7 bridge they emit "requires bridge v0.7.0+ — re-copy examples/tauri-bridge/src/dev_bridge.rs" instead of an opaque 404.

  • process-tree — Tauri PID + registered sidecars rendered as a tree with alive/DEAD annotations.
  • capabilities audit — Devtron-style live audit of declared Tauri capabilities, surfacing wildcard "*", over-broad fs:allow-all/shell:allow-*/http:allow-all, and window labels referenced but not registered.
  • webview attach — print the webview inspector URL (webview2 / webkitgtk) or platform hint (wkwebview — Safari activation). --print-url for scripting, --open to launch the default browser.
  • health — uptime + webview readiness + per-sidecar liveness. Exits non-zero when the app is unhealthy so this can drive CI gates.

Changed — Rust dev bridge (BREAKING for integrators)

  • BRIDGE_VERSION bumped from "0.6.0" to "0.7.0".
  • Four new endpoints: /process, /capabilities, /devtools, /health (all POST + token auth).
  • start_bridge now returns (u16, Arc<LogBuffer>, Arc<SidecarRegistry>) instead of (u16, Arc<LogBuffer>). Integrators destructure the third element to register sidecars.
  • spawn_sidecar_monitored now takes an optional Option<&Arc<SidecarRegistry>> so spawned sidecars appear in process-tree/health. Pass None to opt out.
  • New register_sidecar() for users who spawn children manually.
  • Added libc = "0.2" Cargo dep (Unix only) for the cheap kill(pid, 0) liveness probe.

Integrators must re-copy examples/tauri-bridge/src/dev_bridge.rs and adjust main.rs to destructure the new return shape. The CLI's new commands fail loudly with a "re-copy" error against older bridges, so partial upgrades are obvious.

Internal

  • src/bridge/client.ts — new requireEndpoint() helper caches /version per BridgeClient instance, translating missing endpoints into actionable upgrade errors.
  • src/schemas/bridge.ts — added ProcessResponseSchema, CapabilitiesResponseSchema, DevtoolsResponseSchema, HealthResponseSchema.
  • examples/tauri-bridge/ — added minimal tauri.conf.json, build.rs, placeholder icon, and a frontend-stub/index.html so the example crate actually compiles for the first time (it never did).
  • Test count: 696 → 710 (added 7 BridgeClient v0.7 tests + 7 command e2e tests).

Added — Bridge-free diagnostics (Tier 1 of "expand beyond the bridge")

The toolkit can now diagnose Tauri apps without needing a live debug bridge — covering release builds, dead processes, and sidecar protocols.

  • app-paths — resolve a Tauri 2 app's OS data/log/cache/config directories from tauri.conf.json (or a bare --identifier). Encodes Tauri 2's PathResolver semantics for all three platforms; --exists flag annotates which paths are present on disk.
  • config inspect — emit a structured snapshot of tauri.conf.json plus a Devtron-style capability matrix. Cross-checks capability permissions against Cargo.toml's plugin declarations and flags wildcard / over-broad scopes (*, fs:allow-all, shell:allow-spawn, …).
  • os-logs — tail the host OS's log stream filtered to a Tauri bundle id. macOS uses log stream with a subsystem == "<id>" predicate; Linux uses journalctl --user -t <productName>. Output is one normalized NDJSON envelope per line ({ ts, level, source, subsystem, message, raw }). Windows is stubbed for v0.7.
  • sidecar tap / sidecar replay — wrap-and-run a sidecar binary, frame its stdout as NDJSON, validate each envelope against an optional JSON Schema (--schema <path>, powered by Ajv), and record the raw stream to a file with --record. sidecar replay reads the recording back to stdout or pipes it into a fresh process via --to-exec, optionally rate-limited with --rate <lps>.
  • forensics — one-shot bundle for post-crash analysis. Resolves the project, lists files in appDataDir/appLogDir, tails the most-recent log for panic markers, pulls macOS DiagnosticReports filtered by productName, captures a brief live OS-log tail, and writes summary.md + summary.json + supporting artifacts. Zero bridge calls — works on a dead app.

Internal

  • src/util/tauriConfig.ts — tauri.conf.json loader (JSONC-tolerant), identifier resolver for v1+v2 layouts, capability discovery, resolveTauriPaths matching the dirs crate semantics for all three platforms.
  • src/util/ndjson.ts — LineFramer (CRLF/LF, chunked input, blank-line preservation) and NdjsonValidator (Ajv wrapper that distinguishes parse errors from schema mismatches).
  • src/platform/oslog/{darwin,linux,windows}.ts — per-platform OS log adapter pattern, mirrors the existing src/platform/{x11,wayland,...}.ts shape.
  • Per-domain schemas: src/schemas/{tauriConfig,osLog,sidecar}.ts.
  • New dependencies: ajv ^8, ajv-formats ^3 — loaded via createRequire to dodge ESM/CJS interop friction.
  • Command count: 25 → 31. Test count: 623 → 696.

Notes for skill / docs consumers

  • The agent skill (.agents/skills/tauri-agent-tools) now distinguishes bridge-required vs bridge-free commands, and adds a debugging decision tree: bridge is healthy → existing 25 commands; bridge isn't responding → start with forensics; sidecar is the suspect → sidecar tap.

[0.6.0] - 2026-04-04

Added

  • Interaction commands — click, type, scroll, focus, navigate, select for agent-driven UI interaction (debug builds only)
  • invoke command — call Tauri IPC commands from the CLI with JSON payload support
  • store-inspect command — inspect reactive store state (Pinia, Vue devtools, custom __DEBUG_STORES__ hook)
  • capture command — collect screenshot + DOM + page state + storage into a single debug evidence bundle
  • check command — structured assertions against DOM state with pass/fail results
  • probe command — target discovery and bridge health check
  • eval --file option — load JavaScript from a file instead of inline string
  • --pid and --window-label bridge options for multi-app and multi-window targeting
  • BridgeClient multi-window eval via optional windowLabel parameter
  • Zod schemas for interaction command results (schemas/interact.ts)
  • Shared interaction utilities: escapeSelector(), buildFindElementScript()

Changed

  • Rust bridge example: added /version and /describe endpoints, multi-window eval support
  • Command count increased from 14 to 25

[0.5.1] - 2026-03-24

Added

  • src/util/magick.ts — ImageMagick version detection module with caching; auto-detects v6 (standalone convert) vs v7 (unified magick binary) at runtime (#4)

Fixed

  • ImageMagick v7 compatibility — all ImageMagick invocations (convert, import, identify, compare) now route through the version-aware magickCommand() resolver, using magick <subcommand> on v7 and standalone commands on v6
  • resizeImage() backslash escape bug — -resize argument was 800x\> (literal backslash) instead of 800x>, causing "invalid argument" errors on ImageMagick v7
  • Tool availability checks (detect.ts) now recognize magick binary as valid ImageMagick installation, falling back to convert for v6

[0.5.0] - 2026-03-23

Added

  • Hyprland Wayland compositor support via HyprlandAdapter using hyprctl for window management and grim for screenshots (#3 by @gabrielpgagne)
  • HYPRLAND_INSTANCE_SIGNATURE environment variable detection for automatic adapter selection
  • checkHyprlandTools() for verifying Hyprland-specific tool availability
  • HyprClientSchema Zod schema for validated hyprctl clients -j output

Changed

  • DisplayServer type now distinguishes wayland-sway, wayland-hyprland, and generic wayland
  • detectDisplayServer() checks SWAYSOCK and HYPRLAND_INSTANCE_SIGNATURE for compositor-specific adapters
  • checkWaylandTools() renamed to checkSwayTools() for clarity

[0.4.0] - 2026-03-19

Added

  • rust-logs command — monitor Rust backend tracing/log output and sidecar process stdout/stderr in real-time via the bridge's /logs endpoint
  • RustLogEntry type for structured Rust log entries with timestamp, level, target, message, and source fields
  • BridgeClient.fetchLogs() method for polling the /logs endpoint with 404 detection for old bridges
  • Severity-based level filtering (--level warn shows warn and error, matching Rust RUST_LOG convention)
  • --target <regex> filtering by Rust module path
  • --source <source> filtering by origin (rust, sidecar, all, or sidecar:<name>)
  • Rust bridge: LogBuffer ring buffer (max 1000 entries), BridgeLogLayer tracing layer, spawn_sidecar_monitored() helper, POST /logs endpoint, create_log_layer() public API
  • Zod schema validation at all trust boundaries
  • Domain-split schema files (schemas/bridge.ts, schemas/dom.ts, schemas/commands.ts, schemas/platform.ts) with barrel re-export
  • Cross-module boundary integration tests
  • Import DAG linter (scripts/check-imports.mjs)

Changed

  • start_bridge() now returns (u16, Arc<LogBuffer>) instead of u16
  • Bridge example requires tracing and tracing-subscriber crate dependencies
  • Replaced manual validation with Zod enum schemas for levels, modes, and IDs
  • Replaced z.lazy with getter-based recursion for recursive schemas
  • Additional TypeScript strictness options enabled (noUncheckedIndexedAccess, noImplicitReturns, noFallthroughCasesInSwitch)

Fixed

  • CLI output consistency, validation, and discoverability improvements
  • Schema validation hardening, regex safety, and dedup X11 parser
  • parseEnum generics updated for Zod v4 compatibility

[0.3.0] - 2026-03-17

Added

  • diff command — compare two screenshots with pixel-level difference metrics, threshold gating, and diff image output
  • mutations command — watch DOM mutations on a CSS selector with polling, attribute tracking, and auto-cleanup
  • snapshot command — capture screenshot + DOM tree + page state + storage in a single invocation
  • dom --text <pattern> option — find elements by text content (case-insensitive), respects --first, --count, and selector scoping

Fixed

  • CSS selector escaping in mutation observer now escapes backslashes before single quotes (consistent with bridge client)
  • dom --text now scopes search to the provided selector instead of always searching document.body
  • dom --text --first flag is now respected (was previously ignored)
  • diff --threshold now throws a clear error when identify fails instead of silently reporting 0%

Changed

  • buildSerializerScript exported from dom.ts for reuse by snapshot command
  • formatEntry and MutationEntry exported from mutations.ts
  • snapshot deduplicates window discovery via shared resolveWindowId helper

[0.2.1] - 2026-03-17

Fixed

  • CLI --version flag now reads from package.json instead of being hardcoded

[0.2.0] - 2026-03-17

Fixed

  • Dev bridge now returns actual JS eval results instead of echoing back the expression string
  • Uses Tauri command callback pattern (__TAURI__.core.invoke) for reliable round-trip evaluation
  • All bridge-dependent commands (dom, eval, screenshot --selector, storage, console-monitor, ipc-monitor, page-state) now work correctly

Changed

  • Bridge setup requires uuid crate and invoke_handler registration in main.rs
  • Updated integration guide and agent skill with new setup steps

[0.1.0] - 2026-03-17

Added

  • Initial CLI with 10 commands: screenshot, dom, eval, wait, info, list-windows, ipc-monitor, console-monitor, storage, page-state
  • Rust dev bridge with token-authenticated localhost HTTP server
  • Platform support: Linux X11, Linux Wayland/Sway, macOS CoreGraphics
  • Agent Skills (.agents/skills/) and AGENTS.md for agent-driven discovery
  • DOM-targeted pixel capture using bridge + ImageMagick crop
  • Auto-discovery of bridge via /tmp token files
  • All commands read-only with --json structured output