mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Bound WSL local curated discovery (#26669)
## Context The installed-app suggestion expansion added in #24996 reads plugin details for trusted file-backed marketplace candidates because the list response does not include app ids. On Windows-backed WSL mounts, the local `openai-curated` checkout lives under `$CODEX_HOME/.tmp/plugins`, and those per-plugin detail reads can be very slow. Remote curated already has cached app ids, so it does not need the same local filesystem traversal. ## Summary - Keep only the WSL Windows-backed local `openai-curated` checkout on the legacy fallback/configured discovery path. - Preserve installed-app expansion for non-WSL file-backed marketplaces and remote curated. - Add focused tests for the WSL local curated path predicate. ## Test - `just test -p codex-core-plugins discoverable` - `just test -p codex-core plugins::discoverable::tests`
This commit is contained in:
committed by
GitHub
Unverified
parent
bb7d19bc24
commit
679cc08445
@@ -4,6 +4,8 @@ use codex_app_server_protocol::PluginInstallPolicy;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_plugin::PluginCapabilitySummary;
|
||||
use std::collections::HashSet;
|
||||
use std::path::Component;
|
||||
use std::path::Path;
|
||||
use tracing::warn;
|
||||
|
||||
use crate::OPENAI_BUNDLED_MARKETPLACE_NAME;
|
||||
@@ -53,6 +55,9 @@ const TOOL_SUGGEST_DISCOVERABLE_MARKETPLACE_ALLOWLIST: &[&str] = &[
|
||||
REMOTE_GLOBAL_MARKETPLACE_NAME,
|
||||
];
|
||||
|
||||
const OPENAI_CURATED_MARKETPLACE_PATH_SUFFIX: &str =
|
||||
".tmp/plugins/.agents/plugins/marketplace.json";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ToolSuggestPluginDiscoveryInput {
|
||||
pub plugins: PluginsConfigInput,
|
||||
@@ -108,6 +113,10 @@ impl PluginsManager {
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let use_legacy_local_curated_filter = should_use_legacy_local_curated_discovery_filter(
|
||||
&marketplace_name,
|
||||
marketplace.path.as_path(),
|
||||
);
|
||||
let is_allowlisted_marketplace = TOOL_SUGGEST_DISCOVERABLE_MARKETPLACE_ALLOWLIST
|
||||
.contains(&marketplace_name.as_str());
|
||||
|
||||
@@ -123,6 +132,13 @@ impl PluginsManager {
|
||||
continue;
|
||||
}
|
||||
|
||||
// On Windows-backed WSL mounts, keep local curated discovery bounded to the
|
||||
// legacy fallback/configured set instead of reading every plugin detail for app
|
||||
// ids. Remote curated has cached app ids and still expands by installed apps.
|
||||
if use_legacy_local_curated_filter && !is_configured_plugin && !is_fallback_plugin {
|
||||
continue;
|
||||
}
|
||||
|
||||
let plugin_id = plugin.id.clone();
|
||||
|
||||
match self
|
||||
@@ -216,3 +232,30 @@ impl PluginsManager {
|
||||
Ok(discoverable_plugins)
|
||||
}
|
||||
}
|
||||
|
||||
fn should_use_legacy_local_curated_discovery_filter(
|
||||
marketplace_name: &str,
|
||||
marketplace_path: &Path,
|
||||
) -> bool {
|
||||
marketplace_name == OPENAI_CURATED_MARKETPLACE_NAME
|
||||
&& is_wsl_windows_drive_path(marketplace_path)
|
||||
&& marketplace_path.ends_with(Path::new(OPENAI_CURATED_MARKETPLACE_PATH_SUFFIX))
|
||||
}
|
||||
|
||||
fn is_wsl_windows_drive_path(path: &Path) -> bool {
|
||||
let mut components = path.components();
|
||||
if components.next() != Some(Component::RootDir) {
|
||||
return false;
|
||||
}
|
||||
if components.next().and_then(|part| part.as_os_str().to_str()) != Some("mnt") {
|
||||
return false;
|
||||
}
|
||||
let Some(drive) = components.next().and_then(|part| part.as_os_str().to_str()) else {
|
||||
return false;
|
||||
};
|
||||
drive.len() == 1 && drive.as_bytes()[0].is_ascii_alphabetic()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "discoverable_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
use std::path::Path;
|
||||
|
||||
use super::is_wsl_windows_drive_path;
|
||||
use super::should_use_legacy_local_curated_discovery_filter;
|
||||
use crate::OPENAI_BUNDLED_MARKETPLACE_NAME;
|
||||
use crate::OPENAI_CURATED_MARKETPLACE_NAME;
|
||||
|
||||
#[test]
|
||||
fn legacy_local_curated_filter_matches_wsl_windows_backed_curated_checkout() {
|
||||
let marketplace_path =
|
||||
Path::new("/mnt/c/Users/user/.codex/.tmp/plugins/.agents/plugins/marketplace.json");
|
||||
|
||||
assert!(should_use_legacy_local_curated_discovery_filter(
|
||||
OPENAI_CURATED_MARKETPLACE_NAME,
|
||||
marketplace_path,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_local_curated_filter_does_not_match_native_wsl_curated_checkout() {
|
||||
let marketplace_path =
|
||||
Path::new("/home/user/.codex/.tmp/plugins/.agents/plugins/marketplace.json");
|
||||
|
||||
assert!(!should_use_legacy_local_curated_discovery_filter(
|
||||
OPENAI_CURATED_MARKETPLACE_NAME,
|
||||
marketplace_path,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_local_curated_filter_does_not_match_other_wsl_marketplaces() {
|
||||
let other_marketplace_path = Path::new(
|
||||
"/mnt/c/Users/user/.codex/.tmp/marketplaces/other/.agents/plugins/marketplace.json",
|
||||
);
|
||||
let local_curated_marketplace_path =
|
||||
Path::new("/mnt/c/Users/user/.codex/.tmp/plugins/.agents/plugins/marketplace.json");
|
||||
|
||||
assert!(!should_use_legacy_local_curated_discovery_filter(
|
||||
OPENAI_CURATED_MARKETPLACE_NAME,
|
||||
other_marketplace_path,
|
||||
));
|
||||
assert!(!should_use_legacy_local_curated_discovery_filter(
|
||||
OPENAI_BUNDLED_MARKETPLACE_NAME,
|
||||
local_curated_marketplace_path,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wsl_windows_drive_path_matches_only_mnt_drive_paths() {
|
||||
assert!(is_wsl_windows_drive_path(Path::new(
|
||||
"/mnt/c/Users/user/.codex/.tmp/plugins",
|
||||
)));
|
||||
assert!(is_wsl_windows_drive_path(Path::new("/mnt/Z/tmp")));
|
||||
assert!(!is_wsl_windows_drive_path(Path::new("/home/user/.codex")));
|
||||
assert!(!is_wsl_windows_drive_path(Path::new(
|
||||
"/mnt/codex/Users/user/.codex",
|
||||
)));
|
||||
assert!(!is_wsl_windows_drive_path(Path::new(
|
||||
"/media/c/Users/user/.codex",
|
||||
)));
|
||||
}
|
||||
Reference in New Issue
Block a user