use crate::api::editor::{delete_tool, deprecate_tool, list_tools};
use crate::cli::commands::shared::{hard_confirm, make_client};
use crate::cli::{GlobalArgs, ToolsAction};
use crate::error::{OlError, OL_4200_TOKEN_EXPIRED};
use crate::ui::output::OutputConfig;
use clap::Args;
use tabled::Table;
#[derive(Args, Debug)]
pub struct DeprecateArgs {
pub spec: String,
pub message: String,
}
pub async fn run(g: &GlobalArgs, action: ToolsAction) -> Result<(), OlError> {
match action {
ToolsAction::List => list(g).await,
ToolsAction::Delete { slug, yes } => delete(g, &slug, yes).await,
ToolsAction::Deprecate(args) => deprecate_body(g, args).await,
}
}
pub async fn deprecate(g: &GlobalArgs, args: DeprecateArgs) -> Result<(), OlError> {
deprecate_body(g, args).await
}
async fn list(g: &GlobalArgs) -> Result<(), OlError> {
let out = OutputConfig::resolve(g);
let client = make_client().await?;
let tools = list_tools(&client).await?;
if out.is_machine() {
out.print_json(&tools);
return Ok(());
}
if tools.is_empty() {
out.print_info("No tools found.");
return Ok(());
}
let rows: Vec<crate::ui::tables::ToolRow> = tools
.into_iter()
.map(|t| crate::ui::tables::ToolRow {
slug: t.slug,
version: t.version.unwrap_or_else(|| "(none)".into()),
state: t.lifecycle_state.unwrap_or_else(|| "active".into()),
routing_score: t
.routing_score
.map(|s| format!("{s:.1}"))
.unwrap_or_else(|| "—".into()),
})
.collect();
println!("{}", Table::new(rows));
Ok(())
}
async fn delete(g: &GlobalArgs, slug: &str, yes_flag: bool) -> Result<(), OlError> {
let out = OutputConfig::resolve(g);
let yes = g.yes || yes_flag;
if g.dry_run {
out.print_step(&format!(
"--dry-run: would DELETE /api/v1/editor/tools/{slug}"
));
return Ok(());
}
hard_confirm(slug, out.interactive, yes)?;
let client = make_client().await?;
match delete_tool(&client, slug).await {
Ok(()) => {
out.print_step(&format!("Deleted tool `{slug}`"));
Ok(())
}
Err(e) if e.code.code == "OL-4234" => {
out.print_step(&format!("Tool `{slug}` already absent — no-op"));
Ok(())
}
Err(e) => Err(e),
}
}
async fn deprecate_body(g: &GlobalArgs, args: DeprecateArgs) -> Result<(), OlError> {
let out = OutputConfig::resolve(g);
let slug = args.spec.split('@').next().unwrap_or("");
if slug.is_empty() {
return Err(OlError::new(
OL_4200_TOKEN_EXPIRED,
format!(
"invalid tool spec `{}` (expected slug or slug@range)",
args.spec
),
));
}
if g.dry_run {
out.print_step(&format!(
"--dry-run: would PATCH /api/v1/editor/tools/{slug} (lifecycle_state=deprecated)"
));
return Ok(());
}
let client = make_client().await?;
let resp = deprecate_tool(&client, slug, &args.message).await?;
if out.is_machine() {
out.print_json(&resp);
} else {
out.print_step(&format!(
"Marked `{slug}` deprecated with message: {}",
args.message
));
}
Ok(())
}