Skip to content

Commit cf2d7c9

Browse files
chore(app): wire all new features into app shell, store, and IPC layer
Register all new Tauri commands, update app store with browser/diff/naming state, merge toolbar buttons into tab bar, add draggable pane dividers with responsive vertical/horizontal layout.
1 parent 8e24056 commit cf2d7c9

11 files changed

Lines changed: 6143 additions & 76 deletions

File tree

Cargo.lock

Lines changed: 5381 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/persistence/src/migrations.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,23 @@ pub fn run_migrations(conn: &Connection) -> rusqlite::Result<()> {
5555
conn.execute_batch("ALTER TABLE threads ADD COLUMN color TEXT;")?;
5656
}
5757

58+
// Usage logs table
59+
conn.execute_batch(
60+
"
61+
CREATE TABLE IF NOT EXISTS usage_logs (
62+
id TEXT PRIMARY KEY NOT NULL,
63+
thread_id TEXT NOT NULL,
64+
session_id TEXT,
65+
input_tokens INTEGER NOT NULL DEFAULT 0,
66+
output_tokens INTEGER NOT NULL DEFAULT 0,
67+
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
68+
cache_write_tokens INTEGER NOT NULL DEFAULT 0,
69+
cost_usd REAL NOT NULL DEFAULT 0,
70+
model TEXT,
71+
created_at TEXT NOT NULL
72+
);
73+
",
74+
)?;
75+
5876
Ok(())
5977
}

crates/persistence/src/queries.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,90 @@ pub fn delete_setting(conn: &Connection, key: &str) -> anyhow::Result<()> {
268268
Ok(())
269269
}
270270

271+
// ---------------------------------------------------------------------------
272+
// Usage Logs
273+
// ---------------------------------------------------------------------------
274+
275+
pub fn insert_usage_log(
276+
conn: &Connection,
277+
id: &str,
278+
thread_id: &str,
279+
session_id: Option<&str>,
280+
input_tokens: i64,
281+
output_tokens: i64,
282+
cache_read_tokens: i64,
283+
cache_write_tokens: i64,
284+
cost_usd: f64,
285+
model: Option<&str>,
286+
created_at: &str,
287+
) -> anyhow::Result<()> {
288+
conn.execute(
289+
"INSERT INTO usage_logs (id, thread_id, session_id, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, cost_usd, model, created_at) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)",
290+
params![id, thread_id, session_id, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, cost_usd, model, created_at],
291+
)?;
292+
Ok(())
293+
}
294+
295+
pub fn get_usage_totals(conn: &Connection) -> anyhow::Result<(i64, i64, i64, i64, f64)> {
296+
let mut stmt = conn.prepare(
297+
"SELECT COALESCE(SUM(input_tokens),0), COALESCE(SUM(output_tokens),0), COALESCE(SUM(cache_read_tokens),0), COALESCE(SUM(cache_write_tokens),0), COALESCE(SUM(cost_usd),0.0) FROM usage_logs",
298+
)?;
299+
let result = stmt.query_row([], |row| {
300+
Ok((
301+
row.get::<_, i64>(0)?,
302+
row.get::<_, i64>(1)?,
303+
row.get::<_, i64>(2)?,
304+
row.get::<_, i64>(3)?,
305+
row.get::<_, f64>(4)?,
306+
))
307+
})?;
308+
Ok(result)
309+
}
310+
311+
pub fn get_usage_by_thread(conn: &Connection) -> anyhow::Result<Vec<(String, f64, i64)>> {
312+
let mut stmt = conn.prepare(
313+
"SELECT u.thread_id, COALESCE(SUM(u.cost_usd),0.0), COALESCE(SUM(u.input_tokens + u.output_tokens),0) FROM usage_logs u GROUP BY u.thread_id ORDER BY SUM(u.cost_usd) DESC",
314+
)?;
315+
let rows = stmt.query_map([], |row| {
316+
Ok((
317+
row.get::<_, String>(0)?,
318+
row.get::<_, f64>(1)?,
319+
row.get::<_, i64>(2)?,
320+
))
321+
})?;
322+
rows.map(|r| r.map_err(Into::into)).collect()
323+
}
324+
325+
pub fn get_usage_by_model(conn: &Connection) -> anyhow::Result<Vec<(String, f64, i64)>> {
326+
let mut stmt = conn.prepare(
327+
"SELECT COALESCE(model,'unknown'), COALESCE(SUM(cost_usd),0.0), COALESCE(SUM(input_tokens + output_tokens),0) FROM usage_logs GROUP BY model ORDER BY SUM(cost_usd) DESC",
328+
)?;
329+
let rows = stmt.query_map([], |row| {
330+
Ok((
331+
row.get::<_, String>(0)?,
332+
row.get::<_, f64>(1)?,
333+
row.get::<_, i64>(2)?,
334+
))
335+
})?;
336+
rows.map(|r| r.map_err(Into::into)).collect()
337+
}
338+
339+
pub fn get_usage_for_thread(conn: &Connection, thread_id: &str) -> anyhow::Result<(i64, i64, i64, i64, f64)> {
340+
let mut stmt = conn.prepare(
341+
"SELECT COALESCE(SUM(input_tokens),0), COALESCE(SUM(output_tokens),0), COALESCE(SUM(cache_read_tokens),0), COALESCE(SUM(cache_write_tokens),0), COALESCE(SUM(cost_usd),0.0) FROM usage_logs WHERE thread_id = ?1",
342+
)?;
343+
let result = stmt.query_row(params![thread_id], |row| {
344+
Ok((
345+
row.get::<_, i64>(0)?,
346+
row.get::<_, i64>(1)?,
347+
row.get::<_, i64>(2)?,
348+
row.get::<_, i64>(3)?,
349+
row.get::<_, f64>(4)?,
350+
))
351+
})?;
352+
Ok(result)
353+
}
354+
271355
// ---------------------------------------------------------------------------
272356
// Internal row types for mapping from SQLite text columns
273357
// ---------------------------------------------------------------------------

crates/session/src/types.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ pub enum AgentEvent {
4545
SessionReady,
4646
/// An error occurred in the session.
4747
SessionError { message: String },
48+
/// Usage/cost report for a completed turn.
49+
UsageReport {
50+
input_tokens: u64,
51+
output_tokens: u64,
52+
cache_read_tokens: u64,
53+
cache_write_tokens: u64,
54+
cost_usd: f64,
55+
model: String,
56+
},
4857
}
4958

5059
/// Metadata for an active session.

crates/tauri-app/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ edition.workspace = true
77
tauri-build = { version = "2", features = [] }
88

99
[dependencies]
10-
tauri = { version = "2", features = [] }
10+
tauri = { version = "2", features = ["unstable"] }
1111
tauri-plugin-dialog = "2"
1212
tauri-plugin-shell = "2"
1313
codeforge-session = { path = "../session" }
@@ -21,3 +21,4 @@ uuid = { workspace = true }
2121
chrono = { workspace = true }
2222
anyhow = { workspace = true }
2323
rusqlite = "0.31"
24+
url = "2"

0 commit comments

Comments
 (0)