Implement auto-launch functionality with proper state synchronization and error handling across Windows, macOS, and Linux platforms. Key changes: - Add auto_launch module using auto-launch crate 0.5 - Define typed errors (AutoLaunchPathError, AutoLaunchEnableError, etc.) - Sync system state with settings.json on app startup - Only call system API when auto-launch state actually changes - Add UI toggle in Window Settings panel - Add i18n support for auto-launch settings (en/zh) Implementation details: - Settings file (settings.json) is the single source of truth - On startup, system state is synced to match settings.json - Error handling uses Rust type system with proper error propagation - Frontend optimized to avoid unnecessary system API calls Platform support: - Windows: HKEY_CURRENT_USER registry modification - macOS: AppleScript-based launch item (configurable to Launch Agent) - Linux: XDG autostart desktop file
130 lines
3.2 KiB
Rust
130 lines
3.2 KiB
Rust
use std::path::Path;
|
|
use std::sync::PoisonError;
|
|
|
|
use thiserror::Error;
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum AppError {
|
|
#[error("配置错误: {0}")]
|
|
Config(String),
|
|
#[error("无效输入: {0}")]
|
|
InvalidInput(String),
|
|
#[error("IO 错误: {path}: {source}")]
|
|
Io {
|
|
path: String,
|
|
#[source]
|
|
source: std::io::Error,
|
|
},
|
|
#[error("{context}: {source}")]
|
|
IoContext {
|
|
context: String,
|
|
#[source]
|
|
source: std::io::Error,
|
|
},
|
|
#[error("JSON 解析错误: {path}: {source}")]
|
|
Json {
|
|
path: String,
|
|
#[source]
|
|
source: serde_json::Error,
|
|
},
|
|
#[error("JSON 序列化失败: {source}")]
|
|
JsonSerialize {
|
|
#[source]
|
|
source: serde_json::Error,
|
|
},
|
|
#[error("TOML 解析错误: {path}: {source}")]
|
|
Toml {
|
|
path: String,
|
|
#[source]
|
|
source: toml::de::Error,
|
|
},
|
|
#[error("锁获取失败: {0}")]
|
|
Lock(String),
|
|
#[error("MCP 校验失败: {0}")]
|
|
McpValidation(String),
|
|
#[error("{0}")]
|
|
Message(String),
|
|
#[error("{zh} ({en})")]
|
|
Localized {
|
|
key: &'static str,
|
|
zh: String,
|
|
en: String,
|
|
},
|
|
#[error("Failed to get application path for auto-launch: {0}")]
|
|
AutoLaunchPathError(#[source] std::io::Error),
|
|
#[error("Failed to enable auto-launch: {0}")]
|
|
AutoLaunchEnableError(String),
|
|
#[error("Failed to disable auto-launch: {0}")]
|
|
AutoLaunchDisableError(String),
|
|
#[error("Failed to check auto-launch status: {0}")]
|
|
AutoLaunchCheckError(String),
|
|
}
|
|
|
|
impl AppError {
|
|
pub fn io(path: impl AsRef<Path>, source: std::io::Error) -> Self {
|
|
Self::Io {
|
|
path: path.as_ref().display().to_string(),
|
|
source,
|
|
}
|
|
}
|
|
|
|
pub fn json(path: impl AsRef<Path>, source: serde_json::Error) -> Self {
|
|
Self::Json {
|
|
path: path.as_ref().display().to_string(),
|
|
source,
|
|
}
|
|
}
|
|
|
|
pub fn toml(path: impl AsRef<Path>, source: toml::de::Error) -> Self {
|
|
Self::Toml {
|
|
path: path.as_ref().display().to_string(),
|
|
source,
|
|
}
|
|
}
|
|
|
|
pub fn localized(key: &'static str, zh: impl Into<String>, en: impl Into<String>) -> Self {
|
|
Self::Localized {
|
|
key,
|
|
zh: zh.into(),
|
|
en: en.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> From<PoisonError<T>> for AppError {
|
|
fn from(err: PoisonError<T>) -> Self {
|
|
Self::Lock(err.to_string())
|
|
}
|
|
}
|
|
|
|
impl From<AppError> for String {
|
|
fn from(err: AppError) -> Self {
|
|
err.to_string()
|
|
}
|
|
}
|
|
|
|
/// 格式化为 JSON 错误字符串,前端可解析为结构化错误
|
|
pub fn format_skill_error(
|
|
code: &str,
|
|
context: &[(&str, &str)],
|
|
suggestion: Option<&str>,
|
|
) -> String {
|
|
use serde_json::json;
|
|
|
|
let mut ctx_map = serde_json::Map::new();
|
|
for (key, value) in context {
|
|
ctx_map.insert(key.to_string(), json!(value));
|
|
}
|
|
|
|
let error_obj = json!({
|
|
"code": code,
|
|
"context": ctx_map,
|
|
"suggestion": suggestion,
|
|
});
|
|
|
|
serde_json::to_string(&error_obj).unwrap_or_else(|_| {
|
|
// 如果 JSON 序列化失败,返回简单格式
|
|
format!("ERROR:{}", code)
|
|
})
|
|
}
|