Skip to main content

browser_automation_cli/
cli.rs

1//! Clap derive surface for browser-automation-cli (PRD Layer L).
2//!
3//! Help text on flags is the primary documentation for this module.
4#![allow(missing_docs)]
5
6use clap::{Parser, Subcommand, ValueEnum};
7
8/// One-shot browser automation CLI for AI agents.
9#[derive(Debug, Parser)]
10#[command(
11    name = "browser-automation-cli",
12    version,
13    about = "One-shot browser automation CLI (Chrome CDP). BORN, EXECUTE, FINALIZE, DIE.",
14    long_about = None,
15    propagate_version = true
16)]
17pub struct Cli {
18    #[command(flatten)]
19    pub globals: GlobalOpts,
20
21    #[command(subcommand)]
22    pub command: Commands,
23}
24
25#[derive(Debug, Clone, Parser)]
26pub struct GlobalOpts {
27    #[arg(long, global = true)]
28    pub json: bool,
29
30    /// Suppress non-error human logs on stderr
31    #[arg(short = 'q', long = "quiet", global = true)]
32    pub quiet: bool,
33
34    /// Increase stderr verbosity (`--verbose` once = info; or `config set log_level debug`)
35    #[arg(long = "verbose", global = true)]
36    pub verbose: bool,
37
38    /// Maximum tracing detail on stderr (debug/trace)
39    #[arg(long = "debug", global = true)]
40    pub debug: bool,
41
42    #[arg(long, global = true, default_value_t = 0)]
43    pub timeout: u64,
44
45    /// Per-step timeout in seconds for `run` scripts (0 = inherit global timeout)
46    #[arg(long, global = true, default_value_t = 0)]
47    pub step_timeout: u64,
48
49    /// Launch Chrome with a visible window (debug; default headless=new)
50    #[arg(long, global = true)]
51    pub headed: bool,
52
53    #[arg(long, global = true)]
54    pub artifacts_dir: Option<std::path::PathBuf>,
55
56    #[arg(long, global = true)]
57    pub lang: Option<String>,
58
59    #[arg(long, global = true)]
60    pub capture_console: bool,
61
62    #[arg(long, global = true)]
63    pub capture_network: bool,
64
65    #[arg(long, global = true)]
66    pub ignore_robots: bool,
67
68    #[arg(long, global = true)]
69    pub i_accept_robots_risk: bool,
70
71    /// Enable deep heap analysis tools (PRD category-memory)
72    #[arg(long, global = true)]
73    pub category_memory: bool,
74
75    /// Enable extension management tools
76    #[arg(long, global = true)]
77    pub category_extensions: bool,
78
79    /// Enable third-party developer tool surface
80    #[arg(long, global = true)]
81    pub category_third_party: bool,
82
83    /// Enable WebMCP-compatible tool surface
84    #[arg(long, global = true)]
85    pub category_webmcp: bool,
86
87    /// Enable experimental screencast (may require ffmpeg for file export)
88    #[arg(long, global = true)]
89    pub experimental_screencast: bool,
90
91    /// Enable coordinate click-at (vision) tools
92    #[arg(long, global = true)]
93    pub experimental_vision: bool,
94}
95
96#[derive(Debug, Subcommand)]
97pub enum Commands {
98    /// Diagnose Chrome install and one-shot readiness
99    Doctor {
100        #[arg(long)]
101        offline: bool,
102        #[arg(long)]
103        quick: bool,
104        #[arg(long)]
105        fix: bool,
106        #[arg(long)]
107        json: bool,
108    },
109    /// List available commands
110    Commands {
111        #[arg(long)]
112        json: bool,
113    },
114    /// JSON Schema fragment for a command (agent discovery)
115    Schema {
116        #[arg(long = "cmd", value_name = "CMD")]
117        cmd: String,
118    },
119    /// Print CLI version
120    Version,
121    /// Navigate to a URL (one-shot)
122    Goto {
123        url: String,
124        /// JS to evaluate before navigation (tool-ref initScript)
125        #[arg(long)]
126        init_script: Option<String>,
127        /// Accept beforeunload dialogs automatically
128        #[arg(long)]
129        handle_before_unload: bool,
130        /// Navigation timeout override in milliseconds
131        #[arg(long)]
132        navigation_timeout_ms: Option<u64>,
133    },
134    /// Accessibility snapshot with @eN refs
135    View {
136        #[arg(long)]
137        verbose: bool,
138        #[arg(long)]
139        path: Option<std::path::PathBuf>,
140    },
141    /// Click an element (selector or @eN)
142    Press {
143        target: String,
144        #[arg(long)]
145        dblclick: bool,
146        /// Attach slim a11y snapshot in the same process after the action
147        #[arg(long)]
148        include_snapshot: bool,
149    },
150    /// Click at page CSS coordinates (requires --experimental-vision)
151    ClickAt {
152        #[arg(long)]
153        x: f64,
154        #[arg(long)]
155        y: f64,
156        #[arg(long)]
157        dblclick: bool,
158        /// Attach slim a11y snapshot after the click
159        #[arg(long)]
160        include_snapshot: bool,
161    },
162    /// Fill an input value (select/checkbox/radio/text smart fill)
163    Write {
164        target: String,
165        value: String,
166        /// Attach slim a11y snapshot after fill
167        #[arg(long)]
168        include_snapshot: bool,
169    },
170    /// Press a keyboard key
171    Keys {
172        key: String,
173        /// Attach slim a11y snapshot after the key press
174        #[arg(long)]
175        include_snapshot: bool,
176    },
177    /// Type text (tool-ref type_text). Use --target or --focus-only.
178    Type {
179        /// Text to type (required positional)
180        text: String,
181        /// CSS selector or @eN (optional; use --focus-only for focused element)
182        #[arg(long)]
183        target: Option<String>,
184        #[arg(long)]
185        clear: bool,
186        /// Optional key to press after typing (e.g. Enter)
187        #[arg(long)]
188        submit: Option<String>,
189        /// Type into currently focused element without resolving a target
190        #[arg(long)]
191        focus_only: bool,
192    },
193    /// Wait for ms and/or text and/or selector and/or load state
194    Wait {
195        #[arg(long, default_value_t = 0)]
196        ms: u64,
197        /// Text to wait for (repeatable; resolves when any value appears — tool-ref OR)
198        #[arg(long = "text", action = clap::ArgAction::Append)]
199        text: Vec<String>,
200        #[arg(long)]
201        selector: Option<String>,
202        /// Page lifecycle: load | domcontentloaded | networkidle | none
203        #[arg(long)]
204        state: Option<String>,
205        /// Max wait time in milliseconds for text/selector/state (0 = default)
206        #[arg(long)]
207        wait_timeout_ms: Option<u64>,
208        /// Attach slim a11y snapshot after the wait succeeds
209        #[arg(long)]
210        include_snapshot: bool,
211    },
212    /// Hover an element
213    Hover {
214        target: String,
215        /// Attach slim a11y snapshot after hover
216        #[arg(long)]
217        include_snapshot: bool,
218    },
219    /// Drag from one target to another
220    Drag {
221        #[arg(long)]
222        from: String,
223        #[arg(long)]
224        to: String,
225        /// Attach slim a11y snapshot after drag
226        #[arg(long)]
227        include_snapshot: bool,
228    },
229    /// Fill multiple form fields from JSON `[{target|uid,value},...]`
230    FillForm {
231        #[arg(long)]
232        json: String,
233        /// Attach slim a11y snapshot after fill-form
234        #[arg(long)]
235        include_snapshot: bool,
236    },
237    /// Upload a file to a file input
238    Upload {
239        target: String,
240        path: std::path::PathBuf,
241        /// Attach slim a11y snapshot after upload
242        #[arg(long)]
243        include_snapshot: bool,
244    },
245    /// History back
246    Back,
247    /// History forward
248    Forward,
249    /// Reload current page
250    Reload {
251        #[arg(long)]
252        ignore_cache: bool,
253        /// JS to run before navigation/reload (tool-ref initScript)
254        #[arg(long)]
255        init_script: Option<String>,
256        /// Accept beforeunload dialogs automatically
257        #[arg(long)]
258        handle_before_unload: bool,
259    },
260    /// Evaluate JavaScript (expression or function declaration)
261    Eval {
262        /// JS expression or function declaration `() => ...`
263        expression: String,
264        /// Snapshot uids (@eN) passed as function args (JSON array of strings)
265        #[arg(long)]
266        args: Option<String>,
267        /// accept | dismiss | prompt response text (default accept)
268        #[arg(long)]
269        dialog_action: Option<String>,
270        /// Write evaluate result JSON to this path
271        #[arg(long)]
272        file_path: Option<std::path::PathBuf>,
273        /// Evaluate inside an extension service worker target (tool-ref serviceWorkerId)
274        #[arg(long)]
275        service_worker_id: Option<String>,
276    },
277    /// Capture a screenshot
278    Grab {
279        #[arg(long)]
280        path: Option<std::path::PathBuf>,
281        #[arg(long, value_enum, default_value_t = GrabFormat::Png)]
282        format: GrabFormat,
283        #[arg(long)]
284        full_page: bool,
285        #[arg(long)]
286        quality: Option<i32>,
287        /// CSS selector or @eN element to capture
288        #[arg(long)]
289        element: Option<String>,
290    },
291    /// Print current page to PDF via CDP Page.printToPDF (one-shot)
292    PrintPdf {
293        /// Output path for the PDF artifact
294        #[arg(long)]
295        path: Option<std::path::PathBuf>,
296        /// Optional URL to navigate before printing (one-shot)
297        #[arg(long)]
298        url: Option<String>,
299    },
300    /// One-shot change check against a baseline file (hash/text)
301    Monitor {
302        #[command(subcommand)]
303        action: MonitorAction,
304    },
305    /// Run multi-step NDJSON script in one process
306    Run {
307        #[arg(long)]
308        script: std::path::PathBuf,
309    },
310    /// Single-step inline command (same surface as `run` steps: goto, wait, view, press, …)
311    Exec {
312        // Do NOT set allow_hyphen_values: global flags like --json after `exec`
313        // must stay on GlobalOpts, not be swallowed into trailing args.
314        #[arg(trailing_var_arg = true)]
315        args: Vec<String>,
316    },
317    /// Extract text/attribute from a target, or LLM extract with --llm
318    Extract {
319        /// Selector, @eN ref, about:blank target, or http(s) URL for LLM/text path
320        target: String,
321        #[arg(long)]
322        attr: Option<String>,
323        /// Opt-in LLM HTTP extract (requires XDG openrouter_api_key)
324        #[arg(long)]
325        llm: bool,
326        /// Question for LLM extract
327        #[arg(long)]
328        question: Option<String>,
329        /// Path to JSON schema file for structured LLM extract
330        #[arg(long)]
331        schema_json: Option<std::path::PathBuf>,
332    },
333    /// Extract visible text from a target (PRD §7 `text`)
334    Text { target: String },
335    /// Scroll page or element by delta pixels (PRD §7 `scroll`)
336    Scroll {
337        /// CSS selector or @eN (optional; omit for window scroll)
338        #[arg(long)]
339        target: Option<String>,
340        #[arg(long, default_value_t = 0.0)]
341        delta_x: f64,
342        #[arg(long, default_value_t = 0.0)]
343        delta_y: f64,
344    },
345    /// Cookie jar helpers for the active page (Network domain)
346    Cookie {
347        #[command(subcommand)]
348        action: CookieAction,
349    },
350    /// Read one attribute from a target
351    Attr { target: String, name: String },
352    /// Assertions (url / text / console)
353    Assert {
354        #[command(subcommand)]
355        kind: AssertKind,
356    },
357    /// Captured console messages (--capture-console)
358    Console {
359        #[command(subcommand)]
360        action: ConsoleAction,
361    },
362    /// Captured network requests (--capture-network)
363    Net {
364        #[command(subcommand)]
365        action: NetAction,
366    },
367    /// Page info or multi-tab management
368    Page {
369        #[command(subcommand)]
370        action: Option<PageAction>,
371    },
372    /// Accept or dismiss dialogs
373    Dialog {
374        #[command(subcommand)]
375        action: DialogAction,
376    },
377    /// Navigate and return body text / formats (local HTTP or CDP scrape)
378    Scrape {
379        url: String,
380        /// text | markdown | html | links | metadata | raw-html | screenshot
381        #[arg(long, default_value = "text")]
382        format: String,
383        /// http (reqwest+scraper) or browser (CDP)
384        #[arg(long, default_value = "browser")]
385        engine: String,
386        /// Prefer main/article content heuristics
387        #[arg(long)]
388        only_main_content: bool,
389        /// Optional one-shot webhook POST of the result envelope data (127.0.0.1/operator URL)
390        #[arg(long)]
391        webhook_url: Option<String>,
392    },
393    /// Scrape many URLs from a file (HTTP engine, one-shot)
394    BatchScrape {
395        #[arg(long)]
396        urls_file: std::path::PathBuf,
397        #[arg(long, default_value = "text")]
398        format: String,
399        #[arg(long, default_value_t = 2)]
400        concurrency: usize,
401    },
402    /// Crawl from a seed URL (HTTP BFS, one-shot)
403    Crawl {
404        url: String,
405        #[arg(long, default_value_t = 20)]
406        limit: usize,
407        #[arg(long, default_value_t = 2)]
408        max_depth: usize,
409        #[arg(long, default_value = "text")]
410        format: String,
411        /// Stay on seed host
412        #[arg(long, default_value_t = true)]
413        same_host: bool,
414    },
415    /// Map site URLs from a seed (HTTP)
416    Map {
417        url: String,
418        #[arg(long, default_value_t = 50)]
419        limit: usize,
420        #[arg(long, default_value_t = 2)]
421        max_depth: usize,
422    },
423    /// Local search (HTTP SERP links or URL map)
424    Search {
425        query: String,
426        #[arg(long, default_value_t = 10)]
427        limit: usize,
428    },
429    /// Parse a local file (html/md/txt/pdf/docx/xlsx text extract)
430    Parse {
431        path: std::path::PathBuf,
432        /// Mask email/phone/card-like patterns in text output
433        #[arg(long)]
434        redact_pii: bool,
435    },
436    /// QR encode/decode one-shot (no Chrome)
437    Qr {
438        #[command(subcommand)]
439        action: QrAction,
440    },
441    /// Discover filesystem paths (fd-like UX; binary remains browser-automation-cli)
442    FindPaths {
443        /// Regex pattern on name/path (optional)
444        pattern: Option<String>,
445        /// Root paths to search
446        #[arg(num_args = 0..)]
447        paths: Vec<String>,
448        /// Filter by extension (e.g. rs, html)
449        #[arg(long)]
450        extension: Option<String>,
451        /// Include hidden files
452        #[arg(long)]
453        hidden: bool,
454        /// Do not respect .gitignore
455        #[arg(long)]
456        no_ignore: bool,
457        /// Max directory depth
458        #[arg(long)]
459        max_depth: Option<usize>,
460        /// Entry type: f|d
461        #[arg(long = "type")]
462        entry_type: Option<String>,
463        /// Max results
464        #[arg(long, default_value_t = 10000)]
465        limit: usize,
466        /// Shell-style glob filter (e.g. `**/*.rs`) — GAP-A011 / §5AE
467        #[arg(long)]
468        glob: Option<String>,
469    },
470    /// Structural lint scan for forbidden product patterns (one-shot; §5AC / GAP-A011)
471    SgScan {
472        /// Roots to scan (default: `.`)
473        #[arg(num_args = 0..)]
474        paths: Vec<String>,
475        /// Max findings (0 = unlimited)
476        #[arg(long, default_value_t = 500)]
477        limit: usize,
478    },
479    /// Structural rewrite for known-safe fixes (dry-run default; `--apply` writes)
480    SgRewrite {
481        /// Roots to rewrite (default: `.`)
482        #[arg(num_args = 0..)]
483        paths: Vec<String>,
484        /// Apply changes (default is dry-run report only)
485        #[arg(long)]
486        apply: bool,
487    },
488    /// Write a simple XLSX workbook from CSV/JSON (one-shot; §5Z / GAP-A011)
489    SheetWrite {
490        /// Input path (.csv or .json array-of-objects)
491        input: std::path::PathBuf,
492        /// Output .xlsx path
493        #[arg(long, short = 'o')]
494        out: std::path::PathBuf,
495        /// Worksheet name
496        #[arg(long, default_value = "Sheet1")]
497        sheet: String,
498    },
499    /// MITM capture / CA / HAR (one-shot local)
500    Mitm {
501        #[command(subcommand)]
502        action: MitmAction,
503    },
504    /// Workflow journal DAG (petgraph + SQLite)
505    Workflow {
506        #[command(subcommand)]
507        action: WorkflowAction,
508    },
509    /// XDG config and path management (no .env at runtime)
510    Config {
511        #[command(subcommand)]
512        action: ConfigAction,
513    },
514    /// Emulate device / network / UA / geo / CPU
515    Emulate {
516        #[arg(long)]
517        user_agent: Option<String>,
518        #[arg(long)]
519        locale: Option<String>,
520        #[arg(long)]
521        timezone: Option<String>,
522        #[arg(long)]
523        offline: bool,
524        #[arg(long)]
525        latitude: Option<f64>,
526        #[arg(long)]
527        longitude: Option<f64>,
528        #[arg(long)]
529        media: Option<String>,
530        /// Network preset: Offline, No throttling, Slow 3G, Fast 3G, Slow 4G, Fast 4G
531        #[arg(long)]
532        network_conditions: Option<String>,
533        /// CPU slowdown factor 1..=20 (1 disables)
534        #[arg(long)]
535        cpu_throttling_rate: Option<f64>,
536        /// prefers-color-scheme: dark | light | auto
537        #[arg(long)]
538        color_scheme: Option<String>,
539        /// Extra HTTP headers as JSON object string
540        #[arg(long)]
541        extra_headers: Option<String>,
542        /// Viewport `WxHxDPR` with optional `,mobile`, `,touch`, `,landscape` flags
543        #[arg(long)]
544        viewport: Option<String>,
545    },
546    /// Resize page viewport
547    Resize {
548        #[arg(long)]
549        width: i32,
550        #[arg(long)]
551        height: i32,
552        #[arg(long, default_value_t = 1.0)]
553        scale: f64,
554        #[arg(long)]
555        mobile: bool,
556    },
557    /// Performance trace / metrics
558    Perf {
559        #[command(subcommand)]
560        action: PerfAction,
561    },
562    /// Run Lighthouse audit (external binary)
563    Lighthouse {
564        url: String,
565        #[arg(long)]
566        out_dir: Option<std::path::PathBuf>,
567        #[arg(long, default_value = "desktop")]
568        device: String,
569        /// navigation (default) or snapshot (maps to navigation in one-shot CLI)
570        #[arg(long, default_value = "navigation")]
571        mode: String,
572        #[arg(long)]
573        lighthouse_path: Option<std::path::PathBuf>,
574    },
575    /// Screencast start/stop (experimental)
576    Screencast {
577        #[command(subcommand)]
578        action: ScreencastAction,
579    },
580    /// Heap snapshot tools (requires --category-memory for deep analysis)
581    Heap {
582        #[command(subcommand)]
583        action: HeapAction,
584    },
585    /// Chrome extension tools (requires --category-extensions)
586    Extension {
587        #[command(subcommand)]
588        action: ExtensionAction,
589    },
590    /// Third-party developer tools surface (requires --category-third-party)
591    Devtools3p {
592        #[command(subcommand)]
593        action: Devtools3pAction,
594    },
595    /// Web surface tools (requires --category-webmcp)
596    Webmcp {
597        #[command(subcommand)]
598        action: WebmcpAction,
599    },
600    /// Generate shell completions (path leve, no Chrome)
601    Completions {
602        #[arg(value_enum)]
603        shell: CompletionShell,
604    },
605}
606
607#[derive(Debug, Clone, Subcommand)]
608pub enum PerfAction {
609    Start {
610        #[arg(long)]
611        path: Option<std::path::PathBuf>,
612        #[arg(long)]
613        reload: bool,
614        /// Auto-stop after page load/reload (tool-ref autoStop)
615        #[arg(long)]
616        auto_stop: bool,
617    },
618    Stop {
619        #[arg(long)]
620        path: Option<std::path::PathBuf>,
621    },
622    Insight {
623        /// Insight name (e.g. DocumentLatency, LCPBreakdown)
624        #[arg(long)]
625        name: Option<String>,
626        /// Insight set id from perf stop "available_insight_sets"
627        #[arg(long)]
628        insight_set_id: Option<String>,
629        /// Alias for --name (tool-ref insightName)
630        #[arg(long)]
631        insight_name: Option<String>,
632    },
633}
634
635#[derive(Debug, Clone, Subcommand)]
636pub enum ScreencastAction {
637    Start {
638        #[arg(long)]
639        path: Option<std::path::PathBuf>,
640    },
641    Stop {
642        /// Output path (.webm/.mp4 encodes via ffmpeg; otherwise PNG frames dir)
643        #[arg(long)]
644        path: Option<std::path::PathBuf>,
645    },
646}
647
648#[derive(Debug, Clone, Subcommand)]
649pub enum HeapAction {
650    Take {
651        #[arg(long)]
652        path: std::path::PathBuf,
653    },
654    Close {
655        #[arg(long)]
656        path: std::path::PathBuf,
657    },
658    Compare {
659        #[arg(long)]
660        base: std::path::PathBuf,
661        #[arg(long)]
662        current: std::path::PathBuf,
663        /// Optional class index filter (tool-ref classIndex)
664        #[arg(long)]
665        class_index: Option<u64>,
666    },
667    Summary {
668        #[arg(long)]
669        path: std::path::PathBuf,
670    },
671    Details {
672        #[arg(long)]
673        path: std::path::PathBuf,
674        #[arg(long)]
675        filter_name: Option<String>,
676        #[arg(long)]
677        page_idx: Option<usize>,
678        #[arg(long)]
679        page_size: Option<usize>,
680    },
681    ClassNodes {
682        #[arg(long)]
683        path: std::path::PathBuf,
684        #[arg(long)]
685        id: u64,
686        #[arg(long)]
687        filter_name: Option<String>,
688        #[arg(long)]
689        page_idx: Option<usize>,
690        #[arg(long)]
691        page_size: Option<usize>,
692    },
693    Dominators {
694        #[arg(long)]
695        path: std::path::PathBuf,
696        #[arg(long)]
697        node: u64,
698    },
699    DupStrings {
700        #[arg(long)]
701        path: std::path::PathBuf,
702        #[arg(long)]
703        page_idx: Option<usize>,
704        #[arg(long)]
705        page_size: Option<usize>,
706    },
707    Edges {
708        #[arg(long)]
709        path: std::path::PathBuf,
710        #[arg(long)]
711        node: u64,
712        #[arg(long)]
713        page_idx: Option<usize>,
714        #[arg(long)]
715        page_size: Option<usize>,
716    },
717    Retainers {
718        #[arg(long)]
719        path: std::path::PathBuf,
720        #[arg(long)]
721        node: u64,
722        #[arg(long)]
723        page_idx: Option<usize>,
724        #[arg(long)]
725        page_size: Option<usize>,
726    },
727    Paths {
728        #[arg(long)]
729        path: std::path::PathBuf,
730        #[arg(long)]
731        node: u64,
732        #[arg(long, default_value_t = 8)]
733        max_depth: u64,
734        #[arg(long)]
735        max_nodes: Option<u64>,
736        #[arg(long)]
737        max_siblings: Option<u64>,
738    },
739    /// Detailed info for one heap object (size, distance, retained size, detachedness)
740    ObjectDetails {
741        #[arg(long)]
742        path: std::path::PathBuf,
743        #[arg(long)]
744        node: u64,
745    },
746}
747
748#[derive(Debug, Clone, Subcommand)]
749pub enum ExtensionAction {
750    List,
751    Install {
752        path: std::path::PathBuf,
753    },
754    Reload {
755        id: String,
756        /// Unpacked extension dir so one-shot can --load-extension before reload
757        #[arg(long)]
758        path: Option<std::path::PathBuf>,
759    },
760    Trigger {
761        id: String,
762        /// Unpacked extension dir so one-shot can --load-extension before trigger
763        #[arg(long)]
764        path: Option<std::path::PathBuf>,
765    },
766    Uninstall {
767        id: String,
768    },
769}
770
771#[derive(Debug, Clone, Subcommand)]
772pub enum Devtools3pAction {
773    List {
774        /// Optional page URL to open before discovery
775        #[arg(long)]
776        url: Option<String>,
777    },
778    Exec {
779        name: String,
780        #[arg(long)]
781        params: Option<String>,
782        #[arg(long)]
783        url: Option<String>,
784    },
785}
786
787#[derive(Debug, Clone, Subcommand)]
788pub enum WebmcpAction {
789    List {
790        #[arg(long)]
791        url: Option<String>,
792    },
793    Exec {
794        name: String,
795        #[arg(long)]
796        input: Option<String>,
797        #[arg(long)]
798        url: Option<String>,
799    },
800}
801
802#[derive(Debug, Clone, Copy, ValueEnum)]
803pub enum CompletionShell {
804    Bash,
805    Zsh,
806    Fish,
807    Elvish,
808    Powershell,
809}
810
811#[derive(Debug, Clone, Subcommand)]
812pub enum QrAction {
813    /// Encode text to PNG, SVG, or terminal matrix
814    Encode {
815        #[arg(long)]
816        text: String,
817        /// png | svg | terminal
818        #[arg(long, default_value = "png")]
819        format: String,
820        #[arg(long)]
821        path: Option<std::path::PathBuf>,
822    },
823    /// Decode QR payload from an image file
824    Decode {
825        #[arg(long)]
826        path: std::path::PathBuf,
827    },
828}
829
830#[derive(Debug, Clone, Subcommand)]
831pub enum MonitorAction {
832    /// Compare URL body hash/text to a baseline file and exit
833    Check {
834        /// URL to fetch/scrape one-shot
835        #[arg(long)]
836        url: String,
837        /// Baseline file path (created on first run if missing when --write-baseline)
838        #[arg(long)]
839        baseline: std::path::PathBuf,
840        /// Write/update baseline after check
841        #[arg(long)]
842        write_baseline: bool,
843        /// Use browser engine instead of HTTP
844        #[arg(long, default_value = "http")]
845        engine: String,
846    },
847}
848
849#[derive(Debug, Clone, Subcommand)]
850pub enum PageAction {
851    /// Current page url and title (default when bare `page`)
852    Info,
853    /// List tabs in this one-shot process
854    List,
855    /// Open a new tab
856    New {
857        #[arg(long)]
858        url: Option<String>,
859        /// Open without focusing (tool-ref background)
860        #[arg(long)]
861        background: bool,
862        /// Create isolated browser context when supported
863        #[arg(long)]
864        isolated_context: bool,
865    },
866    /// Select tab by zero-based index (alias: --page-id)
867    Select {
868        #[arg(value_name = "INDEX")]
869        index: Option<usize>,
870        /// Tool-ref pageId alias for index
871        #[arg(long = "page-id")]
872        page_id: Option<usize>,
873        /// Bring selected tab to front (tool-ref bringToFront)
874        #[arg(long, default_value_t = true)]
875        bring_to_front: bool,
876    },
877    /// Close a tab (default: active)
878    Close {
879        #[arg(long)]
880        index: Option<usize>,
881        /// Tool-ref pageId alias for index
882        #[arg(long = "page-id")]
883        page_id: Option<usize>,
884    },
885    /// Return the stable tab id of the active page (tool-ref get_tab_id)
886    TabId,
887}
888
889#[derive(Debug, Clone, Subcommand)]
890pub enum CookieAction {
891    /// List cookies (optional URL filter)
892    List {
893        #[arg(long)]
894        url: Option<String>,
895    },
896    /// Set cookies from a JSON array of cookie objects
897    Set {
898        /// JSON array: [{"name":"a","value":"b","url":"https://..."}]
899        #[arg(long)]
900        json: String,
901    },
902    /// Clear all browser cookies in this one-shot process
903    Clear,
904}
905
906#[derive(Debug, Clone, Copy, ValueEnum, Default)]
907pub enum GrabFormat {
908    #[default]
909    Png,
910    Jpeg,
911    Webp,
912}
913
914#[derive(Debug, Clone, Subcommand)]
915pub enum AssertKind {
916    Url {
917        value: String,
918        #[arg(long)]
919        contains: bool,
920    },
921    Text {
922        value: String,
923        #[arg(long)]
924        target: Option<String>,
925    },
926    Console {
927        #[arg(long, default_value = "error")]
928        level: String,
929        #[arg(long, default_value_t = 0)]
930        max: u64,
931    },
932}
933
934#[derive(Debug, Clone, Subcommand)]
935pub enum ConsoleAction {
936    List {
937        /// 0-based page index for pagination
938        #[arg(long)]
939        page_idx: Option<usize>,
940        /// Max messages per page
941        #[arg(long)]
942        page_size: Option<usize>,
943        /// Filter by types (comma-separated: log,warning,error,info,debug)
944        #[arg(long)]
945        types: Option<String>,
946        /// Include messages preserved across navigations in this process
947        #[arg(long)]
948        include_preserved: bool,
949        /// Optional service worker id filter
950        #[arg(long)]
951        service_worker_id: Option<String>,
952    },
953    Get {
954        id: usize,
955    },
956    Clear,
957    Dump {
958        #[arg(long)]
959        path: std::path::PathBuf,
960    },
961}
962
963#[derive(Debug, Clone, Subcommand)]
964pub enum NetAction {
965    List {
966        /// 0-based page index for pagination
967        #[arg(long)]
968        page_idx: Option<usize>,
969        /// Max requests per page
970        #[arg(long)]
971        page_size: Option<usize>,
972        /// Filter resource types (comma-separated: Document,Script,XHR,Fetch,...)
973        #[arg(long)]
974        resource_types: Option<String>,
975        /// Include requests preserved over recent navigations in this process
976        #[arg(long)]
977        include_preserved: bool,
978    },
979    Get {
980        /// 0-based index in net list, or CDP requestId string
981        id: String,
982        #[arg(long)]
983        request_path: Option<std::path::PathBuf>,
984        #[arg(long)]
985        response_path: Option<std::path::PathBuf>,
986    },
987}
988
989#[derive(Debug, Clone, Subcommand)]
990pub enum DialogAction {
991    Accept {
992        #[arg(long)]
993        text: Option<String>,
994    },
995    Dismiss,
996}
997
998#[derive(Debug, Clone, Subcommand)]
999pub enum MitmAction {
1000    /// CA paths, capture count, bind policy
1001    Status,
1002    /// List captured exchanges
1003    List {
1004        #[arg(long)]
1005        host: Option<String>,
1006        #[arg(long, default_value_t = 100)]
1007        limit: usize,
1008    },
1009    /// Get one exchange by id
1010    Get { id: u64 },
1011    /// Export HAR 1.2 JSON
1012    Har {
1013        #[arg(long)]
1014        out: std::path::PathBuf,
1015    },
1016    /// Export capture as JSON/NDJSON
1017    Export {
1018        #[arg(long, default_value = "json")]
1019        format: String,
1020        #[arg(long)]
1021        out: std::path::PathBuf,
1022    },
1023    /// Unique hosts seen
1024    Domains,
1025    /// REST/GraphQL endpoint discovery
1026    Apis {
1027        #[arg(long)]
1028        kind: Option<String>,
1029    },
1030    /// Ensure local CA under XDG data
1031    InitCa,
1032    /// Start one-shot MITM proxy on 127.0.0.1 (ephemeral port); captures until timeout
1033    Start {
1034        /// Seconds to keep the proxy alive (one-shot; default 30)
1035        #[arg(long, default_value_t = 30)]
1036        seconds: u64,
1037    },
1038}
1039
1040#[derive(Debug, Clone, Subcommand)]
1041pub enum WorkflowAction {
1042    /// Validate DAG and execute offline steps; journal under XDG state
1043    Run {
1044        #[arg(long)]
1045        manifest: std::path::PathBuf,
1046        #[arg(long)]
1047        journal: Option<std::path::PathBuf>,
1048    },
1049    /// Resume / re-run from journal + manifest
1050    Resume {
1051        #[arg(long)]
1052        manifest: std::path::PathBuf,
1053        #[arg(long)]
1054        journal: Option<std::path::PathBuf>,
1055    },
1056    /// Show journal step statuses
1057    Status {
1058        #[arg(long)]
1059        journal: Option<std::path::PathBuf>,
1060        #[arg(long)]
1061        name: Option<String>,
1062    },
1063}
1064
1065#[derive(Debug, Clone, Subcommand)]
1066pub enum ConfigAction {
1067    /// Print resolved XDG paths
1068    Path,
1069    /// Create XDG layout + default config.toml
1070    Init,
1071    /// Show config values
1072    Show,
1073    /// Set a config key (lang|timeout|artifacts_dir|ignore_robots|namespace|encryption_key|color|log_level|log_to_file|chrome_path|lighthouse_path|openrouter_api_key|llm_base_url|llm_model|cache_backend|cache_redis_url)
1074    Set { key: String, value: String },
1075    /// Get one config key
1076    Get { key: Option<String> },
1077    /// List supported config keys and defaults (GAP-018)
1078    ListKeys,
1079}