Commit Graph

599 Commits

Author SHA1 Message Date
mcfn.feng e5299ad485 [packages/cli-v2]fix: delete non-default profile dirs on session close
Restore profile directory cleanup on close, but only for non-default
profiles. The default profile ("actionbook") preserves user state
(cookies, localStorage) across sessions. Test-generated profiles
(e.g. "profile-s-12345-0") are cleaned up automatically.

Profile deletion happens after Chrome has fully exited to avoid
EBUSY from held locks.
2026-03-30 18:00:23 +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 0f9aab1d70 [packages/cli-v2]fix: use chrome_reaper in launch timeout path, fix misleading doc
- browser.rs: replace inline child.kill() (no wait) with
  chrome_reaper::kill_and_reap() to prevent zombie on launch timeout
- chrome_reaper.rs: remove misleading setsid reference from doc comment
2026-03-30 17:41:52 +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
Asen's Agent ac1772f8ee fix: update argument descriptions to mention @ref alongside CSS/XPath
The clap argument descriptions for <SELECTOR> fields now read
"Selector (CSS, XPath, or @ref)" instead of generic "Target element
selector" or "CSS selector". Updated 19 command structs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 17:01:06 +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
mcfn 6cdfa25737 [packages/cli-v2]feat: relax version check to major.minor only (#186)
Replace exact BUILD_VERSION match with major_minor() comparison.
1.0.x-<hash> variants are now compatible as long as major.minor match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 16:04:23 +08:00
Junliang Feng b419084676 [packages/cli-v2]test: cover version compatibility relaxation (#394) 2026-03-30 16:03:11 +08:00
mcfn 15174e38c8 [packages/cli-v2]test: cover version exact hash edges 2026-03-30 16:00:46 +08:00
Asen's Agent b6cb7776af feat: add snapshot ref (@eN) examples to all selector-based commands
Every command that accepts a <selector> now shows an @eN ref example
and mentions that refs come from snapshot output. Updated 18 commands
across interaction and observation groups.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 15:52:35 +08:00
Asen's Agent 56c49d3467 fix: unify all help entry points to show custom output
All equivalent invocations now show the same custom help:
  actionbook / actionbook help / actionbook --help / actionbook -h
  actionbook browser / actionbook browser help / actionbook browser --help

Pre-parse interception catches these before clap can emit its
auto-generated flat listing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 15:45:52 +08:00
mcfn 65fdfc796f [packages/cli-v2]test: cover version compatibility relaxation 2026-03-30 15:42:19 +08:00
Asen's Agent f2c404b4d7 fix: intercept top-level --help to show custom help instead of clap default
Both `actionbook --help` and `actionbook -h` now show our custom
agent-friendly help instead of clap's auto-generated output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 15:41:12 +08:00
asensagent 713eea732e fix: unify browser --help with grouped help, add new command docs (#368)
fix: unify browser --help with grouped help and add new command docs

- Intercept `browser --help` to show grouped listing instead of clap's
  flat ungrouped output. Both `browser help` and `browser --help` now
  show the same grouped view.
- Add after_help examples to 5 new observation commands: attrs, box,
  styles, describe, state.
- Update grouped help listing with all 40 browser commands.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 15:35:59 +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 439a8c1c2f [packages/cli-v2]feat: filter insignificant nodes from describe --nearby output (#138)
Add isSignificant(e) check in the nearby JS: keep a node only if it has
an explicit accessible name (aria-label, labelledby, label[for], closest
label), direct text node children, or is an interactive element
(button/a/input/select/textarea). Structural wrapper divs/spans with no
own text and no name are filtered to null (parent/sibling) or excluded
(children).

Uses a dedicated gna() helper (like gn() but without the innerText
fallback) so descendant text doesn't make empty wrappers appear
significant.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 15:28:44 +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 1dca8e1d90 [packages/cli-v2]feat: add qualifier enrichment to describe summary (#137)
Summary now appends [disabled], [checked], [selected] qualifiers based
on element state. Multiple qualifiers use comma separation: [disabled, checked].
Default states (enabled, unchecked, unselected) produce no qualifier.

Changes:
- describe.rs gn(): add label lookup via label[for] and closest('label')
  so checkbox/radio names resolve to associated label text
- describe.rs gst(): add checked and selected to state object
- describe.rs summary builder: append qualifiers from state
- output.rs: use pre-computed summary field from response data

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 15:13:40 +08:00
Junliang Feng 28a76809ce [packages/cli-v2] test describe summary qualifiers (#389) 2026-03-30 15:09:15 +08:00
mcfn 3c7d0e93bc [packages/cli-v2]test: fix describe qualifier fixture 2026-03-30 15:07:59 +08:00
4bmis 521f2055ad Merge branch 'release/1.0.0' of github.com:actionbook/actionbook into release/1.0.0 2026-03-30 15:03:04 +08:00
4bmis 17dc3d219c [packages/cli-v2]fix: print help when call actionbook with no subcommand 2026-03-30 15:02:54 +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
Junliang Feng d29cdb7edd fix(cli-v2): cargo fmt formatting for short tab ID change (#388) 2026-03-30 14:48:40 +08:00
mcfn 9d2ad69507 [packages/cli-v2]chore: cargo fmt + remove dead resolve_tab_ws_url function
- cargo fmt: reformat tracing::warn! in close.rs per rustfmt rules
- Remove resolve_tab_ws_url() from daemon/cdp.rs: function was never
  called and contained a stale tab.id.0 reference (short ID) where
  the WS URL needs the native CDP target ID

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 14:47:28 +08:00
mcfn c5258e7f55 [packages/cli-v2]fix: use native_id for CDP calls in close-tab, cookies, and session reuse
Short tab IDs (t1, t2, ...) are user-facing labels, not CDP target IDs.
Three call sites were incorrectly passing the short ID to CDP methods:

- close.rs: extract native_id from registry before lock release;
  use it for cdp.detach() and Target.closeTarget
- cookies/{list,get,set,delete,clear}.rs: use t.native_id instead of
  t.id.0 when looking up the target for execute_on_tab
- session/start.rs ReuseTarget: add first_native_id field (CDP target
  ID); use it for Page.navigate, /json/list lookup, and cloud registry
  lookup; keep first_tab_id (short ID) for JSON response only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 14:43:56 +08:00
mcfn bc570c8b31 [packages/cli-v2]test: cover describe qualifiers 2026-03-30 14:39:04 +08:00
mcfn c417da59ae [packages/cli-v2]fix: cargo fmt formatting
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 14:37:47 +08:00
Junliang Feng 329d7a18c7 feat(cli-v2): short tab IDs (t1, t2, ...) with native_tab_id (#386) 2026-03-30 14:34:18 +08:00
Junliang Feng 41eecd4d65 [cli-v2] fix: replace opaque CDP channel errors with SESSION_CLOSED (#387) 2026-03-30 14:17:06 +08:00
mcfn c9141e610c [packages/cli-v2]feat: short tab IDs (t1, t2, ...) with native_tab_id
- TabEntry gains native_id (Chrome CDP target ID); id becomes short form
- SessionEntry.push_tab() assigns t1/t2/... sequentially and stores native ID
- get_cdp_and_target resolves short ID → native ID for CDP calls
- start/new-tab/list-tabs/status responses include both tab_id and native_tab_id
- E2E: assert_tab_id validates t\d+ format; tests updated for native_tab_id presence

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 14:00:48 +08:00
mcfn.feng 49830e8434 [packages/cli-v2]fix: replace opaque CDP channel errors with SESSION_CLOSED
When a session is closed while commands are still in flight, the error
was "cdp error: writer channel closed" or "cdp error: connection closed"
which gave no indication of the root cause. Replace with a dedicated
SessionClosed variant that outputs "SESSION_CLOSED: session was closed
while command was pending" with an actionable hint.
2026-03-30 13:59:53 +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
Junliang Feng efe8a1661f feat(cli-v2): enable parallel E2E tests with profile cleanup (#383) 2026-03-30 13:19:15 +08:00
mcfn.feng 2febbe0f49 [packages/cli-v2]fix: address PR review — scope profile cleanup to local sessions + release lock early
P1: Only delete profile directory for local sessions (those with a
    Chrome child process). Cloud sessions don't own a local profile
    and could share a profile name with an active local session.
P2: Release the registry lock before slow I/O (Chrome kill, recursive
    directory removal) to avoid blocking concurrent session operations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 12:45:14 +08:00
4bmis 0ae1b83770 Merge branch 'release/1.0.0' of github.com:actionbook/actionbook into release/1.0.0 2026-03-30 12:43:02 +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 21dfd720f0 [packages/cli-v2]refactor: introduce TabContext to eliminate repetitive resolver params
Replace the 6-param pattern (cdp, target_id, selector, registry,
session_id, tab_id) with a TabContext struct created once per command.

Before: element::resolve_node(&cdp, &target_id, &sel, registry, &s, &t)
After:  ctx.resolve_node(&sel)

TabContext bundles (cdp, target_id, registry, session, tab) and exposes
resolve_node, resolve_center, resolve_object, scroll_into_view, and
resolve_object_id. Public fields cdp/target_id for direct CDP calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 12:12:26 +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 148649e8e8 [packages/cli-v2]fix: address PR review — synthetic ref guard + CDP error routing + AX fallback
P1: Skip CDP DOM.resolveNode for synthetic backendNodeIds (< 0, from AX
    nodes without a backing DOM element) — go straight to AX fallback.
P2: Distinguish CDP -32000 (stale node) from other errors (connection
    lost, etc.) — only return REF_STALE for true staleness, propagate
    other CDP errors through the standard error path.
Fallback: When backendNodeId resolution fails or is synthetic, use
    Accessibility.queryAXTree with the stored role + name to find the
    element in the current AX tree.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 11:45:09 +08:00
mcfn.feng 70d2907bb4 [packages/cli-v2]style: cargo fmt after merge with release/1.0.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 11:40:05 +08:00