use crate::AppModel;
use crate::cli_outbound::Cli;
use crate::delete::agent::{AgentConfirmation, Census};
use crate::nav::convs::root_of;
use crate::theme;
use std::path::{Path, PathBuf};
use super::ShellState;
#[derive(Default)]
pub struct DeleteAgentState {
pub target: Option<(PathBuf, String)>,
pub census: Option<Census>,
pub typed: String,
pub error: String,
}
pub(super) fn open(state: &mut ShellState, lernie: &Cli, ws: &Path, root: &str) {
let (census, error) = match crate::delete::agent::census(lernie, ws, root) {
Ok(census) => (Some(census), String::new()),
Err(e) => (None, e),
};
state.delete_agent = DeleteAgentState {
target: Some((ws.to_path_buf(), root.to_owned())),
census,
typed: String::new(),
error,
};
}
pub(super) fn danger_row(
ui: &mut egui::Ui,
model: &AppModel,
state: &mut ShellState,
lernie: &Cli,
ws: &Path,
) {
let Some(agent) = model.focused_agent().map(|a| a.agent_id.clone()) else {
return;
};
let agents = model
.focused_tree()
.map(|t| t.agents.clone())
.unwrap_or_default();
let root = root_of(&agents, &agent).unwrap_or(agent);
if model.agent_delete_confirmation(ws, &root).is_none() {
return;
}
ui.separator();
if ui
.button(egui::RichText::new("delete this conversation…").color(theme::ICHOR))
.on_hover_text(
"removes the agent, its children and their pending inbox — irrecoverable. \
Typed, it is `/delete-agent [typed name]`.",
)
.clicked()
{
open(state, lernie, ws, &root);
}
}
pub(super) fn dialog(
ctx: &egui::Context,
model: &mut AppModel,
state: &mut ShellState,
lernie: &Cli,
bl: &Cli,
) {
if state.delete_agent.target.is_none() {
return;
}
window(ctx, model, state, lernie, bl);
if state.delete_agent.target.is_none() {
super::focus::request(state);
}
}
fn window(
ctx: &egui::Context,
model: &mut AppModel,
state: &mut ShellState,
lernie: &Cli,
bl: &Cli,
) {
let Some((ws, root)) = state.delete_agent.target.clone() else {
return;
};
let Some(confirm) = model.agent_delete_confirmation(&ws, &root) else {
state.delete_agent = DeleteAgentState::default();
return;
};
let mut shown = true;
egui::Window::new(format!("delete conversation {}", confirm.name))
.collapsible(false)
.resizable(false)
.open(&mut shown)
.show(ctx, |ui| body(ui, model, state, lernie, bl, &confirm));
if !shown {
state.delete_agent = DeleteAgentState::default();
}
}
fn body(
ui: &mut egui::Ui,
model: &mut AppModel,
state: &mut ShellState,
lernie: &Cli,
bl: &Cli,
confirm: &AgentConfirmation,
) {
ui.colored_label(
theme::ICHOR,
"this destroys the conversation — transcript, steps, worktree, marks — irrecoverably",
);
let Some(census) = state.delete_agent.census.clone() else {
ui.colored_label(theme::ICHOR, &state.delete_agent.error);
return;
};
ui.label("children that die with it:");
if census.descendants.is_empty() {
ui.weak("(none)");
}
for id in &census.descendants {
ui.weak(id);
}
ui.label(format!(
"pending inbox deposits that die: {}",
census.pending_deposits
));
ui.separator();
if confirm.refused() {
ui.colored_label(
theme::ICHOR,
format!("live: {} — stop them first", confirm.live.join(", ")),
);
return;
}
let armed = if census.descendants.is_empty() {
true
} else {
ui.horizontal(|ui| {
ui.label(format!("type “{}” to confirm:", confirm.name));
ui.text_edit_singleline(&mut state.delete_agent.typed)
.on_hover_text(
"Retype the conversation's name exactly — deleting its children \
too is confirmed by the name, not a checkbox. It is the name \
`/delete-agent [typed name]` carries.",
);
});
confirm.subtree_armed(&state.delete_agent.typed)
};
if ui
.add_enabled(armed, egui::Button::new("Delete conversation"))
.on_hover_text(
"Remove this conversation from the workspace, permanently. Typed, it is \
`/delete-agent [typed name]`.",
)
.on_disabled_hover_text("Type the conversation's name above to enable this.")
.clicked()
{
fire(model, state, lernie, bl);
}
if !state.delete_agent.error.is_empty() {
ui.colored_label(theme::ICHOR, &state.delete_agent.error);
}
}
fn fire(model: &mut AppModel, state: &mut ShellState, lernie: &Cli, bl: &Cli) {
let Some((ws, root)) = state.delete_agent.target.clone() else {
return;
};
let typed = state.delete_agent.typed.clone();
match model.delete_agent(lernie, bl, &ws, &root, &typed, &super::now_ts()) {
Ok(()) => state.delete_agent = DeleteAgentState::default(),
Err(e) => state.delete_agent.error = e,
}
}