Files
zesdex/src/app/state/rest.rs
T

163 lines
5.6 KiB
Rust
Raw Normal View History

use std::collections::VecDeque;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use tokio::sync::RwLock;
use super::misc::{DirCache, InputState, MiscState, ScrollState};
use super::runtime::{SessionRuntime, TurnEvent};
use super::types::{Origin, Toast, TranscriptCache};
use crate::app::mcp::manager::McpManager;
use crate::app::workflow::engine::WorkflowEngine;
use crate::model::app_config::AppConfig;
use crate::model::editlog::EditLog;
use crate::model::settings::Settings;
#[derive(Debug, Clone, PartialEq)]
pub struct ChatMessageDisplay {
pub role: crate::dto::chat::message::Role,
pub content: String,
pub timestamp: i64,
}
impl ChatMessageDisplay {
pub fn new(role: crate::dto::chat::message::Role, content: String) -> Self {
ChatMessageDisplay {
role,
content,
timestamp: chrono::Utc::now().timestamp_millis(),
}
}
}
#[derive(Clone)]
pub struct AppStateRest {
pub settings: Settings,
pub app_config: AppConfig,
pub workspace_roots: Vec<PathBuf>,
pub session_id: String,
pub session_dir: PathBuf,
pub memory_dir: PathBuf,
pub download_dir: PathBuf,
pub worktrees_dir: PathBuf,
pub dir_cache: Arc<RwLock<DirCache>>,
pub edit_log: EditLog,
pub session_runtime: Option<SessionRuntime>,
pub sessions: Vec<crate::model::session::Session>,
pub transcript_cache: TranscriptCache,
pub scroll: ScrollState,
pub input: InputState,
pub misc: MiscState,
pub turn_events: Arc<Mutex<VecDeque<TurnEvent>>>,
pub turn_in_flight: Arc<Mutex<bool>>,
pub abort_flag: Arc<std::sync::atomic::AtomicBool>,
pub workflow_engine: WorkflowEngine,
pub mcp_manager: McpManager,
pub dirty: bool,
pub quit: bool,
}
impl AppStateRest {
pub fn new(workspace_roots: Vec<PathBuf>, session_dir: PathBuf, memory_dir: PathBuf) -> Self {
let settings = Settings::load();
let app_config = AppConfig::load();
let download_dir = memory_dir.parent().unwrap_or_else(|| {
eprintln!("[state] memory_dir '{}' has no parent, using it for downloads", memory_dir.display());
&memory_dir
}).join("downloads");
let worktrees_dir = memory_dir.parent().unwrap_or_else(|| {
eprintln!("[state] memory_dir '{}' has no parent, using it for worktrees", memory_dir.display());
&memory_dir
}).join("worktrees");
let dir_cache = DirCache::new();
let session_id = session_dir
.file_name()
.map(|n| n.to_string_lossy().to_string())
.unwrap_or_else(|| {
eprintln!("[state] session_dir has no file_name component, using empty session_id");
String::new()
});
AppStateRest {
settings,
app_config,
workspace_roots,
session_id,
session_dir: session_dir.clone(),
memory_dir,
download_dir,
worktrees_dir,
turn_events: Arc::new(Mutex::new(VecDeque::new())),
turn_in_flight: Arc::new(Mutex::new(false)),
abort_flag: Arc::new(std::sync::atomic::AtomicBool::new(false)),
dir_cache: Arc::new(RwLock::new(dir_cache)),
edit_log: EditLog::new(&session_dir),
session_runtime: Some(SessionRuntime::new(session_dir.clone())),
workflow_engine: WorkflowEngine::new(),
mcp_manager: McpManager::new(),
sessions: Vec::new(),
transcript_cache: TranscriptCache::new(200),
scroll: ScrollState::new(),
input: InputState::new(),
misc: MiscState::new(),
dirty: true,
quit: false,
}
}
pub fn turn_in_flight(&self) -> bool {
self.turn_in_flight.lock().map(|g| *g).unwrap_or_else(|_| {
eprintln!("[state] turn_in_flight mutex poisoned");
false
})
}
pub fn push_transcript(&mut self, msg: ChatMessageDisplay) {
self.transcript_cache.messages.push(msg);
if self.transcript_cache.messages.len() > self.transcript_cache.max_lines {
self.transcript_cache.messages.remove(0);
}
self.transcript_cache.dirty = true;
self.dirty = true;
}
pub fn push_toast(&mut self, toast: Toast) {
self.misc.push_toast(toast);
self.dirty = true;
}
pub fn store_base_dir(&self) -> std::path::PathBuf {
self.session_dir.parent()
.and_then(|p| p.parent())
.map(|p| p.to_path_buf())
.unwrap_or_else(|| {
eprintln!("[state] session_dir '{}' has no grandparent, using parent", self.session_dir.display());
self.session_dir.parent()
.map(|p| p.to_path_buf())
.unwrap_or_else(|| {
eprintln!("[state] session_dir '{}' has no parent at all, using itself", self.session_dir.display());
self.session_dir.clone()
})
})
}
pub fn tool_ctx(&self) -> crate::tool::ToolCtx {
self.tool_ctx_for(Origin::Main)
}
pub fn tool_ctx_for(&self, origin: Origin) -> crate::tool::ToolCtx {
crate::tool::ToolCtx {
workspaces: self.workspace_roots.clone(),
session_dir: self.session_dir.clone(),
memory_dir: self.memory_dir.clone(),
_download_dir: self.download_dir.clone(),
worktrees_dir: self.worktrees_dir.clone(),
dir_cache: self.dir_cache.clone(),
origin,
graduated_checks: Vec::new(),
}
}
}