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:
asepharyana
2026-07-20 09:04:57 +07:00
parent bceba665c0
commit da2ed6da25
454 changed files with 13979 additions and 29539 deletions
@@ -0,0 +1,88 @@
//! SQLite database connection initialisation and schema migrations.
use std::sync::{Arc, Mutex};
/// A shared SQLite connection wrapped for thread-safe access.
#[derive(Clone)]
pub struct DbConn {
conn: Arc<Mutex<rusqlite::Connection>>,
}
impl DbConn {
/// Execute a closure with a reference to the underlying connection.
pub fn with<F, T>(&self, f: F) -> anyhow::Result<T>
where
F: FnOnce(&rusqlite::Connection) -> anyhow::Result<T>,
{
let conn = self
.conn
.lock()
.map_err(|e| anyhow::anyhow!("db lock poisoned: {e}"))?;
f(&conn)
}
}
const SCHEMA_SQL: &str = r#"
CREATE TABLE IF NOT EXISTS sessions (
id TEXT PRIMARY KEY,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
title TEXT NOT NULL DEFAULT '',
model TEXT NOT NULL DEFAULT '',
workspace_roots TEXT NOT NULL DEFAULT '[]',
message_count INTEGER NOT NULL DEFAULT 0,
token_count INTEGER NOT NULL DEFAULT 0,
archived INTEGER NOT NULL DEFAULT 0,
summary TEXT
);
CREATE TABLE IF NOT EXISTS settings (
id INTEGER PRIMARY KEY CHECK (id = 1),
data TEXT NOT NULL DEFAULT '{}',
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS conversations (
session_id TEXT PRIMARY KEY,
data TEXT NOT NULL DEFAULT '{}',
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS memories (
name TEXT PRIMARY KEY,
data TEXT NOT NULL DEFAULT '{}',
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS edit_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
entry TEXT NOT NULL,
created_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_edit_logs_session
ON edit_logs (session_id);
"#;
/// Initialise a shared SQLite connection at the given path.
pub fn init_db(db_path: &str) -> anyhow::Result<DbConn> {
let conn = rusqlite::Connection::open(db_path)
.map_err(|e| anyhow::anyhow!("failed to open SQLite database at '{db_path}': {e}"))?;
conn.execute_batch("PRAGMA journal_mode = WAL;")?;
conn.execute_batch("PRAGMA busy_timeout = 5000;")?;
Ok(DbConn {
conn: Arc::new(Mutex::new(conn)),
})
}
/// Run embedded SQL schema migrations.
pub fn run_migrations(db: &DbConn) -> anyhow::Result<()> {
db.with(|conn| {
conn.execute_batch(SCHEMA_SQL)
.map_err(|e| anyhow::anyhow!("failed to execute database schema migrations: {e}"))
})?;
Ok(())
}