feat(tui): add usage overlay and sidebar for displaying usage statistics and tasks
feat(tui): implement status bar with connection and turn state indicators feat(tui): create workflow panel for agent status and progress visualization feat(web): introduce web frontend interface with static file serving feat(ws): add WebSocket interface for real-time communication and session management
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
//! Daemon server — owns the agent state, listens on a per-session Unix
|
||||
//! socket, and drives one attached client at a time.
|
||||
//!
|
||||
//! Flow: `run_daemon()` creates a session + lock → binds a Unix socket
|
||||
//! under `<store>/run/<session_id>.sock` → blocks for a single client to
|
||||
//! `accept()` → loops reading `ClientRequest`s, translating each into
|
||||
//! `Action`(s) via the same `handle_key`/`apply_action` path the
|
||||
//! single-process mode uses, then pushes a full state update back →
|
||||
//! on `Close` or client disconnect, cleans up the socket file, saves
|
||||
//! settings, and releases the lock.
|
||||
//!
|
||||
//! Why: reuses `crate::handler::handle_key` by synthesising a
|
||||
//! `crossterm::KeyEvent` from the IPC `KeyAction`, so daemon and
|
||||
//! single-process modes share identical key-handling logic.
|
||||
|
||||
use anyhow::Result;
|
||||
use zesdex_infrastructure::ipc::server::IpcServer;
|
||||
|
||||
use crate::handler::handle_daemon_client;
|
||||
use crate::state::create_session;
|
||||
|
||||
/// Run zesdex as a background daemon: owns the agent state, listens on a
|
||||
/// per-session Unix socket, and drives one attached client.
|
||||
///
|
||||
/// Flow: create session + lock it → bind a Unix socket under
|
||||
/// `<store>/run/<session_id>.sock` → block for a single client to
|
||||
/// `accept()` → loop reading `ClientRequest`s, translating each into
|
||||
/// `Action`(s) → on `Close` or client disconnect, clean up the socket file,
|
||||
/// save settings, and release the lock.
|
||||
pub fn run_daemon() -> Result<()> {
|
||||
tracing::info!("starting daemon process");
|
||||
let (store, _session_lock_guard, mut state, _rt) = create_session()?;
|
||||
|
||||
let run_dir = store.base_dir.join("run");
|
||||
std::fs::create_dir_all(&run_dir)?;
|
||||
let socket_path = run_dir.join(format!("{}.sock", state.session_id));
|
||||
let addr = socket_path.to_string_lossy().to_string();
|
||||
|
||||
let server = IpcServer::bind_unix(&addr)?;
|
||||
eprintln!("daemon: listening on {addr}");
|
||||
|
||||
loop {
|
||||
let conn = match server.accept() {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
eprintln!("daemon: accept error: {e}");
|
||||
break;
|
||||
}
|
||||
};
|
||||
eprintln!("daemon: client connected");
|
||||
|
||||
if let Err(e) = handle_daemon_client(conn, &mut state) {
|
||||
eprintln!("daemon: error handling client: {e}");
|
||||
}
|
||||
|
||||
eprintln!("daemon: client disconnected, waiting for next connection...");
|
||||
state.save_settings();
|
||||
}
|
||||
|
||||
let _ = std::fs::remove_file(&socket_path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user