From b15d4d1e61d8bc3f7b4e03dcb51f8efd54fdb749 Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Tue, 11 Aug 2026 02:21:04 +0800 Subject: [PATCH 1/3] Refactor macOS Dock visibility control to use AppHandle API and clean up related helpers Closes: #110 --- src-tauri/src/app_update.rs | 7 ++++--- src-tauri/src/core_config/yaml.rs | 5 +++-- src-tauri/src/core_runtime.rs | 4 +--- src-tauri/src/main.rs | 8 +++----- src-tauri/src/tray.rs | 23 +++++------------------ 5 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src-tauri/src/app_update.rs b/src-tauri/src/app_update.rs index 09726e1..2d8cc0d 100644 --- a/src-tauri/src/app_update.rs +++ b/src-tauri/src/app_update.rs @@ -712,14 +712,15 @@ pub(crate) async fn download_and_stage_portable_app_update( let helper_path = work_dir.join("EasyCLIProxyAPI-updater"); fs::copy(¤t_exe, &helper_path) .map_err(|error| format!("准备应用更新助手失败: {error}"))?; - let app_parent = current_app + let backup_app = current_app .parent() - .ok_or_else(|| "macOS 应用程序路径没有父目录".to_string())?; + .ok_or_else(|| "macOS 应用程序路径没有父目录".to_string())? + .join(".EasyCLIProxyAPI.app.update-backup"); let descriptor = MacosUpdateDescriptor { parent_pid: std::process::id(), current_app, staged_app, - backup_app: app_parent.join(".EasyCLIProxyAPI.app.update-backup"), + backup_app, executable_relative_path, ack_path: work_dir.join("update-started.ack"), work_dir: work_dir.clone(), diff --git a/src-tauri/src/core_config/yaml.rs b/src-tauri/src/core_config/yaml.rs index b1a1724..9f0974f 100644 --- a/src-tauri/src/core_config/yaml.rs +++ b/src-tauri/src/core_config/yaml.rs @@ -216,6 +216,8 @@ pub(crate) struct YamlValueChange { value: serde_norway::Value, } +type MissingNestedYamlGroup = (Vec, Vec<(String, serde_norway::Value)>); + pub(crate) fn render_yaml_value_changes( content: &str, original: &serde_norway::Value, @@ -243,8 +245,7 @@ pub(crate) fn render_yaml_value_changes( remaining_changes.push(change); } } - let mut missing_nested_groups: Vec<(Vec, Vec<(String, serde_norway::Value)>)> = - Vec::new(); + let mut missing_nested_groups: Vec = Vec::new(); let mut yaml_edit_changes = Vec::new(); for change in remaining_changes { if change.path.len() < 2 diff --git a/src-tauri/src/core_runtime.rs b/src-tauri/src/core_runtime.rs index ec345c6..803005a 100644 --- a/src-tauri/src/core_runtime.rs +++ b/src-tauri/src/core_runtime.rs @@ -1829,9 +1829,7 @@ pub(crate) fn configure_initial_main_window( .ok_or_else(|| "主窗口不存在".to_string())?; #[cfg(target_os = "macos")] - if !set_macos_dock_visible(!start_hidden) { - return Err("更新 Dock 图标状态失败".to_string()); - } + set_macos_dock_visible(app_handle, !start_hidden); if start_hidden { return window diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index b815395..89e277f 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -33,7 +33,7 @@ use futures_util::StreamExt; #[cfg(target_os = "macos")] use objc2::MainThreadMarker; #[cfg(target_os = "macos")] -use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy, NSEvent}; +use objc2_app_kit::NSEvent; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; #[cfg(target_os = "windows")] @@ -1697,12 +1697,10 @@ fn main() { if window.label() == "main" { if let tauri::WindowEvent::CloseRequested { api, .. } = event { api.prevent_close(); - if !set_macos_dock_visible(false) { - return; - } + set_macos_dock_visible(window.app_handle(), false); if let Err(error) = window.hide() { eprintln!("隐藏主窗口失败: {error}"); - set_macos_dock_visible(true); + set_macos_dock_visible(window.app_handle(), true); } } } diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs index 5714b3a..edaf68c 100644 --- a/src-tauri/src/tray.rs +++ b/src-tauri/src/tray.rs @@ -11,21 +11,10 @@ pub(crate) struct MacosTrayClickState { } #[cfg(target_os = "macos")] -pub(crate) fn set_macos_dock_visible(visible: bool) -> bool { - let Some(mtm) = MainThreadMarker::new() else { - eprintln!("更新 Dock 图标状态必须在主线程执行"); - return false; - }; - let policy = if visible { - NSApplicationActivationPolicy::Regular - } else { - NSApplicationActivationPolicy::Accessory - }; - if !NSApplication::sharedApplication(mtm).setActivationPolicy(policy) { - eprintln!("更新 Dock 图标状态失败"); - return false; +pub(crate) fn set_macos_dock_visible(app_handle: &tauri::AppHandle, visible: bool) { + if let Err(error) = app_handle.set_dock_visibility(visible) { + eprintln!("更新 Dock 图标状态失败: {error}"); } - true } #[cfg(target_os = "macos")] @@ -33,12 +22,10 @@ pub(crate) fn show_main_window_on_main_thread(app_handle: &tauri::AppHandle) { let Some(window) = app_handle.get_webview_window("main") else { return; }; - if !set_macos_dock_visible(true) { - return; - } + set_macos_dock_visible(app_handle, true); if let Err(error) = window.show() { eprintln!("显示主窗口失败: {error}"); - set_macos_dock_visible(false); + set_macos_dock_visible(app_handle, false); return; } if window.is_minimized().unwrap_or(false) { From 3fbfb81f22476fabd318c0e7157aeadafab7f3b3 Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Tue, 11 Aug 2026 02:29:49 +0800 Subject: [PATCH 2/3] Refactor Claude agent discovery and test formatting cleanup --- src-tauri/src/agents/discovery.rs | 15 ++++----------- src-tauri/src/tests/agent_configuration.rs | 6 ++---- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src-tauri/src/agents/discovery.rs b/src-tauri/src/agents/discovery.rs index 6b2923e..3918184 100644 --- a/src-tauri/src/agents/discovery.rs +++ b/src-tauri/src/agents/discovery.rs @@ -1743,7 +1743,8 @@ pub(crate) fn inspect_claude_code_model_mappings( .map(str::trim) .filter(|value| !value.is_empty()); let read_model = |key: &str| { - let value = env.get(key) + let value = env + .get(key) .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) @@ -1893,10 +1894,7 @@ pub(crate) fn claude_code_model_effort_level( claude_catalog::claude_code_effort_level_for(agent_model_source_name(models, model_name)) } -pub(crate) fn claude_code_model_setting( - model_name: &str, - enable_1m_variant: bool, -) -> String { +pub(crate) fn claude_code_model_setting(model_name: &str, enable_1m_variant: bool) -> String { let model_name = strip_claude_code_context_suffix(model_name); if enable_1m_variant { format!("{model_name}[1m]") @@ -1974,12 +1972,7 @@ pub(crate) fn claude_code_model_presentation_environment( mappings.sonnet_1m, Some("Fable mapping"), ); - let custom = claude_code_model_presentation( - models, - &mappings.sonnet, - mappings.sonnet_1m, - None, - ); + let custom = claude_code_model_presentation(models, &mappings.sonnet, mappings.sonnet_1m, None); let custom_model = claude_code_model_setting(&mappings.sonnet, mappings.sonnet_1m); Ok([ ("ANTHROPIC_DEFAULT_OPUS_MODEL_NAME", opus.0), diff --git a/src-tauri/src/tests/agent_configuration.rs b/src-tauri/src/tests/agent_configuration.rs index 659187b..fb5d7bc 100644 --- a/src-tauri/src/tests/agent_configuration.rs +++ b/src-tauri/src/tests/agent_configuration.rs @@ -67,10 +67,8 @@ fn claude_code_inspection_normalizes_1m_suffix() { #[test] fn claude_mapping_legacy_json_defaults_1m_preferences_off() { - let mappings: ClaudeDesktopModelMappings = serde_json::from_str( - r#"{"opus":"model-a","sonnet":"model-b","haiku":"model-c"}"#, - ) - .unwrap(); + let mappings: ClaudeDesktopModelMappings = + serde_json::from_str(r#"{"opus":"model-a","sonnet":"model-b","haiku":"model-c"}"#).unwrap(); assert!(!mappings.opus_1m); assert!(!mappings.sonnet_1m); From 7a95f3c9948fa9b982e680277f2af9012fd979a3 Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Tue, 11 Aug 2026 02:37:47 +0800 Subject: [PATCH 3/3] Conditionally compile tray module and imports for macOS and Windows targets --- src-tauri/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 89e277f..1e6d66e 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -11,6 +11,7 @@ mod core_config; mod core_runtime; mod management_api; mod provider_health; +#[cfg(any(target_os = "macos", target_os = "windows"))] mod tray; mod usage; @@ -66,6 +67,7 @@ use tauri::{Emitter, LogicalSize, Manager}; use tauri_plugin_autostart::ManagerExt as AutostartManagerExt; use tauri_plugin_opener::OpenerExt; use tokio_util::sync::CancellationToken; +#[cfg(any(target_os = "macos", target_os = "windows"))] use tray::*; use zip::ZipArchive;