- session.rs: Neues Modul mit 7 Tauri-Commands (CRUD, Resume, aktive Session) - db.rs: Sessions-Tabelle + CRUD-Methoden (bleiben bis User sie löscht) - claude.rs: Session-ID und Token/Kosten automatisch in DB speichern - SessionList.svelte: Sidebar mit Session-Liste, Erstellen, Fortsetzen, Löschen - +page.svelte: 4-Panel Layout (Sessions | Chat | Aktivität | Agents) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
155 lines
4.4 KiB
Rust
155 lines
4.4 KiB
Rust
// Claude Desktop — Session-Verwaltung
|
|
// Sessions bleiben permanent gespeichert bis der User sie löscht
|
|
|
|
use std::sync::{Arc, Mutex};
|
|
use tauri::{AppHandle, Manager};
|
|
|
|
use crate::db::{self, Session};
|
|
|
|
// ============ Tauri Commands ============
|
|
|
|
/// Neue Session erstellen
|
|
#[tauri::command]
|
|
pub async fn create_session(
|
|
app: AppHandle,
|
|
title: String,
|
|
working_dir: Option<String>,
|
|
) -> Result<Session, String> {
|
|
let session = Session {
|
|
id: uuid::Uuid::new_v4().to_string(),
|
|
claude_session_id: None,
|
|
title,
|
|
working_dir,
|
|
message_count: 0,
|
|
token_input: 0,
|
|
token_output: 0,
|
|
cost_usd: 0.0,
|
|
status: "active".to_string(),
|
|
created_at: chrono::Local::now().to_rfc3339(),
|
|
updated_at: chrono::Local::now().to_rfc3339(),
|
|
last_message: None,
|
|
};
|
|
|
|
let state = app.state::<Arc<Mutex<db::Database>>>();
|
|
let db = state.lock().unwrap();
|
|
db.create_session(&session).map_err(|e| e.to_string())?;
|
|
|
|
// Als aktive Session speichern
|
|
db.set_setting("active_session_id", &session.id).map_err(|e| e.to_string())?;
|
|
|
|
println!("📝 Neue Session: {} ({})", session.title, session.id);
|
|
|
|
Ok(session)
|
|
}
|
|
|
|
/// Session aktualisieren (nach Nachrichten, Token-Update, etc.)
|
|
#[tauri::command]
|
|
pub async fn update_session(
|
|
app: AppHandle,
|
|
session: Session,
|
|
) -> Result<(), String> {
|
|
let state = app.state::<Arc<Mutex<db::Database>>>();
|
|
let db = state.lock().unwrap();
|
|
db.update_session(&session).map_err(|e| e.to_string())
|
|
}
|
|
|
|
/// Alle Sessions laden
|
|
#[tauri::command]
|
|
pub async fn list_sessions(
|
|
app: AppHandle,
|
|
limit: Option<usize>,
|
|
) -> Result<Vec<Session>, String> {
|
|
let limit = limit.unwrap_or(50);
|
|
let state = app.state::<Arc<Mutex<db::Database>>>();
|
|
let db = state.lock().unwrap();
|
|
db.load_sessions(limit).map_err(|e| e.to_string())
|
|
}
|
|
|
|
/// Session nach ID laden
|
|
#[tauri::command]
|
|
pub async fn get_session(
|
|
app: AppHandle,
|
|
id: String,
|
|
) -> Result<Option<Session>, String> {
|
|
let state = app.state::<Arc<Mutex<db::Database>>>();
|
|
let db = state.lock().unwrap();
|
|
db.get_session(&id).map_err(|e| e.to_string())
|
|
}
|
|
|
|
/// Session löschen
|
|
#[tauri::command]
|
|
pub async fn delete_session(
|
|
app: AppHandle,
|
|
id: String,
|
|
) -> Result<(), String> {
|
|
let state = app.state::<Arc<Mutex<db::Database>>>();
|
|
let db = state.lock().unwrap();
|
|
db.delete_session(&id).map_err(|e| e.to_string())?;
|
|
|
|
// Falls es die aktive Session war, Setting löschen
|
|
if let Ok(Some(active_id)) = db.get_setting("active_session_id") {
|
|
if active_id == id {
|
|
let _ = db.set_setting("active_session_id", "");
|
|
}
|
|
}
|
|
|
|
println!("🗑️ Session gelöscht: {}", id);
|
|
Ok(())
|
|
}
|
|
|
|
/// Session fortsetzen — setzt die aktive Session und gibt die claude_session_id zurück
|
|
#[tauri::command]
|
|
pub async fn resume_session(
|
|
app: AppHandle,
|
|
id: String,
|
|
) -> Result<Session, String> {
|
|
let state = app.state::<Arc<Mutex<db::Database>>>();
|
|
let db = state.lock().unwrap();
|
|
|
|
let session = db.get_session(&id)
|
|
.map_err(|e| e.to_string())?
|
|
.ok_or_else(|| format!("Session {} nicht gefunden", id))?;
|
|
|
|
// Als aktive Session setzen
|
|
db.set_setting("active_session_id", &session.id).map_err(|e| e.to_string())?;
|
|
|
|
println!("▶️ Session fortgesetzt: {} (claude: {:?})", session.title, session.claude_session_id);
|
|
|
|
Ok(session)
|
|
}
|
|
|
|
/// Aktive Session holen (nach App-Start)
|
|
#[tauri::command]
|
|
pub async fn get_active_session(
|
|
app: AppHandle,
|
|
) -> Result<Option<Session>, String> {
|
|
let state = app.state::<Arc<Mutex<db::Database>>>();
|
|
let db = state.lock().unwrap();
|
|
|
|
if let Ok(Some(id)) = db.get_setting("active_session_id") {
|
|
if !id.is_empty() {
|
|
return db.get_session(&id).map_err(|e| e.to_string());
|
|
}
|
|
}
|
|
|
|
Ok(None)
|
|
}
|
|
|
|
/// Claude Session-ID speichern (kommt von der Bridge nach erstem Request)
|
|
#[tauri::command]
|
|
pub async fn set_claude_session_id(
|
|
app: AppHandle,
|
|
session_id: String,
|
|
claude_session_id: String,
|
|
) -> Result<(), String> {
|
|
let state = app.state::<Arc<Mutex<db::Database>>>();
|
|
let db = state.lock().unwrap();
|
|
|
|
if let Ok(Some(mut session)) = db.get_session(&session_id) {
|
|
session.claude_session_id = Some(claude_session_id.clone());
|
|
db.update_session(&session).map_err(|e| e.to_string())?;
|
|
println!("🔗 Claude Session-ID gesetzt: {} → {}", session_id, claude_session_id);
|
|
}
|
|
|
|
Ok(())
|
|
}
|