Skip to main content

agent_first_mail/
runner.rs

1mod dispatch;
2mod lock;
3mod output;
4mod purge;
5mod push;
6#[cfg(feature = "ui")]
7mod ui;
8
9pub use dispatch::execute_command;
10pub use output::{emit_result, emit_value};
11
12use crate::cli::Command;
13use crate::progress::{object_with_phase, ProgressCallback};
14use agent_first_data::OutputFormat;
15use dispatch::execute_command_with_progress;
16use output::{command_name, log_enabled, log_event, output_format_name, redact_argv};
17use serde_json::{json, Value};
18use std::time::Instant;
19
20pub fn run_command(
21    command: Command,
22    output: OutputFormat,
23    log_filters: &[String],
24    argv: &[String],
25) -> i32 {
26    #[cfg(feature = "ui")]
27    if let Command::Ui(command) = command {
28        return ui::run_ui_command(command, output);
29    }
30    let started = Instant::now();
31    let command_name = command_name(&command).to_string();
32    if log_enabled(log_filters, "startup") {
33        let argv = redact_argv(argv);
34        emit_value(
35            &log_event(
36                "startup",
37                "info",
38                json!({
39                    "version": env!("CARGO_PKG_VERSION"),
40                    "argv": argv,
41                    "command": command_name.as_str(),
42                    "output_format": output_format_name(output),
43                    "log_filters": log_filters,
44                }),
45                0,
46            ),
47            output,
48        );
49    }
50    if log_enabled(log_filters, "request") {
51        let cwd = std::env::current_dir()
52            .map(|path| path.to_string_lossy().replace('\\', "/"))
53            .unwrap_or_default();
54        emit_value(
55            &log_event(
56                "request",
57                "info",
58                json!({
59                    "phase": "start",
60                    "command": command_name.as_str(),
61                    "cwd_path": cwd,
62                }),
63                0,
64            ),
65            output,
66        );
67    }
68
69    let progress_enabled = log_enabled(log_filters, "progress");
70    let mut emit_progress = |phase: &str, fields: Value| {
71        emit_value(
72            &log_event(
73                "progress",
74                "info",
75                object_with_phase(phase, fields),
76                started.elapsed().as_millis() as u64,
77            ),
78            output,
79        );
80    };
81    let progress = if progress_enabled {
82        Some(&mut emit_progress as &mut ProgressCallback<'_>)
83    } else {
84        None
85    };
86    let result = execute_command_with_progress(command, progress);
87    let duration_ms = started.elapsed().as_millis() as u64;
88    if let Err(err) = &result {
89        if err.retryable && log_enabled(log_filters, "retry") {
90            emit_value(
91                &log_event(
92                    "retry",
93                    "warn",
94                    json!({
95                        "phase": "retryable_error",
96                        "command": command_name.as_str(),
97                        "error_code": err.error_code,
98                        "error": err.message,
99                    }),
100                    duration_ms,
101                ),
102                output,
103            );
104        }
105    }
106    if log_enabled(log_filters, "progress") {
107        emit_value(
108            &log_event(
109                "progress",
110                "info",
111                json!({
112                    "phase": "finish",
113                    "command": command_name.as_str(),
114                    "success": result.is_ok(),
115                    "exit_code": if result.is_ok() { 0 } else { 1 },
116                }),
117                duration_ms,
118            ),
119            output,
120        );
121    }
122    emit_result(result, output, duration_ms)
123}