diff --git a/v2/src-tauri/src/btmsg.rs b/v2/src-tauri/src/btmsg.rs index e4b2e3e..48a53b5 100644 --- a/v2/src-tauri/src/btmsg.rs +++ b/v2/src-tauri/src/btmsg.rs @@ -1,4 +1,4 @@ -// btmsg — Read-only access to btmsg SQLite database +// btmsg — Access to btmsg SQLite database // Database at ~/.local/share/bterminal/btmsg.db (created by btmsg CLI) use rusqlite::{params, Connection, OpenFlags}; @@ -17,8 +17,13 @@ fn open_db() -> Result { if !path.exists() { return Err("btmsg database not found. Run 'btmsg register' first.".into()); } - Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE) - .map_err(|e| format!("Failed to open btmsg.db: {e}")) + let conn = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE) + .map_err(|e| format!("Failed to open btmsg.db: {e}"))?; + conn.pragma_update(None, "journal_mode", "WAL") + .map_err(|e| format!("Failed to set WAL mode: {e}"))?; + conn.pragma_update(None, "busy_timeout", 5000) + .map_err(|e| format!("Failed to set busy_timeout: {e}"))?; + Ok(conn) } #[derive(Debug, Serialize, Deserialize)] @@ -95,13 +100,13 @@ pub fn get_agents(group_id: &str) -> Result, String> { let agents = stmt.query_map(params![group_id], |row| { Ok(BtmsgAgent { - id: row.get(0)?, - name: row.get(1)?, - role: row.get(2)?, - group_id: row.get(3)?, - tier: row.get(4)?, - model: row.get(5)?, - status: row.get::<_, Option>(7)?.unwrap_or_else(|| "stopped".into()), + id: row.get("id")?, + name: row.get("name")?, + role: row.get("role")?, + group_id: row.get("group_id")?, + tier: row.get("tier")?, + model: row.get("model")?, + status: row.get::<_, Option>("status")?.unwrap_or_else(|| "stopped".into()), unread_count: row.get("unread_count")?, }) }).map_err(|e| format!("Query error: {e}"))?; @@ -122,22 +127,22 @@ pub fn unread_messages(agent_id: &str) -> Result, String> { let db = open_db()?; let mut stmt = db.prepare( "SELECT m.id, m.from_agent, m.to_agent, m.content, m.read, m.reply_to, m.created_at, \ - a.name, a.role \ + a.name AS sender_name, a.role AS sender_role \ FROM messages m JOIN agents a ON m.from_agent = a.id \ WHERE m.to_agent = ? AND m.read = 0 ORDER BY m.created_at ASC" ).map_err(|e| format!("Query error: {e}"))?; let msgs = stmt.query_map(params![agent_id], |row| { Ok(BtmsgMessage { - id: row.get(0)?, - from_agent: row.get(1)?, - to_agent: row.get(2)?, - content: row.get(3)?, - read: row.get::<_, i32>(4)? != 0, - reply_to: row.get(5)?, - created_at: row.get(6)?, - sender_name: row.get(7)?, - sender_role: row.get(8)?, + id: row.get("id")?, + from_agent: row.get("from_agent")?, + to_agent: row.get("to_agent")?, + content: row.get("content")?, + read: row.get::<_, i32>("read")? != 0, + reply_to: row.get("reply_to")?, + created_at: row.get("created_at")?, + sender_name: row.get("sender_name")?, + sender_role: row.get("sender_role")?, }) }).map_err(|e| format!("Query error: {e}"))?; @@ -148,7 +153,7 @@ pub fn history(agent_id: &str, other_id: &str, limit: i32) -> Result Result(4)? != 0, - reply_to: row.get(5)?, - created_at: row.get(6)?, - sender_name: row.get(7)?, - sender_role: row.get(8)?, + id: row.get("id")?, + from_agent: row.get("from_agent")?, + to_agent: row.get("to_agent")?, + content: row.get("content")?, + read: row.get::<_, i32>("read")? != 0, + reply_to: row.get("reply_to")?, + created_at: row.get("created_at")?, + sender_name: row.get("sender_name")?, + sender_role: row.get("sender_role")?, }) }).map_err(|e| format!("Query error: {e}"))?; @@ -257,7 +262,8 @@ pub fn all_feed(group_id: &str, limit: i32) -> Result, Str let db = open_db()?; let mut stmt = db.prepare( "SELECT m.id, m.from_agent, m.to_agent, m.content, m.created_at, m.reply_to, \ - a1.name, a1.role, a2.name, a2.role \ + a1.name AS sender_name, a1.role AS sender_role, \ + a2.name AS recipient_name, a2.role AS recipient_role \ FROM messages m \ JOIN agents a1 ON m.from_agent = a1.id \ JOIN agents a2 ON m.to_agent = a2.id \ @@ -267,16 +273,16 @@ pub fn all_feed(group_id: &str, limit: i32) -> Result, Str let msgs = stmt.query_map(params![group_id, limit], |row| { Ok(BtmsgFeedMessage { - id: row.get(0)?, - from_agent: row.get(1)?, - to_agent: row.get(2)?, - content: row.get(3)?, - created_at: row.get(4)?, - reply_to: row.get(5)?, - sender_name: row.get(6)?, - sender_role: row.get(7)?, - recipient_name: row.get(8)?, - recipient_role: row.get(9)?, + id: row.get("id")?, + from_agent: row.get("from_agent")?, + to_agent: row.get("to_agent")?, + content: row.get("content")?, + created_at: row.get("created_at")?, + reply_to: row.get("reply_to")?, + sender_name: row.get("sender_name")?, + sender_role: row.get("sender_role")?, + recipient_name: row.get("recipient_name")?, + recipient_role: row.get("recipient_role")?, }) }).map_err(|e| format!("Query error: {e}"))?; @@ -296,19 +302,19 @@ pub fn get_channels(group_id: &str) -> Result, String> { let db = open_db()?; let mut stmt = db.prepare( "SELECT c.id, c.name, c.group_id, c.created_by, \ - (SELECT COUNT(*) FROM channel_members cm WHERE cm.channel_id = c.id), \ + (SELECT COUNT(*) FROM channel_members cm WHERE cm.channel_id = c.id) AS member_count, \ c.created_at \ FROM channels c WHERE c.group_id = ? ORDER BY c.name" ).map_err(|e| format!("Query error: {e}"))?; let channels = stmt.query_map(params![group_id], |row| { Ok(BtmsgChannel { - id: row.get(0)?, - name: row.get(1)?, - group_id: row.get(2)?, - created_by: row.get(3)?, - member_count: row.get(4)?, - created_at: row.get(5)?, + id: row.get("id")?, + name: row.get("name")?, + group_id: row.get("group_id")?, + created_by: row.get("created_by")?, + member_count: row.get("member_count")?, + created_at: row.get("created_at")?, }) }).map_err(|e| format!("Query error: {e}"))?; @@ -319,20 +325,20 @@ pub fn get_channel_messages(channel_id: &str, limit: i32) -> Result Result { if !path.exists() { return Err("btmsg database not found".into()); } - Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE) - .map_err(|e| format!("Failed to open btmsg.db: {e}")) + let conn = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE) + .map_err(|e| format!("Failed to open btmsg.db: {e}"))?; + conn.pragma_update(None, "journal_mode", "WAL") + .map_err(|e| format!("Failed to set WAL mode: {e}"))?; + conn.pragma_update(None, "busy_timeout", 5000) + .map_err(|e| format!("Failed to set busy_timeout: {e}"))?; + Ok(conn) } #[derive(Debug, Serialize, Deserialize)] @@ -64,18 +69,18 @@ pub fn list_tasks(group_id: &str) -> Result, String> { let rows = stmt .query_map(params![group_id], |row| { Ok(Task { - id: row.get(0)?, - title: row.get(1)?, - description: row.get::<_, String>(2).unwrap_or_default(), - status: row.get::<_, String>(3).unwrap_or_else(|_| "todo".into()), - priority: row.get::<_, String>(4).unwrap_or_else(|_| "medium".into()), - assigned_to: row.get(5)?, - created_by: row.get(6)?, - group_id: row.get(7)?, - parent_task_id: row.get(8)?, - sort_order: row.get::<_, i32>(9).unwrap_or(0), - created_at: row.get::<_, String>(10).unwrap_or_default(), - updated_at: row.get::<_, String>(11).unwrap_or_default(), + id: row.get("id")?, + title: row.get("title")?, + description: row.get::<_, String>("description").unwrap_or_default(), + status: row.get::<_, String>("status").unwrap_or_else(|_| "todo".into()), + priority: row.get::<_, String>("priority").unwrap_or_else(|_| "medium".into()), + assigned_to: row.get("assigned_to")?, + created_by: row.get("created_by")?, + group_id: row.get("group_id")?, + parent_task_id: row.get("parent_task_id")?, + sort_order: row.get::<_, i32>("sort_order").unwrap_or(0), + created_at: row.get::<_, String>("created_at").unwrap_or_default(), + updated_at: row.get::<_, String>("updated_at").unwrap_or_default(), }) }) .map_err(|e| format!("Query error: {e}"))?; @@ -98,11 +103,11 @@ pub fn task_comments(task_id: &str) -> Result, String> { let rows = stmt .query_map(params![task_id], |row| { Ok(TaskComment { - id: row.get(0)?, - task_id: row.get(1)?, - agent_id: row.get(2)?, - content: row.get(3)?, - created_at: row.get::<_, String>(4).unwrap_or_default(), + id: row.get("id")?, + task_id: row.get("task_id")?, + agent_id: row.get("agent_id")?, + content: row.get("content")?, + created_at: row.get::<_, String>("created_at").unwrap_or_default(), }) }) .map_err(|e| format!("Query error: {e}"))?; diff --git a/v2/src/lib/adapters/btmsg-bridge.ts b/v2/src/lib/adapters/btmsg-bridge.ts index 2060a6b..682bf26 100644 --- a/v2/src/lib/adapters/btmsg-bridge.ts +++ b/v2/src/lib/adapters/btmsg-bridge.ts @@ -10,23 +10,23 @@ export interface BtmsgAgent { id: string; name: string; role: string; - group_id: string; + groupId: string; tier: number; model: string | null; status: string; - unread_count: number; + unreadCount: number; } export interface BtmsgMessage { id: string; - from_agent: string; - to_agent: string; + fromAgent: string; + toAgent: string; content: string; read: boolean; - reply_to: string | null; - created_at: string; - sender_name?: string; - sender_role?: string; + replyTo: string | null; + createdAt: string; + senderName?: string; + senderRole?: string; } export interface BtmsgFeedMessage { diff --git a/v2/src/lib/components/Workspace/CommsTab.svelte b/v2/src/lib/components/Workspace/CommsTab.svelte index b007d05..0739ab1 100644 --- a/v2/src/lib/components/Workspace/CommsTab.svelte +++ b/v2/src/lib/components/Workspace/CommsTab.svelte @@ -257,8 +257,8 @@ {getAgentIcon(agent.role)} {agent.name} - {#if agent.unread_count > 0} - {agent.unread_count} + {#if agent.unreadCount > 0} + {agent.unreadCount} {/if} {/each} @@ -301,11 +301,11 @@
No messages yet. Start the conversation!
{:else} {#each dmMessages as msg (msg.id)} - {@const isMe = msg.from_agent === ADMIN_ID} + {@const isMe = msg.fromAgent === ADMIN_ID}
- {isMe ? 'You' : (msg.sender_name ?? msg.from_agent)} - {formatTime(msg.created_at)} + {isMe ? 'You' : (msg.senderName ?? msg.fromAgent)} + {formatTime(msg.createdAt)}
{msg.content}