Skip to main content

browser_automation_cli/
cli.rs

1//! Clap derive surface for browser-automation-cli (PRD Camada 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). NASCE, EXECUTA, FINALIZE, MORRE.",
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, env = "BROWSER_AUTOMATION_CLI_JSON")]
28    pub json: bool,
29
30    /// Suppress non-error human logs on stderr
31    #[arg(
32        short = 'q',
33        long = "quiet",
34        global = true,
35        env = "BROWSER_AUTOMATION_CLI_QUIET"
36    )]
37    pub quiet: bool,
38
39    /// Increase stderr verbosity (`--verbose` once = info; use RUST_LOG for finer control)
40    #[arg(
41        long = "verbose",
42        global = true,
43        env = "BROWSER_AUTOMATION_CLI_VERBOSE"
44    )]
45    pub verbose: bool,
46
47    /// Maximum tracing detail on stderr (debug/trace)
48    #[arg(long = "debug", global = true, env = "BROWSER_AUTOMATION_CLI_DEBUG")]
49    pub debug: bool,
50
51    #[arg(
52        long,
53        global = true,
54        env = "BROWSER_AUTOMATION_CLI_TIMEOUT",
55        default_value_t = 0
56    )]
57    pub timeout: u64,
58
59    /// Per-step timeout in seconds for `run` scripts (0 = inherit global timeout)
60    #[arg(
61        long,
62        global = true,
63        env = "BROWSER_AUTOMATION_CLI_STEP_TIMEOUT",
64        default_value_t = 0
65    )]
66    pub step_timeout: u64,
67
68    /// Launch Chrome with a visible window (debug; default headless=new)
69    #[arg(long, global = true, env = "BROWSER_AUTOMATION_CLI_HEADED")]
70    pub headed: bool,
71
72    #[arg(long, global = true, env = "BROWSER_AUTOMATION_CLI_ARTIFACTS_DIR")]
73    pub artifacts_dir: Option<std::path::PathBuf>,
74
75    #[arg(long, global = true, env = "BROWSER_AUTOMATION_CLI_LANG")]
76    pub lang: Option<String>,
77
78    #[arg(long, global = true, env = "BROWSER_AUTOMATION_CLI_CAPTURE_CONSOLE")]
79    pub capture_console: bool,
80
81    #[arg(long, global = true, env = "BROWSER_AUTOMATION_CLI_CAPTURE_NETWORK")]
82    pub capture_network: bool,
83
84    #[arg(long, global = true, env = "BROWSER_AUTOMATION_CLI_IGNORE_ROBOTS")]
85    pub ignore_robots: bool,
86
87    #[arg(
88        long,
89        global = true,
90        env = "BROWSER_AUTOMATION_CLI_I_ACCEPT_ROBOTS_RISK"
91    )]
92    pub i_accept_robots_risk: bool,
93
94    /// Enable deep heap analysis tools (PRD category-memory)
95    #[arg(long, global = true, env = "BROWSER_AUTOMATION_CLI_CATEGORY_MEMORY")]
96    pub category_memory: bool,
97
98    /// Enable extension management tools
99    #[arg(
100        long,
101        global = true,
102        env = "BROWSER_AUTOMATION_CLI_CATEGORY_EXTENSIONS"
103    )]
104    pub category_extensions: bool,
105
106    /// Enable third-party developer tool surface
107    #[arg(
108        long,
109        global = true,
110        env = "BROWSER_AUTOMATION_CLI_CATEGORY_THIRD_PARTY"
111    )]
112    pub category_third_party: bool,
113
114    /// Enable WebMCP-compatible tool surface
115    #[arg(long, global = true, env = "BROWSER_AUTOMATION_CLI_CATEGORY_WEBMCP")]
116    pub category_webmcp: bool,
117
118    /// Enable experimental screencast (may require ffmpeg for file export)
119    #[arg(
120        long,
121        global = true,
122        env = "BROWSER_AUTOMATION_CLI_EXPERIMENTAL_SCREENCAST"
123    )]
124    pub experimental_screencast: bool,
125
126    /// Enable coordinate click-at (vision) tools
127    #[arg(
128        long,
129        global = true,
130        env = "BROWSER_AUTOMATION_CLI_EXPERIMENTAL_VISION"
131    )]
132    pub experimental_vision: bool,
133}
134
135#[derive(Debug, Subcommand)]
136pub enum Commands {
137    /// Diagnose Chrome install and one-shot readiness
138    Doctor {
139        #[arg(long)]
140        offline: bool,
141        #[arg(long)]
142        quick: bool,
143        #[arg(long)]
144        fix: bool,
145        #[arg(long)]
146        json: bool,
147    },
148    /// List available commands
149    Commands {
150        #[arg(long)]
151        json: bool,
152    },
153    /// JSON Schema fragment for a command (agent discovery)
154    Schema {
155        #[arg(long = "cmd", value_name = "CMD")]
156        cmd: String,
157    },
158    /// Print CLI version
159    Version,
160    /// Navigate to a URL (one-shot)
161    Goto {
162        url: String,
163        /// JS to evaluate before navigation (tool-ref initScript)
164        #[arg(long)]
165        init_script: Option<String>,
166        /// Accept beforeunload dialogs automatically
167        #[arg(long)]
168        handle_before_unload: bool,
169        /// Navigation timeout override in milliseconds
170        #[arg(long)]
171        navigation_timeout_ms: Option<u64>,
172    },
173    /// Accessibility snapshot with @eN refs
174    View {
175        #[arg(long)]
176        verbose: bool,
177        #[arg(long)]
178        path: Option<std::path::PathBuf>,
179    },
180    /// Click an element (selector or @eN)
181    Press {
182        target: String,
183        #[arg(long)]
184        dblclick: bool,
185        /// Attach slim a11y snapshot in the same process after the action
186        #[arg(long)]
187        include_snapshot: bool,
188    },
189    /// Click at page CSS coordinates (requires --experimental-vision)
190    ClickAt {
191        #[arg(long)]
192        x: f64,
193        #[arg(long)]
194        y: f64,
195        #[arg(long)]
196        dblclick: bool,
197        /// Attach slim a11y snapshot after the click
198        #[arg(long)]
199        include_snapshot: bool,
200    },
201    /// Fill an input value (select/checkbox/radio/text smart fill)
202    Write {
203        target: String,
204        value: String,
205        /// Attach slim a11y snapshot after fill
206        #[arg(long)]
207        include_snapshot: bool,
208    },
209    /// Press a keyboard key
210    Keys {
211        key: String,
212        /// Attach slim a11y snapshot after the key press
213        #[arg(long)]
214        include_snapshot: bool,
215    },
216    /// Type text (tool-ref type_text). Use --target or --focus-only.
217    Type {
218        /// Text to type (required positional)
219        text: String,
220        /// CSS selector or @eN (optional; use --focus-only for focused element)
221        #[arg(long)]
222        target: Option<String>,
223        #[arg(long)]
224        clear: bool,
225        /// Optional key to press after typing (e.g. Enter)
226        #[arg(long)]
227        submit: Option<String>,
228        /// Type into currently focused element without resolving a target
229        #[arg(long)]
230        focus_only: bool,
231    },
232    /// Wait for ms and/or text and/or selector and/or load state
233    Wait {
234        #[arg(long, default_value_t = 0)]
235        ms: u64,
236        /// Text to wait for (repeatable; resolves when any value appears — tool-ref OR)
237        #[arg(long = "text", action = clap::ArgAction::Append)]
238        text: Vec<String>,
239        #[arg(long)]
240        selector: Option<String>,
241        /// Page lifecycle: load | domcontentloaded | networkidle | none
242        #[arg(long)]
243        state: Option<String>,
244        /// Max wait time in milliseconds for text/selector/state (0 = default)
245        #[arg(long)]
246        wait_timeout_ms: Option<u64>,
247        /// Attach slim a11y snapshot after the wait succeeds
248        #[arg(long)]
249        include_snapshot: bool,
250    },
251    /// Hover an element
252    Hover {
253        target: String,
254        /// Attach slim a11y snapshot after hover
255        #[arg(long)]
256        include_snapshot: bool,
257    },
258    /// Drag from one target to another
259    Drag {
260        #[arg(long)]
261        from: String,
262        #[arg(long)]
263        to: String,
264        /// Attach slim a11y snapshot after drag
265        #[arg(long)]
266        include_snapshot: bool,
267    },
268    /// Fill multiple form fields from JSON `[{target|uid,value},...]`
269    FillForm {
270        #[arg(long)]
271        json: String,
272        /// Attach slim a11y snapshot after fill-form
273        #[arg(long)]
274        include_snapshot: bool,
275    },
276    /// Upload a file to a file input
277    Upload {
278        target: String,
279        path: std::path::PathBuf,
280        /// Attach slim a11y snapshot after upload
281        #[arg(long)]
282        include_snapshot: bool,
283    },
284    /// History back
285    Back,
286    /// History forward
287    Forward,
288    /// Reload current page
289    Reload {
290        #[arg(long)]
291        ignore_cache: bool,
292        /// JS to run before navigation/reload (tool-ref initScript)
293        #[arg(long)]
294        init_script: Option<String>,
295        /// Accept beforeunload dialogs automatically
296        #[arg(long)]
297        handle_before_unload: bool,
298    },
299    /// Evaluate JavaScript (expression or function declaration)
300    Eval {
301        /// JS expression or function declaration `() => ...`
302        expression: String,
303        /// Snapshot uids (@eN) passed as function args (JSON array of strings)
304        #[arg(long)]
305        args: Option<String>,
306        /// accept | dismiss | prompt response text (default accept)
307        #[arg(long)]
308        dialog_action: Option<String>,
309        /// Write evaluate result JSON to this path
310        #[arg(long)]
311        file_path: Option<std::path::PathBuf>,
312    },
313    /// Capture a screenshot
314    Grab {
315        #[arg(long)]
316        path: Option<std::path::PathBuf>,
317        #[arg(long, value_enum, default_value_t = GrabFormat::Png)]
318        format: GrabFormat,
319        #[arg(long)]
320        full_page: bool,
321        #[arg(long)]
322        quality: Option<i32>,
323        /// CSS selector or @eN element to capture
324        #[arg(long)]
325        element: Option<String>,
326    },
327    /// Run multi-step NDJSON script in one process
328    Run {
329        #[arg(long)]
330        script: std::path::PathBuf,
331    },
332    /// Limited inline subcommand (goto)
333    Exec {
334        // Do NOT set allow_hyphen_values: global flags like --json after `exec`
335        // must stay on GlobalOpts, not be swallowed into trailing args.
336        #[arg(trailing_var_arg = true)]
337        args: Vec<String>,
338    },
339    /// Extract text or attribute from a target
340    Extract {
341        target: String,
342        #[arg(long)]
343        attr: Option<String>,
344    },
345    /// Extract visible text from a target (PRD §7 `text`)
346    Text { target: String },
347    /// Scroll page or element by delta pixels (PRD §7 `scroll`)
348    Scroll {
349        /// CSS selector or @eN (optional; omit for window scroll)
350        #[arg(long)]
351        target: Option<String>,
352        #[arg(long, default_value_t = 0.0)]
353        delta_x: f64,
354        #[arg(long, default_value_t = 0.0)]
355        delta_y: f64,
356    },
357    /// Cookie jar helpers for the active page (Network domain)
358    Cookie {
359        #[command(subcommand)]
360        action: CookieAction,
361    },
362    /// Read one attribute from a target
363    Attr { target: String, name: String },
364    /// Assertions (url / text / console)
365    Assert {
366        #[command(subcommand)]
367        kind: AssertKind,
368    },
369    /// Captured console messages (--capture-console)
370    Console {
371        #[command(subcommand)]
372        action: ConsoleAction,
373    },
374    /// Captured network requests (--capture-network)
375    Net {
376        #[command(subcommand)]
377        action: NetAction,
378    },
379    /// Page info or multi-tab management
380    Page {
381        #[command(subcommand)]
382        action: Option<PageAction>,
383    },
384    /// Accept or dismiss dialogs
385    Dialog {
386        #[command(subcommand)]
387        action: DialogAction,
388    },
389    /// Navigate and return body text
390    Scrape { url: String },
391    /// Emulate device / network / UA / geo / CPU
392    Emulate {
393        #[arg(long)]
394        user_agent: Option<String>,
395        #[arg(long)]
396        locale: Option<String>,
397        #[arg(long)]
398        timezone: Option<String>,
399        #[arg(long)]
400        offline: bool,
401        #[arg(long)]
402        latitude: Option<f64>,
403        #[arg(long)]
404        longitude: Option<f64>,
405        #[arg(long)]
406        media: Option<String>,
407        /// Network preset: Offline, No throttling, Slow 3G, Fast 3G, Slow 4G, Fast 4G
408        #[arg(long)]
409        network_conditions: Option<String>,
410        /// CPU slowdown factor 1..=20 (1 disables)
411        #[arg(long)]
412        cpu_throttling_rate: Option<f64>,
413        /// prefers-color-scheme: dark | light | auto
414        #[arg(long)]
415        color_scheme: Option<String>,
416        /// Extra HTTP headers as JSON object string
417        #[arg(long)]
418        extra_headers: Option<String>,
419        /// Viewport `WxHxDPR` with optional `,mobile`, `,touch`, `,landscape` flags
420        #[arg(long)]
421        viewport: Option<String>,
422    },
423    /// Resize page viewport
424    Resize {
425        #[arg(long)]
426        width: i32,
427        #[arg(long)]
428        height: i32,
429        #[arg(long, default_value_t = 1.0)]
430        scale: f64,
431        #[arg(long)]
432        mobile: bool,
433    },
434    /// Performance trace / metrics
435    Perf {
436        #[command(subcommand)]
437        action: PerfAction,
438    },
439    /// Run Lighthouse audit (external binary)
440    Lighthouse {
441        url: String,
442        #[arg(long)]
443        out_dir: Option<std::path::PathBuf>,
444        #[arg(long, default_value = "desktop")]
445        device: String,
446        /// navigation (default) or snapshot (maps to navigation in one-shot CLI)
447        #[arg(long, default_value = "navigation")]
448        mode: String,
449        #[arg(long)]
450        lighthouse_path: Option<std::path::PathBuf>,
451    },
452    /// Screencast start/stop (experimental)
453    Screencast {
454        #[command(subcommand)]
455        action: ScreencastAction,
456    },
457    /// Heap snapshot tools (requires --category-memory for deep analysis)
458    Heap {
459        #[command(subcommand)]
460        action: HeapAction,
461    },
462    /// Chrome extension tools (requires --category-extensions)
463    Extension {
464        #[command(subcommand)]
465        action: ExtensionAction,
466    },
467    /// Third-party developer tools surface (requires --category-third-party)
468    Devtools3p {
469        #[command(subcommand)]
470        action: Devtools3pAction,
471    },
472    /// Web surface tools (requires --category-webmcp)
473    Webmcp {
474        #[command(subcommand)]
475        action: WebmcpAction,
476    },
477    /// Generate shell completions (path leve, no Chrome)
478    Completions {
479        #[arg(value_enum)]
480        shell: CompletionShell,
481    },
482}
483
484#[derive(Debug, Clone, Subcommand)]
485pub enum PerfAction {
486    Start {
487        #[arg(long)]
488        path: Option<std::path::PathBuf>,
489        #[arg(long)]
490        reload: bool,
491        /// Auto-stop after page load/reload (tool-ref autoStop)
492        #[arg(long)]
493        auto_stop: bool,
494    },
495    Stop {
496        #[arg(long)]
497        path: Option<std::path::PathBuf>,
498    },
499    Insight {
500        /// Insight name (e.g. DocumentLatency, LCPBreakdown)
501        #[arg(long)]
502        name: Option<String>,
503        /// Insight set id from perf stop "available_insight_sets"
504        #[arg(long)]
505        insight_set_id: Option<String>,
506        /// Alias for --name (tool-ref insightName)
507        #[arg(long)]
508        insight_name: Option<String>,
509    },
510}
511
512#[derive(Debug, Clone, Subcommand)]
513pub enum ScreencastAction {
514    Start {
515        #[arg(long)]
516        path: Option<std::path::PathBuf>,
517    },
518    Stop {
519        /// Output path (.webm/.mp4 encodes via ffmpeg; otherwise PNG frames dir)
520        #[arg(long)]
521        path: Option<std::path::PathBuf>,
522    },
523}
524
525#[derive(Debug, Clone, Subcommand)]
526pub enum HeapAction {
527    Take {
528        #[arg(long)]
529        path: std::path::PathBuf,
530    },
531    Close {
532        #[arg(long)]
533        path: std::path::PathBuf,
534    },
535    Compare {
536        #[arg(long)]
537        base: std::path::PathBuf,
538        #[arg(long)]
539        current: std::path::PathBuf,
540        /// Optional class index filter (tool-ref classIndex)
541        #[arg(long)]
542        class_index: Option<u64>,
543    },
544    Summary {
545        #[arg(long)]
546        path: std::path::PathBuf,
547    },
548    Details {
549        #[arg(long)]
550        path: std::path::PathBuf,
551        #[arg(long)]
552        filter_name: Option<String>,
553        #[arg(long)]
554        page_idx: Option<usize>,
555        #[arg(long)]
556        page_size: Option<usize>,
557    },
558    ClassNodes {
559        #[arg(long)]
560        path: std::path::PathBuf,
561        #[arg(long)]
562        id: u64,
563        #[arg(long)]
564        filter_name: Option<String>,
565        #[arg(long)]
566        page_idx: Option<usize>,
567        #[arg(long)]
568        page_size: Option<usize>,
569    },
570    Dominators {
571        #[arg(long)]
572        path: std::path::PathBuf,
573        #[arg(long)]
574        node: u64,
575    },
576    DupStrings {
577        #[arg(long)]
578        path: std::path::PathBuf,
579        #[arg(long)]
580        page_idx: Option<usize>,
581        #[arg(long)]
582        page_size: Option<usize>,
583    },
584    Edges {
585        #[arg(long)]
586        path: std::path::PathBuf,
587        #[arg(long)]
588        node: u64,
589        #[arg(long)]
590        page_idx: Option<usize>,
591        #[arg(long)]
592        page_size: Option<usize>,
593    },
594    Retainers {
595        #[arg(long)]
596        path: std::path::PathBuf,
597        #[arg(long)]
598        node: u64,
599        #[arg(long)]
600        page_idx: Option<usize>,
601        #[arg(long)]
602        page_size: Option<usize>,
603    },
604    Paths {
605        #[arg(long)]
606        path: std::path::PathBuf,
607        #[arg(long)]
608        node: u64,
609        #[arg(long, default_value_t = 8)]
610        max_depth: u64,
611        #[arg(long)]
612        max_nodes: Option<u64>,
613        #[arg(long)]
614        max_siblings: Option<u64>,
615    },
616    /// Detailed info for one heap object (size, distance, retained size, detachedness)
617    ObjectDetails {
618        #[arg(long)]
619        path: std::path::PathBuf,
620        #[arg(long)]
621        node: u64,
622    },
623}
624
625#[derive(Debug, Clone, Subcommand)]
626pub enum ExtensionAction {
627    List,
628    Install {
629        path: std::path::PathBuf,
630    },
631    Reload {
632        id: String,
633        /// Unpacked extension dir so one-shot can --load-extension before reload
634        #[arg(long)]
635        path: Option<std::path::PathBuf>,
636    },
637    Trigger {
638        id: String,
639        /// Unpacked extension dir so one-shot can --load-extension before trigger
640        #[arg(long)]
641        path: Option<std::path::PathBuf>,
642    },
643    Uninstall {
644        id: String,
645    },
646}
647
648#[derive(Debug, Clone, Subcommand)]
649pub enum Devtools3pAction {
650    List {
651        /// Optional page URL to open before discovery
652        #[arg(long)]
653        url: Option<String>,
654    },
655    Exec {
656        name: String,
657        #[arg(long)]
658        params: Option<String>,
659        #[arg(long)]
660        url: Option<String>,
661    },
662}
663
664#[derive(Debug, Clone, Subcommand)]
665pub enum WebmcpAction {
666    List {
667        #[arg(long)]
668        url: Option<String>,
669    },
670    Exec {
671        name: String,
672        #[arg(long)]
673        input: Option<String>,
674        #[arg(long)]
675        url: Option<String>,
676    },
677}
678
679#[derive(Debug, Clone, Copy, ValueEnum)]
680pub enum CompletionShell {
681    Bash,
682    Zsh,
683    Fish,
684    Elvish,
685    Powershell,
686}
687
688#[derive(Debug, Clone, Subcommand)]
689pub enum PageAction {
690    /// Current page url and title (default when bare `page`)
691    Info,
692    /// List tabs in this one-shot process
693    List,
694    /// Open a new tab
695    New {
696        #[arg(long)]
697        url: Option<String>,
698        /// Open without focusing (tool-ref background)
699        #[arg(long)]
700        background: bool,
701        /// Create isolated browser context when supported
702        #[arg(long)]
703        isolated_context: bool,
704    },
705    /// Select tab by zero-based index (alias: --page-id)
706    Select {
707        #[arg(value_name = "INDEX")]
708        index: Option<usize>,
709        /// Tool-ref pageId alias for index
710        #[arg(long = "page-id")]
711        page_id: Option<usize>,
712        /// Bring selected tab to front (tool-ref bringToFront)
713        #[arg(long, default_value_t = true)]
714        bring_to_front: bool,
715    },
716    /// Close a tab (default: active)
717    Close {
718        #[arg(long)]
719        index: Option<usize>,
720        /// Tool-ref pageId alias for index
721        #[arg(long = "page-id")]
722        page_id: Option<usize>,
723    },
724}
725
726#[derive(Debug, Clone, Subcommand)]
727pub enum CookieAction {
728    /// List cookies (optional URL filter)
729    List {
730        #[arg(long)]
731        url: Option<String>,
732    },
733    /// Set cookies from a JSON array of cookie objects
734    Set {
735        /// JSON array: [{"name":"a","value":"b","url":"https://..."}]
736        #[arg(long)]
737        json: String,
738    },
739    /// Clear all browser cookies in this one-shot process
740    Clear,
741}
742
743#[derive(Debug, Clone, Copy, ValueEnum, Default)]
744pub enum GrabFormat {
745    #[default]
746    Png,
747    Jpeg,
748    Webp,
749}
750
751#[derive(Debug, Clone, Subcommand)]
752pub enum AssertKind {
753    Url {
754        value: String,
755        #[arg(long)]
756        contains: bool,
757    },
758    Text {
759        value: String,
760        #[arg(long)]
761        target: Option<String>,
762    },
763    Console {
764        #[arg(long, default_value = "error")]
765        level: String,
766        #[arg(long, default_value_t = 0)]
767        max: u64,
768    },
769}
770
771#[derive(Debug, Clone, Subcommand)]
772pub enum ConsoleAction {
773    List {
774        /// 0-based page index for pagination
775        #[arg(long)]
776        page_idx: Option<usize>,
777        /// Max messages per page
778        #[arg(long)]
779        page_size: Option<usize>,
780        /// Filter by types (comma-separated: log,warning,error,info,debug)
781        #[arg(long)]
782        types: Option<String>,
783        /// Include messages preserved across navigations in this process
784        #[arg(long)]
785        include_preserved: bool,
786        /// Optional service worker id filter
787        #[arg(long)]
788        service_worker_id: Option<String>,
789    },
790    Get {
791        id: usize,
792    },
793    Clear,
794    Dump {
795        #[arg(long)]
796        path: std::path::PathBuf,
797    },
798}
799
800#[derive(Debug, Clone, Subcommand)]
801pub enum NetAction {
802    List {
803        /// 0-based page index for pagination
804        #[arg(long)]
805        page_idx: Option<usize>,
806        /// Max requests per page
807        #[arg(long)]
808        page_size: Option<usize>,
809        /// Filter resource types (comma-separated: Document,Script,XHR,Fetch,...)
810        #[arg(long)]
811        resource_types: Option<String>,
812        /// Include requests preserved over recent navigations in this process
813        #[arg(long)]
814        include_preserved: bool,
815    },
816    Get {
817        /// 0-based index in net list, or CDP requestId string
818        id: String,
819        #[arg(long)]
820        request_path: Option<std::path::PathBuf>,
821        #[arg(long)]
822        response_path: Option<std::path::PathBuf>,
823    },
824}
825
826#[derive(Debug, Clone, Subcommand)]
827pub enum DialogAction {
828    Accept {
829        #[arg(long)]
830        text: Option<String>,
831    },
832    Dismiss,
833}