Commit Graph
770 Commits
Author SHA1 Message Date
leeguooooo e8864c96e2 chore(release): 1.2.2 — non-blocking 'update available' notice + release changelogs
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
- feat(cli): non-blocking update-available notice (stderr, once/day, opt-out) so users learn to upgrade
- ci(release): auto-generate changelog from commit log on every release
v1.2.2
2026-06-12 22:47:03 +09:00
leeguooooo 8432f6cd69 feat(cli): non-blocking 'update available' notice so users know to upgrade
The CLI ships as a GitHub Release binary with a manual `chrome-use upgrade`,
but nothing told users a newer version existed — so releases didn't reach them.

Add a lightweight update check: each run reads a cached latest-version and, if
it's newer than the running binary, prints a one-line hint to STDERR (never
stdout, so --json stays clean): "⚠ chrome-use X.Y.Z is available — run
chrome-use upgrade". The cache is refreshed at most once a day by a DETACHED
`__update-check` worker (curl → GitHub latest release), so the current command
never waits on the network. Skipped for meta commands (upgrade/install/doctor/
__*/--version/--help), in CI, in daemon mode, and via
CHROME_USE_NO_UPDATE_CHECK / AGENT_BROWSER_NO_UPDATE_CHECK.

Verified: nag shows for a newer cached version, suppressed by the opt-out env +
on meta commands + when up-to-date; the detached worker writes the real latest
tag from the GitHub API.
2026-06-12 22:46:44 +09:00
leeguooooo a8089310a6 ci(release): build changelog from commit log (not PR-only notes)
GitHub's generate_release_notes only lists merged PRs — near-empty for this
commit-to-main repo, so releases still showed nothing. Render the
conventional-commit subjects since the previous tag instead, and full-clone
(fetch-depth:0) so the diff is available.
2026-06-12 18:18:11 +09:00
leeguooooo ab92d2590b ci(release): auto-generate release changelog (commits + merged PRs since last tag)
GitHub Releases had an empty body — you couldn't tell what changed between
versions. Add generate_release_notes:true so every release ships an
auto-generated changelog.
2026-06-12 18:15:18 +09:00
leeguooooo c1417c3c70 chore(release): 1.2.1 — relay tab-drift pin on open (#14/#18) + stable per-tab relay session (#17)
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
- fix(relay): pin active target on open so commands don't drift tabs (#14, #18)
- fix(connect): stable per-tab relay session id — re-attach auto-recovers (#17)
- docs: chrome-use test in README
v1.2.1
2026-06-12 18:08:49 +09:00
郭立lee 7cb69bd444 fix(relay): pin active target on open so commands don't drift tabs (#14) (#18)
When connected to the user's real Chrome via the extension relay, sequential
commands could land on the wrong tab: `get url` returned x.com/home, then with
no navigation in between `eval` executed against x.com/notifications — so it
read the wrong page and returned nothing.

Root cause: the session's anti-drift anchor is `active_target_id` (pinned by
stable target_id), documented to be set "on every explicit open". But `open`
runs through `navigate()`, which never pinned. On the relay path `open` reuses
an existing tab via `navigate` rather than `add_page` (the only "explicit" path
that pins), so `active_target_id` stayed `None` and the session rode the fragile
`active_page_index`. A later passive tab close/reorder (drained before every
command) then drifted `eval`/`get url`/`snapshot` onto a foreign tab.

Fix:
- `navigate()` now syncs the index to the resolved active page and pins it by
  target_id after a successful navigation — restoring the "pin on explicit open"
  invariant for the relay path.
- `ensure_page()` pins its freshly-created tab too (matches `add_page`).
- Extract the pin-vs-index resolution into a pure `resolve_active_index()` and
  cover the invariant with unit tests (pin beats stale index; falls back when
  the pin is gone; survives passive background-tab discovery).

cargo fmt + clippy -D warnings clean; full suite 816 passed.
2026-06-12 17:02:21 +08:00
leeguooooo fb27835ebc fix(connect): stable per-tab relay session id — re-attach auto-recovers (#17)
When a tab's chrome.debugger session was torn down and re-established
(cross-process navigation, MV3 service-worker restart wiping the in-memory
maps, DevTools stealing the debugger), the extension minted a brand-new
monotonic `cb-tab-N` for the same tab. The daemon stays bound to the old id and
the relay consumes attach/detach events without telling it to rebind, so the
session was orphaned permanently → `stale sessionId / tab is gone`, and re-open
never recovered.

Derive the session id from the STABLE Chrome tabId (`cb-tab-<tabId>`) instead.
Any re-attach of the same tab now restores the SAME session the daemon already
holds, so eval/snapshot transparently follow the new page after a navigation.
Extension 0.4.3 → 0.4.4. Adds a relay unit test for the detach→reattach-same-
session recovery contract.
2026-06-12 17:43:48 +09:00
leeguooooo 2859da7b7c docs: document chrome-use test in README + point core skill at it 2026-06-12 17:33:24 +09:00
leeguooooo 9ba43e0cbd chore(release): 1.2.0 — chrome-use test (browser test suites)
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
v1.2.0
2026-06-12 17:27:38 +09:00
leeguooooo d740884299 feat(test): chrome-use test <suite.yaml> — re-runnable browser test suites
Turn repetitive browser checks into unit-test-style YAML suites. Steps reuse
chrome-use's own commands; assertions (url/visible/hidden/text/count/eval)
compile to a single truthy `eval`. The runner re-invokes the binary per step
(inherits all flag/launch/daemon/ref semantics; the daemon stays up so each
step is a fast socket call), launches an isolated browser by default, captures a
screenshot on failure, and exits non-zero for CI. `setup: account:` injects a
cookie-use login. Ships a `test` skill (skills get test). Unit-tested step/assert
compilation.
2026-06-12 17:27:38 +09:00
leeguooooo db484f2ac9 fix(cli): absolute screenshot path (#16) + show relay in session list (#15)
#16: handle_screenshot now returns a canonicalized ABSOLUTE path, so the
`✓ Screenshot saved to …` line is the same regardless of process cwd and the
agent can read the file without guessing the cwd.

#15: `session list` now reflects the extension-relay connection — when the relay
is up it shows the active session as `(relay/extension → live Chrome)` instead
of "No active sessions", and the --json output gains a `relay` bool. Stops agents
misjudging a live relay connection as down.
2026-06-12 16:43:39 +09:00
leeguooooo b475038e25 fix(upload): actionable error when file upload hits the extension-relay limit (#13)
DOM.setFileInputFiles is forbidden by Chrome's chrome.debugger API, so upload
always fails over the extension relay with an opaque -32000 "Not allowed". Map
it to a clear message: file upload needs a --launch/direct-CDP session, and
point at the cookies export|set --curl workaround. Note the limit in the core
skill upload line too.
2026-06-12 16:09:55 +09:00
leeguooooo 545e2545b4 fix(cookies): drop needless return in transfer arm (clippy -D warnings, CI red)
The cookies transfer arm's tail `return Ok(...)` tripped clippy::needless_return,
failing the CI lint gate (-D warnings). Make it a tail expression.
2026-06-12 15:49:16 +09:00
leeguooooo 5f342e34a2 docs(store): rewrite submission guide for rename-existing-item flow
The CWS rename to chrome-use updates the EXISTING item (knfcmbam…) with a
key-stripped package, not a new key-locked item — existing users auto-update and
reviews are kept. Native host allow_origins already lists both ids so the relay
doesn't break. Also point the icon/screenshots section at the generated assets.
2026-06-12 15:43:43 +09:00
leeguooooo 4106a151a1 feat(connect): install + recognize BOTH native-messaging host names (staged extension migration)
Stage 1 of the agent-browser → chrome-use extension migration: the CLI now
writes a host manifest under both com.agent_browser.connect (extension ≤0.4.2)
AND com.leeguoo.chrome_use (the rebrand 0.5.0+), both pointing at the same
launcher, and host_installed()/uninstall recognize both. So the relay works no
matter which extension version a user has, with no forced re-install — which
lets the store roll 0.4.3 (cosmetic name only, host unchanged) and later 0.5.0
(new host) without ever breaking the relay or re-popping the consent dialog.
2026-06-12 14:50:42 +09:00
leeguooooo eb60053183 fix(launch): serialize concurrent same-profile launches (issue #11)
N parallel `open --profile <same>` (e.g. chatgpt-imagegen's web backend firing
3 image gens at once) collided on the profile-copy disk I/O and Chrome's profile
lock: every candidate burned its full ~30s launch timeout and ALL failed (0
success), because the loser instances hung without writing DevToolsActivePort.

ProfileLaunchLock takes a cross-process flock on a per-resolved-profile lock
file, held across the copy + launch until Chrome is up, so concurrent
same-profile launches queue instead of colliding — the storm becomes
all-succeed-serially instead of all-fail. The kernel releases the lock when the
holder exits, so a crash can't wedge the queue; acquisition is best-effort
(launch proceeds unlocked if it can't be taken). Uncontended single launches
are unaffected.
2026-06-12 14:40:03 +09:00
leeguooooo 2aa216dd7a fix(config): brand-compat config dir (~/.chrome-use ⇄ ~/.agent-browser) so the relay survives the rename
After the agent-browser → chrome-use rename, the new binary used ~/.chrome-use
+ host com.leeguoo.chrome_use and couldn't find the relay that the still-old
native-messaging host wrote to ~/.agent-browser → it fell back to raw
--remote-debugging-port and re-popped 'Allow remote debugging?'.

- config_home()/config_dir_basename(): decide once per run — prefer the new
  .chrome-use, but keep using an existing .agent-browser install if that's the
  only one present; fresh installs get .chrome-use. get_socket_dir() routes
  through it so sockets/state are consistent within a run.
- relay_url_path(): the relay-cdp-url is a cross-binary handoff (host writes,
  CLI reads), so read from whichever brand dir actually has the file
  (~/.chrome-use OR ~/.agent-browser).

Combined with keeping HOST_NAME=com.agent_browser.connect (b6febbe), the renamed
chrome-use binary now relays through the existing ab-connect 0.4.2 extension
with zero dialog. Verified live: chrome-use found ~/.agent-browser/relay-cdp-url
and listed the user's real tabs, no consent dialog.
2026-06-12 14:29:21 +09:00
leeguooooo b6febbef39 fix(connect): keep native-messaging host as com.agent_browser.connect (no relay break)
Reverting the host-name rename from the chrome-use rebrand. The host name is
invisible internal plumbing (lives only in NativeMessagingHosts/*.json and the
extension), so renaming it to com.leeguoo.chrome_use bought nothing user-facing
but broke the relay for every existing user: the new chrome-use binary couldn't
find a matching host/extension, silently fell back to raw --remote-debugging-port,
and re-popped the 'Allow remote debugging?' consent dialog.

Keeping com.agent_browser.connect means the renamed chrome-use binary keeps
working with the already-installed host json and the live ab-connect 0.4.2
extension — zero relay break, no dialog, and the store republish becomes an
OPTIONAL cosmetic display-name update (manifest bumped 0.5.0 → 0.4.3, name stays
chrome-use). Only the binary/command name changed for users.
2026-06-12 14:07:10 +09:00
leeguooooo 5addb94dc4 chore(release): 1.1.0 — cross-profile cookies export/transfer
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
v1.1.0
2026-06-12 13:59:38 +09:00
leeguooooo f76ed1ddf5 feat(cookies): cross-profile cookies export / cookies transfer
Transferring a logged-in session between Chrome profiles previously needed
an ad-hoc external script to decrypt the source profile's cookie store. Make
it first-class:

- `cookies export --from <profile> [--domain <d>[,<d>]]` decrypts another
  profile's on-disk cookies and prints CDP-shaped JSON for `cookies set --curl`.
- `cookies transfer --from <profile> [--domain <d>]` exports + injects into
  the connected browser in one shot (reuses the cookies_set path).

Source profile is resolved by directory name, display name, or "auto". The
store is copied to a temp file (immune to a running Chrome's lock/WAL), read
via sqlite3, and values are decrypted (macOS v10: AES-128-CBC, key from the
shared 'Chrome Safe Storage' Keychain entry). httpOnly/secure/per-domain
auth cookies round-trip intact; SameSite=None without Secure is downgraded
so CDP accepts it. macOS only for now (clear error elsewhere).
2026-06-12 13:59:37 +09:00
leeguooooo 7ba82bc6cc art: redo all README illustrations in crude MS-Paint style
Regenerated hero, fingerprint, how-it-works, architecture, and shield as
deliberately crude mouse-drawn Windows-Paint doodles on white — big blocky
flood-fill colors, wobbly aliased outlines, low-res, intentionally rough.
2026-06-12 13:38:12 +09:00
leeguooooo 61060486f4 rebrand: agent-browser-stealth → chrome-use, de-fork, reset to v1.0.0
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
Standalone product rename across the whole repo (issue: project identity):

- Binary/package/repo/skill/docs: agent-browser[-stealth] → chrome-use
  (single binary name `chrome-use`; old aliases agent-browser/abs dropped).
- Version: 0.27.0-fork.51 → 1.0.0 (drop the upstream-fork counter).
- Native-messaging host: com.agent_browser.connect → com.leeguoo.chrome_use
  (CLI + ab-connect extension in lockstep — this is a breaking handshake change,
  extension bumped 0.4.2 → 0.5.0, needs a Web Store republish).
- Config dir: ~/.agent-browser → ~/.chrome-use.
- README/zh: reframed from "stealth fork of agent-browser" to a standalone
  product with a small `originally based on vercel-labs/agent-browser` credit.
- Kept AGENT_BROWSER_* env vars working (63 vars across the codebase; renaming
  them would break every existing script/skill for no user-facing gain).

Build green, 802 unit tests pass, fmt + clippy clean. Upstream attribution to
vercel-labs/agent-browser preserved.
v1.0.0
2026-06-12 12:56:21 +09:00
leeguooooo b4c1707a01 fix(open): graceful load-timeout + --wait-until override for SPAs (issue #10)
`open` waits for the `load` event by default. SPAs whose `load` never fires
(a long-pending XHR or a stuck sub-resource holds it open) made `open`
hard-fail after the lifecycle timeout — even though the DOM was ready and
eval/screenshot worked immediately right after.

- Graceful degradation: if the lifecycle event times out but document.readyState
  is interactive/complete, navigate returns success carrying a `warning` in the
  response (the CLI prints it to stderr; --json keeps the field) instead of
  erroring. Only a still-loading document is a real failure.
- `open/goto/navigate` now accept `--wait-until <load|domcontentloaded|
  networkidle|none>` so SPAs can return as soon as the DOM is parsed. The URL
  parser skips the --wait-until value so it isn't mistaken for the URL.
- WaitUntil::as_str() for the warning label; output.rs surfaces response warnings.

Verified live: --wait-until domcontentloaded returns immediately on a page whose
load never fires; default load on the same page now succeeds at the timeout with
a clear stderr warning instead of failing. Adds parse tests for both arg orders
+ bogus value.
2026-06-12 12:19:36 +09:00
leeguooooo 266b610358 feat(launch): label the throwaway --launch profile + document escape hatches (issue #9)
A bare --launch opens an isolated empty profile (no cookies/login/
extensions). A human watching the desktop sees a mystery Chrome window
under an unfamiliar profile and reads it as broken/suspicious.

- Seed the temp profile's Local State (profile.info_cache.Default.name,
  the field Chrome's profile chip reads) + Default/Preferences with
  'agent-browser (<session>)', so the window self-identifies which agent
  session owns it.
- Rewrite the --launch warning to explain it's an isolated test profile and
  point at the escape hatches: --profile auto / AGENT_BROWSER_PROFILE=auto
  to reuse real Chrome, and --args "--load-extension=<dir>" for extensions.
- SKILL.md documents the same.

Adds a unit test for the profile-label writer.
2026-06-12 12:07:46 +09:00
leeguooooo 36f9b99549 docs(skill/help): document fork.51 features — coordinate click, aliases, stale-sessionId + @url drift checks
SKILL.md + click --help + README now cover what agents could otherwise
only discover by trial:
- coordinate click (click <x> <y> / <x>,<y> / --coords) as a first-class form
- tabs / get-text aliases
- the 'stale sessionId … re-open your target URL' relay error and how to recover
- eval/screenshot/network '@ <url>' stamps as a per-read wrong-tab sanity check
- network requests --clear as the 'start capturing fresh' step
2026-06-12 09:56:02 +09:00
leeguooooo 0cf7de2dd6 style: rustfmt the issue #7 regression tests (CI format gate)
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
v0.27.0-fork.51
2026-06-12 01:42:36 +09:00
leeguooooo 658bf4226f chore(release): 0.27.0-fork.51 — --launch Illegal-invocation fix, tab-pin hardening (#7), field-report ergonomics + observability (#8)
- fix(stealth): bind iframe contentWindow proxy methods to the real window
  (--launch "Illegal invocation" on srcdoc-iframe pages)
- fix(tabs): re-pin active target when the pinned page is removed (issue #7)
- feat(cli): coordinate click (click <x> <y> / --coords), tabs/get-text
  aliases, clearer find error (issue #8.4)
- fix(observability): screenshot/network stamp @ <url>; network --clear
  enables capture immediately (issues #8.1/#8.3)
- fix(ab-connect 0.4.2): stale sessionId fails loudly instead of routing to a
  random tab (issue #8.1) — needs a Chrome Web Store republish
- restart notice now flags in-memory context reset (issue #8.2)
2026-06-12 01:39:29 +09:00
leeguooooo 37cd9b91e1 fix(ab-connect): fail loudly on a stale sessionId instead of routing to a random tab (issue #8.1)
handleForwardCdpCommand fell through to anyConnectedTab() when a
daemon-supplied sessionId didn't map to an attached tab, so eval/screenshot/
network silently ran on an arbitrary tab — the root of "eval ran on the
wrong page, no warning" and the blank-screenshot-after-restart symptom.

Now: a provided sessionId/targetId MUST resolve to a real tab or the command
throws an actionable error ("stale sessionId … re-open your target URL").
anyConnectedTab() is only used for genuinely browser-level commands that
specify neither. Manifest 0.4.1 → 0.4.2 (needs a Chrome Web Store republish
for installed users to pick this up).
2026-06-12 01:34:15 +09:00
leeguooooo b2c4aa0004 fix(observability): stamp page URL on screenshot/network; enable capture on --clear (issue #8)
Field report #8: in extension-relay sessions, reads (eval/screenshot/network)
could silently run against whatever tab drifted into focus, with no signal,
and network capture was intermittently empty.

- #8.1: screenshot and `network requests` now print `screenshot @ <url>` /
  `network @ <url>` to stderr (mirrors the existing `eval @ <url>`), and the
  responses carry `origin`. A read against the wrong/drifted tab — and the
  "0 captured" vs "wrong page" ambiguity — is now obvious.
- #8.3: `network requests --clear` now enables Network capture immediately
  instead of lazily on the next read, so requests fired between `--clear` and
  the following read are tracked (fixes the "No requests captured" on first
  try, works on retry" race). Extracted enable_request_tracking helper.
- #8.2: the daemon version-mismatch restart notice now spells out that
  in-memory context (active tab, refs, captured requests) is reset and tells
  the user to re-open the target URL if the next read looks blank/wrong.

Verified on a launched browser: coordinate clicks land, screenshot/network
stamps appear, and a fetch after --clear is captured on the first read.
2026-06-12 01:34:15 +09:00
leeguooooo ec8d01ef4c feat(cli): coordinate click + command aliases + clearer find error (issue #8.4)
Field-report ergonomics fixes so agents stop wasting a round on a wrong guess:

- Coordinate click is now first-class: `click <x> <y>`, `click <x>,<y>`,
  and `click --coords <x>,<y>` dispatch a raw viewport-point click (no
  element resolution), reusing the humanize trajectory + press dwell. Was
  previously only reachable via eval(elementFromPoint(...).click()).
- Aliases: `tabs` (plural) → the `tab` subcommand tree; `get-text`/`get_text`
  → `get text <selector>`.
- `find <value> <action>` with a bare value (no locator keyword), e.g.
  `find "I'm not a robot" click`, now errors with the corrected command
  (`find text "I'm not a robot" click`) plus concrete examples, instead of
  a bare "Valid options: role, text, ..." list.

Adds parse-layer regression tests for every form.
2026-06-12 01:21:39 +09:00
leeguooooo 0e5409a81e fix(tabs): re-pin active target when the pinned page is removed (issue #7)
remove_page_by_target_id left active_target_id dangling when the pinned
page itself was removed, so resolved_active_index silently fell back to
active_page_index — which after a passive about:blank discovery can point
at a blank tab. That matches issue #7's intermittent symptom: `wait` then
eval/snapshot landing on about:blank in a --launch session.

Re-pin to the surviving active page after removing the pinned target so
the pin is never left pointing at a target that no longer exists. Adds
pure regression tests for the re-anchor invariant (BrowserManager needs a
live CDP client, so the method can't be unit-constructed directly).
2026-06-12 01:05:33 +09:00
leeguooooo 3ded30c210 fix(stealth): bind iframe contentWindow proxy methods to the real window
The srcdoc-iframe contentWindow Proxy returned native window methods
unbound, so iframe.contentWindow.getComputedStyle()/addEventListener()/
setTimeout() ran with the Proxy as `this` and threw "Illegal invocation"
on any page that uses a srcdoc iframe under --launch (FullLaunch). The
sibling matchMedia proxy already bound its methods; this one did not.

Wrap each function in an apply/construct trap that swaps the Proxy
receiver for the real window while passing .prototype/.name/.toString/
identity straight through (a plain .bind() drops .prototype and breaks
instanceof/constructors). Cached in a WeakMap for stable identity.

Verified before/after on a launched stealth browser: getComputedStyle,
addEventListener, setTimeout all OK; .prototype preserved.
2026-06-12 01:05:33 +09:00
leeguooooo 6e50f0ecab chore(release): 0.27.0-fork.50 — tab-title truncation + multi-agent/eval/type docs
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
v0.27.0-fork.50
2026-06-11 23:55:01 +09:00
leeguooooo 6f71f4e1ff fix: truncate tab-list title too; doc raw --cdp isolation limit + eval/type notes
From Hermes's fork.49 re-dogfood (9/11 fixes confirmed PASS):
- tab list: a page can set its title to a multi-KB string (= a giant URL); cap
  the title column like the URL so the row stays readable.
- skill: clarify that true multi-agent isolation needs the extension-connect path
  (per-session tab groups) — raw `--cdp` shares the browser, so a sibling
  session's `open` can navigate your tab. Use the extension for concurrent agents.
- skill: prefer `eval --json` for array/object results (plain render is
  multi-line / pipe-hostile); note type/fill don't fire keydown (use `keyboard
  type` when key events are required).

(Hermes's "find-text click bypasses humanize" was a false alarm — verified both
paths curve; the apparent 1-vs-12 was cursor continuity on the same target.)
2026-06-11 23:55:00 +09:00
leeguooooo 31ef0d7e6a chore(release): 0.27.0-fork.49 — embed stealth-status + multi-agent skill guidance
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
v0.27.0-fork.49
2026-06-11 23:36:14 +09:00
leeguooooo 42560b56fc docs(skill): concurrent agents must use distinct --session (issue #6)
Within a session, commands are pinned to the agent's opened tab (fork.47). But
two agents on the same (default) session share one daemon + active tab and
clobber each other. Document that each concurrent agent must use a unique
--session — which gives it its own isolated tab group on the shared real Chrome.
2026-06-11 23:35:03 +09:00
leeguooooo 0c7534d9b2 chore(release): 0.27.0-fork.48 — iframe-proxy toggle (#4) + stealth status (#5)
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
v0.27.0-fork.48
2026-06-11 23:33:26 +09:00
leeguooooo ad4fb14ed9 feat: stealth status self-check command (issue #5)
Local stealth verification with no external detector: reports mode (connect vs
launch), live fingerprint probes (navigator.webdriver / window.chrome / plugins /
UA-headless) as pass/fail, and an audit of the active overrides for the path
(incl. the iframe-proxy state from #4). `--json` for a stable shape agents can
gate a sensitive flow on. Distinct from `doctor` (install/env health).
2026-06-11 23:33:24 +09:00
leeguooooo a976287f03 fix(stealth): AGENT_BROWSER_DISABLE_IFRAME_PROXY for a clean 0% CreepJS (issue #4)
--launch mode scored ~20% stealth on CreepJS because the srcdoc-iframe
contentWindow Proxy trips `hasIframeProxy` — the proxy that hides automation is
itself a fingerprintable tell (violates this fork's own "native > JS lies" rule).
Add a config-driven opt-out (no detectable global): AGENT_BROWSER_DISABLE_IFRAME_PROXY=1
drops the patch via __abStealth.disableIframeProxy → the iframe IIFE early-returns
→ clean 0% CreepJS, trading the niche srcdoc-iframe masking. Default keeps current
behavior. README now documents the --launch 20% honestly and scopes the headline
0% to the extension-connect path. Verified: launch + srcdoc page intact with the
toggle; stealth tests green (config strip-prefix kept in sync).
2026-06-11 23:25:24 +09:00
leeguooooo 649fa4ce94 chore(release): 0.27.0-fork.47 — tab-drift pin, snapshot -c keeps interactive, stale-ref guidance
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
v0.27.0-fork.47
2026-06-11 23:15:38 +09:00
leeguooooo 3ac69e822a fix: keep interactive nodes in snapshot -c; better stale-ref guidance (issue #2/#3)
- snapshot -c (compact) now always keeps lines with an interactive ARIA role
  (button/link/textbox/combobox/option/…), not only `ref=`/`": "` lines — so a
  clickable control can't vanish from compact output and leave the agent clicking
  an empty ref (issue #2 P1). Additive: only ever keeps more. compact tests green.
- stale-ref error now leads with "take a fresh snapshot" and points to the `eval`
  fallback for ref-churning SPAs, and demotes AGENT_BROWSER_VERIFY_REF=0 to a
  flagged last resort instead of presenting it as the fix (issue #3 P1).
2026-06-11 23:15:37 +09:00
leeguooooo d7a0ed85f9 fix(tabs): pin the active tab by target_id — stop command drift (issue #2/#3 P0)
The session's active tab was a bare index into `pages`, which drifts when a
foreign/user/other-session tab is passively discovered, a tab closes, or the list
reorders — so `eval`/`screenshot`/`snapshot`/`click` could land on the wrong page.
With login state that's a safety bug (a fetch firing on the wrong origin), and it
made screenshot disagree with snapshot/eval.

Pin the intended tab by stable target_id (`active_target_id`), set on every
explicit open / tab new / tab switch / connect. `active_session_id` and
`active_target_id` resolve through it (falling back to the index only if the
pinned tab is gone), so all commands stick to the agent's tab regardless of
passive churn — and they all agree.

Verified (--cdp, multi-tab): a window.open foreign tab no longer drifts eval;
tab new / switch re-pin correctly.
2026-06-11 23:10:29 +09:00
leeguooooo 9eaa5495ae chore(release): 0.27.0-fork.46 — cap --annotate legend
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
v0.27.0-fork.46
2026-06-11 22:58:58 +09:00
leeguooooo 68734fcb36 fix(screenshot): cap the --annotate legend (don't flood the terminal)
Dense pages produced hundreds of legend lines on stdout (Hermes: HN dumped 320).
Print the first 40 with a "… and N more" summary; every marker is still drawn in
the image, and --json still returns the full list.
2026-06-11 22:58:56 +09:00
leeguooooo 4b33dbadb4 chore(release): 0.27.0-fork.45 — pick combobox atomic op
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
v0.27.0-fork.45
2026-06-11 22:55:35 +09:00
leeguooooo fc73ee6c90 feat(pick): atomic combobox select for react-select / ARIA / native (issue #2 P1)
The biggest manual-cost point in the dogfood reports: `select @ref` is a silent
no-op on non-native dropdowns, and click+wait+Enter on react-select/ARIA/portal
menus took ~20 turns of hand-written eval to get right.

New `pick <selector> --option "<text>"` does it atomically in one in-page async
routine: native <select> → set value + input/change; custom widget → focus +
open (pointer/mouse sequence), poll up to 2.5s for the option to render anywhere
(portals included), match by visible text, scroll it in, fire the full
pointer/mouse sequence. ERRORS loudly if the option never appears — no silent
success.

Verified headless: native <select> → "Gamma"; portal combobox → "欧洲"
(non-ASCII); missing option → explicit error. Documented in the skill.
2026-06-11 22:55:32 +09:00
leeguooooo 28d3748c06 chore(release): 0.27.0-fork.44 — eval origin stamp, type --focused, humanize bogus warn
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
v0.27.0-fork.44
2026-06-11 22:48:32 +09:00
leeguooooo fa47a0b8e5 feat: eval prints its origin URL, type --focused, AGENT_BROWSER_HUMANIZE bogus warn
- eval now prints `eval @ <url>` to stderr (stdout stays the raw value) so an
  agent can catch tab drift — e.g. a logged-in fetch that hit the wrong origin —
  before trusting the result. Mitigates the issue #2/#3 P0 safety concern. (eval
  already returned the origin; the default output just never surfaced it.)
- `type --focused <text>`: type into the currently-focused element with no
  selector, for custom widgets that move focus to a hidden input (issue #2 P3).
- AGENT_BROWSER_HUMANIZE set to an unrecognized value now warns once (like the
  --humanize flag) instead of being silently ignored (Hermes #3).
2026-06-11 22:48:31 +09:00
leeguooooo 36c593631c chore(release): 0.27.0-fork.43 — issue/Hermes batch 1 (silent-click, live env, eval --file, tab-list, docs)
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
v0.27.0-fork.43
2026-06-11 22:35:35 +09:00
leeguooooo b92757412d fix(click): occlusion guard for selector clicks — no more silent false success
A coordinate click resolved from a CSS selector (incl. the getByText/find path's
located node) skipped the occlusion check that @ref clicks already get, so an
overlay on top made the click land on the overlay while still reporting ✓ Done —
the worst failure mode for an agent (Hermes #1, issue #2/#3). Now: if the click
point doesn't hit the target (elementFromPoint isn't the element / a descendant /
an ancestor wrapper), dispatch through the DOM instead, which fires the real
handler. Best-effort probe (a flaky check never blocks the normal path); skipped
for strict CLICK_MODE=coord and non-left/multi-clicks.

Verified: occluded button click hits 0→1 (was silent ✓Done); normal click
unaffected.
2026-06-11 22:34:12 +09:00