generated from nhcarrigan/template
172 lines
5.0 KiB
Rust
172 lines
5.0 KiB
Rust
use tauri::{AppHandle, State};
|
|
use tauri_plugin_store::StoreExt;
|
|
|
|
use crate::config::{ClaudeStartOptions, HikariConfig};
|
|
use crate::stats::UsageStats;
|
|
use crate::bridge_manager::SharedBridgeManager;
|
|
use crate::achievements::{load_achievements, get_achievement_info, AchievementUnlockedEvent};
|
|
|
|
const CONFIG_STORE_KEY: &str = "config";
|
|
|
|
#[tauri::command]
|
|
pub async fn start_claude(
|
|
bridge_manager: State<'_, SharedBridgeManager>,
|
|
conversation_id: String,
|
|
options: ClaudeStartOptions,
|
|
) -> Result<(), String> {
|
|
let mut manager = bridge_manager.lock();
|
|
manager.start_claude(&conversation_id, options)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn stop_claude(
|
|
bridge_manager: State<'_, SharedBridgeManager>,
|
|
conversation_id: String,
|
|
) -> Result<(), String> {
|
|
let mut manager = bridge_manager.lock();
|
|
manager.stop_claude(&conversation_id)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn interrupt_claude(
|
|
bridge_manager: State<'_, SharedBridgeManager>,
|
|
conversation_id: String,
|
|
) -> Result<(), String> {
|
|
let mut manager = bridge_manager.lock();
|
|
manager.interrupt_claude(&conversation_id)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn send_prompt(
|
|
bridge_manager: State<'_, SharedBridgeManager>,
|
|
conversation_id: String,
|
|
message: String,
|
|
) -> Result<(), String> {
|
|
let mut manager = bridge_manager.lock();
|
|
manager.send_prompt(&conversation_id, message)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn is_claude_running(
|
|
bridge_manager: State<'_, SharedBridgeManager>,
|
|
conversation_id: String,
|
|
) -> Result<bool, String> {
|
|
let manager = bridge_manager.lock();
|
|
Ok(manager.is_claude_running(&conversation_id))
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn get_working_directory(
|
|
bridge_manager: State<'_, SharedBridgeManager>,
|
|
conversation_id: String,
|
|
) -> Result<String, String> {
|
|
let manager = bridge_manager.lock();
|
|
manager.get_working_directory(&conversation_id)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn select_wsl_directory() -> Result<String, String> {
|
|
Ok("/home".to_string())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn get_config(app: AppHandle) -> Result<HikariConfig, String> {
|
|
let store = app
|
|
.store("hikari-config.json")
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
match store.get(CONFIG_STORE_KEY) {
|
|
Some(value) => {
|
|
serde_json::from_value(value.clone()).map_err(|e| e.to_string())
|
|
}
|
|
None => Ok(HikariConfig::default()),
|
|
}
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn save_config(app: AppHandle, config: HikariConfig) -> Result<(), String> {
|
|
let store = app
|
|
.store("hikari-config.json")
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
let value = serde_json::to_value(&config).map_err(|e| e.to_string())?;
|
|
store.set(CONFIG_STORE_KEY, value);
|
|
store.save().map_err(|e| e.to_string())?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn get_usage_stats(
|
|
bridge_manager: State<'_, SharedBridgeManager>,
|
|
conversation_id: String,
|
|
) -> Result<UsageStats, String> {
|
|
let manager = bridge_manager.lock();
|
|
manager.get_usage_stats(&conversation_id)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn validate_directory(path: String, current_dir: Option<String>) -> Result<String, String> {
|
|
use std::path::Path;
|
|
|
|
let path = Path::new(&path);
|
|
|
|
// Expand ~ to home directory
|
|
let expanded_path = if path.starts_with("~") {
|
|
if let Some(home) = std::env::var_os("HOME") {
|
|
let home_path = Path::new(&home);
|
|
if path == Path::new("~") {
|
|
home_path.to_path_buf()
|
|
} else {
|
|
home_path.join(path.strip_prefix("~").unwrap())
|
|
}
|
|
} else {
|
|
return Err("Could not determine home directory".to_string());
|
|
}
|
|
} else if path.is_relative() {
|
|
// Handle relative paths (., .., or any relative path) by resolving against current_dir
|
|
if let Some(ref cwd) = current_dir {
|
|
Path::new(cwd).join(path)
|
|
} else {
|
|
path.to_path_buf()
|
|
}
|
|
} else {
|
|
path.to_path_buf()
|
|
};
|
|
|
|
// Check if the path exists and is a directory
|
|
if !expanded_path.exists() {
|
|
return Err(format!("Directory does not exist: {}", expanded_path.display()));
|
|
}
|
|
|
|
if !expanded_path.is_dir() {
|
|
return Err(format!("Path is not a directory: {}", expanded_path.display()));
|
|
}
|
|
|
|
// Return the canonicalized (absolute) path
|
|
expanded_path
|
|
.canonicalize()
|
|
.map(|p| p.to_string_lossy().to_string())
|
|
.map_err(|e| format!("Failed to resolve path: {}", e))
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn load_saved_achievements(app: AppHandle) -> Result<Vec<AchievementUnlockedEvent>, String> {
|
|
use chrono::Utc;
|
|
|
|
// Load achievements from persistent store
|
|
let progress = load_achievements(&app).await;
|
|
|
|
// Create events for all previously unlocked achievements
|
|
let mut events = Vec::new();
|
|
for achievement_id in &progress.unlocked {
|
|
let mut info = get_achievement_info(achievement_id);
|
|
info.unlocked_at = Some(Utc::now()); // We don't store timestamps, so just use now
|
|
events.push(AchievementUnlockedEvent {
|
|
achievement: info,
|
|
});
|
|
}
|
|
|
|
Ok(events)
|
|
}
|