use anyhow::Result;
use super::super::BatchContext;
use cqs::store::DeadConfidence;
pub(in crate::cli::batch) fn dispatch_dead(
ctx: &BatchContext,
include_pub: bool,
min_confidence: &DeadConfidence,
) -> Result<serde_json::Value> {
let _span = tracing::info_span!("batch_dead").entered();
let (confident, possibly_pub) = ctx.store().find_dead_code(include_pub)?;
let confident: Vec<_> = confident
.into_iter()
.filter(|d| d.confidence >= *min_confidence)
.collect();
let possibly_pub: Vec<_> = possibly_pub
.into_iter()
.filter(|d| d.confidence >= *min_confidence)
.collect();
let output = crate::cli::commands::build_dead_output(&confident, &possibly_pub, &ctx.root);
Ok(serde_json::to_value(&output)?)
}
pub(in crate::cli::batch) fn dispatch_stale(ctx: &BatchContext) -> Result<serde_json::Value> {
let _span = tracing::info_span!("batch_stale").entered();
let file_set = ctx.file_set()?;
let report = ctx.store().list_stale_files(&file_set)?;
let output = crate::cli::commands::build_stale(&report);
Ok(serde_json::to_value(&output)?)
}
pub(in crate::cli::batch) fn dispatch_health(ctx: &BatchContext) -> Result<serde_json::Value> {
let _span = tracing::info_span!("batch_health").entered();
let file_set = ctx.file_set()?;
let report = cqs::health::health_check(&ctx.store(), &file_set, &ctx.cqs_dir)?;
Ok(serde_json::to_value(&report)?)
}
pub(in crate::cli::batch) fn dispatch_suggest(
ctx: &BatchContext,
apply: bool,
) -> Result<serde_json::Value> {
let _span = tracing::info_span!("batch_suggest", apply).entered();
let suggestions = cqs::suggest::suggest_notes(&ctx.store(), &ctx.root)?;
if apply && !suggestions.is_empty() {
let notes_path = ctx.root.join("docs/notes.toml");
let entries: Vec<cqs::NoteEntry> = suggestions
.iter()
.map(|s| cqs::NoteEntry {
sentiment: s.sentiment,
text: s.text.clone(),
mentions: s.mentions.clone(),
})
.collect();
cqs::rewrite_notes_file(¬es_path, |notes| {
notes.extend(entries);
Ok(())
})?;
let notes = cqs::parse_notes(¬es_path)?;
cqs::index_notes(¬es, ¬es_path, &ctx.store())?;
}
let json_val: Vec<_> = suggestions
.iter()
.map(|s| {
serde_json::json!({
"text": s.text,
"sentiment": s.sentiment,
"mentions": s.mentions,
"reason": s.reason,
})
})
.collect();
Ok(serde_json::json!({
"suggestions": json_val,
"total": suggestions.len(),
"applied": apply,
}))
}
pub(in crate::cli::batch) fn dispatch_review(
ctx: &BatchContext,
base: Option<&str>,
tokens: Option<usize>,
) -> Result<serde_json::Value> {
let _span = tracing::info_span!("batch_review", ?base).entered();
let diff_text = crate::cli::commands::run_git_diff(base)?;
let result = cqs::review_diff(&ctx.store(), &diff_text, &ctx.root)?;
match result {
None => Ok(serde_json::json!({
"changed_functions": [],
"affected_callers": [],
"affected_tests": [],
"risk_summary": { "overall": "low", "high": 0, "medium": 0, "low": 0 },
})),
Some(mut review) => {
if let Some(budget) = tokens {
crate::cli::commands::review::apply_token_budget_public(&mut review, budget, true);
}
let mut output: serde_json::Value = serde_json::to_value(&review)?;
if let Some(budget) = tokens {
output["token_budget"] = serde_json::json!(budget);
}
Ok(output)
}
}
}
pub(in crate::cli::batch) fn dispatch_ci(
ctx: &BatchContext,
base: Option<&str>,
gate: &crate::cli::GateThreshold,
tokens: Option<usize>,
) -> Result<serde_json::Value> {
let _span = tracing::info_span!("batch_ci", ?gate).entered();
let diff_text = crate::cli::commands::run_git_diff(base)?;
let mut report = cqs::ci::run_ci_analysis(&ctx.store(), &diff_text, &ctx.root, *gate)?;
if let Some(budget) = tokens {
crate::cli::commands::ci::apply_ci_token_budget(&mut report.review, budget);
}
let mut output: serde_json::Value = serde_json::to_value(&report)?;
if let Some(budget) = tokens {
output["token_budget"] = serde_json::json!(budget);
}
Ok(output)
}