Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 55 additions & 2 deletions src-tauri/src/codex_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -898,8 +898,23 @@ fn set_codex_model_catalog_json_field(

match catalog_path {
Some(_path) => {
// 使用相对文件名而非绝对路径,保持与 Codex 自身引用方式一致
doc["model_catalog_json"] = toml_edit::value(CC_SWITCH_CODEX_MODEL_CATALOG_FILENAME);
// Only claim the pointer when it is absent or already cc-switch-owned.
// A user-managed external catalog file (custom filename or path) is
// left untouched, mirroring the None arm's ownership rule that
// `resolve_cc_switch_catalog_path` relies on.
let is_cc_switch_owned = doc
.get("model_catalog_json")
.and_then(|item| item.as_str())
.map(|path| {
Path::new(path).file_name().and_then(|name| name.to_str())
== Some(CC_SWITCH_CODEX_MODEL_CATALOG_FILENAME)
})
.unwrap_or(true);
if is_cc_switch_owned {
// 使用相对文件名而非绝对路径,保持与 Codex 自身引用方式一致
doc["model_catalog_json"] =
toml_edit::value(CC_SWITCH_CODEX_MODEL_CATALOG_FILENAME);
}
}
None => {
let should_remove = doc
Expand Down Expand Up @@ -3039,6 +3054,44 @@ name = "any"
);
}

#[test]
fn set_catalog_json_some_preserves_user_owned_catalog() {
// When cc-switch generates a catalog (Some arm), it must still respect a
// user-managed external catalog file instead of clobbering it with the
// cc-switch-owned filename. Only an absent or cc-switch-owned pointer is
// claimed; this mirrors the None arm's ownership rule.
let input = r#"model_provider = "custom"
model = "glm-5"
model_catalog_json = "/Users/me/.codex/my-custom-catalog.json"
"#;
let catalog_path = Path::new("/tmp/cc-switch-model-catalog.json");
let result = set_codex_model_catalog_json_field(input, Some(catalog_path)).unwrap();
let parsed: toml::Value = toml::from_str(&result).unwrap();
assert_eq!(
parsed.get("model_catalog_json").and_then(|v| v.as_str()),
Some("/Users/me/.codex/my-custom-catalog.json"),
"Some arm should NOT clobber a user-owned catalog (full path)"
);
}

#[test]
fn set_catalog_json_some_preserves_user_owned_relative_filename() {
// A bare custom filename (no directory component) is also user-owned
// and must be preserved by the Some arm.
let input = r#"model_provider = "custom"
model = "glm-5"
model_catalog_json = "my-custom-catalog.json"
"#;
let catalog_path = Path::new("/tmp/cc-switch-model-catalog.json");
let result = set_codex_model_catalog_json_field(input, Some(catalog_path)).unwrap();
let parsed: toml::Value = toml::from_str(&result).unwrap();
assert_eq!(
parsed.get("model_catalog_json").and_then(|v| v.as_str()),
Some("my-custom-catalog.json"),
"Some arm should NOT clobber a relative user-owned catalog"
);
}

#[test]
fn resolve_catalog_path_returns_none_when_config_missing_field() {
let generated = PathBuf::from("/tmp/.codex/cc-switch-model-catalog.json");
Expand Down