Commit Graph

736 Commits

Author SHA1 Message Date
github-actions[bot] 805bb8f171 chore: version packages (#487)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-09 20:43:41 +08:00
sen 86905ebe11 feat(cli): restore extension browser mode with bridge relay (#486)
* [packages/cli]feat: restore extension browser mode with bridge relay

Add a WebSocket bridge server inside the daemon that transparently
relays CDP messages between the Chrome extension and CdpSession.
Extension mode was removed in v1.0.0; this restores it with minimal
changes by reusing the existing cloud-mode CDP connection flow.

- daemon/bridge.rs: WS bridge on port 19222, hello handshake with
  extension origin validation, bidirectional CDP message relay
- daemon/server.rs: spawn bridge as tokio task (non-fatal on bind fail)
- daemon/registry.rs: store SharedBridgeState for session start access
- browser/session/start.rs: execute_extension() reusing cloud CDP flow
- setup: unblock extension mode in wizard and --browser flag
- CdpSession: zero changes
- Extension side: zero changes

* [packages/cli]fix: use Extension API for tab discovery in extension mode

Extension bridge requires Extension.attachTab before any CDP command
can be relayed. Replaced Target.getTargets + Target.attachToTarget
with Extension.createTab / Extension.attachActiveTab flow. Added
CdpSession.register_extension_tab() to register tabs without CDP
flat-session handshake. Local and cloud modes are unaffected.

* [packages/cli]fix: close tabs and detach debugger in extension mode

Session close and close-tab now use Extension.closeTab / Extension.detachTab
in extension mode instead of Target.closeTarget which the bridge doesn't
support. Added Extension.closeTab to the extension that detaches the
debugger and removes the tab via chrome.tabs.remove. Local and cloud
modes are unaffected.

* [packages/cli]fix: revert extension JS change, use detachTab for close

Extension is loaded from CWS — local JS changes don't take effect.
Reverted Extension.closeTab addition to background.js. Session close
and close-tab now use Extension.detachTab to release the debugger in
extension mode. Tabs are left open since CLI doesn't own the browser.

* [packages/cli]fix: read default browser mode from config instead of hardcoding Local

When --mode is not specified, browser start now reads browser.mode from
config.toml (e.g. mode = "extension") instead of always falling back to
Local mode. This allows users with extension mode configured to connect
to their existing browser without explicitly passing --mode extension.

* [packages/cli]fix: build.rs track branch ref for accurate BUILD_VERSION in worktrees

build.rs only watched .git/HEAD which doesn't change on new commits in a
worktree (it stays as ref: refs/heads/branch-name). This caused stale
BUILD_VERSION, preventing daemon version-mismatch detection when the
npm-installed binary shared the same cached hash.

Now also watches the actual ref file and packed-refs via --git-common-dir
so BUILD_VERSION updates on every new commit.

Also adds a guard in start.rs Local mode section to reject non-Local
modes explicitly instead of silently launching a local Chrome.

* [packages/cli]fix: clippy/fmt fixes and reject concurrent CDP clients in bridge

- Fix rustfmt formatting (collapsed if chains, import order, line width)
- Fix clippy collapsible-if warnings
- Reject concurrent CDP clients in bridge relay to prevent response
  channel hijacking between sessions

* [packages/cli]fix: suppress result_large_err for accept_hdr_async callback

The closure signature is dictated by tokio-tungstenite's API and cannot
use Box<Err>. Allow the lint on this specific closure.

* [root]chore: add changeset for CLI v1.2.0 (extension mode restore)
2026-04-09 20:01:37 +08:00
github-actions[bot] c59638d50a chore: version packages (#484)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-07 23:20:31 +08:00
s1mba 2e9ee9c245 [packages/cli]fix: batch new-tab session-loss failures (#482)
Fix skipped batch new-tab failures
2026-04-07 21:21:07 +08:00
4bmis f8c3be406b Fix e2e test helper import 2026-04-07 17:10:49 +08:00
4bmis b3498b9625 Support multi-URL browser new-tab 2026-04-07 17:03:12 +08:00
Junliang Feng 0711c870e7 feat(browser): save snapshot as Playwright-style YAML (#477)
* test(browser): add render_yaml unit tests

* test(browser): extend render_yaml edge coverage

* feat(browser): save snapshot as Playwright-style YAML

Add render_yaml() to snapshot_transform.rs that converts a flat AXNode
list into a nested Playwright-style YAML DSL string. Format rules:
- Container nodes (children or URL): `- role "name" [ref=eN]:`
- Leaf with ref: `- role "name" [ref=eN]`
- Leaf with value (no ref): `- role "name": value`
- Leaf with name only (no ref): `- role: name`
- URL rendered as child: `- /url: <url>`
- [cursor=pointer] added when cursor_info has cursor:pointer hint

Switch build_output() to call render_yaml() instead of render_content(),
and change snapshot file extension from .txt to .yaml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(browser): escape name and value in render_yaml leaf nodes

- Use escaped_name (not node.name) in the inline leaf branch
- Escape node.value with the same rules to prevent injection

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(browser): render value inline even when ref is present in render_yaml

Textbox/combobox nodes are interactive and typically have both a ref and
a value. Previously, the ref branch dropped the value entirely. Now the
value is appended inline: `- textbox "Label" [ref=eN]: value`.

Also moves escaped_value computation to the top of the loop so it can be
shared across both the ref and no-ref branches.

Adds unit test for the ref+value path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(browser): update snapshot e2e for yaml artifacts

- assert data.path ends with .yaml
- snapshot_content() validates .yaml extension before reading
- rename assert_content_has_refs to assert_content_is_yaml_snapshot
- add assertions: no legacy `url=` format, at least one YAML container line

Co-Authored-By: cli-roger-test <cli-roger-test@local>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* style: fix rustfmt formatting in render_yaml tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: rustfmt formatting and update link URL test for YAML format

Apply rustfmt-required formatting:
- Expand format!() call with 3+ args to multi-line
- Expand assert!(cond, msg) to multi-line
- Expand assert_eq! with long string to multi-line

Update test_build_output_renders_link_urls_from_ax_properties:
- Old format: `url=https://...` inline
- New YAML format: `- link "Docs" [ref=e1]:` + child `- /url: https://...`

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* style: fix final rustfmt issue in link URL test assertion

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: replace map_or(false) with is_some_and per clippy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: cli-roger-test <cli-roger-test@local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 15:10:56 +08:00
Junliang Feng 7336c1e11f fix(cli): native-ish stealth + OOPIF iframe click offset (#465) 2026-04-03 14:51:37 +08:00
Asen's Agent 350f4fa8db chore: version packages (cli v1.0.2)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 14:32:01 +08:00
asensagent 4ee5e44703 docs: remove search and get from help and skills (#476)
docs: remove search and get commands from help and skills

Search and get commands are being removed from the CLI. This removes
all references from help output, SKILL.md, and command-reference.md.
The workflow now starts directly with browser automation via snapshot.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 14:29:42 +08:00
mcfn.feng ee83689aa2 [packages/cli]docs: add 1.0.1 entry to CHANGELOG 2026-04-02 23:35:48 +08:00
mcfn.feng 8aa6116cbd [packages/cli]chore: bump version to 1.0.1 (npm rejected 1.0.0 re-publish) 2026-04-02 23:34:40 +08:00
Junliang Feng fcf79b96f1 fix: Windows build, E2E stability, README in npm, workflow_dispatch (#471) 2026-04-02 23:27:23 +08:00
mcfn.feng a171ea2192 [root]fix: copy root README.md to CLI package before npm publish 2026-04-02 23:23:56 +08:00
Junliang Feng b706b2b291 fix: gate Unix-specific APIs for Windows build (#470) 2026-04-02 23:09:54 +08:00
mcfn.feng 6a2b6010fd [packages/cli]fix: increase Chrome startup timeout to 30s and relax snapshot assertion
- Increase DevTools URL discovery timeout from 15s to 30s for CI environments
- Relax snap_selector_flag_limits_subtree assertion to allow ±2 node tolerance
- Increase E2E test workflow timeout to 20 minutes
2026-04-02 23:01:55 +08:00
mcfn.feng fd0dfe3f63 [packages/cli]fix: gate Unix-specific APIs behind #[cfg(unix)] for Windows build
- server.rs: gate flock, kill FFI, UnixListener, SIGHUP behind #[cfg(unix)]
- chrome_reaper.rs: gate SIGTERM FFI, fall back to child.kill() on Windows
- client.rs: gate UnixStream usage, return error on non-Unix platforms
2026-04-02 22:49:36 +08:00
github-actions[bot] 8b55277dad chore: version packages 2026-04-02 14:27:45 +00:00
mcfn.feng 696d3e0e85 [root]fix: restore minimal CHANGELOG.md for platform packages
changesets/action reads CHANGELOG.md of changed packages when creating
the Version PR. Empty placeholders prevent ENOENT crash.
2026-04-02 22:15:50 +08:00
AlexZ 022ab6ea1d [packages/cli]chore: fix clippy collapsible-if warnings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 22:04:13 +08:00
AlexZ 1c7c02eb63 [packages/cli]fix: address Codex review — OOPIF expansion + ref stability
- P1: expand_undiscovered_oopifs now uses frame_ids expanded in the
  current pass (returned by expand_iframes) instead of persisted cache.
  Prevents stale cache entries from causing OOPIF frames to be skipped.
- P1: remap_frame_id_for_backend_nodes skips if the new (frame_id, bid)
  key already exists, preserving stable ref_ids across snapshots.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 21:56:51 +08:00
AlexZ 850e4430a3 [packages/cli]chore: fix formatting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 21:50:14 +08:00
AlexZ 8b2b64d56b merge: resolve conflicts with main (browser.rs, cdp_session.rs)
- browser.rs: keep native-ish stealth flags, drop duplicate WebRTC line
- cdp_session.rs: keep apply_stealth() refactor over inline version

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 21:48:34 +08:00
AlexZ d31d70ead1 [packages/cli]fix: native-ish stealth + OOPIF iframe click offset
Stealth rewrite ("native-ish" strategy):
- Only remove automation traces (webdriver, cdc_*, Playwright markers)
- Preserve real system fingerprints (plugins, screen, language, WebGL)
- Minimal chrome.runtime stub for Cloudflare Turnstile compatibility
- Canvas noise for fingerprint tracking prevention
- Remove heavy spoofing that triggered Akamai/DataDome detection

OOPIF iframe click offset:
- Add get_iframe_offset() via DOM.getFrameOwner + DOM.getBoxModel
- Remap RefCache frame_id for nodes inlined by Chrome AX tree
- Expand undiscovered OOPIF frames in snapshot
- RefCache.remap_frame_id_for_backend_nodes() for closed shadow root iframes

Stealth apply refactor:
- Extract apply_stealth() method on CdpSession
- Apply stealth to already-attached tabs (Target.setAutoAttach race)
- Remove DeviceMetricsOverride (fixed 1920x1080 is a bot signal)

Tested: Reddit, BBB Scam Tracker (Cloudflare Turnstile), Etsy (DataDome)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 21:44:22 +08:00
mcfn.feng 00a9b8ef14 [feat] update version 2026-04-02 20:02:06 +08:00
mcfn.feng c2a2a43de5 [packages/cli]fix: select fixture uses DOM APIs to avoid TrustedHTML error
Chrome 146+ may enforce Trusted Types on certain pages, causing
innerHTML assignments to fail. Replace innerHTML with createElement
+ appendChild in install_select_fixture.
2026-04-02 18:13:32 +08:00
mcfn.feng 5cee89cde8 [packages/cli]fix: type/press key events not reaching correct tab + contenteditable fix
Three issues fixed:

1. Input.dispatchKeyEvent routes to Chrome's active tab, ignoring sessionId.
   - type: add Target.activateTarget before key dispatch loop
   - press: add Target.activateTarget before key dispatch

2. type command used minimal key definitions (just key+text) which didn't
   trigger native text insertion on contenteditable elements.
   - Reuse key_definition() from press module for full CDP key definitions
     (code, windowsVirtualKeyCode, nativeVirtualKeyCode, unmodifiedText)

3. Contenteditable e2e test fixture had element at top:500px, whose center
   (y=531) exceeded headless viewport height (513), causing click to miss.
   - Changed to top:200px

Closes ACT-822
2026-04-02 18:02:23 +08:00
mcfn.feng 66b732b84e [packages/cli]chore: bump version to 1.0.0-alpha.10 2026-04-02 17:49:20 +08:00
Junliang Feng ead3cbe740 fix(cli): support contenteditable elements in type/fill/focus (#461) 2026-04-02 17:44:26 +08:00
AlexZ a2024fbcb1 [packages/cli]chore: fix formatting in contenteditable test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 17:41:29 +08:00
AlexZ 7ab8a7c576 [packages/cli]fix: support contenteditable elements in type/fill/focus commands
CDP DOM.focus fails on contenteditable divs (e.g., Lark/Notion/Slate editors)
with "Element is not focusable" (-32000). This change adds a JS .focus()
fallback and click-to-place-cursor for rich text editors.

Changes:
- Add TabContext::focus_element() with JS .focus() fallback when DOM.focus fails
- type command: detect contenteditable and click element center to establish
  cursor position (required by Slate/ProseMirror internal cursor management)
- fill/focus commands: use focus_element() instead of raw DOM.focus
- Add E2E tests for type and focus on contenteditable elements

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 17:39:34 +08:00
mcfn.feng ca4303a73d [packages/cli]chore: bump version to 1.0.0-alpha.9 2026-04-02 17:23:37 +08:00
mcfn.feng f472fd2912 [packages/cli]fix: graceful Chrome shutdown via SIGTERM before SIGKILL
Send SIGTERM first so Chrome can flush Preferences (window placement,
cookies, etc.), wait up to 3s for graceful exit, then fall back to
SIGKILL. This allows Chrome to restore window position and size on
next launch.
2026-04-02 17:15:26 +08:00
mcfn.feng 4128749c00 Merge branch 'bugfix/remove-device-metrics-override' into release/1.0.0 2026-04-02 17:08:30 +08:00
mcfn.feng 4f833ac38a [feat] update version. 2026-04-02 17:08:04 +08:00
Junliang Feng b486d8a476 fix(cli): remove setDeviceMetricsOverride to avoid bot detection (#458)
[packages/cli]fix: remove setDeviceMetricsOverride and hardcoded window-size to avoid bot detection

setDeviceMetricsOverride creates detectable inconsistencies between
window.outerWidth/innerWidth and screen dimensions that anti-fingerprint
scripts use to flag automated browsers. The hardcoded --window-size
Chrome arg is also removed to let the browser use its default size.
2026-04-02 17:05:49 +08:00
mcfn.feng ac13df5522 [packages/cli]fix: remove setDeviceMetricsOverride and hardcoded window-size to avoid bot detection
setDeviceMetricsOverride creates detectable inconsistencies between
window.outerWidth/innerWidth and screen dimensions that anti-fingerprint
scripts use to flag automated browsers. The hardcoded --window-size
Chrome arg is also removed to let the browser use its default size.
2026-04-02 17:04:51 +08:00
Junliang Feng 7cbff7fc00 [codex] cli: keep setup and switch its browser modes to local/cloud (#455) 2026-04-02 16:50:47 +08:00
mcfn.feng 9a1d5a756a cli: fix setup clippy lint 2026-04-02 16:42:24 +08:00
mcfn.feng 192905515f cli: restore setup command entrypoint 2026-04-02 16:30:26 +08:00
mcfn.feng 0758c9ef62 [packages/cli]feat: add --session get-or-create and --tab alias for browser commands
browser start --session sid: get-or-create semantics — reuses existing
session if found, creates with that ID if not. Works for both local and
cloud modes. Conflicts with --set-session-id (which always force-creates).

browser new-tab --tab tid: visible alias for --set-tab-id — creates tab
with custom ID, returns TAB_ID_CONFLICT on duplicate.
2026-04-02 16:21:56 +08:00
mcfn.feng d358a27ed0 cli: remove setup command and mark it coming soon 2026-04-02 16:17:34 +08:00
mcfn.feng 8af064f04b cli: switch setup browser modes to local/cloud 2026-04-02 16:13:22 +08:00
mcfn.feng 13abe9370d [packages/cli]fix: key events not reaching correct tab in multi-tab sessions
Input.dispatchKeyEvent always routes to Chrome's active/foreground tab,
ignoring the CDP sessionId. This caused type and press commands to
silently fail when the target tab was not the active one.

- type: replace per-character Input.dispatchKeyEvent with Input.insertText
  which correctly routes via CDP session. Also faster (1 CDP call vs 2N).
- press: add Target.activateTarget before dispatching key events since
  functional keys (Enter, Tab, etc.) require Input.dispatchKeyEvent.
- type: add contentEditable support for cursor positioning (Selection/Range
  API fallback when setSelectionRange is unavailable).

Closes ACT-822
2026-04-02 16:10:17 +08:00
mcfn.feng 969ef0e038 cli: rename setup isolated mode to local 2026-04-02 16:00:22 +08:00
mcfn.feng 69df3da59f [packages/cli]chore: bump version to 1.0.0-alpha.6 2026-04-02 15:15:47 +08:00
mcfn.feng 5c1cf5db0c [root]fix: release workflow — add workflow_dispatch and alpha npm tag
- Add workflow_dispatch trigger to allow manual releases from any branch
- Add --tag alpha for prerelease versions so alpha doesn't overwrite latest
- Remove stale CHANGELOG.md from 6 CLI platform packages (stuck at 0.8.0)
2026-04-02 15:15:46 +08:00
asensagent d824149fe6 docs(cli): remove deprecated -i/-c/--cursor from snapshot help (#452)
* docs(cli): remove -i/-c/--cursor from snapshot help, mention path output

These flags are being deprecated. Updated snapshot after_help and
command-reference.md to remove all -i/-c/--cursor examples. Added note
about the path field in snapshot output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs(cli): keep -i/-c in snapshot help, remove only --cursor, add sample output

Per @junliang-mk: -i (interactive) and -c (compact) stay, only --cursor
is removed from help. Added sample snapshot output showing the tree
structure with refs, links, combobox, and clickable elements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs(cli): describe default snapshot as all-inclusive, remove flag descriptions

Default snapshot contains everything. Use additional flags as needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 13:56:08 +08:00
Junliang Feng d2f9ab93e0 fix: send mouseMoved before mousePressed in dispatch_click (#220)
* [packages/cli]fix: send mouseMoved before mousePressed in dispatch_click (#220)

SPA frameworks (React Router, Vue Router, Next.js) require a prior
mouseMoved event to establish pointer hover state before the click
event synthesizes correctly. Without it, the router's click listener
never fires and the URL remains unchanged (url_changed: false).

Add a single mouseMoved dispatch at (x, y) with button=none before
the existing mousePressed/mouseReleased loop — matches Playwright's
standard click implementation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [packages/cli]test: fix click_spa_navigation — use hash for pushState in about:blank (#220)

history.pushState with a path-only URL (/spa-destination) throws a
SecurityError in about:blank (null origin). Use a hash fragment
(#spa-destination) instead, which is always allowed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 13:15:06 +08:00
asensagent 60ecefc56b docs(skills): rewrite command-reference.md for CLI v2 (#447) 2026-04-02 13:13:11 +08:00