Commit Graph

133 Commits

Author SHA1 Message Date
mcfn.feng 229ce0d844 [packages/cli-v2]fix: align e2e tests with space-separated command names + fix type clap args
- Update all e2e test assertions from dot notation ("ok browser.start")
  to space-separated ("ok browser start") matching the refactored
  COMMAND_NAME constants
- Fix type command clap panic: change from separate selector/text fields
  to `#[arg(num_args = 1..=2)] args: Vec<String>` pattern (same as fill)
  to avoid "non-required positional before required" clap assertion
- Fix storage test command_name helper to use space separator

Reduces e2e failures from 57 (on release/1.0.0 CI) to ~5 pre-existing
timing/flaky issues.
2026-03-31 20:38:35 +08:00
Junliang Feng 25aaa33fa3 [packages/cli-v2]test: cover iframe text extraction (#423) 2026-03-31 19:09:45 +08:00
Junliang Feng 70b3ad9059 [packages/cli-v2]test: cover fill type target modes (#420) 2026-03-31 18:15:34 +08:00
Junliang Feng 652f4e5d11 feat: add --wait-until flag to browser goto (#415) 2026-03-31 17:17:45 +08:00
4bmis 95d892be0b [packages/cli-v2]refactor: use space-separated command names instead of dot notation
Command names in JSON output and internal COMMAND_NAME constants now use
spaces (e.g., "browser snapshot") to match the CLI subcommand format,
replacing the previous dot notation (e.g., "browser.snapshot").

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 17:13:19 +08:00
Junliang Feng bc5010b45a [packages/cli-v2]fix: clarify profile conflict recovery (#417) 2026-03-31 17:01:43 +08:00
mcfn.feng e29d2a9a89 [packages/cli-v2]feat: add --wait-until flag to browser goto
goto now waits for page load by default instead of returning immediately
after Page.navigate. This ensures snapshot refs are stable and URLs/titles
reflect the loaded page.

Options:
- load (default): wait for Page.loadEventFired
- domcontentloaded: wait for Page.domContentEventFired (faster)
- none: return immediately (old behavior)

Uses CDP event subscription (Page.enable already called) instead of
JS polling. No internal timeout — relies on global --timeout flag.
Wire-compatible via #[serde(default)] on the new field.
2026-03-31 16:58:27 +08:00
Junliang Feng e335b0f931 [packages/cli-v2]test: cover version flag output (#413) 2026-03-31 15:41:22 +08:00
Junliang Feng 977c00676e [packages/cli-v2]fix: press Enter triggers native browser actions (#407)
* [packages/cli-v2]fix: send full CDP key definitions in press command

press Enter (and other functional keys) was not triggering native browser
behaviours like form submission because Input.dispatchKeyEvent was missing
critical CDP parameters (code, windowsVirtualKeyCode, text).

Two issues fixed:
- Added KeyDef mapping table covering 15 functional keys, F1-F12, and
  single printable characters with their CDP code, keyCode, and text
- Use "keyDown" type (with text) for keys that produce text (Enter, Space,
  letters, digits) so Chrome fires native actions; use "rawKeyDown" for
  pure-functional keys (Tab, Escape, arrows)

* [packages/cli-v2]test: add e2e tests for press CDP key definitions

- press_enter_sends_cdp_key_definitions: verify code="Enter", keyCode=13
- press_enter_submits_form: verify Enter triggers native form submission
- press_escape_sends_cdp_key_definitions: verify code="Escape", keyCode=27
- press_tab_sends_cdp_key_definitions: verify code="Tab", keyCode=9

* [packages/cli-v2]fix: address PR review — symbol keys and Shift modifier

- Include ASCII symbol/punctuation keys (/, ., -, ;, etc.) in printable
  key mapping so they dispatch as keyDown with text, not rawKeyDown
- Only suppress text for shortcut modifiers (Ctrl/Alt/Meta), not Shift;
  Shift+A, Shift+1 (!) etc. are text-producing and need native behaviour
2026-03-31 12:16:37 +08:00
Alex f542a72f82 [packages/cli-v2] feat: iframe content expansion and frame-aware interaction (#406)
* [root]chore: add changeset for screenshot timeout fix

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [packages/cli-v2]feat: add iframe content expansion and frame-aware interaction support

Snapshot now automatically expands 1 level of iframe content, and all
interaction/observation commands route CDP operations to the correct
frame session for cross-origin iframe elements. This is fully transparent
to agents — no new commands or flags required.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [packages/cli-v2]fix: complete frame routing in screenshot annotate + clarify flag semantics

- get_rect_for_object() now uses execute_for_frame() for Runtime.callFunctionOn,
  fixing iframe element annotation boxes that would fail on cross-origin objectIds
- Design doc: replace overly broad "all flags work as before" with precise per-flag
  iframe semantics (--selector/--cursor main-frame only, --depth per-frame)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [packages/cli-v2]style: apply rustfmt formatting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [packages/cli-v2]style: fix clippy collapsible_if warning

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [packages/cli-v2]test: add iframe E2E tests + RefCache unit tests + fix fill for iframe

- 7 E2E tests: snapshot expansion, interactive filter, html/click/fill/value
  on iframe refs, ref uniqueness across frames
- 4 RefCache unit tests: composite key collision, frame_id round-trip,
  cross-frame stability
- fix fill.rs: use Runtime.callFunctionOn(objectId) instead of
  document.activeElement to work correctly for iframe elements

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [packages/cli-v2]test: add cross-origin (OOPIF) iframe E2E tests

- Second HTTP server on different port for true cross-origin iframes
- 4 new tests: xo_iframe_snapshot_expands, xo_iframe_html, xo_iframe_fill,
  xo_iframe_click — all validate execute_for_frame() session routing
- Total iframe E2E coverage: 11 tests (7 same-origin + 4 cross-origin)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [packages/cli-v2]style: apply rustfmt to test files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [packages/cli-v2]style: fix clippy useless_format in test harness

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [packages/cli-v2]refactor: rename execute_in_frame → execute_on_element

Rename frame-aware CDP execution methods to better reflect semantics:
- execute_in_frame → execute_on_element (TabContext method)
- execute_for_frame → execute_for_element (standalone helper)

The old names leaked the iframe implementation detail. The new names
express the caller's intent ("execute on the resolved element") without
implying frame awareness — consistent with the cli-v2 principle that
agents should not need to know about iframe boundaries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [packages/cli-v2]refactor: restore execute_for_frame name for low-level helper

Layered naming convention:
- High-level (command files): ctx.execute_on_element() — named by intent
- Low-level (infrastructure): execute_for_frame() — named by mechanism

The low-level helper takes frame_id as input and routes by frame/session,
so execute_for_frame accurately describes what it does. Renaming it to
execute_for_element would obscure the mechanism it implements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [packages/cli-v2]test: add screenshot --annotate and scroll into-view iframe E2E tests

Complete the iframe E2E test matrix:
- iframe_screenshot_annotate_includes_iframe_elements: verifies annotated
  screenshot succeeds with iframe refs in RefCache
- iframe_scroll_into_view_works_on_iframe_element: verifies scroll into-view
  routes callFunctionOn to correct frame session

Total: 13 iframe E2E tests (9 same-origin + 4 cross-origin)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 11:25:14 +08:00
Junliang Feng d23a681034 feat(cli-v2): stealth/anti-detection V1 (#192) (#404)
* [packages/cli-v2]feat: implement stealth/anti-detection V1 (#192)

- daemon/browser.rs: add --stealth flag to launch_chrome (5th param); add 5
  Chrome args when stealth=true; Chrome starts on about:blank (open_url removed)
- browser/stealth.rs: new file with STEALTH_JS constant (format!() for WebGL
  vendor/renderer, navigator.webdriver, cdc_ cleanup, window.chrome, plugins,
  permissions, idempotency guard)
- browser/mod.rs: register stealth module
- daemon/cdp_session.rs: attach(target_id, user_agent: Option<&str>) — when
  Some(ua): Page.enable + Page.addScriptToEvaluateOnNewDocument + UA override
- browser/session/start.rs: --stealth flag (default true); Browser.getVersion
  for UA; Page.navigate after attach for open_url; stealth stored in SessionEntry
- browser/session/restart.rs: preserve session's stealth setting on restart
- daemon/registry.rs: SessionEntry.stealth field; reserve_session_start(stealth)
- browser/navigation/goto.rs: remove Page.addScriptToEvaluateOnNewDocument
- browser/tab/open.rs, browser/interaction/click.rs: attach(id, None)
- tests/stealth_contract.rs: fix launch_chrome call (5th arg true) + add
  start_source_exposes_stealth_flags_and_defaults_them_on test

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

* [packages/cli-v2]chore: remove unused ensure_scheme from daemon/browser.rs

Fixes clippy -D warnings failure in CI.

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

* [packages/cli-v2]chore: cargo fmt trailing newline fix

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 01:06:44 +08:00
Junliang Feng 9546e7dd9a [packages/cli-v2]test: cover stealth v1 contract (#403) 2026-03-31 00:39:17 +08:00
Junliang Feng abc2d56e39 [packages/cli-v2]feat: session ID format change SLOCAL-N/SCLOUD-N/SEXT-N (#189) (#401)
* [packages/cli-v2]feat: session ID format change SLOCAL-N/SCLOUD-N/SEXT-N (#189)

- SessionId.is_valid() now accepts SLOCAL-N, SCLOUD-N, SEXT-N (uppercase prefix + digits)
- auto_generate(mode, n) replaces old auto_generate(n); generates mode-prefixed IDs
- from_profile() updated to pass mode to auto_generate fallback
- SessionRegistry drops next_auto_id counter; generates IDs via per-prefix max active N scan
- generate_session_id() takes Mode instead of profile; profile no longer affects ID
- Wrap at 10000, skip occupied (active) slots

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

* [packages/cli-v2]chore: cargo fmt

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 22:54:24 +08:00
Junliang Feng 6afbe52f5b [packages/cli-v2]test: cover session id format change (#400) 2026-03-30 22:46:34 +08:00
4bmis 99480676d6 [packages/cli-v2]feat: add --by-ref flag to select command
Select an <option> by its snapshot ref (@eN) instead of value or text.
Resolves the ref to a remote object and passes it directly via CDP
arguments, avoiding intermediate value lookups. Includes mutual
exclusivity with --by-text, updated text output, and e2e tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:36:44 +08:00
mcfn.feng c5db7c5c6d [packages/cli-v2]test: add E2E tests for restart Chrome cleanup and double-close
- restart_kills_old_chrome_and_spawns_new: verify old Chrome PIDs are
  dead after restart and new PIDs are different from old ones
- double_close_returns_not_found: verify second close returns
  SESSION_NOT_FOUND without panic or crash
2026-03-30 17:48:18 +08:00
mcfn.feng 894716c00b [packages/cli-v2]fix: prevent Chrome process leak with centralized cleanup
Chrome processes were not being cleaned up in several scenarios:
- SessionEntry had no Drop impl, so dropping it leaked the Chrome process
- CdpSession had no close() method, so background reader/writer tasks leaked
- close/restart/shutdown held the registry lock during slow CDP/Chrome cleanup
- child.wait() in spawn_blocking was fire-and-forget (never awaited)

Changes:
- Add chrome_reaper module with centralized kill_and_reap helpers
- Add Drop impl on SessionEntry as last-resort backstop
- Add CdpSession::close() that drops the writer channel and fails pending requests
- Move all slow I/O (cdp.close(), Chrome kill/reap) outside registry lock
- Use kill_and_reap_async (awaited) instead of fire-and-forget spawn_blocking
- kill_and_reap_option takes ownership (sets to None) to prevent double-cleanup
2026-03-30 17:40:30 +08:00
mcfn.feng 89b40c9e0f [packages/cli-v2]test: add wait_page_ready poll and limit parallel threads
Two fixes for remaining flaky E2E failures (5-10 random tests per run):

1. Limit parallel threads to 8 (package.json test:e2e) to reduce Chrome
   process contention and CPU pressure during parallel test runs.

2. Add wait_page_ready() helper that polls document.readyState every 200ms
   (up to 2s) after session start/goto. Called in all 14 local start_session()
   functions and both harness helpers. Prevents tests from interacting with
   pages before DOM is ready under high parallel load.

Result: 441 passed, 0 failed (was 5-10 random failures per run).
2026-03-30 16:53:10 +08:00
mcfn.feng 6f3eb95d74 [packages/cli-v2]test: isolate parallel E2E tests with unique session/profile
14 test files defined local start_session() without unique_session(),
causing all parallel tests to share the default profile and hit
SESSION_STARTING rejections (238 failures).

Fix: add unique_session("s") to each local start_session(), passing
--set-session-id and --profile to browser start. This gives each test
its own isolated Chrome profile, matching the pattern in harness.rs.

Result: 238 failures → 3 flaky (unrelated to session isolation).
2026-03-30 16:16:48 +08:00
Junliang Feng 9109bf2f54 [cli-v2] fix: prevent daemon process accumulation with flock singleton (#390) 2026-03-30 15:34:07 +08:00
mcfn 9bbae2a20e [packages/cli-v2]test: cover nearby significance filter 2026-03-30 15:23:33 +08:00
mcfn.feng 15a529ccbe [packages/cli-v2]fix: address review — flock EINTR, idle timeout config, faster E2E
Fixes from dual code review (code-reviewer + codex challenge):
- P0: Invalid ACTIONBOOK_DAEMON_IDLE_TIMEOUT_SECS now falls back to default
  instead of silently disabling timeout
- P1: Replace std::thread::sleep with tokio::time::sleep in async fn
- P1: Extract parse_idle_timeout() pure function for race-free unit testing
- P2: Add ACTIONBOOK_DAEMON_HOUSEKEEPING_INTERVAL_SECS for fast E2E tests
  (idle timeout tests now run in 12s instead of 72s)
- P2: Remove manual stale file cleanup from crash_recovery test
- Minor: Handle EINTR in flock with retry loop
2026-03-30 15:20:32 +08:00
mcfn 3c7d0e93bc [packages/cli-v2]test: fix describe qualifier fixture 2026-03-30 15:07:59 +08:00
mcfn.feng 3336a07258 [packages/cli-v2]fix: prevent daemon process accumulation with flock singleton
Replace the PID file + kill(pid, 0) singleton mechanism with flock-based
locking. The kernel guarantees flock atomicity (no TOCTOU race) and
auto-releases on process exit (including SIGKILL / panic=abort), solving
the root cause of 30+ orphaned daemon processes accumulating over time.

Changes:
- Use flock(LOCK_EX | LOCK_NB) on PID file for daemon singleton
- is_daemon_running() now probes flock instead of PID + kill(pid, 0)
- Losing daemon retries 3 times, checks if winner's socket is ready
- Add idle timeout (default 30min, ACTIONBOOK_DAEMON_IDLE_TIMEOUT_SECS)
- Add has_active_sessions() helper to SessionRegistry
- Add unit tests for flock, idle timeout config, registry
- Add E2E tests for concurrent start, idle timeout, crash recovery
2026-03-30 14:59:09 +08:00
mcfn bc570c8b31 [packages/cli-v2]test: cover describe qualifiers 2026-03-30 14:39:04 +08:00
Junliang Feng 02fa15b54c [packages/cli-v2] test short tab id contract (#385) 2026-03-30 13:59:19 +08:00
mcfn 4cd3d79a28 [packages/cli-v2]test: pin short tab lookup 2026-03-30 13:42:55 +08:00
4bmis 593dceca04 Merge branch 'release/1.0.0' of github.com:actionbook/actionbook into release/1.0.0 2026-03-30 13:40:24 +08:00
mcfn 1f9a1695e9 [packages/cli-v2]test: cover short tab ids 2026-03-30 13:38:35 +08:00
mcfn.feng 15399f4ffc [packages/cli-v2]fix: cloud_concurrent_eval_multi_tab assertion — compare numbers not strings
eval "1+1" returns number 2, not string "2". The test used as_str()
which returns None for numbers, causing the assertion to always fail.
Fix: compare with assert_eq!(value, 2) directly. Remove #[ignore].

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:28:24 +08:00
4bmis 8b3b1b59f2 Merge branch 'release/1.0.0' of github.com:actionbook/actionbook into release/1.0.0 2026-03-30 13:19:53 +08:00
mcfn.feng 15726ad7b1 [packages/cli-v2]fix: wait navigation race condition + ignore flaky cloud concurrent test
- wait navigation: use two-phase detection (URL change → readyState
  complete) instead of OR logic that false-positives on initial page's
  readyState=complete before navigation fires
- cloud_concurrent_eval_multi_tab: mark #[ignore] — known CDP
  multiplexing issue mis-routes concurrent responses across tabs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 12:42:53 +08:00
mcfn.feng e51ec6ec9d [packages/cli-v2]feat: enable parallel E2E tests with profile cleanup
- browser close now removes the Chrome profile directory after killing
  the process, preventing disk accumulation from test runs
- Remove --test-threads=1 from CI — each test already uses a unique
  session/profile via unique_session(), so parallel execution is safe
- Profile isolation: each test gets its own Chrome user-data-dir,
  no shared state between concurrent tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 12:31:54 +08:00
4bmis c59de08a13 Fix cli-v2 global timeout handling 2026-03-30 12:18:19 +08:00
mcfn.feng e4c2a6b72a [packages/cli-v2]fix: allow too_many_arguments on assert_cookie_shape in e2e test
Pre-existing clippy lint — CI runs --all-targets which includes tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 11:48:45 +08:00
mcfn.feng 4ec3705cc6 Merge remote-tracking branch 'origin/release/1.0.0' into bugfix/click-ref 2026-03-30 11:39:24 +08:00
mcfn.feng 7a1cc2207a [packages/cli-v2]fix: misc fixes from cookies, logs, wait, and CDP session
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 11:35:46 +08:00
mcfn fbfffeec6c [packages/cli-v2]test: assert storage set context 2026-03-30 10:33:54 +08:00
mcfn fb7c338a81 [packages/cli-v2]test: add storage e2e coverage 2026-03-30 10:27:13 +08:00
mcfn 58d9894a67 [packages/cli-v2]test: relax cookies expires assertion 2026-03-30 10:19:06 +08:00
mcfn f3845687fc [packages/cli-v2]test: pin cookies miss contract 2026-03-30 09:12:29 +08:00
mcfn 2eb6b2c0d2 [packages/cli-v2]test: add cookies e2e coverage 2026-03-30 09:06:49 +08:00
mcfn ec2700ab45 [packages/cli-v2]test: add condition timeout coverage 2026-03-30 01:14:44 +08:00
mcfn ba8d546973 [packages/cli-v2]test: add wait e2e coverage 2026-03-30 01:09:45 +08:00
mcfn b5906c858e [packages/cli-v2]test: extend logs filter coverage 2026-03-29 23:59:59 +08:00
mcfn 0e530e3965 [packages/cli-v2]test: add logs e2e coverage 2026-03-29 23:55:26 +08:00
mcfn.feng 29ce2f380b [packages/cli-v2]chore: merge release/1.0.0 and resolve cli-v2 conflicts
Integrate new commands from release/1.0.0 (pdf, query, hover, focus,
press, drag, upload, mouse-move, cursor-position, scroll, etc.) with
screenshot implementation. Deduplicate base64 dependency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 23:39:25 +08:00
mcfn dd6c46ec5b [packages/cli-v2]test: add pdf e2e coverage 2026-03-29 20:12:11 +08:00
mcfn 9e2d7321b6 [packages/cli-v2]test: cover disabled query state 2026-03-29 19:09:38 +08:00
mcfn 6e1bcca0fe [packages/cli-v2]test: add query e2e coverage 2026-03-29 19:00:43 +08:00