feat: add Codex configuration cleanup action

This commit is contained in:
lzt404 committed 2026-07-26 12:10:22 +08:00
1 parent 4e8125b94a
commit e6a4c8a755
5 files changed
+166 -2

No files matched your search

+69
View File
@@ -1653,6 +1653,18 @@ async fn reset_agent_config_to_default(
)
}
#[tauri::command]
fn clear_codex_config(app: tauri::AppHandle) -> Result<Vec<String>, String> {
let home = app
.path()
.home_dir()
.map_err(|error| format!("无法获取用户目录: {error}"))?;
let _guard = AGENT_CONFIG_FILE_LOCK
.lock()
.map_err(|_| "智能体配置文件锁已损坏".to_string())?;
clear_codex_config_files(&home)
}
#[tauri::command]
async fn set_agent_config_enabled(
app: tauri::AppHandle,
@@ -2137,6 +2149,37 @@ fn agent_config_paths(client: AgentClient, home: &Path) -> Vec<PathBuf> {
}
}
fn remove_codex_config_file(path: &Path) -> Result<bool, String> {
match fs::remove_file(path) {
Ok(()) => Ok(true),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(false),
Err(error) => Err(format!(
"删除 Codex 配置文件失败 {}: {error}",
path_to_string(path)
)),
}
}
fn clear_codex_config_files(home: &Path) -> Result<Vec<String>, String> {
let codex_dir = home.join(".codex");
let config_path = codex_dir.join("config.toml");
let targets = [codex_dir.join("auth.json"), config_path.clone()];
let mut deleted = Vec::new();
for path in targets {
if remove_codex_config_file(&path)? {
deleted.push(path_to_string(&path));
}
}
// The state file belongs to this app. Remove it after the Codex files are
// cleared so the UI does not report the deliberate deletion as an external edit.
let state_path = agent_state_path(std::slice::from_ref(&config_path))?;
remove_codex_config_file(&state_path)?;
Ok(deleted)
}
fn codex_model_catalog_path(home: &Path) -> PathBuf {
home.join(".codex").join(CODEX_MODEL_CATALOG_FILE)
}
@@ -12782,6 +12825,7 @@ fn main() {
delete_thinking_alias,
apply_agent_config,
reset_agent_config_to_default,
clear_codex_config,
set_agent_config_enabled,
update_agent_config,
launch_agent,
@@ -12993,6 +13037,31 @@ mod tests {
fs::remove_dir_all(home).unwrap();
}
#[test]
fn clear_codex_config_removes_only_requested_config_files_and_application_state() {
let home = agent_test_home("clear-codex-config");
let codex_dir = home.join(".codex");
fs::create_dir_all(&codex_dir).unwrap();
let auth_path = codex_dir.join("auth.json");
let config_path = codex_dir.join("config.toml");
let state_path = agent_state_path(std::slice::from_ref(&config_path)).unwrap();
let preserved_path = codex_dir.join("history.jsonl");
fs::write(&auth_path, "{}").unwrap();
fs::write(&config_path, "model = \"gpt-test\"\n").unwrap();
fs::write(&state_path, "{}").unwrap();
fs::write(&preserved_path, "keep").unwrap();
let deleted = clear_codex_config_files(&home).unwrap();
assert_eq!(deleted.len(), 2);
assert!(!auth_path.exists());
assert!(!config_path.exists());
assert!(!state_path.exists());
assert_eq!(fs::read_to_string(&preserved_path).unwrap(), "keep");
assert!(clear_codex_config_files(&home).unwrap().is_empty());
fs::remove_dir_all(home).unwrap();
}
#[test]
fn direct_agent_apply_rebuilds_an_unparseable_file_without_backup() {
let home = agent_test_home("invalid-apply");