Skip to content

Commit 82dee84

Browse files
committed
fix(cli): narrow agent output to oxlint
1 parent 54fe2af commit 82dee84

6 files changed

Lines changed: 36 additions & 201 deletions

File tree

apps/oxfmt/src/cli/command.rs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ pub struct FormatCommand {
2323
#[bpaf(external(mode))]
2424
pub mode: Mode,
2525
#[bpaf(external)]
26-
pub output_options: OutputOptions,
27-
#[bpaf(external)]
2826
pub config_options: ConfigOptions,
2927
#[bpaf(external)]
3028
pub ignore_options: IgnoreOptions,
@@ -130,14 +128,6 @@ fn output_mode() -> impl bpaf::Parser<OutputMode> {
130128
bpaf::construct!([write, check, list_different]).group_help("Output Options:")
131129
}
132130

133-
/// Output options
134-
#[derive(Debug, Clone, Bpaf)]
135-
pub struct OutputOptions {
136-
/// Reduce CLI output for agents: print only changed paths and one-line diagnostics
137-
#[bpaf(long("agent"), switch, hide)]
138-
pub agent: bool,
139-
}
140-
141131
/// Migration Source
142132
#[cfg(feature = "napi")]
143133
#[derive(Debug, Clone)]
@@ -183,16 +173,3 @@ pub struct RuntimeOptions {
183173
#[bpaf(argument("INT"), hide_usage)]
184174
pub threads: Option<usize>,
185175
}
186-
187-
#[cfg(test)]
188-
mod tests {
189-
use super::{Mode, OutputMode, format_command};
190-
191-
#[test]
192-
fn agent_output_option() {
193-
let command = format_command().run_inner(&["--agent", "--check", "."]).unwrap();
194-
195-
assert!(command.output_options.agent);
196-
assert!(matches!(command.mode, Mode::Cli(OutputMode::Check)));
197-
}
198-
}

apps/oxfmt/src/cli/reporter.rs

Lines changed: 2 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use oxc_diagnostics::{
2-
Error, GraphicalReportHandler, Severity,
3-
reporter::{DiagnosticReporter, DiagnosticResult, Info},
2+
Error, GraphicalReportHandler,
3+
reporter::{DiagnosticReporter, DiagnosticResult},
44
};
55

66
// This reporter is used with stderr and displays diagnostics only in a graphical way.
@@ -36,85 +36,3 @@ impl DiagnosticReporter for DefaultReporter {
3636
Some(output)
3737
}
3838
}
39-
40-
#[derive(Debug, Default)]
41-
pub struct AgentReporter;
42-
43-
impl DiagnosticReporter for AgentReporter {
44-
fn finish(&mut self, _result: &DiagnosticResult) -> Option<String> {
45-
None
46-
}
47-
48-
fn supports_minified_file_fallback(&self) -> bool {
49-
false
50-
}
51-
52-
fn render_error(&mut self, error: Error) -> Option<String> {
53-
Some(format_agent(&error))
54-
}
55-
}
56-
57-
fn format_agent(diagnostic: &Error) -> String {
58-
let Info { start, filename, .. } = Info::new(diagnostic);
59-
let filename = if filename.is_empty() {
60-
diagnostic
61-
.source_code()
62-
.and_then(miette::SourceCode::name)
63-
.map_or_else(|| "<unknown>".to_string(), ToString::to_string)
64-
} else {
65-
filename
66-
};
67-
let severity = match diagnostic.severity() {
68-
Some(Severity::Warning) => "warning",
69-
Some(Severity::Advice) => "advice",
70-
_ => "error",
71-
};
72-
let message = compact_message(&diagnostic.to_string());
73-
74-
if start.line == 0 {
75-
format!("{filename}: {severity}: {message}\n")
76-
} else {
77-
format!("{filename}:{}:{}: {severity}: {message}\n", start.line, start.column)
78-
}
79-
}
80-
81-
fn compact_message(message: &str) -> String {
82-
let mut compact = String::new();
83-
for word in message.split_whitespace() {
84-
if !compact.is_empty() {
85-
compact.push(' ');
86-
}
87-
compact.push_str(word);
88-
}
89-
compact
90-
}
91-
92-
#[cfg(test)]
93-
mod tests {
94-
use oxc_diagnostics::{NamedSource, OxcDiagnostic, reporter::DiagnosticReporter};
95-
use oxc_span::Span;
96-
97-
use super::AgentReporter;
98-
99-
#[test]
100-
fn agent_reporter_with_label() {
101-
let mut reporter = AgentReporter;
102-
let error = OxcDiagnostic::error("Unexpected token")
103-
.with_label(Span::new(0, 1))
104-
.with_source_code(NamedSource::new("file.js", "!"));
105-
106-
assert_eq!(reporter.render_error(error).unwrap(), "file.js:1:1: error: Unexpected token\n");
107-
}
108-
109-
#[test]
110-
fn agent_reporter_without_label() {
111-
let mut reporter = AgentReporter;
112-
let error = OxcDiagnostic::error("Failed to save file\npermission denied")
113-
.with_source_code(NamedSource::new("file.js", ""));
114-
115-
assert_eq!(
116-
reporter.render_error(error).unwrap(),
117-
"file.js: error: Failed to save file permission denied\n"
118-
);
119-
}
120-
}

apps/oxfmt/src/cli/service.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,14 @@ pub struct FormatService {
2222
cwd: Box<Path>,
2323
format_mode: OutputMode,
2424
formatter: SourceFormatter,
25-
agent_output: bool,
2625
}
2726

2827
impl FormatService {
29-
pub fn new<T>(
30-
cwd: T,
31-
format_mode: OutputMode,
32-
formatter: SourceFormatter,
33-
agent_output: bool,
34-
) -> Self
28+
pub fn new<T>(cwd: T, format_mode: OutputMode, formatter: SourceFormatter) -> Self
3529
where
3630
T: Into<Box<Path>>,
3731
{
38-
Self { cwd: cwd.into(), format_mode, formatter, agent_output }
32+
Self { cwd: cwd.into(), format_mode, formatter }
3933
}
4034

4135
/// Process entries as they are received from the channel
@@ -46,8 +40,7 @@ impl FormatService {
4640
tx_success: &mpsc::Sender<SuccessResult>,
4741
) {
4842
rx_entry.into_iter().par_bridge().for_each(|strategy| {
49-
let start_time = (matches!(self.format_mode, OutputMode::Check) && !self.agent_output)
50-
.then(Instant::now);
43+
let start_time = matches!(self.format_mode, OutputMode::Check).then(Instant::now);
5144

5245
let path: Arc<Path> = Arc::clone(strategy.path());
5346
let Ok(source_text) = utils::read_to_string(&path) else {
@@ -115,7 +108,7 @@ impl FormatService {
115108
.cow_replace('\\', "/")
116109
.to_string();
117110

118-
if matches!(self.format_mode, OutputMode::Check) && !self.agent_output {
111+
if matches!(self.format_mode, OutputMode::Check) {
119112
let elapsed = start_time.unwrap().elapsed().as_millis();
120113
SuccessResult::Changed(format!("{display_path} ({elapsed}ms)"))
121114
} else {

apps/oxfmt/src/cli/walk_runner.rs

Lines changed: 29 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use std::{env, io::BufWriter, path::PathBuf, sync::mpsc, time::Instant};
22

3-
use oxc_diagnostics::{DiagnosticService, reporter::DiagnosticReporter};
3+
use oxc_diagnostics::DiagnosticService;
44

55
use super::{
66
command::{FormatCommand, Mode, OutputMode},
7-
reporter::{AgentReporter, DefaultReporter},
7+
reporter::DefaultReporter,
88
resolve::resolve_ignore_paths,
99
result::CliRunResult,
1010
service::{FormatService, SuccessResult},
@@ -69,20 +69,13 @@ impl WalkRunner {
6969
let start_time = Instant::now();
7070

7171
let cwd = self.cwd;
72-
let FormatCommand {
73-
paths,
74-
mode,
75-
output_options,
76-
config_options,
77-
ignore_options,
78-
runtime_options,
79-
} = self.options;
72+
let FormatCommand { paths, mode, config_options, ignore_options, runtime_options } =
73+
self.options;
8074
// If `napi` feature is disabled, there is no other mode.
8175
#[cfg_attr(not(feature = "napi"), expect(irrefutable_let_patterns))]
8276
let Mode::Cli(format_mode) = mode else {
8377
unreachable!("`WalkRunner` should only be called with Mode::Cli");
8478
};
85-
let agent_output = output_options.agent;
8679
let num_of_threads = rayon::current_num_threads();
8780

8881
// Find and load root config file
@@ -147,14 +140,10 @@ impl WalkRunner {
147140
// Collect format results (changed paths or unchanged count)
148141
let (tx_success, rx_success) = mpsc::channel();
149142
// Diagnostic from formatting service
150-
let reporter: Box<dyn DiagnosticReporter> = if agent_output {
151-
Box::new(AgentReporter)
152-
} else {
153-
Box::new(DefaultReporter::default())
154-
};
155-
let (mut diagnostic_service, tx_error) = DiagnosticService::new(reporter);
143+
let (mut diagnostic_service, tx_error) =
144+
DiagnosticService::new(Box::new(DefaultReporter::default()));
156145

157-
if matches!(format_mode, OutputMode::Check) && !agent_output {
146+
if matches!(format_mode, OutputMode::Check) {
158147
utils::print_and_flush(stdout, "Checking formatting...\n");
159148
utils::print_and_flush(stdout, "\n");
160149
}
@@ -172,8 +161,7 @@ impl WalkRunner {
172161
// Spawn formatting service on a dedicated thread so it doesn't occupy the rayon pool.
173162
// It just blocks on `rx_entry` waiting for entries; `par_bridge()` inside still uses rayon.
174163
std::thread::spawn(move || {
175-
let format_service =
176-
FormatService::new(cwd, format_mode, source_formatter, agent_output);
164+
let format_service = FormatService::new(cwd, format_mode, source_formatter);
177165
format_service.run_streaming(rx_entry, &tx_error_for_format, &tx_success);
178166
});
179167

@@ -218,11 +206,7 @@ impl WalkRunner {
218206
// Print sorted changed file paths to stdout
219207
if !changed_paths.is_empty() {
220208
changed_paths.sort_unstable();
221-
if agent_output {
222-
utils::print_and_flush(stdout, &format!("{}\n", changed_paths.join("\n")));
223-
} else {
224-
utils::print_and_flush(stdout, &changed_paths.join("\n"));
225-
}
209+
utils::print_and_flush(stdout, &changed_paths.join("\n"));
226210
}
227211

228212
// Then, output diagnostics errors to stderr
@@ -234,10 +218,6 @@ impl WalkRunner {
234218
// Count the processed files
235219
let total_target_files_count = changed_paths.len() + unchanged_count + error_count;
236220
let print_stats = |stdout, stderr| {
237-
if agent_output {
238-
return;
239-
}
240-
241221
utils::print_and_flush(
242222
stdout,
243223
&format!(
@@ -259,32 +239,24 @@ impl WalkRunner {
259239
// Check if no files were found
260240
if total_target_files_count == 0 {
261241
if runtime_options.no_error_on_unmatched_pattern {
262-
if !agent_output {
263-
utils::print_and_flush(stderr, "No files found matching the given patterns.\n");
264-
print_stats(stdout, stderr);
265-
}
242+
utils::print_and_flush(stderr, "No files found matching the given patterns.\n");
243+
print_stats(stdout, stderr);
266244
return CliRunResult::None;
267245
}
268246

269-
if agent_output {
270-
utils::print_and_flush(stderr, "No files found.\n");
271-
} else {
272-
utils::print_and_flush(
273-
stderr,
274-
"Expected at least one target file. All matched files may have been excluded by ignore rules.\n",
275-
);
276-
}
247+
utils::print_and_flush(
248+
stderr,
249+
"Expected at least one target file. All matched files may have been excluded by ignore rules.\n",
250+
);
277251
return CliRunResult::NoFilesFound;
278252
}
279253

280254
if 0 < error_count {
281255
// Each error is already printed in reporter
282-
if !agent_output {
283-
utils::print_and_flush(
284-
stderr,
285-
"Error occurred when checking code style in the above files.\n",
286-
);
287-
}
256+
utils::print_and_flush(
257+
stderr,
258+
"Error occurred when checking code style in the above files.\n",
259+
);
288260
return CliRunResult::FormatFailed;
289261
}
290262

@@ -294,23 +266,19 @@ impl WalkRunner {
294266
(OutputMode::ListDifferent, _) => CliRunResult::FormatMismatch,
295267
// `--check` outputs friendly summary
296268
(OutputMode::Check, 0) => {
297-
if !agent_output {
298-
utils::print_and_flush(stdout, "All matched files use the correct format.\n");
299-
print_stats(stdout, stderr);
300-
}
269+
utils::print_and_flush(stdout, "All matched files use the correct format.\n");
270+
print_stats(stdout, stderr);
301271
CliRunResult::FormatSucceeded
302272
}
303273
(OutputMode::Check, changed_count) => {
304-
if !agent_output {
305-
utils::print_and_flush(stdout, "\n\n");
306-
utils::print_and_flush(
307-
stdout,
308-
&format!(
309-
"Format issues found in above {changed_count} files. Run without `--check` to fix.\n",
310-
),
311-
);
312-
print_stats(stdout, stderr);
313-
}
274+
utils::print_and_flush(stdout, "\n\n");
275+
utils::print_and_flush(
276+
stdout,
277+
&format!(
278+
"Format issues found in above {changed_count} files. Run without `--check` to fix.\n",
279+
),
280+
);
281+
print_stats(stdout, stderr);
314282
CliRunResult::FormatMismatch
315283
}
316284
// Default (write) outputs only stats

apps/oxlint/src/command/lint.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -256,16 +256,6 @@ pub struct OutputOptions {
256256
/// `checkstyle`, `default`, `github`, `gitlab`, `json`, `junit`, `stylish`, `unix`
257257
#[bpaf(long, short, fallback_with(default_output_format), hide_usage)]
258258
pub format: OutputFormat,
259-
260-
/// Reduce CLI output for agents. Alias for `--format agent`.
261-
#[bpaf(long("agent"), switch, hide)]
262-
pub agent: bool,
263-
}
264-
265-
impl OutputOptions {
266-
pub fn effective_format(&self) -> OutputFormat {
267-
if self.agent { OutputFormat::Agent } else { self.format }
268-
}
269259
}
270260

271261
#[expect(clippy::unnecessary_wraps)]
@@ -554,7 +544,6 @@ mod lint_options {
554544
assert!(!options.fix_options.fix);
555545
assert!(!options.list_rules);
556546
assert_eq!(options.output_options.format, OutputFormat::Default);
557-
assert!(!options.output_options.agent);
558547
}
559548

560549
#[test]
@@ -615,20 +604,10 @@ mod lint_options {
615604
fn format() {
616605
let options = get_lint_options("-f json");
617606
assert_eq!(options.output_options.format, OutputFormat::Json);
618-
assert!(!options.output_options.agent);
619607
assert!(options.paths.is_empty());
620608

621609
let options = get_lint_options("-f agent");
622610
assert_eq!(options.output_options.format, OutputFormat::Agent);
623-
assert_eq!(options.output_options.effective_format(), OutputFormat::Agent);
624-
}
625-
626-
#[test]
627-
fn agent() {
628-
let options = get_lint_options("--agent");
629-
assert_eq!(options.output_options.format, OutputFormat::Default);
630-
assert!(options.output_options.agent);
631-
assert_eq!(options.output_options.effective_format(), OutputFormat::Agent);
632611
}
633612

634613
#[test]

apps/oxlint/src/lint.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ impl CliRunner {
6868

6969
/// # Panics
7070
pub fn run(self, stdout: &mut dyn Write) -> CliRunResult {
71-
let format_str = self.options.output_options.effective_format();
71+
let format_str = self.options.output_options.format;
7272
let output_formatter = OutputFormatter::new(format_str);
7373

7474
let LintCommand {

0 commit comments

Comments
 (0)