Fix critical integration issues for end-to-end functionality

- Rewrite SidecarManager as singleton with OnceLock, reusing one Python
  process across all commands instead of spawning per call
- Separate stdin/stdout ownership with dedicated BufReader to prevent
  data corruption between wait_for_ready and send_and_receive
- Add ensure_running() for auto-start on first command
- Fix asset protocol URL: use convertFileSrc() instead of manual
  encodeURIComponent which broke file paths with slashes
- Add +layout.svelte with global dark theme, CSS reset, and custom
  scrollbar styling to prevent white flash on startup
- Register AppState with Tauri .manage(), initialize SQLite database
  on app startup at ~/.voicetonotes/voice_to_notes.db
- Wire project commands (create/get/list) to real database queries
  instead of placeholder stubs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 16:50:14 -08:00
parent d3c2954c5e
commit d00281f0c7
9 changed files with 205 additions and 134 deletions

View File

@@ -1,19 +1,7 @@
use serde_json::{json, Value};
use crate::sidecar::messages::IPCMessage;
use crate::sidecar::SidecarManager;
fn get_sidecar() -> Result<SidecarManager, String> {
let python_path = std::env::current_dir()
.map_err(|e| e.to_string())?
.join("../python")
.canonicalize()
.map_err(|e| format!("Cannot find python directory: {e}"))?;
let manager = SidecarManager::new();
manager.start(&python_path.to_string_lossy())?;
Ok(manager)
}
use crate::sidecar::sidecar;
/// Send a chat message to the AI provider via the Python sidecar.
#[tauri::command]
@@ -22,14 +10,8 @@ pub fn ai_chat(
transcript_context: Option<String>,
provider: Option<String>,
) -> Result<Value, String> {
let manager = get_sidecar()?;
let request_id = uuid::Uuid::new_v4().to_string();
let payload = json!({
"action": "chat",
"messages": messages,
"transcript_context": transcript_context.unwrap_or_default(),
});
let manager = sidecar();
manager.ensure_running()?;
// If a specific provider is requested, set it first
if let Some(p) = provider {
@@ -41,7 +23,17 @@ pub fn ai_chat(
let _ = manager.send_and_receive(&set_msg)?;
}
let msg = IPCMessage::new(&request_id, "ai.chat", payload);
let request_id = uuid::Uuid::new_v4().to_string();
let msg = IPCMessage::new(
&request_id,
"ai.chat",
json!({
"action": "chat",
"messages": messages,
"transcript_context": transcript_context.unwrap_or_default(),
}),
);
let response = manager.send_and_receive(&msg)?;
if response.msg_type == "error" {
@@ -57,7 +49,8 @@ pub fn ai_chat(
/// List available AI providers.
#[tauri::command]
pub fn ai_list_providers() -> Result<Value, String> {
let manager = get_sidecar()?;
let manager = sidecar();
manager.ensure_running()?;
let request_id = uuid::Uuid::new_v4().to_string();
let msg = IPCMessage::new(
@@ -73,7 +66,8 @@ pub fn ai_list_providers() -> Result<Value, String> {
/// Configure an AI provider with API key/settings.
#[tauri::command]
pub fn ai_configure(provider: String, config: Value) -> Result<Value, String> {
let manager = get_sidecar()?;
let manager = sidecar();
manager.ensure_running()?;
let request_id = uuid::Uuid::new_v4().to_string();
let msg = IPCMessage::new(