Skip to main content

agent_first_mail/
runner.rs

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