aico/commands/
session_cmds.rs

1use crate::exceptions::AicoError;
2use crate::fs::atomic_write_json;
3use crate::models::{SessionView, default_timestamp};
4use crate::session::Session;
5use std::fs;
6
7pub fn list() -> Result<(), AicoError> {
8    let session = Session::load_active()?;
9    let sessions_dir = session.sessions_dir();
10
11    if !sessions_dir.exists() {
12        return Err(AicoError::Session("Sessions directory not found.".into()));
13    }
14
15    // Get active name from the current view path
16    let active_name = session
17        .view_path
18        .file_stem()
19        .and_then(|s| s.to_str())
20        .unwrap_or("unknown");
21
22    let mut views: Vec<_> = fs::read_dir(sessions_dir)?
23        .filter_map(Result::ok) // Ignore IO errors on specific entries
24        .map(|e| e.path())
25        .filter(|p| p.extension().is_some_and(|e| e == "json"))
26        .filter_map(|p| p.file_stem().map(|s| s.to_string_lossy().into_owned()))
27        .collect();
28
29    views.sort();
30
31    if views.is_empty() {
32        println!("No session views found.");
33        return Ok(());
34    }
35
36    println!("Available sessions:");
37    for name in views {
38        if name == active_name {
39            println!("  - {} (active)", name);
40        } else {
41            println!("  - {}", name);
42        }
43    }
44
45    Ok(())
46}
47
48pub fn switch(name: String) -> Result<(), AicoError> {
49    let session = Session::load_active()?;
50    let target_path = session.get_view_path(&name);
51
52    if !target_path.exists() {
53        return Err(AicoError::InvalidInput(format!(
54            "Session view '{}' not found at {}.",
55            name,
56            target_path.display()
57        )));
58    }
59
60    session.switch_to_view(&target_path)?;
61    println!("Switched active session to: {}", name);
62    Ok(())
63}
64
65pub fn new_session(name: String, model: Option<String>) -> Result<(), AicoError> {
66    let session = Session::load_active()?;
67    let new_view_path = session.get_view_path(&name);
68
69    if new_view_path.exists() {
70        return Err(AicoError::InvalidInput(format!(
71            "A session view named '{}' already exists.",
72            name
73        )));
74    }
75
76    let new_model = model.unwrap_or_else(|| session.view.model.clone());
77
78    let view = SessionView {
79        model: new_model.clone(),
80        context_files: vec![],
81        message_indices: vec![],
82        history_start_pair: 0,
83        excluded_pairs: vec![],
84        created_at: default_timestamp(),
85    };
86
87    atomic_write_json(&new_view_path, &view)?;
88
89    session.switch_to_view(&new_view_path)?;
90    println!(
91        "Created new empty session '{}' with model '{}' and switched to it.",
92        name, new_model
93    );
94
95    Ok(())
96}