(install_dir: &Path)
| 965 | } |
| 966 | |
| 967 | fn remove_codex_plugin_install(install_dir: &Path) -> Result<()> { |
| 968 | let Ok(metadata) = std::fs::symlink_metadata(install_dir) else { |
| 969 | return Ok(()); |
| 970 | }; |
| 971 | if metadata.file_type().is_symlink() || metadata.is_file() { |
| 972 | std::fs::remove_file(install_dir).map_err(|e| TraceDecayError::Config { |
| 973 | message: format!("failed to remove {}: {e}", install_dir.display()), |
| 974 | })?; |
| 975 | return Ok(()); |
| 976 | } |
| 977 | if !metadata.is_dir() { |
| 978 | return Err(TraceDecayError::Config { |
| 979 | message: format!( |
| 980 | "refusing to replace non-directory Codex plugin path {}", |
| 981 | install_dir.display() |
| 982 | ), |
| 983 | }); |
| 984 | } |
| 985 | if !codex_plugin_dir_is_tracedecay(install_dir) { |
| 986 | return Err(TraceDecayError::Config { |
| 987 | message: format!( |
| 988 | "refusing to replace unmanaged Codex plugin directory {}", |
| 989 | install_dir.display() |
| 990 | ), |
| 991 | }); |
| 992 | } |
| 993 | remove_codex_plugin_skills_dir(install_dir)?; |
| 994 | if codex_plugin_dir_has_only_managed_files(install_dir) { |
| 995 | std::fs::remove_dir_all(install_dir).map_err(|e| TraceDecayError::Config { |
| 996 | message: format!("failed to remove {}: {e}", install_dir.display()), |
| 997 | })?; |
| 998 | } else { |
| 999 | for path in codex_plugin_managed_paths(install_dir) { |
| 1000 | std::fs::remove_file(&path).ok(); |
| 1001 | } |
| 1002 | } |
| 1003 | Ok(()) |
| 1004 | } |
| 1005 | |
| 1006 | fn codex_plugin_dir_is_tracedecay(install_dir: &Path) -> bool { |
| 1007 | let manifest = load_json_file(&install_dir.join(".codex-plugin/plugin.json")); |
no test coverage detected