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,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(())
|
||||
}
|
||||
Reference in New Issue
Block a user