#![allow(clippy::doc_markdown)]
#![allow(dead_code)]
use std::path::PathBuf;
use clap::{ArgAction, Args, Parser, Subcommand, ValueEnum};
use clap_complete::Shell;
#[derive(Parser)]
#[command(
name = "chrome-cli",
version,
about = "Browser automation via the Chrome DevTools Protocol",
long_about = "chrome-cli is a command-line tool for browser automation via the Chrome DevTools \
Protocol (CDP). It provides subcommands for connecting to Chrome/Chromium instances, \
managing tabs, navigating pages, inspecting the DOM, executing JavaScript, monitoring \
console output, intercepting network requests, simulating user interactions, filling forms, \
emulating devices, and collecting performance metrics.\n\n\
Designed for AI agents and shell scripting, every subcommand produces structured JSON \
output on stdout and structured JSON errors on stderr. Global flags control connection \
settings, output format, and target tab selection.",
after_long_help = "\
QUICK START:
# Connect to a running Chrome instance
chrome-cli connect
# Launch a new headless Chrome and connect
chrome-cli connect --launch --headless
# List open tabs and navigate to a URL
chrome-cli tabs list
chrome-cli navigate https://example.com
# Take a full-page screenshot
chrome-cli page screenshot --full-page --file shot.png
# Execute JavaScript and get the result
chrome-cli js exec \"document.title\"
# Capture the accessibility tree and fill a form field
chrome-cli page snapshot
chrome-cli form fill s5 \"hello@example.com\"
# Monitor console output in real time
chrome-cli console follow --timeout 5000
EXIT CODES:
0 Success
1 General error (invalid arguments, internal failure)
2 Connection error (Chrome not running, session expired)
3 Target error (tab not found, no page targets)
4 Timeout error (navigation or trace timeout)
5 Protocol error (CDP protocol failure, dialog handling error)
ENVIRONMENT VARIABLES:
CHROME_CLI_PORT CDP port number (default: 9222)
CHROME_CLI_HOST CDP host address (default: 127.0.0.1)
CHROME_CLI_TIMEOUT Default command timeout in milliseconds
CHROME_CLI_CONFIG Path to configuration file",
term_width = 100
)]
pub struct Cli {
#[command(flatten)]
pub global: GlobalOpts,
#[command(subcommand)]
pub command: Command,
}
#[derive(Args)]
pub struct GlobalOpts {
#[arg(long, global = true, env = "CHROME_CLI_PORT")]
pub port: Option<u16>,
#[arg(
long,
default_value = "127.0.0.1",
global = true,
env = "CHROME_CLI_HOST"
)]
pub host: String,
#[arg(long, global = true)]
pub ws_url: Option<String>,
#[arg(long, global = true, env = "CHROME_CLI_TIMEOUT")]
pub timeout: Option<u64>,
#[arg(long, global = true)]
pub tab: Option<String>,
#[arg(long, global = true)]
pub auto_dismiss_dialogs: bool,
#[arg(long, global = true, env = "CHROME_CLI_CONFIG")]
pub config: Option<PathBuf>,
#[command(flatten)]
pub output: OutputFormat,
}
impl GlobalOpts {
const DEFAULT_PORT: u16 = 9222;
#[must_use]
pub fn port_or_default(&self) -> u16 {
self.port.unwrap_or(Self::DEFAULT_PORT)
}
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Args)]
#[group(multiple = false)]
pub struct OutputFormat {
#[arg(long, global = true)]
pub json: bool,
#[arg(long, global = true)]
pub pretty: bool,
#[arg(long, global = true)]
pub plain: bool,
}
#[derive(Subcommand)]
pub enum Command {
#[command(
long_about = "Connect to a running Chrome/Chromium instance via the Chrome DevTools \
Protocol, or launch a new one. Tests the connection and prints browser metadata \
(browser version, WebSocket URL, user agent). The session is persisted to a \
local file so subsequent commands reuse the same connection.",
after_long_help = "\
EXAMPLES:
# Connect to Chrome on the default port (9222)
chrome-cli connect
# Launch a new headless Chrome instance
chrome-cli connect --launch --headless
# Connect to a specific port
chrome-cli connect --port 9333
# Check connection status
chrome-cli connect --status
# Disconnect and remove session file
chrome-cli connect --disconnect"
)]
Connect(ConnectArgs),
#[command(
long_about = "Tab management commands: list open tabs, create new tabs, close tabs, and \
activate (focus) a specific tab. Each operation returns structured JSON with tab IDs \
and metadata.",
after_long_help = "\
EXAMPLES:
# List all open tabs
chrome-cli tabs list
# Open a new tab and get its ID
chrome-cli tabs create https://example.com
# Close tabs by ID
chrome-cli tabs close ABC123 DEF456
# Activate a specific tab
chrome-cli tabs activate ABC123"
)]
Tabs(TabsArgs),
#[command(
long_about = "Navigate to URLs, reload pages, go back/forward in history, and wait for \
navigation events. Supports waiting for load, DOMContentLoaded, or network idle.",
after_long_help = "\
EXAMPLES:
# Navigate to a URL and wait for page load
chrome-cli navigate https://example.com
# Navigate and wait for network idle
chrome-cli navigate https://example.com --wait-until networkidle
# Go back in browser history
chrome-cli navigate back
# Reload the current page, bypassing cache
chrome-cli navigate reload --ignore-cache"
)]
Navigate(NavigateArgs),
#[command(
long_about = "Inspect the current page: capture screenshots (full page or element), \
extract visible text, dump the accessibility tree, or search for text/elements on \
the page.",
after_long_help = "\
EXAMPLES:
# Extract all visible text from the page
chrome-cli page text
# Capture the accessibility tree (assigns UIDs to elements)
chrome-cli page snapshot
# Take a full-page screenshot
chrome-cli page screenshot --full-page --file page.png
# Find elements by text
chrome-cli page find \"Sign in\"
# Resize the viewport
chrome-cli page resize 1280x720"
)]
Page(PageArgs),
#[command(
long_about = "Query and manipulate the DOM: select elements by CSS selector or XPath, \
get/set attributes and text, read outerHTML, inspect computed styles, navigate the \
element tree, and remove elements. Target elements by node ID (from 'dom select'), \
snapshot UID (from 'page snapshot'), or CSS selector (prefixed with 'css:').",
after_long_help = "\
EXAMPLES:
# Select elements by CSS selector
chrome-cli dom select \"h1\"
# Select by XPath
chrome-cli dom select \"//a[@href]\" --xpath
# Get an element's attribute
chrome-cli dom get-attribute s3 href
# Read element text
chrome-cli dom get-text css:h1
# Set an attribute
chrome-cli dom set-attribute s5 class \"highlight\"
# View the DOM tree
chrome-cli dom tree --depth 3"
)]
Dom(DomArgs),
#[command(
long_about = "Execute JavaScript expressions or scripts in the page context. Returns \
the result as structured JSON. Supports both synchronous expressions and async \
functions.",
after_long_help = "\
EXAMPLES:
# Get the page title
chrome-cli js exec \"document.title\"
# Execute a script file
chrome-cli js exec --file script.js
# Run code on a specific element (by UID from snapshot)
chrome-cli js exec --uid s3 \"(el) => el.textContent\"
# Read from stdin
echo 'document.URL' | chrome-cli js exec -"
)]
Js(JsArgs),
#[command(
long_about = "Read and monitor browser console messages (log, warn, error, info). \
Can capture existing messages or stream new messages in real time.",
after_long_help = "\
EXAMPLES:
# Read recent console messages
chrome-cli console read
# Show only error messages
chrome-cli console read --errors-only
# Stream console messages in real time
chrome-cli console follow
# Stream errors for 10 seconds
chrome-cli console follow --errors-only --timeout 10000"
)]
Console(ConsoleArgs),
#[command(
long_about = "Monitor and intercept network requests. List recent requests, filter by \
URL pattern or resource type, capture request/response bodies, and stream requests \
in real time.",
after_long_help = "\
EXAMPLES:
# List recent network requests
chrome-cli network list
# Filter by resource type
chrome-cli network list --type xhr,fetch
# Get details of a specific request
chrome-cli network get 42
# Stream network requests in real time
chrome-cli network follow --url api.example.com"
)]
Network(NetworkArgs),
#[command(
long_about = "Simulate user interactions: click elements, type text, press key \
combinations, scroll the page, hover over elements, and perform drag-and-drop \
operations. Target elements by UID (from 'page snapshot') or CSS selector \
(prefixed with 'css:').",
after_long_help = "\
EXAMPLES:
# Click an element by UID
chrome-cli interact click s5
# Click by CSS selector
chrome-cli interact click css:#submit-btn
# Type text into the focused element
chrome-cli interact type \"Hello, world!\"
# Press a key combination
chrome-cli interact key Control+A
# Scroll down one viewport height
chrome-cli interact scroll"
)]
Interact(InteractArgs),
#[command(
long_about = "Fill in form fields, select dropdown options, toggle checkboxes, and clear \
fields. Supports targeting fields by UID (from accessibility snapshot) or CSS \
selector (prefixed with 'css:'). Run 'page snapshot' first to discover field UIDs.",
after_long_help = "\
EXAMPLES:
# Fill a field by UID (from page snapshot)
chrome-cli form fill s5 \"hello@example.com\"
# Fill by CSS selector
chrome-cli form fill css:#email \"user@example.com\"
# Fill multiple fields at once
chrome-cli form fill-many '[{\"uid\":\"s5\",\"value\":\"Alice\"},{\"uid\":\"s7\",\"value\":\"alice@example.com\"}]'
# Clear a field
chrome-cli form clear s5
# Upload a file
chrome-cli form upload s10 ./photo.jpg"
)]
Form(FormArgs),
#[command(
long_about = "Emulate different devices, screen sizes, and network conditions. Set \
custom user agents, viewport dimensions, device scale factor, and network throttling \
profiles.",
after_long_help = "\
EXAMPLES:
# Emulate a mobile device
chrome-cli emulate set --viewport 375x667 --device-scale 2 --mobile
# Simulate slow 3G network
chrome-cli emulate set --network 3g
# Force dark mode
chrome-cli emulate set --color-scheme dark
# Check current emulation settings
chrome-cli emulate status
# Clear all emulation overrides
chrome-cli emulate reset"
)]
Emulate(EmulateArgs),
#[command(
long_about = "Collect performance metrics, capture trace files, measure page load timing, \
and analyze runtime performance. Outputs metrics as structured JSON for analysis.",
after_long_help = "\
EXAMPLES:
# Quick Core Web Vitals measurement
chrome-cli perf vitals
# Record a trace until Ctrl+C
chrome-cli perf record
# Record a trace for 5 seconds
chrome-cli perf record --duration 5000
# Record with page reload
chrome-cli perf record --reload --duration 5000
# Analyze a trace for render-blocking resources
chrome-cli perf analyze RenderBlocking --trace-file trace.json"
)]
Perf(PerfArgs),
#[command(
long_about = "Detect and handle browser JavaScript dialogs (alert, confirm, prompt, \
beforeunload). Query whether a dialog is open, accept or dismiss it, and provide \
prompt text. Useful for automation scripts that need to respond to dialogs \
programmatically.",
after_long_help = "\
EXAMPLES:
# Check if a dialog is open
chrome-cli dialog info
# Accept an alert or confirm dialog
chrome-cli dialog handle accept
# Dismiss a dialog
chrome-cli dialog handle dismiss
# Accept a prompt with text
chrome-cli dialog handle accept --text \"my input\""
)]
Dialog(DialogArgs),
#[command(
long_about = "Manage the chrome-cli configuration file. Show the resolved configuration \
from all sources, create a default config file, or display the active config file path. \
Config files use TOML format and are searched in priority order: --config flag, \
$CHROME_CLI_CONFIG env var, project-local, XDG config dir, home directory.",
after_long_help = "\
EXAMPLES:
# Show the resolved configuration
chrome-cli config show
# Create a default config file
chrome-cli config init
# Create a config at a custom path
chrome-cli config init --path ./my-config.toml
# Show the active config file path
chrome-cli config path"
)]
Config(ConfigArgs),
#[command(
long_about = "Generate shell completion scripts for tab-completion of commands, flags, \
and enum values. Pipe the output to the appropriate file for your shell.",
after_long_help = "\
EXAMPLES:
# Bash
chrome-cli completions bash > /etc/bash_completion.d/chrome-cli
# Zsh
chrome-cli completions zsh > ~/.zfunc/_chrome-cli
# Fish
chrome-cli completions fish > ~/.config/fish/completions/chrome-cli.fish
# PowerShell
chrome-cli completions powershell >> $PROFILE
# Elvish
chrome-cli completions elvish >> ~/.elvish/rc.elv"
)]
Completions(CompletionsArgs),
#[command(
long_about = "Show usage examples for chrome-cli commands. Without arguments, lists all \
command groups with a brief description and one example each. With a command name, \
shows detailed examples for that specific command group.",
after_long_help = "\
EXAMPLES:
# List all command groups with summary examples
chrome-cli examples
# Show detailed examples for the navigate command
chrome-cli examples navigate
# Get all examples as JSON (for programmatic use)
chrome-cli examples --json
# Pretty-printed JSON output
chrome-cli examples --pretty"
)]
Examples(ExamplesArgs),
#[command(
long_about = "Output a complete, machine-readable JSON manifest describing every command, \
subcommand, flag, argument, and type in the CLI. Designed for AI agents and tooling \
that need to programmatically discover the CLI surface. The manifest is generated at \
runtime from the clap command tree, so it is always in sync with the binary.",
after_long_help = "\
EXAMPLES:
# Full capabilities manifest
chrome-cli capabilities
# Pretty-printed for readability
chrome-cli capabilities --pretty
# Capabilities for a specific command
chrome-cli capabilities --command navigate
# Compact listing (names and descriptions only)
chrome-cli capabilities --compact"
)]
Capabilities(CapabilitiesArgs),
#[command(
long_about = "Display man pages for chrome-cli commands. Without arguments, displays \
the main chrome-cli man page. With a subcommand name, displays the man page for \
that specific command. Output is in roff format, suitable for piping to a pager.",
after_long_help = "\
EXAMPLES:
# Display the main chrome-cli man page
chrome-cli man
# Display the man page for the connect command
chrome-cli man connect
# Display the man page for the tabs command
chrome-cli man tabs
# Pipe to a pager
chrome-cli man navigate | less"
)]
Man(ManArgs),
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum ChromeChannel {
Stable,
Canary,
Beta,
Dev,
}
#[derive(Args)]
pub struct TabsArgs {
#[command(subcommand)]
pub command: TabsCommand,
}
#[derive(Subcommand)]
pub enum TabsCommand {
#[command(
long_about = "List all open browser tabs. Returns JSON with each tab's ID, title, URL, \
and type. By default, only page tabs are shown; use --all to include internal \
Chrome pages (chrome://, chrome-extension://).",
after_long_help = "\
EXAMPLES:
# List page tabs
chrome-cli tabs list
# Include internal Chrome pages
chrome-cli tabs list --all"
)]
List(TabsListArgs),
#[command(
long_about = "Create a new browser tab. Optionally specify a URL to open; defaults to \
about:blank. Returns JSON with the new tab's ID and URL. Use --background to open \
the tab without switching focus to it.",
after_long_help = "\
EXAMPLES:
# Open a blank tab
chrome-cli tabs create
# Open a URL
chrome-cli tabs create https://example.com
# Open in the background
chrome-cli tabs create https://example.com --background"
)]
Create(TabsCreateArgs),
#[command(
long_about = "Close one or more browser tabs by their IDs. Accepts multiple tab IDs \
as arguments. Returns JSON confirming which tabs were closed. Cannot close the \
last remaining tab (Chrome requires at least one open tab).",
after_long_help = "\
EXAMPLES:
# Close a single tab
chrome-cli tabs close ABC123
# Close multiple tabs
chrome-cli tabs close ABC123 DEF456 GHI789"
)]
Close(TabsCloseArgs),
#[command(
long_about = "Activate (bring to front) a specific browser tab by its ID. The tab \
becomes the active target for subsequent commands. Returns JSON confirming the \
activated tab.",
after_long_help = "\
EXAMPLES:
# Activate a tab by ID
chrome-cli tabs activate ABC123
# Activate silently
chrome-cli tabs activate ABC123 --quiet"
)]
Activate(TabsActivateArgs),
}
#[derive(Args)]
pub struct TabsListArgs {
#[arg(long)]
pub all: bool,
}
#[derive(Args)]
pub struct TabsCreateArgs {
pub url: Option<String>,
#[arg(long)]
pub background: bool,
}
#[derive(Args)]
pub struct TabsCloseArgs {
#[arg(required = true)]
pub targets: Vec<String>,
}
#[derive(Args)]
pub struct TabsActivateArgs {
pub target: String,
#[arg(long)]
pub quiet: bool,
}
#[derive(Args)]
#[command(args_conflicts_with_subcommands = true)]
pub struct NavigateArgs {
#[command(subcommand)]
pub command: Option<NavigateCommand>,
#[command(flatten)]
pub url_args: NavigateUrlArgs,
}
#[derive(Subcommand)]
pub enum NavigateCommand {
#[command(
long_about = "Navigate back one step in the browser's session history, equivalent to \
clicking the browser's back button. Returns JSON with the new URL after navigation.",
after_long_help = "\
EXAMPLES:
# Go back
chrome-cli navigate back"
)]
Back,
#[command(
long_about = "Navigate forward one step in the browser's session history, equivalent to \
clicking the browser's forward button. Only works if the user previously navigated \
back. Returns JSON with the new URL after navigation.",
after_long_help = "\
EXAMPLES:
# Go forward
chrome-cli navigate forward"
)]
Forward,
#[command(
long_about = "Reload the current page. Use --ignore-cache to bypass the browser cache \
and force a full reload from the server. Returns JSON with the page URL after reload.",
after_long_help = "\
EXAMPLES:
# Reload the page
chrome-cli navigate reload
# Reload bypassing cache
chrome-cli navigate reload --ignore-cache"
)]
Reload(NavigateReloadArgs),
}
#[derive(Args)]
pub struct NavigateUrlArgs {
pub url: Option<String>,
#[arg(long, value_enum, default_value_t = WaitUntil::Load)]
pub wait_until: WaitUntil,
#[arg(long)]
pub timeout: Option<u64>,
#[arg(long)]
pub ignore_cache: bool,
}
#[derive(Args)]
pub struct NavigateReloadArgs {
#[arg(long)]
pub ignore_cache: bool,
}
#[derive(Args)]
pub struct PageArgs {
#[command(subcommand)]
pub command: PageCommand,
}
#[derive(Subcommand)]
pub enum PageCommand {
#[command(
long_about = "Extract the visible text content from the current page or a specific \
element. Returns the text as a plain string. Useful for reading page content \
without HTML markup.",
after_long_help = "\
EXAMPLES:
# Get all visible text
chrome-cli page text
# Get text from a specific element
chrome-cli page text --selector \"#main-content\""
)]
Text(PageTextArgs),
#[command(
long_about = "Capture the accessibility tree (AX tree) of the current page. Each \
interactive element is assigned a UID (e.g., s1, s2, s3) that can be used with \
'interact', 'form', and 'js exec --uid' commands. Use --verbose to include \
additional properties like checked, disabled, and level.",
after_long_help = "\
EXAMPLES:
# Capture the accessibility tree
chrome-cli page snapshot
# Verbose output with extra properties
chrome-cli page snapshot --verbose
# Save to a file
chrome-cli page snapshot --file snapshot.txt"
)]
Snapshot(PageSnapshotArgs),
#[command(
long_about = "Search for elements on the page by text content, CSS selector, or \
accessibility role. Returns matching elements with their UIDs, roles, and names. \
By default, performs a case-insensitive substring match; use --exact for exact \
matching.",
after_long_help = "\
EXAMPLES:
# Find elements by text
chrome-cli page find \"Sign in\"
# Find by CSS selector
chrome-cli page find --selector \"button.primary\"
# Find by accessibility role
chrome-cli page find --role button
# Exact text match with limit
chrome-cli page find \"Submit\" --exact --limit 1"
)]
Find(PageFindArgs),
#[command(
long_about = "Capture a screenshot of the current page, a specific element, or a \
viewport region. Supports PNG (default), JPEG, and WebP formats. Use --full-page \
to capture the entire scrollable page, --selector or --uid to capture a specific \
element, or --clip to capture a region. Note: --full-page conflicts with \
--selector, --uid, and --clip.",
after_long_help = "\
EXAMPLES:
# Screenshot the visible viewport
chrome-cli page screenshot --file shot.png
# Full-page screenshot
chrome-cli page screenshot --full-page --file full.png
# Screenshot a specific element by UID
chrome-cli page screenshot --uid s3 --file element.png
# JPEG format with quality
chrome-cli page screenshot --format jpeg --quality 80 --file shot.jpg"
)]
Screenshot(PageScreenshotArgs),
#[command(
long_about = "Resize the browser viewport to the specified dimensions. The size is \
given as WIDTHxHEIGHT in pixels (e.g., 1280x720). Useful for testing responsive \
layouts. See also: 'emulate set --viewport' for device emulation.",
after_long_help = "\
EXAMPLES:
# Resize to 1280x720
chrome-cli page resize 1280x720
# Mobile viewport
chrome-cli page resize 375x667"
)]
Resize(PageResizeArgs),
}
#[derive(Debug, Clone, Copy, ValueEnum, Default)]
pub enum ScreenshotFormat {
#[default]
Png,
Jpeg,
Webp,
}
#[derive(Args)]
pub struct PageScreenshotArgs {
#[arg(long)]
pub full_page: bool,
#[arg(long)]
pub selector: Option<String>,
#[arg(long)]
pub uid: Option<String>,
#[arg(long, value_enum, default_value_t = ScreenshotFormat::Png)]
pub format: ScreenshotFormat,
#[arg(long, value_parser = clap::value_parser!(u8).range(0..=100))]
pub quality: Option<u8>,
#[arg(long)]
pub file: Option<PathBuf>,
#[arg(long)]
pub clip: Option<String>,
}
#[derive(Args)]
pub struct PageTextArgs {
#[arg(long)]
pub selector: Option<String>,
}
#[derive(Args)]
pub struct PageSnapshotArgs {
#[arg(long)]
pub verbose: bool,
#[arg(long)]
pub file: Option<PathBuf>,
}
#[derive(Args)]
pub struct PageFindArgs {
pub query: Option<String>,
#[arg(long)]
pub selector: Option<String>,
#[arg(long)]
pub role: Option<String>,
#[arg(long)]
pub exact: bool,
#[arg(long, default_value_t = 10)]
pub limit: usize,
}
#[derive(Args)]
pub struct PerfArgs {
#[command(subcommand)]
pub command: PerfCommand,
}
#[derive(Subcommand)]
pub enum PerfCommand {
#[command(
long_about = "Record a performance trace in a single long-running session. The trace \
captures JavaScript execution, layout, paint, network, and other browser activity. \
Recording continues until you press Ctrl+C or the --duration timeout elapses. \
Use --reload to reload the page before recording. The trace is saved to a JSON \
file that can be opened in Chrome DevTools or analyzed with 'perf analyze'.",
after_long_help = "\
EXAMPLES:
# Record until Ctrl+C
chrome-cli perf record
# Record for 5 seconds
chrome-cli perf record --duration 5000
# Record with page reload
chrome-cli perf record --reload --duration 5000
# Save to a specific file
chrome-cli perf record --file my-trace.json"
)]
Record(PerfRecordArgs),
#[command(
long_about = "Analyze a previously saved trace file for a specific performance insight. \
Available insights: DocumentLatency (document request timing), LCPBreakdown (Largest \
Contentful Paint phases), RenderBlocking (render-blocking resources), LongTasks \
(JavaScript tasks > 50ms). Returns structured JSON with the analysis results.",
after_long_help = "\
EXAMPLES:
# Analyze LCP breakdown
chrome-cli perf analyze LCPBreakdown --trace-file trace.json
# Find render-blocking resources
chrome-cli perf analyze RenderBlocking --trace-file trace.json
# Identify long tasks
chrome-cli perf analyze LongTasks --trace-file trace.json"
)]
Analyze(PerfAnalyzeArgs),
#[command(
long_about = "Perform a quick Core Web Vitals measurement. Automatically starts a \
trace, reloads the page, collects vitals (LCP, FID, CLS), and stops the trace. \
Returns structured JSON with the web vitals metrics.",
after_long_help = "\
EXAMPLES:
# Measure web vitals
chrome-cli perf vitals
# Save the underlying trace file
chrome-cli perf vitals --file vitals-trace.json"
)]
Vitals(PerfVitalsArgs),
}
#[derive(Args)]
pub struct PerfRecordArgs {
#[arg(long)]
pub reload: bool,
#[arg(long)]
pub duration: Option<u64>,
#[arg(long)]
pub file: Option<PathBuf>,
}
#[derive(Args)]
pub struct PerfAnalyzeArgs {
pub insight: String,
#[arg(long)]
pub trace_file: PathBuf,
}
#[derive(Args)]
pub struct PerfVitalsArgs {
#[arg(long)]
pub file: Option<PathBuf>,
}
#[derive(Args)]
pub struct JsArgs {
#[command(subcommand)]
pub command: JsCommand,
}
#[derive(Subcommand)]
pub enum JsCommand {
#[command(
long_about = "Execute a JavaScript expression or script in the page context and return \
the result as JSON. Code can be provided as an inline argument, read from a file \
with --file, or piped via stdin using '-'. When --uid is specified, the code is \
wrapped in a function that receives the element as its first argument. By default, \
promise results are awaited; use --no-await to return immediately.",
after_long_help = "\
EXAMPLES:
# Evaluate an expression
chrome-cli js exec \"document.title\"
# Execute a script file
chrome-cli js exec --file script.js
# Run code on a specific element
chrome-cli js exec --uid s3 \"(el) => el.textContent\"
# Read from stdin
echo 'document.URL' | chrome-cli js exec -
# Skip awaiting promises
chrome-cli js exec --no-await \"fetch('/api/data')\""
)]
Exec(JsExecArgs),
}
#[derive(Args)]
pub struct JsExecArgs {
#[arg(conflicts_with = "file")]
pub code: Option<String>,
#[arg(long)]
pub file: Option<PathBuf>,
#[arg(long)]
pub uid: Option<String>,
#[arg(long, action = ArgAction::SetTrue)]
pub no_await: bool,
#[arg(long)]
pub timeout: Option<u64>,
#[arg(long)]
pub max_size: Option<usize>,
}
#[derive(Args)]
pub struct DialogArgs {
#[command(subcommand)]
pub command: DialogCommand,
}
#[derive(Subcommand)]
pub enum DialogCommand {
#[command(
long_about = "Accept or dismiss the currently open browser dialog (alert, confirm, \
prompt, or beforeunload). A dialog must be open before this command can be used. \
For prompt dialogs, use --text to provide the response text when accepting.",
after_long_help = "\
EXAMPLES:
# Accept an alert
chrome-cli dialog handle accept
# Dismiss a confirm dialog
chrome-cli dialog handle dismiss
# Accept a prompt with text
chrome-cli dialog handle accept --text \"my response\""
)]
Handle(DialogHandleArgs),
#[command(
long_about = "Check whether a JavaScript dialog (alert, confirm, prompt, or \
beforeunload) is currently open. Returns JSON with the dialog's type, message, \
and default prompt text if applicable. Returns {\"open\": false} when no dialog \
is present.",
after_long_help = "\
EXAMPLES:
# Check for open dialog
chrome-cli dialog info"
)]
Info,
}
#[derive(Args)]
pub struct DialogHandleArgs {
pub action: DialogAction,
#[arg(long)]
pub text: Option<String>,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum DialogAction {
Accept,
Dismiss,
}
#[derive(Debug, Clone, Copy, ValueEnum, Default, PartialEq, Eq)]
pub enum WaitUntil {
#[default]
Load,
Domcontentloaded,
Networkidle,
None,
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Args)]
pub struct ConnectArgs {
#[arg(long)]
pub launch: bool,
#[arg(long, conflicts_with_all = ["launch", "disconnect"])]
pub status: bool,
#[arg(long, conflicts_with_all = ["launch", "status"])]
pub disconnect: bool,
#[arg(long, requires = "launch")]
pub headless: bool,
#[arg(long, requires = "launch", default_value = "stable")]
pub channel: ChromeChannel,
#[arg(long, requires = "launch")]
pub chrome_path: Option<PathBuf>,
#[arg(long, requires = "launch")]
pub chrome_arg: Vec<String>,
}
#[derive(Args)]
pub struct InteractArgs {
#[command(subcommand)]
pub command: InteractCommand,
}
#[derive(Subcommand)]
pub enum InteractCommand {
#[command(
long_about = "Click an element identified by UID (from 'page snapshot', e.g., 's5') or \
CSS selector (prefixed with 'css:', e.g., 'css:#submit'). By default, performs a \
left single-click at the element's center. Use --double for double-click or --right \
for right-click (context menu). These flags are mutually exclusive.",
after_long_help = "\
EXAMPLES:
# Click by UID
chrome-cli interact click s5
# Click by CSS selector
chrome-cli interact click css:#submit-btn
# Double-click
chrome-cli interact click s5 --double
# Right-click (context menu)
chrome-cli interact click s5 --right"
)]
Click(ClickArgs),
#[command(
long_about = "Click at specific viewport coordinates (X, Y in pixels). Useful when \
targeting elements that are not in the accessibility tree or for precise coordinate-\
based interactions. Use --double for double-click or --right for right-click.",
after_long_help = "\
EXAMPLES:
# Click at coordinates
chrome-cli interact click-at 100 200
# Double-click at coordinates
chrome-cli interact click-at 100 200 --double"
)]
ClickAt(ClickAtArgs),
#[command(
long_about = "Move the mouse over an element identified by UID or CSS selector. \
Triggers hover effects, tooltips, and mouseover events. Does not click.",
after_long_help = "\
EXAMPLES:
# Hover by UID
chrome-cli interact hover s3
# Hover by CSS selector
chrome-cli interact hover css:.tooltip-trigger"
)]
Hover(HoverArgs),
#[command(
long_about = "Drag from one element to another. Both source and target are identified \
by UID or CSS selector. Simulates mouse down on the source, move to the target, \
and mouse up on the target.",
after_long_help = "\
EXAMPLES:
# Drag between elements by UID
chrome-cli interact drag s3 s7
# Drag using CSS selectors
chrome-cli interact drag css:#item css:#dropzone"
)]
Drag(DragArgs),
#[command(
long_about = "Type text character-by-character into the currently focused element. \
Simulates individual key press and release events for each character. Use --delay \
to add a pause between keystrokes. To focus an element first, use 'interact click'.",
after_long_help = "\
EXAMPLES:
# Type text
chrome-cli interact type \"Hello, world!\"
# Type with delay between keystrokes
chrome-cli interact type \"slow typing\" --delay 50"
)]
Type(TypeArgs),
#[command(
long_about = "Press a key or key combination. Supports modifier keys (Control, Shift, \
Alt, Meta) combined with regular keys using '+' separator. Use --repeat to press \
the key multiple times. Common keys: Enter, Tab, Escape, Backspace, ArrowUp, \
ArrowDown, ArrowLeft, ArrowRight, Home, End, PageUp, PageDown, Delete.",
after_long_help = "\
EXAMPLES:
# Press Enter
chrome-cli interact key Enter
# Select all (Ctrl+A)
chrome-cli interact key Control+A
# Press Tab 3 times
chrome-cli interact key Tab --repeat 3
# Multi-modifier combo
chrome-cli interact key Control+Shift+ArrowRight"
)]
Key(KeyArgs),
#[command(
long_about = "Scroll the page or a specific container element. By default, scrolls \
down by one viewport height. Use --direction to scroll in other directions, \
--amount to set a custom distance in pixels, or the shortcut flags --to-top, \
--to-bottom, --to-element to scroll to specific positions. Use --container to \
scroll within a scrollable child element. Use --smooth for animated scrolling.",
after_long_help = "\
EXAMPLES:
# Scroll down one viewport height
chrome-cli interact scroll
# Scroll up 200 pixels
chrome-cli interact scroll --direction up --amount 200
# Scroll to bottom of page
chrome-cli interact scroll --to-bottom
# Scroll until an element is visible
chrome-cli interact scroll --to-element s15
# Smooth scroll within a container
chrome-cli interact scroll --container css:.scrollable --smooth"
)]
Scroll(ScrollArgs),
}
#[derive(Args)]
pub struct ClickArgs {
pub target: String,
#[arg(long, conflicts_with = "right")]
pub double: bool,
#[arg(long, conflicts_with = "double")]
pub right: bool,
#[arg(long)]
pub include_snapshot: bool,
}
#[derive(Args)]
pub struct ClickAtArgs {
pub x: f64,
pub y: f64,
#[arg(long, conflicts_with = "right")]
pub double: bool,
#[arg(long, conflicts_with = "double")]
pub right: bool,
#[arg(long)]
pub include_snapshot: bool,
}
#[derive(Args)]
pub struct HoverArgs {
pub target: String,
#[arg(long)]
pub include_snapshot: bool,
}
#[derive(Args)]
pub struct DragArgs {
pub from: String,
pub to: String,
#[arg(long)]
pub include_snapshot: bool,
}
#[derive(Args)]
pub struct TypeArgs {
#[arg(required = true)]
pub text: String,
#[arg(long, default_value_t = 0)]
pub delay: u64,
#[arg(long)]
pub include_snapshot: bool,
}
#[derive(Args)]
pub struct KeyArgs {
#[arg(required = true)]
pub keys: String,
#[arg(long, default_value_t = 1)]
pub repeat: u32,
#[arg(long)]
pub include_snapshot: bool,
}
#[derive(Debug, Clone, Copy, ValueEnum, Default)]
pub enum ScrollDirection {
#[default]
Down,
Up,
Left,
Right,
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Args)]
pub struct ScrollArgs {
#[arg(long, value_enum, default_value_t = ScrollDirection::Down,
conflicts_with_all = ["to_element", "to_top", "to_bottom"])]
pub direction: ScrollDirection,
#[arg(long, conflicts_with_all = ["to_element", "to_top", "to_bottom"])]
pub amount: Option<u32>,
#[arg(long, conflicts_with_all = ["direction", "amount", "to_top", "to_bottom", "container"])]
pub to_element: Option<String>,
#[arg(long, conflicts_with_all = ["direction", "amount", "to_element", "to_bottom", "container"])]
pub to_top: bool,
#[arg(long, conflicts_with_all = ["direction", "amount", "to_element", "to_top", "container"])]
pub to_bottom: bool,
#[arg(long)]
pub smooth: bool,
#[arg(long, conflicts_with_all = ["to_element", "to_top", "to_bottom"])]
pub container: Option<String>,
#[arg(long)]
pub include_snapshot: bool,
}
#[derive(Args)]
pub struct FormArgs {
#[command(subcommand)]
pub command: FormCommand,
}
#[derive(Subcommand)]
pub enum FormCommand {
#[command(
long_about = "Set the value of a form field identified by UID (from 'page snapshot', \
e.g., 's5') or CSS selector (prefixed with 'css:', e.g., 'css:#email'). Works \
with text inputs, textareas, select dropdowns, and checkboxes. Dispatches change \
and input events to trigger form validation.",
after_long_help = "\
EXAMPLES:
# Fill by UID
chrome-cli form fill s5 \"hello@example.com\"
# Fill by CSS selector
chrome-cli form fill css:#email \"user@example.com\"
# Select a dropdown option
chrome-cli form fill s8 \"Option B\""
)]
Fill(FormFillArgs),
#[command(
long_about = "Fill multiple form fields in a single command. Accepts a JSON array of \
{uid, value} objects either as an inline argument or from a file with --file. Each \
field is filled in order. Useful for completing entire forms in one step.",
after_long_help = "\
EXAMPLES:
# Fill multiple fields inline
chrome-cli form fill-many '[{\"uid\":\"s5\",\"value\":\"Alice\"},{\"uid\":\"s7\",\"value\":\"alice@example.com\"}]'
# Fill from a JSON file
chrome-cli form fill-many --file form-data.json"
)]
FillMany(FormFillManyArgs),
#[command(
long_about = "Clear the value of a form field identified by UID or CSS selector. \
Sets the field to an empty string and dispatches change and input events.",
after_long_help = "\
EXAMPLES:
# Clear a field by UID
chrome-cli form clear s5
# Clear by CSS selector
chrome-cli form clear css:#search-input"
)]
Clear(FormClearArgs),
#[command(
long_about = "Upload one or more files to a file input element identified by UID or \
CSS selector. The element must be an <input type=\"file\">. Multiple file paths \
can be specified for multi-file upload inputs.",
after_long_help = "\
EXAMPLES:
# Upload a single file
chrome-cli form upload s10 ./photo.jpg
# Upload multiple files
chrome-cli form upload css:#file-input ./doc1.pdf ./doc2.pdf"
)]
Upload(FormUploadArgs),
}
#[derive(Args)]
pub struct FormFillArgs {
pub target: String,
pub value: String,
#[arg(long)]
pub include_snapshot: bool,
}
#[derive(Args)]
pub struct FormFillManyArgs {
#[arg(value_name = "JSON")]
pub input: Option<String>,
#[arg(long)]
pub file: Option<PathBuf>,
#[arg(long)]
pub include_snapshot: bool,
}
#[derive(Args)]
pub struct FormClearArgs {
pub target: String,
#[arg(long)]
pub include_snapshot: bool,
}
#[derive(Args)]
pub struct FormUploadArgs {
pub target: String,
#[arg(required = true)]
pub files: Vec<PathBuf>,
#[arg(long)]
pub include_snapshot: bool,
}
#[derive(Args)]
pub struct ConsoleArgs {
#[command(subcommand)]
pub command: ConsoleCommand,
}
#[derive(Subcommand)]
pub enum ConsoleCommand {
#[command(
long_about = "Read captured console messages from the current page. Without arguments, \
lists recent messages with their IDs, types, and text. Pass a message ID to get \
full details including stack trace and arguments. Filter by type or use --errors-only \
for error and assert messages only.",
after_long_help = "\
EXAMPLES:
# List recent console messages
chrome-cli console read
# Get details of a specific message
chrome-cli console read 42
# Show only errors
chrome-cli console read --errors-only
# Filter by type
chrome-cli console read --type warn,error --limit 20"
)]
Read(ConsoleReadArgs),
#[command(
long_about = "Stream new console messages in real time as they are logged, similar to \
'tail -f'. Each message is printed as a JSON line. Use --timeout to auto-exit \
after a specified duration. Filter by type or use --errors-only to stream only \
error and assert messages.",
after_long_help = "\
EXAMPLES:
# Stream all console output
chrome-cli console follow
# Stream errors only for 10 seconds
chrome-cli console follow --errors-only --timeout 10000
# Stream specific message types
chrome-cli console follow --type log,warn"
)]
Follow(ConsoleFollowArgs),
}
#[derive(Args)]
pub struct ConsoleReadArgs {
pub msg_id: Option<u64>,
#[arg(long, value_name = "TYPES", conflicts_with = "errors_only")]
pub r#type: Option<String>,
#[arg(long, conflicts_with = "type")]
pub errors_only: bool,
#[arg(long, default_value_t = 50)]
pub limit: usize,
#[arg(long, default_value_t = 0)]
pub page: usize,
#[arg(long)]
pub include_preserved: bool,
}
#[derive(Args)]
pub struct ConsoleFollowArgs {
#[arg(long, value_name = "TYPES", conflicts_with = "errors_only")]
pub r#type: Option<String>,
#[arg(long, conflicts_with = "type")]
pub errors_only: bool,
#[arg(long)]
pub timeout: Option<u64>,
}
#[derive(Args)]
pub struct NetworkArgs {
#[command(subcommand)]
pub command: NetworkCommand,
}
#[derive(Subcommand)]
pub enum NetworkCommand {
#[command(
long_about = "List captured network requests from the current page. Returns JSON with \
each request's ID, method, URL, status, resource type, and timing. Filter by \
resource type, URL pattern, HTTP status code, or HTTP method. Use --limit and \
--page for pagination.",
after_long_help = "\
EXAMPLES:
# List recent requests
chrome-cli network list
# Filter by resource type
chrome-cli network list --type xhr,fetch
# Filter by URL pattern
chrome-cli network list --url api.example.com
# Filter by status code
chrome-cli network list --status 4xx"
)]
List(NetworkListArgs),
#[command(
long_about = "Get detailed information about a specific network request by its numeric \
ID. Returns JSON with full request and response headers, timing breakdown, and \
body size. Use --save-request or --save-response to save the request or response \
body to a file.",
after_long_help = "\
EXAMPLES:
# Get request details
chrome-cli network get 42
# Save the response body to a file
chrome-cli network get 42 --save-response body.json
# Save both request and response bodies
chrome-cli network get 42 --save-request req.json --save-response resp.json"
)]
Get(NetworkGetArgs),
#[command(
long_about = "Stream network requests in real time as they are made, similar to \
'tail -f'. Each request is printed as a JSON line. Filter by resource type, \
URL pattern, or HTTP method. Use --timeout to auto-exit after a specified \
duration. Use --verbose to include request and response headers.",
after_long_help = "\
EXAMPLES:
# Stream all network requests
chrome-cli network follow
# Stream API requests only
chrome-cli network follow --type xhr,fetch --url /api/
# Stream with headers for 30 seconds
chrome-cli network follow --verbose --timeout 30000"
)]
Follow(NetworkFollowArgs),
}
#[derive(Args)]
pub struct NetworkListArgs {
#[arg(long, value_name = "TYPES")]
pub r#type: Option<String>,
#[arg(long)]
pub url: Option<String>,
#[arg(long)]
pub status: Option<String>,
#[arg(long)]
pub method: Option<String>,
#[arg(long, default_value_t = 50)]
pub limit: usize,
#[arg(long, default_value_t = 0)]
pub page: usize,
#[arg(long)]
pub include_preserved: bool,
}
#[derive(Args)]
pub struct NetworkGetArgs {
pub req_id: u64,
#[arg(long)]
pub save_request: Option<PathBuf>,
#[arg(long)]
pub save_response: Option<PathBuf>,
}
#[derive(Args)]
pub struct NetworkFollowArgs {
#[arg(long, value_name = "TYPES")]
pub r#type: Option<String>,
#[arg(long)]
pub url: Option<String>,
#[arg(long)]
pub method: Option<String>,
#[arg(long)]
pub timeout: Option<u64>,
#[arg(long)]
pub verbose: bool,
}
#[derive(Args)]
pub struct PageResizeArgs {
pub size: String,
}
#[derive(Args)]
pub struct DomArgs {
#[command(subcommand)]
pub command: DomCommand,
}
#[derive(Subcommand)]
pub enum DomCommand {
#[command(
long_about = "Query elements in the DOM by CSS selector (default) or XPath expression \
(with --xpath). Returns a JSON array of matching elements with their node IDs, \
tag names, attributes, and text content. Node IDs can be used with other dom \
subcommands.",
after_long_help = "\
EXAMPLES:
# Select by CSS selector
chrome-cli dom select \"h1\"
# Select by XPath
chrome-cli dom select \"//a[@href]\" --xpath
# Select with a complex CSS selector
chrome-cli dom select \"div.content > p:first-child\""
)]
Select(DomSelectArgs),
#[command(
name = "get-attribute",
long_about = "Read a single attribute value from a DOM element. The element can be \
targeted by node ID (from 'dom select'), snapshot UID (from 'page snapshot'), \
or CSS selector (prefixed with 'css:'). Returns the attribute name and value.",
after_long_help = "\
EXAMPLES:
# Get href by UID
chrome-cli dom get-attribute s3 href
# Get class by CSS selector
chrome-cli dom get-attribute css:h1 class"
)]
GetAttribute(DomGetAttributeArgs),
#[command(
name = "get-text",
long_about = "Read the textContent of a DOM element. Returns the combined text of \
the element and all its descendants.",
after_long_help = "\
EXAMPLES:
# Get text by UID
chrome-cli dom get-text s3
# Get text by CSS selector
chrome-cli dom get-text css:h1"
)]
GetText(DomNodeIdArgs),
#[command(
name = "get-html",
long_about = "Read the outerHTML of a DOM element, including the element itself and \
all its children as an HTML string.",
after_long_help = "\
EXAMPLES:
# Get HTML by UID
chrome-cli dom get-html s3
# Get HTML by CSS selector
chrome-cli dom get-html css:div.content"
)]
GetHtml(DomNodeIdArgs),
#[command(
name = "set-attribute",
long_about = "Set or update an attribute on a DOM element. Creates the attribute if \
it doesn't exist, or updates its value if it does.",
after_long_help = "\
EXAMPLES:
# Set class attribute
chrome-cli dom set-attribute s5 class \"highlight\"
# Set data attribute by CSS selector
chrome-cli dom set-attribute css:#main data-active true"
)]
SetAttribute(DomSetAttributeArgs),
#[command(
name = "set-text",
long_about = "Replace the textContent of a DOM element, removing all child nodes \
and setting the element's content to the given text.",
after_long_help = "\
EXAMPLES:
# Set text by UID
chrome-cli dom set-text s3 \"New heading\"
# Set text by CSS selector
chrome-cli dom set-text css:h1 \"Updated Title\""
)]
SetText(DomSetTextArgs),
#[command(
long_about = "Remove a DOM element and all its children from the document. This is \
irreversible within the current page session.",
after_long_help = "\
EXAMPLES:
# Remove by UID
chrome-cli dom remove s3
# Remove by CSS selector
chrome-cli dom remove css:div.ad-banner"
)]
Remove(DomNodeIdArgs),
#[command(
name = "get-style",
long_about = "Read the computed CSS styles of a DOM element. Without a property name, \
returns all computed styles. With a property name, returns just that property's \
value.",
after_long_help = "\
EXAMPLES:
# Get all computed styles
chrome-cli dom get-style s3
# Get a specific property
chrome-cli dom get-style s3 display
# Get style by CSS selector
chrome-cli dom get-style css:h1 color"
)]
GetStyle(DomGetStyleArgs),
#[command(
name = "set-style",
long_about = "Set the inline style attribute of a DOM element. The style string replaces \
the entire inline style. Use CSS property syntax.",
after_long_help = "\
EXAMPLES:
# Set inline style
chrome-cli dom set-style s3 \"color: red; font-size: 24px\"
# Set style by CSS selector
chrome-cli dom set-style css:h1 \"display: none\""
)]
SetStyle(DomSetStyleArgs),
#[command(
long_about = "Navigate to the parent element of a DOM node. Returns the parent's \
node ID, tag name, attributes, and text content.",
after_long_help = "\
EXAMPLES:
# Get parent of a UID
chrome-cli dom parent s3
# Get parent by CSS selector
chrome-cli dom parent css:span.label"
)]
Parent(DomNodeIdArgs),
#[command(
long_about = "List the direct child elements (element nodes only, nodeType 1) of a \
DOM node. Returns a JSON array of child elements.",
after_long_help = "\
EXAMPLES:
# List children by UID
chrome-cli dom children s3
# List children by CSS selector
chrome-cli dom children css:div.container"
)]
Children(DomNodeIdArgs),
#[command(
long_about = "List the sibling elements of a DOM node (other children of the same \
parent, excluding the target element itself).",
after_long_help = "\
EXAMPLES:
# List siblings by UID
chrome-cli dom siblings s3
# List siblings by CSS selector
chrome-cli dom siblings css:li.active"
)]
Siblings(DomNodeIdArgs),
#[command(
long_about = "Display the DOM tree as indented plain text. By default shows the full \
document tree. Use --depth to limit traversal depth and --root to start from a \
specific element.",
after_long_help = "\
EXAMPLES:
# Show the full DOM tree
chrome-cli dom tree
# Limit depth to 3 levels
chrome-cli dom tree --depth 3
# Show tree from a specific element
chrome-cli dom tree --root css:div.content"
)]
Tree(DomTreeArgs),
}
#[derive(Args)]
pub struct DomSelectArgs {
pub selector: String,
#[arg(long)]
pub xpath: bool,
}
#[derive(Args)]
pub struct DomGetAttributeArgs {
pub node_id: String,
pub attribute: String,
}
#[derive(Args)]
pub struct DomSetAttributeArgs {
pub node_id: String,
pub attribute: String,
pub value: String,
}
#[derive(Args)]
pub struct DomGetStyleArgs {
pub node_id: String,
pub property: Option<String>,
}
#[derive(Args)]
pub struct DomSetStyleArgs {
pub node_id: String,
pub style: String,
}
#[derive(Args)]
pub struct DomSetTextArgs {
pub node_id: String,
pub text: String,
}
#[derive(Args)]
pub struct DomNodeIdArgs {
pub node_id: String,
}
#[derive(Args)]
pub struct DomTreeArgs {
#[arg(long)]
pub depth: Option<u32>,
#[arg(long)]
pub root: Option<String>,
}
#[derive(Args)]
pub struct EmulateArgs {
#[command(subcommand)]
pub command: EmulateCommand,
}
#[derive(Subcommand)]
pub enum EmulateCommand {
#[command(
long_about = "Apply one or more device or network emulation overrides. Multiple \
overrides can be combined in a single command (e.g., viewport + network + user \
agent). Overrides persist until 'emulate reset' is called or the browser is closed. \
Note: --geolocation and --no-geolocation are mutually exclusive, as are \
--user-agent and --no-user-agent.",
after_long_help = "\
EXAMPLES:
# Emulate a mobile device
chrome-cli emulate set --viewport 375x667 --device-scale 2 --mobile
# Simulate slow network
chrome-cli emulate set --network 3g
# Set geolocation (San Francisco)
chrome-cli emulate set --geolocation 37.7749,-122.4194
# Force dark mode with custom user agent
chrome-cli emulate set --color-scheme dark --user-agent \"CustomBot/1.0\"
# Throttle CPU (4x slowdown)
chrome-cli emulate set --cpu 4"
)]
Set(EmulateSetArgs),
#[command(
long_about = "Clear all device and network emulation overrides, restoring the browser \
to its default settings. This removes viewport, user agent, geolocation, network \
throttling, CPU throttling, and color scheme overrides.",
after_long_help = "\
EXAMPLES:
# Reset all overrides
chrome-cli emulate reset"
)]
Reset,
#[command(
long_about = "Display the current emulation state including viewport dimensions, \
user agent, device scale factor, network conditions, CPU throttling, and color \
scheme. Returns JSON with the active emulation configuration.",
after_long_help = "\
EXAMPLES:
# Check emulation status
chrome-cli emulate status"
)]
Status,
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Args)]
pub struct EmulateSetArgs {
#[arg(long, value_enum)]
pub network: Option<NetworkProfile>,
#[arg(long, value_parser = clap::value_parser!(u32).range(1..=20))]
pub cpu: Option<u32>,
#[arg(long, conflicts_with = "no_geolocation")]
pub geolocation: Option<String>,
#[arg(long, conflicts_with = "geolocation")]
pub no_geolocation: bool,
#[arg(long, conflicts_with = "no_user_agent")]
pub user_agent: Option<String>,
#[arg(long, conflicts_with = "user_agent")]
pub no_user_agent: bool,
#[arg(long, value_enum)]
pub color_scheme: Option<ColorScheme>,
#[arg(long)]
pub viewport: Option<String>,
#[arg(long)]
pub device_scale: Option<f64>,
#[arg(long)]
pub mobile: bool,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum NetworkProfile {
Offline,
#[value(name = "slow-4g")]
Slow4g,
#[value(name = "4g")]
FourG,
#[value(name = "3g")]
ThreeG,
None,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum ColorScheme {
Dark,
Light,
Auto,
}
#[derive(Args)]
pub struct ConfigArgs {
#[command(subcommand)]
pub command: ConfigCommand,
}
#[derive(Subcommand)]
pub enum ConfigCommand {
#[command(
long_about = "Display the fully resolved configuration by merging all sources in \
priority order: CLI flags > environment variables > config file > defaults. \
Returns JSON showing every setting and its effective value. Useful for debugging \
which settings are active.",
after_long_help = "\
EXAMPLES:
# Show resolved config
chrome-cli config show
# Show config from a specific file
chrome-cli --config ./my-config.toml config show"
)]
Show,
#[command(
long_about = "Create a new configuration file with all available settings documented \
as comments. By default, the file is created at the XDG config directory \
(~/.config/chrome-cli/config.toml on Linux, ~/Library/Application Support/\
chrome-cli/config.toml on macOS). Use --path to specify a custom location. \
Will not overwrite an existing file.",
after_long_help = "\
EXAMPLES:
# Create default config file
chrome-cli config init
# Create at a custom path
chrome-cli config init --path ./my-config.toml"
)]
Init(ConfigInitArgs),
#[command(
long_about = "Show the path of the active configuration file. Searches in priority \
order: --config flag, $CHROME_CLI_CONFIG env var, project-local \
(.chrome-cli.toml), XDG config dir, home directory (~/.chrome-cli.toml). \
Returns JSON with {\"path\": \"...\"} or {\"path\": null} if no config file is found.",
after_long_help = "\
EXAMPLES:
# Show active config path
chrome-cli config path"
)]
Path,
}
#[derive(Args)]
pub struct ConfigInitArgs {
#[arg(long)]
pub path: Option<PathBuf>,
}
#[derive(Args)]
pub struct CompletionsArgs {
pub shell: Shell,
}
#[derive(Args)]
pub struct ManArgs {
pub command: Option<String>,
}
#[derive(Args)]
pub struct ExamplesArgs {
pub command: Option<String>,
}
#[derive(Args)]
pub struct CapabilitiesArgs {
#[arg(long)]
pub command: Option<String>,
#[arg(long)]
pub compact: bool,
}