diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 3596376..41e3a1b 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -42,6 +42,7 @@ arboard = "3.6.1" # stores it). Must be unconditional, not Linux-only — naming a type from # a transitive dep requires the dep be listed here too. sqlx = { version = "0.8", features = ["sqlite", "runtime-tokio"] } +uuid = { version = "1", features = ["v4"] } [target.'cfg(target_os = "linux")'.dependencies] webkit2gtk = "2.0" diff --git a/src-tauri/src/commands/tasks.rs b/src-tauri/src/commands/tasks.rs index ab9d659..baf3bd4 100644 --- a/src-tauri/src/commands/tasks.rs +++ b/src-tauri/src/commands/tasks.rs @@ -4,10 +4,16 @@ use serde::{Deserialize, Serialize}; +use uuid::Uuid; + use kon_storage::{ + complete_subtask_and_check_parent as db_complete_subtask, complete_task as db_complete_task, delete_task as db_delete_task, + get_task_by_id as db_get_task, + insert_subtask as db_insert_subtask, insert_task as db_insert_task, + list_subtasks as db_list_subtasks, list_tasks as db_list_tasks, TaskRow, }; @@ -115,3 +121,50 @@ pub async fn uncomplete_task_cmd( .map(|_| ()) } +#[tauri::command] +pub async fn decompose_and_store( + state: tauri::State<'_, AppState>, + parent_task_id: String, +) -> Result, String> { + let parent = db_get_task(&state.db, &parent_task_id) + .await + .map_err(|e| e.to_string())? + .ok_or_else(|| format!("Task {parent_task_id} not found"))?; + + let steps = state.llm_engine.decompose_task(&parent.text)?; + + let mut created = Vec::new(); + for text in steps { + let id = Uuid::new_v4().to_string(); + db_insert_subtask(&state.db, &id, &text, &parent_task_id) + .await + .map_err(|e| e.to_string())?; + if let Some(row) = db_get_task(&state.db, &id).await.map_err(|e| e.to_string())? { + created.push(TaskDto::from(row)); + } + } + + Ok(created) +} + +#[tauri::command] +pub async fn list_subtasks_cmd( + state: tauri::State<'_, AppState>, + parent_task_id: String, +) -> Result, String> { + db_list_subtasks(&state.db, &parent_task_id) + .await + .map(|rows| rows.into_iter().map(TaskDto::from).collect()) + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn complete_subtask_cmd( + state: tauri::State<'_, AppState>, + subtask_id: String, +) -> Result<(), String> { + db_complete_subtask(&state.db, &subtask_id) + .await + .map_err(|e| e.to_string()) +} + diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 7f187d5..e92b319 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -8,6 +8,7 @@ use sqlx::SqlitePool; use tauri::Manager; use kon_core::types::EngineName; +use kon_llm::LlmEngine; use kon_storage::{database_path, get_setting, init as init_db, set_setting}; use kon_transcription::LocalEngine; @@ -16,6 +17,7 @@ pub struct AppState { pub whisper_engine: Arc, pub parakeet_engine: Arc, pub db: SqlitePool, + pub llm_engine: Arc, } /// Holds the preferences init script for injection into secondary windows. @@ -214,6 +216,7 @@ pub fn run() { EngineName::new("parakeet"), )), db, + llm_engine: Arc::new(LlmEngine::new()), }); { @@ -258,6 +261,9 @@ pub fn run() { commands::tasks::complete_task_cmd, commands::tasks::delete_task_cmd, commands::tasks::uncomplete_task_cmd, + commands::tasks::decompose_and_store, + commands::tasks::list_subtasks_cmd, + commands::tasks::complete_subtask_cmd, // Transcripts (canonical SQLite-backed history) — Day 4 commands::transcripts::add_transcript, commands::transcripts::list_transcripts,