use std::sync::Arc;
use axum::{Json, extract::State, http::StatusCode, response::IntoResponse};
use serde::Deserialize;
use tracing::warn;
use crate::daemon::state::DaemonState;
use crate::session_manager::PruneFilter;
#[derive(Debug, Deserialize)]
pub struct PruneRequest {
pub state: String,
#[serde(default)]
pub dry_run: bool,
#[serde(default)]
pub include_active: bool,
}
pub async fn decommission_ephemeral_route(
State(state): State<Arc<DaemonState>>,
) -> impl IntoResponse {
let mgr = state.session_manager().await;
match mgr.decommission_all_ephemeral().await {
Ok(count) => Json(serde_json::json!({ "decommissioned": count })).into_response(),
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(),
}
}
#[derive(Debug, Deserialize)]
pub struct PruneWorktreesRequest {
#[serde(default = "default_dry_run")]
pub dry_run: bool,
}
fn default_dry_run() -> bool {
true
}
pub async fn prune_worktrees_route(
State(state): State<Arc<DaemonState>>,
Json(req): Json<PruneWorktreesRequest>,
) -> impl IntoResponse {
let mgr = state.session_manager().await;
let records = mgr.list().await;
let active_workspace_paths: Vec<std::path::PathBuf> = records
.iter()
.filter_map(|r| r.workspace_path.clone())
.collect();
let config = crate::core::trusty_tools_config::TrustyToolsConfig::load();
let repos_root = crate::core::trusty_tools_config::workspace_root(&config);
match mgr
.prune_orphaned_worktrees(&repos_root, &active_workspace_paths, req.dry_run)
.await
{
Ok(outcome) => {
let paths: Vec<String> = outcome
.removed
.iter()
.map(|p| p.to_string_lossy().into_owned())
.collect();
let owner_unknown_paths: Vec<String> = outcome
.owner_unknown
.iter()
.map(|p| p.to_string_lossy().into_owned())
.collect();
Json(serde_json::json!({
"dry_run": req.dry_run,
"paths": paths,
"owner_unknown_paths": owner_unknown_paths,
}))
.into_response()
}
Err(e) => {
warn!("prune-worktrees route: orphan scan failed: {e}");
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("orphan worktree scan failed: {e}"),
)
.into_response()
}
}
}
pub async fn prune_managed_route(
State(state): State<Arc<DaemonState>>,
Json(req): Json<PruneRequest>,
) -> impl IntoResponse {
let filter = match PruneFilter::parse(&req.state) {
Ok(f) => f,
Err(e) => {
warn!("prune route: {e}");
return (StatusCode::BAD_REQUEST, e).into_response();
}
};
let mgr = state.session_manager().await;
match mgr
.prune_managed(filter, req.dry_run, req.include_active, None)
.await
{
Ok(outcome) => Json(outcome).into_response(),
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(),
}
}