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, andcheckawait promises and preserve JavaScript truthiness before the bridge serializes values.false,0,null, andundefinedno longer look truthy just because they arrived as strings; the string"false"remains truthy. Thrown expressions fail, literalERROR:strings remain ordinary results, and escaped selectors survive transport. Evaluation runs in the webview’s global context without shadowing app globals namedvalue,kind, orencoded. - Bounded waiting and one-time clicks. Poll requests and sleeps share the same overall timeout budget.
click --waitpolls 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-errorsassertions fail instead of reporting success after observing only part of the requested duration; interrupted captures preserve available evidence and record warnings andpartial: 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.
diffchecks 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-bridgenow skips bridge enrichment even with an explicit target.
Added
eval --jsonreturns{ "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
partialandwarningsfields. 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, andcaptureuse 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 --followrequires 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.
waitrequires exactly one condition,checkrequires an assertion, and conflicting evaluation sources, click types, scroll actions, and replay destinations are rejected. Sidecar replay examples quote the complete--to-execvalue 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
targetand generatedgendirectories 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
typeandselectno longer report success while React ignores the value (#10, reported by @papercupai). Values are written through the element's native prototypevaluesetter (HTMLInputElement/HTMLTextAreaElement/HTMLSelectElement.prototype; custom elements are resolved up their prototype chain) instead ofel.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--clearwrite and the final write use the native setter.select --togglenow performs a nativeclick()(React only observesclickfor checkbox/radio) instead of assigningel.checkedand firing a syntheticchange, which never reached React either.type/selectscripts are wrapped intry/catchand always return JSON; a bridgeERROR: …payload or non-JSON result now surfaces as an actionable error instead of aSyntaxErrorfromJSON.parse.el.select()is guarded (absent on<select>and custom elements), andselectvalues are JSON-escaped, so values containing newlines no longer produce a script syntax error.
Added
- Write verification for
typeandselect— after dispatchinginput/changethe element is re-read synchronously and then polled (50 ms, default deadline 500 ms). The outcome is reported in new optional result fieldsverified,verification(matched|transformed|reverted),requestedValue,previousValue(previousCheckedfor--toggle),options, andhint. A write the app rolls back (reverted) fails withValue reverted: …(Checked state reverted: …for--toggle) plus a hint on stderr, and the failure object is printed to stdout (type --json;selectalways prints JSON) —verification: "reverted"is the stable signal for scripts; a value the app reformats (masks, formatters) is a success withverification: "transformed"andverified: false. Therevertedbaseline is taken afterfocus()/--clearhave 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.abcintotype=number) fails withBrowser discarded the value: …and the field is restored to what it held right before the write (after--clear, to the pre-clear value, with aninputevent so the app sees the restore); a value the browser clamps or sanitizes back onto the field's current value (e.g.50into atype=rangealready at itsmaxof 10) fails withBrowser did not take the value: …with no events dispatched — a clamp that lands on a different value (50into a range at 5 →10) is amatchedsuccess carrying the normalizedvalueand the originalrequestedValue; a field the app empties after a non-empty write fails withValue cleared: …; an element that leaves the document (or is re-mounted) after focus/--clearis 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 reflectvalueasynchronously 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 insidedispatchEvent); frameworks that leave a rejected value in the DOM are reported asmatched. typeandselectfail fast when the target is a<select>with no<option>matching the value, listing the available values in theoptionsfield and the hint (previously reported success withvalue: "").- Shared helpers in
src/commands/interact/shared.ts(buildSetValueScript(), theNATIVE_VALUE_WRITER_SNIPPET/VERIFY_POLL_SNIPPET/SETTLE_SNIPPET/SELECT_OPTIONS_SNIPPETscript fragments, the verify-timeout constants and option wiring,parseInteractResult()) andWriteVerificationSchemainsrc/schemas/interact.ts. - Regression fixture
tests/integration/react-controlled-forms.test.tsruns 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, andjsdomare added as devDependencies only.
Changed
typeandselect(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/radiovalueattribute — and reported success).type's human output appends a note when the app transformed or the browser normalized the requested value.- On failure,
type --jsonandselectprint the failure result object (error,hint, and anyverification/options/previousValuefields) to stdout before exiting 1; previously only the error message reached stderr. select --togglerefuses 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.selectvalue mode dispatchesinputbeforechange(native order; previously change then input).- Only a
matchedwrite resolves immediately;revertedandtransformedoutcomes 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>onscreenshot,info,snapshot, andcapture(#9, reported by @papercupai) — target a window by its platform id (fromlist-windows) instead of a--titleregex. SkipsfindWindow()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 underxdotool search) become addressable. The id passes through unvalidated at the CLI layer — its format is adapter-specific (X11/macOS/Sway numeric, Hyprland hex0x…); adapters that shell-interpolate ids keep their existingvalidateWindowId()guards.screenshot --window-idfull-window capture needs no bridge at all. Unrelated to--window-label(Tauri webview label, a bridge concept).- Shared
resolveWindowId()export fromsrc/commands/shared.ts(windowId > title > bridgedocument.titleprecedence), replacing three duplicated per-command resolution helpers.CaptureToDirOptionsgains an optionalwindowIdfield, andscreenshot --jsonoutput now includes the resolvedwindowId(both additive).
Changed
info --titleis no longer a required option — one of--titleor--window-idsuffices.--titlehelp 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 adropped-count warning. Against a pre-0.8 bridge it emits a one-timenote:and degrades to drain polling every--intervalms.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 theCaptureManifest, 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/logscursor mode. A pre-0.8 bridge answers without acursorfield, so callers feature-detect by response shape with no extra round-trips (this is howlogs --followdecides to degrade to drain polling). The legacyfetchLogs(timeout?)drain call is unchanged; log-entry/response schemas gain optionalid,cursor, anddroppedfields.scripts/check-bridge-parity.mjs(npmcheck:bridge-parity, part ofnpm run lint) — lint gate that regex-parsesBRIDGE_VERSION+ the endpoint list fromdev_bridge.rsandENDPOINT_MIN_VERSIONfromclient.ts, failing on missing/extra entries or a min-version aboveBRIDGE_VERSION(semver compare, so legacy entries survive protocol bumps).
Changed
- Stronger artifact redaction —
bundlenow redacts via the sharedsrc/util/redactText.tsengine: Bearer/JWT/query-param/env-var secrets, AWS keys, emails, IPs, phone numbers, and home paths (including base64-encoded ones);.json/.ndjsonartifacts 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. AscanResidualSecrets()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. probereports 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) withtarget.alive=falseand an actionablenote, so agents can branch on structured output.
Changed — Rust dev bridge (re-copy recommended, drop-in)
BRIDGE_VERSIONbumped 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 withwaitMs > 0long-poll on a worker thread (the accept loop is serial).LogEntrygains a monotonicid. 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.rsas a drop-in — nomain.rssignature changes this time. Without the re-copy,logs --followdegrades gracefully to drain polling.
Fixed
- Integer CLI flags now parse reliably. Every
.option(..., parseInt, <default>)coercion passed the option default toparseIntas 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-10parseIntArg()helper incommands/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 tapno longer drops or reorders envelopes under bursty output. Async chunk handling is serialized through a promise chain andclosewaits 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-disktauri-plugin-logLogDir files (auto-resolved fromtauri.conf.json, an--identifier, or--log-dir/--log-file) and the live bridge/logsring buffer, then emits NDJSON (--prettyfor humans). Timezone-less timestamps are normalized to UTC so ordering is host-independent. Filters:--level,--source,--filter;--correlateinfersrun_id/requestId-style correlation ids. Works with no bridge.bundle— collect a shareable incident bundle (mergedlogs+ deepprocess-tree+app-paths+forensics, plus an optional UIcapture) 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) viaps. 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.--strictflag (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, andwebview attachnow feature-detect viaGET /versionand emit a clearnote:instead of throwing when the bridge predates v0.7 (default behavior;--strictrestores the hard error).process-treewithout--deepdegrades to the OS walk when the bridge lacks/processand 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. BridgeClientgained a non-throwinghasEndpoint()capability check (shares the/versioncache withrequireEndpoint).- 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.deepUnwraponCGWindowListCopyWindowInfobegan returning a non-array, so.mapthrew"list.map is not a function"and broke every macOS window command (screenshot,info,list-windows,snapshot,capture). The adapter now reads theCFArrayelement-by-element viaCFArrayGetCount/CFArrayGetValueAtIndex/castRefToObject, keeping the macOS adapter dependency-free on the built-inosascript(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/tmpbut Node'sos.tmpdir()resolves to/var/folders/.../T/. Closes #5. - Dev bridge eval callbacks now use Tauri 2's
window.__TAURI_INTERNALS__.invokepath first, so apps no longer needapp.withGlobalTauri: truefor bridge-backed commands (dom,click,eval,page-state,screenshot --selector, etc.). Closes #7. - Documented the missing
libc = "0.2"Cargo dependency inrust-bridge/README.mdanddocs/getting-started/bridge-setup.md. The bridge's/processand/healthendpoints depend onlibc::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. Composesforensics(Tier 1) with live bridge data (Tier 2) into one bundle. Always runs the forensics half; layers/process,/capabilities,/devtools,/healthon 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-bridgeto 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.mdwith a mermaid flowchart mirroring the skill's symptom-table for human readers. Wired intomkdocs.ymlnav.
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 withalive/DEADannotations.capabilities audit— Devtron-style live audit of declared Tauri capabilities, surfacing wildcard"*", over-broadfs: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-urlfor scripting,--opento 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_VERSIONbumped from"0.6.0"to"0.7.0".- Four new endpoints:
/process,/capabilities,/devtools,/health(all POST + token auth). start_bridgenow returns(u16, Arc<LogBuffer>, Arc<SidecarRegistry>)instead of(u16, Arc<LogBuffer>). Integrators destructure the third element to register sidecars.spawn_sidecar_monitorednow takes an optionalOption<&Arc<SidecarRegistry>>so spawned sidecars appear inprocess-tree/health. PassNoneto opt out.- New
register_sidecar()for users who spawn children manually. - Added
libc = "0.2"Cargo dep (Unix only) for the cheapkill(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— newrequireEndpoint()helper caches/versionperBridgeClientinstance, translating missing endpoints into actionable upgrade errors.src/schemas/bridge.ts— addedProcessResponseSchema,CapabilitiesResponseSchema,DevtoolsResponseSchema,HealthResponseSchema.examples/tauri-bridge/— added minimaltauri.conf.json,build.rs, placeholder icon, and afrontend-stub/index.htmlso 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 fromtauri.conf.json(or a bare--identifier). Encodes Tauri 2'sPathResolversemantics for all three platforms;--existsflag annotates which paths are present on disk.config inspect— emit a structured snapshot oftauri.conf.jsonplus a Devtron-style capability matrix. Cross-checks capability permissions againstCargo.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 useslog streamwith asubsystem == "<id>"predicate; Linux usesjournalctl --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 replayreads 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 inappDataDir/appLogDir, tails the most-recent log for panic markers, pulls macOSDiagnosticReportsfiltered byproductName, captures a brief live OS-log tail, and writessummary.md+summary.json+ supporting artifacts. Zero bridge calls — works on a dead app.
Internal
src/util/tauriConfig.ts—tauri.conf.jsonloader (JSONC-tolerant), identifier resolver for v1+v2 layouts, capability discovery,resolveTauriPathsmatching thedirscrate semantics for all three platforms.src/util/ndjson.ts—LineFramer(CRLF/LF, chunked input, blank-line preservation) andNdjsonValidator(Ajv wrapper that distinguishes parse errors from schema mismatches).src/platform/oslog/{darwin,linux,windows}.ts— per-platform OS log adapter pattern, mirrors the existingsrc/platform/{x11,wayland,...}.tsshape.- Per-domain schemas:
src/schemas/{tauriConfig,osLog,sidecar}.ts. - New dependencies:
ajv^8,ajv-formats^3 — loaded viacreateRequireto 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 withforensics; sidecar is the suspect →sidecar tap.
[0.6.0] - 2026-04-04
Added
- Interaction commands —
click,type,scroll,focus,navigate,selectfor agent-driven UI interaction (debug builds only) invokecommand — call Tauri IPC commands from the CLI with JSON payload supportstore-inspectcommand — inspect reactive store state (Pinia, Vue devtools, custom__DEBUG_STORES__hook)capturecommand — collect screenshot + DOM + page state + storage into a single debug evidence bundlecheckcommand — structured assertions against DOM state with pass/fail resultsprobecommand — target discovery and bridge health checkeval --fileoption — load JavaScript from a file instead of inline string--pidand--window-labelbridge options for multi-app and multi-window targetingBridgeClientmulti-window eval via optionalwindowLabelparameter- Zod schemas for interaction command results (
schemas/interact.ts) - Shared interaction utilities:
escapeSelector(),buildFindElementScript()
Changed
- Rust bridge example: added
/versionand/describeendpoints, 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 (standaloneconvert) vs v7 (unifiedmagickbinary) at runtime (#4)
Fixed
- ImageMagick v7 compatibility — all ImageMagick invocations (
convert,import,identify,compare) now route through the version-awaremagickCommand()resolver, usingmagick <subcommand>on v7 and standalone commands on v6 resizeImage()backslash escape bug —-resizeargument was800x\>(literal backslash) instead of800x>, causing "invalid argument" errors on ImageMagick v7- Tool availability checks (
detect.ts) now recognizemagickbinary as valid ImageMagick installation, falling back toconvertfor v6
[0.5.0] - 2026-03-23
Added
- Hyprland Wayland compositor support via
HyprlandAdapterusinghyprctlfor window management andgrimfor screenshots (#3 by @gabrielpgagne) HYPRLAND_INSTANCE_SIGNATUREenvironment variable detection for automatic adapter selectioncheckHyprlandTools()for verifying Hyprland-specific tool availabilityHyprClientSchemaZod schema for validatedhyprctl clients -joutput
Changed
DisplayServertype now distinguisheswayland-sway,wayland-hyprland, and genericwaylanddetectDisplayServer()checksSWAYSOCKandHYPRLAND_INSTANCE_SIGNATUREfor compositor-specific adapterscheckWaylandTools()renamed tocheckSwayTools()for clarity
[0.4.0] - 2026-03-19
Added
rust-logscommand — monitor Rust backendtracing/logoutput and sidecar process stdout/stderr in real-time via the bridge's/logsendpointRustLogEntrytype for structured Rust log entries with timestamp, level, target, message, and source fieldsBridgeClient.fetchLogs()method for polling the/logsendpoint with 404 detection for old bridges- Severity-based level filtering (
--level warnshows warn and error, matching RustRUST_LOGconvention) --target <regex>filtering by Rust module path--source <source>filtering by origin (rust,sidecar,all, orsidecar:<name>)- Rust bridge:
LogBufferring buffer (max 1000 entries),BridgeLogLayertracing layer,spawn_sidecar_monitored()helper,POST /logsendpoint,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 ofu16- Bridge example requires
tracingandtracing-subscribercrate dependencies - Replaced manual validation with Zod enum schemas for levels, modes, and IDs
- Replaced
z.lazywith 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
parseEnumgenerics updated for Zod v4 compatibility
[0.3.0] - 2026-03-17
Added
diffcommand — compare two screenshots with pixel-level difference metrics, threshold gating, and diff image outputmutationscommand — watch DOM mutations on a CSS selector with polling, attribute tracking, and auto-cleanupsnapshotcommand — capture screenshot + DOM tree + page state + storage in a single invocationdom --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 --textnow scopes search to the provided selector instead of always searchingdocument.bodydom --text --firstflag is now respected (was previously ignored)diff --thresholdnow throws a clear error whenidentifyfails instead of silently reporting 0%
Changed
buildSerializerScriptexported fromdom.tsfor reuse bysnapshotcommandformatEntryandMutationEntryexported frommutations.tssnapshotdeduplicates window discovery via sharedresolveWindowIdhelper
[0.2.1] - 2026-03-17
Fixed
- CLI
--versionflag now reads frompackage.jsoninstead 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
uuidcrate andinvoke_handlerregistration inmain.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/) andAGENTS.mdfor agent-driven discovery - DOM-targeted pixel capture using bridge + ImageMagick crop
- Auto-discovery of bridge via
/tmptoken files - All commands read-only with
--jsonstructured output