Address Codex review feedback on PR #235 — extension-mode users would
hit runtime errors copying examples for wait-idle, console, fetch,
emulate, and switch-frame. Add [CDP] inline markers and section-level
<sup>CDP</sup> tags so the limitation is visible before users try.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: migrate install guides to brew/script-first, keep npm (CUE-504)
* docs: keep README install simple (npm only), link to full guide
* docs: use script install in README (no Node.js dependency)
* docs: split Installation into sub-headings per platform
Add new extract skill for structured data extraction from websites.
Produces executable Playwright scripts and extracted data (JSON/CSV).
Includes mechanism-aware strategies for hydration, virtualized lists,
infinite scroll, and pagination.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [packages/actionbook-rs]refactor: remove extension isolated mode, unify browser docs
Simplify browser architecture from three modes to two:
- Isolated (default): launches a fresh Chrome profile via CDP
- Extension: connects to the user's running Chrome via bridge
Remove extension isolated mode entirely:
- Delete isolated_extension.rs, cdp_pipe.rs, cdp_http.rs
- Remove --isolated flag from CLI and config
- Simplify extension_bridge (remove isolated file helpers)
- Simplify launcher (remove pipe transport, LaunchResult)
- Clean up setup wizard and config fields
- Add legacy .isolated file cleanup for upgrade compatibility
- Fix stop() to also resolve legacy bridge-pid.isolated
Merge browser-extension.mdx into unified browser.mdx guide:
- Single page covers both Isolated and Extension modes
- Browser commands listed once (add --extension to switch)
- Update all cross-references in docs
* [packages/actionbook-rs]fix: add liveness check to extension stop PID resolution
Previously, `extension stop` blindly preferred the standard PID file over
the legacy `.isolated` file without checking liveness. In upgrade scenarios
where the legacy file held the live bridge PID and the standard file was
stale (PID possibly reused by OS), this could send SIGTERM to an unrelated
process.
Introduce `resolve_pid_for_port()` with liveness checking:
- Same PID in both files → select safely
- Different PIDs → check liveness, pick the live one
- Both alive → refuse to kill (Ambiguous), warn user
- Both dead → clean up stale files (BothMatchedButDead)
Includes 5 unit tests covering all branches.
* [packages/actionbook-rs]feat: add isolated Chrome profile for extension bridge mode
Support running the extension bridge with a dedicated Chrome profile
that contains no personal data. This adds:
- `extension_isolated_profile` config field with backward-compatible default
- `--isolated` CLI flag on `extension serve`
- `serve_with_shutdown()` bridge refactor for external lifecycle control
- `isolated_extension` orchestrator: launches Chrome with extension
pre-loaded on CDP port 9333, monitors process, handles cleanup
- `with_load_extension()` builder on BrowserLauncher
- Setup wizard prompt for isolated vs shared extension profile
- Recap and completion output updates
CUE-347
* [packages/actionbook-rs]fix: harden isolated extension bridge lifecycle
- Propagate bridge server errors (e.g. port-in-use) instead of
swallowing them; callers now see a non-zero exit code
- Reset extension_isolated_profile flag when switching to built-in
browser, preventing stale config from routing to isolated mode
- Replace shell-based `kill` command with libc::kill() to eliminate
PATH-hijacking risk; only send signals when Chrome hasn't already
exited to avoid hitting a recycled PID
- Tighten "already running" detection: require both SingletonLock in
the isolated profile dir AND a responsive CDP endpoint, preventing
mistaken reuse of a different Chrome instance on the same port
* [packages/actionbook-rs]fix: harden isolated extension bridge with CDP pipe transport
- Replace --load-extension (removed in Chrome 137+) with CDP pipe
transport: launch Chrome with --remote-debugging-pipe, then send
Extensions.loadUnpacked over fd 3/4 post-launch
- Add cdp_pipe.rs: null-terminated pipe protocol, PipeKeepAlive handle,
and load_extension with blocking I/O for spawn_blocking
- Add cdp_http.rs: CDP /json/list target discovery and Runtime.evaluate
for injecting bridge token directly into extension storage via CDP
- Add background.js storage.onChanged listener for CDP-injected tokens
- Fix non-Unix isolated mode: fail early with clear error instead of
silently launching without extension loading capability
- Fix CLOEXEC on fd 3/4: when os_pipe fd already equals target fd
number, clear FD_CLOEXEC via fcntl instead of skipping dup2
- Fix token injection safety: find_any_extension_service_worker now
matches only SWs ending with /background.js to avoid injecting
tokens into third-party extensions
- Fix cleanup cross-contamination: serve_with_shutdown and
isolated_extension only delete files belonging to their own mode,
preventing concurrent bridge interference
- Refactor resolve_cdp_endpoint for reuse across connect and --cdp
- Add session WS URL refresh on reconnect to handle browser restarts
- Update tests for pipe flags, SW filename filtering, stale WS URLs
* [packages/actionbook-rs]feat: add `extension stop` command to gracefully stop bridge server
Adds PID file mechanism so `actionbook extension stop` can locate and
terminate the running bridge process without manual Ctrl+C or `kill`.
- PID files written with 0600 permissions (atomic write) to prevent injection
- Validates bridge is listening on expected port before sending SIGTERM (no PID recycling risk)
- SIGKILL escalation after 2.5s timeout
- Platform guards: #[cfg(unix)] with Windows taskkill fallback
- Tracks isolated vs global PID files independently
* [skills/actionbook]docs: update skill with extension stop command and full lifecycle
- Add `actionbook extension stop` to command list
- Replace manual process kill comment with concrete `extension stop` command
in the cleanup lifecycle (Step 2)
- Update extension mode example to include stop in cleanup
* [docs/guides]docs: add extension stop command to browser extension guide
- Setup Step 3: mention `extension stop` as the way to stop the bridge
- New "Shutdown" section with proper cleanup order (browser close → extension stop)
- Troubleshooting: reference `extension stop` for bridge restart flow
* [docs/guides]docs: add isolated extension mode to browser extension guide
- Overview: expand mode table with Extension (Isolated) as third option
- New "Isolated Mode" section: quick start, config, comparison table,
when-to-use guidance
- Shutdown: separate instructions for standard vs isolated mode
* [packages/actionbook-rs]fix: resolve PID by port and preserve PID file when process alive
Fix two bugs in `extension stop` identified in PR review:
1. Use port files to match the requested port to the correct PID file
(isolated vs standard), preventing SIGTERM to the wrong bridge when
both are running on different ports.
2. Only delete the PID file when the process is confirmed dead (via
kill(pid, 0)), not merely because the port probe failed. This
preserves the PID file for a subsequent `extension stop --port
<correct>` when the bridge is on a different port.
* [packages/actionbook-rs]fix: smart cleanup of cross-mode stale files and prevent ambiguous PID selection
Address follow-up review findings on extension stop and bridge startup:
1. Extract `is_pid_alive()` utility to extension_bridge for cross-platform
PID liveness checks (kill(0) on Unix, tasklist on Windows).
2. Smart cross-mode cleanup at startup: instead of blindly deleting the
other mode's files (breaks concurrent bridges) or never deleting them
(leaves stale tokens that confuse send_command), check if the other
mode's process is alive via PID probe before deciding.
3. Refuse to auto-stop when both PID files exist but no port file matches
the requested port, preventing SIGTERM to the wrong bridge.
4. Make serve_with_shutdown mode-aware: only clean the current mode's
stale port file instead of always cleaning the standard one.
* [packages/actionbook-rs]fix: atomic PID:PORT mapping to prevent SIGTERM to wrong process
Store port alongside PID in the same file (PID:PORT format) to create
an atomic PID-to-port mapping. This eliminates all port-file-based
guessing in `extension stop`, fixing the root cause of the P1 bug
where SIGTERM could be sent to the wrong process.
- write_pid_file/write_isolated_pid_file: write "PID:PORT" format
- read_pid_file/read_isolated_pid_file: return Option<(u32, u16)>
- stop(): deterministic PID selection via embedded port match
- is_pid_alive (Windows): fix tasklist substring match (exact field)
- taskkill: only delete PID file when process confirmed dead
* [packages/actionbook-rs]fix: select token by port in send_command for parallel bridges
Use PID:PORT mapping to select the correct token file based on target
port, so parallel bridges (standard + isolated) authenticate correctly.
Previously the fixed read order (standard first) caused auth failures
when sending commands to the isolated bridge while standard was running.
* [packages/actionbook-rs]fix: clean up Chrome and bridge on isolated extension load failure
When extension loading fails (CDP error, panic, or timeout), the early
return bypassed all cleanup logic, leaving the child Chrome process
running and stale bridge state files on disk. Now performs shutdown
signal, file cleanup, and Chrome termination before returning the error.
* [docs]feat: add browser extension documentation for PR #89
Add comprehensive documentation for the Chrome Extension Bridge feature:
- New guides/browser-extension.mdx with setup, usage, security, and
troubleshooting sections
- docs.json navigation updated with new page entry
- index.mdx gains Integration Options card section (CLI/Extension/MCP)
- installation.mdx table and links include extension method
- cli-and-skills.mdx adds extension mode tip after browser examples
- api-reference/cli.mdx adds extension subcommands and --extension
global flag documentation
* [docs]fix: update extension docs to reflect GitHub Release install flow
Sync documentation with PR #93 changes: extension is now downloaded
from GitHub Releases instead of extracted from embedded CLI binary.