From d32ceb9b80fa8813b2928d458c5497305f49fea4 Mon Sep 17 00:00:00 2001 From: YoVinchen Date: Sat, 15 Nov 2025 16:09:00 +0800 Subject: [PATCH] fix(prompt): correct live file backfill priority in enable flow (#225) Fix backfill logic in prompt enable workflow: - Prioritize backfilling live file content to currently enabled prompt (prevent data loss) - Create backup only when no enabled prompt exists and content is new (avoid duplicate backups) - Implement staged persistence (save after backfill + save after enable) - Add explicit logging for backfill/backup operations Also simplify string formatting in prompt_files.rs with inline format strings. --- src-tauri/src/prompt_files.rs | 7 +--- src-tauri/src/services/prompt.rs | 64 ++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src-tauri/src/prompt_files.rs b/src-tauri/src/prompt_files.rs index 49aa6af..5fe320f 100644 --- a/src-tauri/src/prompt_files.rs +++ b/src-tauri/src/prompt_files.rs @@ -34,11 +34,8 @@ fn get_base_dir_with_fallback( .ok_or_else(|| { AppError::localized( "home_dir_not_found", - format!("无法确定 {} 配置目录:用户主目录不存在", fallback_dir), - format!( - "Cannot determine {} config directory: user home not found", - fallback_dir - ), + format!("无法确定 {fallback_dir} 配置目录:用户主目录不存在"), + format!("Cannot determine {fallback_dir} config directory: user home not found"), ) }) } diff --git a/src-tauri/src/services/prompt.rs b/src-tauri/src/services/prompt.rs index 8b4f54c..42a03f1 100644 --- a/src-tauri/src/services/prompt.rs +++ b/src-tauri/src/services/prompt.rs @@ -72,27 +72,38 @@ impl PromptService { } pub fn enable_prompt(state: &AppState, app: AppType, id: &str) -> Result<(), AppError> { - // 先保存当前文件内容(如果存在且没有对应的提示词) + // 回填当前 live 文件内容到已启用的提示词,或创建备份 let target_path = prompt_file_path(&app)?; if target_path.exists() { - let mut cfg = state.config.write()?; - let prompts = match app { - AppType::Claude => &mut cfg.prompts.claude.prompts, - AppType::Codex => &mut cfg.prompts.codex.prompts, - AppType::Gemini => &mut cfg.prompts.gemini.prompts, - }; - - // 检查是否有已启用的提示词 - let has_enabled = prompts.values().any(|p| p.enabled); - - // 如果没有已启用的提示词,自动保存当前文件 - if !has_enabled { - if let Ok(content) = std::fs::read_to_string(&target_path) { - if !content.trim().is_empty() { - // 检查是否已存在相同内容的提示词,避免重复备份 - let content_exists = - prompts.values().any(|p| p.content.trim() == content.trim()); + if let Ok(live_content) = std::fs::read_to_string(&target_path) { + if !live_content.trim().is_empty() { + let mut cfg = state.config.write()?; + let prompts = match app { + AppType::Claude => &mut cfg.prompts.claude.prompts, + AppType::Codex => &mut cfg.prompts.codex.prompts, + AppType::Gemini => &mut cfg.prompts.gemini.prompts, + }; + // 尝试回填到当前已启用的提示词 + if let Some((enabled_id, enabled_prompt)) = prompts + .iter_mut() + .find(|(_, p)| p.enabled) + .map(|(id, p)| (id.clone(), p)) + { + let timestamp = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() as i64; + enabled_prompt.content = live_content.clone(); + enabled_prompt.updated_at = Some(timestamp); + log::info!("回填 live 提示词内容到已启用项: {enabled_id}"); + drop(cfg); // 释放锁后保存,避免死锁 + state.save()?; // 第一次保存:回填后立即持久化 + } else { + // 没有已启用的提示词,则创建一次备份(避免重复备份) + let content_exists = prompts + .values() + .any(|p| p.content.trim() == live_content.trim()); if !content_exists { let timestamp = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) @@ -105,21 +116,26 @@ impl PromptService { "原始提示词 {}", chrono::Local::now().format("%Y-%m-%d %H:%M") ), - content, + content: live_content, description: Some("自动备份的原始提示词".to_string()), enabled: false, created_at: Some(timestamp), updated_at: Some(timestamp), }; - prompts.insert(backup_id, backup_prompt); + prompts.insert(backup_id.clone(), backup_prompt); + log::info!("回填 live 提示词内容,创建备份: {backup_id}"); + drop(cfg); // 释放锁后保存 + state.save()?; // 第一次保存:回填后立即持久化 + } else { + // 即使内容已存在,也无需重复备份;但不需要保存任何更改 + drop(cfg); } } } } - drop(cfg); } - // 启用目标提示词 + // 启用目标提示词并写入文件 let mut cfg = state.config.write()?; let prompts = match app { AppType::Claude => &mut cfg.prompts.claude.prompts, @@ -133,13 +149,13 @@ impl PromptService { if let Some(prompt) = prompts.get_mut(id) { prompt.enabled = true; - write_text_file(&target_path, &prompt.content)?; + write_text_file(&target_path, &prompt.content)?; // 原子写入 } else { return Err(AppError::InvalidInput(format!("提示词 {id} 不存在"))); } drop(cfg); - state.save()?; + state.save()?; // 第二次保存:启用目标提示词并写入文件后 Ok(()) }