Commit Graph

1152 Commits

Author SHA1 Message Date
mcfn 0fbdd86484 [packages/cli-v2]test: pin stealth default flags 2026-03-31 00:44:17 +08:00
mcfn e3cb34a430 [packages/cli-v2]test: cover stealth v1 contract 2026-03-31 00:37:49 +08:00
4bmis 230bff79ce [packages/cli-v2]feat: add config version field with automatic migration from old format
Old configs (without version field) may have incompatible browser.mode values
like "isolate". On load, the config is now parsed as raw TOML first to check
for a version field. If missing, the old config is backed up to config.toml.bak
and a new config is created with version=1, browser.mode forced to "local",
and all other compatible fields copied over.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:54:27 +08:00
4bmis 895901be6c [packages/cli-v2]fix: use INVALID_SELECTOR error code for invalid CSS selectors
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:26:06 +08:00
asensagent 7fd2f1125f docs(cli): mention stable refs in snapshot help (#402) 2026-03-30 23:16:22 +08:00
Asen's Agent 40bed068ce docs(cli): mention stable refs in snapshot help
Refs are tied to backendNodeId, so they persist across snapshots as long
as the DOM node stays the same. This is a key affordance for agents
chaining commands without re-snapshotting after every step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 23:12:45 +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
asensagent fc908c2ea7 feat(cli): add help for logs, query, and storage commands (#398)
* feat(cli): add help examples for logs, query, and storage commands

Add after_help with usage examples to the remaining commands that were
missing them: logs console, logs errors, query, and all five storage
subcommands (list, get, set, delete, clear). Also update the browser
help listing with new sections for Logs, Wait, Cookies, Storage, and
Query so all commands are discoverable from `actionbook browser help`.

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

* fix(cli): show query nth syntax with required <n> argument in browser help

Codex review caught that `query nth` requires an index before the
selector, but the help listed it grouped as `query one|all|nth|count
<selector>`. Split into two lines so nth shows `query nth <n> <selector>`.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 22:37:39 +08:00
4bmis 95430ea663 [packages/cli-v2]fix: return ELEMENT_NOT_FOUND for invalid CSS selectors
Catch CDP -32000 "DOM Error while querying" from DOM.querySelector
and return a friendly ELEMENT_NOT_FOUND with the selector in details.
For @-prefixed selectors, hint that the correct format is @eN.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:36:44 +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
Asen's Agent 6c1d4dc02a fix(cli): show query nth syntax with required <n> argument in browser help
Codex review caught that `query nth` requires an index before the
selector, but the help listed it grouped as `query one|all|nth|count
<selector>`. Split into two lines so nth shows `query nth <n> <selector>`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 18:26:10 +08:00
Junliang Feng eea025dd0a fix: prevent Chrome process leak with centralized cleanup (#399) 2026-03-30 18:02:45 +08:00
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
4bmis 67fc353765 [packages/cli-v2]chore: add dev/dev:check/dev:test scripts with cargo-watch
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 17:30:23 +08:00
Asen's Agent 2954f7e0c5 feat(cli): add help examples for logs, query, and storage commands
Add after_help with usage examples to the remaining commands that were
missing them: logs console, logs errors, query, and all five storage
subcommands (list, get, set, delete, clear). Also update the browser
help listing with new sections for Logs, Wait, Cookies, Storage, and
Query so all commands are discoverable from `actionbook browser help`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 17:11:36 +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
Junliang Feng 1381b190c3 [cli-v2] test: add wait_page_ready poll and limit parallel threads (#397) 2026-03-30 16:55:58 +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
Junliang Feng eb83e075d0 [cli-v2] test: isolate parallel E2E tests with unique session/profile (#396) 2026-03-30 16:22:46 +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 2390cb4142 [packages/cli-v2]feat: relax version check to major.minor only (#186) (#395) 2026-03-30 16:06:04 +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
Junliang Feng c13e04ea75 feat(cli-v2): describe --nearby significance filter (#138) (#393) 2026-03-30 15:30:12 +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
Junliang Feng c29483f0f9 [packages/cli-v2]test: cover nearby significance filter (#392) 2026-03-30 15:25:47 +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
Junliang Feng 3de97f6aea feat(cli-v2): describe summary qualifier enrichment (#137) (#391) 2026-03-30 15:16:39 +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