mirror of
https://github.com/openai/codex.git
synced 2026-11-05 08:28:29 +00:00
[codex] Enable remote plugins by default (#30297)
## Summary - enable the remote plugin feature by default - promote the remote plugin feature from under development to stable - preserve the existing `features.remote_plugin` override for explicitly disabling it - keep legacy disabled-path coverage explicit in TUI and app-server tests ## Impact Remote plugin functionality is enabled by default for configurations that do not set the feature flag. The existing Codex backend authentication gate still applies. ## Validation - `just fmt` - `just test -p codex-features` - `just test -p codex-tui plugins_popup_remote_section_fallback_states_snapshot` - targeted `codex-app-server` plugin-list and skills-list tests - `git diff --check` The full TUI and app-server suites were also exercised locally. All remote-plugin-related coverage passed; unrelated local sandbox/test-binary failures remain outside this change.
This commit is contained in:
1 parent
bdd282f3bb
commit
e428a12d22
15 files changed
+62
-69
No files matched your search
@@ -124,7 +124,6 @@ pub(super) fn run_cleanup(
|
|||||||
overrides.extend([
|
overrides.extend([
|
||||||
"analytics.enabled=false".to_string(),
|
"analytics.enabled=false".to_string(),
|
||||||
"features.plugins=true".to_string(),
|
"features.plugins=true".to_string(),
|
||||||
"features.remote_plugin=true".to_string(),
|
|
||||||
]);
|
]);
|
||||||
let mut client = CodexClient::spawn_stdio(codex_bin, &overrides)?;
|
let mut client = CodexClient::spawn_stdio(codex_bin, &overrides)?;
|
||||||
client.initialize()?;
|
client.initialize()?;
|
||||||
@@ -199,7 +198,6 @@ fn spawn_client(
|
|||||||
overrides.extend([
|
overrides.extend([
|
||||||
"analytics.enabled=true".to_string(),
|
"analytics.enabled=true".to_string(),
|
||||||
"features.plugins=true".to_string(),
|
"features.plugins=true".to_string(),
|
||||||
"features.remote_plugin=true".to_string(),
|
|
||||||
]);
|
]);
|
||||||
let environment = vec![(
|
let environment = vec![(
|
||||||
OsString::from(ANALYTICS_CAPTURE_ENV_VAR),
|
OsString::from(ANALYTICS_CAPTURE_ENV_VAR),
|
||||||
|
|||||||
@@ -263,7 +263,6 @@ fn smoke_config_overrides(responses_base_url: &str) -> Result<Vec<String>> {
|
|||||||
Ok(vec![
|
Ok(vec![
|
||||||
"analytics.enabled=true".to_string(),
|
"analytics.enabled=true".to_string(),
|
||||||
"features.plugins=true".to_string(),
|
"features.plugins=true".to_string(),
|
||||||
"features.remote_plugin=true".to_string(),
|
|
||||||
format!("model={}", quoted(MOCK_MODEL_SLUG)?),
|
format!("model={}", quoted(MOCK_MODEL_SLUG)?),
|
||||||
format!("model_provider={}", quoted(MOCK_PROVIDER_ID)?),
|
format!("model_provider={}", quoted(MOCK_PROVIDER_ID)?),
|
||||||
format!(
|
format!(
|
||||||
|
|||||||
@@ -2027,7 +2027,6 @@ chatgpt_base_url = "{base_url}"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -2057,7 +2056,6 @@ chatgpt_base_url = "{}/backend-api/"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
connectors = true
|
connectors = true
|
||||||
"#,
|
"#,
|
||||||
server.uri()
|
server.uri()
|
||||||
|
|||||||
@@ -71,6 +71,23 @@ plugins = true
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_remote_plugins_disabled_config_with_base_url(
|
||||||
|
codex_home: &std::path::Path,
|
||||||
|
base_url: &str,
|
||||||
|
) -> std::io::Result<()> {
|
||||||
|
std::fs::write(
|
||||||
|
codex_home.join("config.toml"),
|
||||||
|
format!(
|
||||||
|
r#"chatgpt_base_url = "{base_url}"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
plugins = true
|
||||||
|
remote_plugin = false
|
||||||
|
"#,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn plugin_list_skips_invalid_marketplace_file_and_reports_error() -> Result<()> {
|
async fn plugin_list_skips_invalid_marketplace_file_and_reports_error() -> Result<()> {
|
||||||
let codex_home = TempDir::new()?;
|
let codex_home = TempDir::new()?;
|
||||||
@@ -197,7 +214,6 @@ async fn plugin_installed_prefers_remote_curated_conflicts_when_remote_plugin_en
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
plugin_sharing = false
|
plugin_sharing = false
|
||||||
|
|
||||||
[plugins."linear@openai-curated"]
|
[plugins."linear@openai-curated"]
|
||||||
@@ -1987,10 +2003,11 @@ async fn plugin_list_uses_cached_global_remote_catalog_and_refreshes_it() -> Res
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn plugin_list_includes_openai_curated_remote_collection_when_requested() -> Result<()> {
|
async fn plugin_list_includes_openai_curated_remote_collection_when_remote_plugin_disabled_and_requested()
|
||||||
|
-> Result<()> {
|
||||||
let codex_home = TempDir::new()?;
|
let codex_home = TempDir::new()?;
|
||||||
let server = MockServer::start().await;
|
let server = MockServer::start().await;
|
||||||
write_plugins_enabled_config_with_base_url(
|
write_remote_plugins_disabled_config_with_base_url(
|
||||||
codex_home.path(),
|
codex_home.path(),
|
||||||
&format!("{}/backend-api/", server.uri()),
|
&format!("{}/backend-api/", server.uri()),
|
||||||
)?;
|
)?;
|
||||||
@@ -2092,10 +2109,11 @@ async fn plugin_list_includes_openai_curated_remote_collection_when_requested()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn plugin_list_propagates_explicit_openai_curated_remote_collection_errors() -> Result<()> {
|
async fn plugin_list_propagates_openai_curated_remote_collection_errors_when_remote_plugin_disabled()
|
||||||
|
-> Result<()> {
|
||||||
let codex_home = TempDir::new()?;
|
let codex_home = TempDir::new()?;
|
||||||
let server = MockServer::start().await;
|
let server = MockServer::start().await;
|
||||||
write_plugins_enabled_config_with_base_url(
|
write_remote_plugins_disabled_config_with_base_url(
|
||||||
codex_home.path(),
|
codex_home.path(),
|
||||||
&format!("{}/backend-api/", server.uri()),
|
&format!("{}/backend-api/", server.uri()),
|
||||||
)?;
|
)?;
|
||||||
@@ -2148,10 +2166,11 @@ async fn plugin_list_propagates_explicit_openai_curated_remote_collection_errors
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn plugin_list_skips_explicit_openai_curated_remote_collection_for_api_auth() -> Result<()> {
|
async fn plugin_list_skips_openai_curated_remote_collection_for_api_auth_when_remote_plugin_disabled()
|
||||||
|
-> Result<()> {
|
||||||
let codex_home = TempDir::new()?;
|
let codex_home = TempDir::new()?;
|
||||||
let server = MockServer::start().await;
|
let server = MockServer::start().await;
|
||||||
write_plugins_enabled_config_with_base_url(
|
write_remote_plugins_disabled_config_with_base_url(
|
||||||
codex_home.path(),
|
codex_home.path(),
|
||||||
&format!("{}/backend-api/", server.uri()),
|
&format!("{}/backend-api/", server.uri()),
|
||||||
)?;
|
)?;
|
||||||
@@ -2391,7 +2410,8 @@ async fn plugin_list_does_not_append_global_remote_when_marketplace_kinds_are_ex
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn plugin_installed_includes_remote_shared_with_me_plugins() -> Result<()> {
|
async fn plugin_installed_includes_remote_shared_with_me_plugins_when_remote_plugin_disabled()
|
||||||
|
-> Result<()> {
|
||||||
let codex_home = TempDir::new()?;
|
let codex_home = TempDir::new()?;
|
||||||
let server = MockServer::start().await;
|
let server = MockServer::start().await;
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
@@ -2493,7 +2513,8 @@ plugin_sharing = true
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn plugin_installed_includes_workspace_directory_without_plugin_sharing() -> Result<()> {
|
async fn plugin_installed_includes_workspace_directory_without_plugin_sharing_when_remote_plugin_disabled()
|
||||||
|
-> Result<()> {
|
||||||
let codex_home = TempDir::new()?;
|
let codex_home = TempDir::new()?;
|
||||||
let server = MockServer::start().await;
|
let server = MockServer::start().await;
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
@@ -2590,7 +2611,6 @@ async fn plugin_installed_includes_created_by_me_when_remote_plugins_enabled() -
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
plugin_sharing = false
|
plugin_sharing = false
|
||||||
"#,
|
"#,
|
||||||
server.uri()
|
server.uri()
|
||||||
@@ -2681,7 +2701,6 @@ async fn plugin_installed_starts_remote_installed_bundle_sync() -> Result<()> {
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
plugin_sharing = false
|
plugin_sharing = false
|
||||||
"#,
|
"#,
|
||||||
server.uri()
|
server.uri()
|
||||||
@@ -2750,10 +2769,10 @@ plugin_sharing = false
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn plugin_list_fetches_workspace_directory_kind_without_remote_plugin_flag() -> Result<()> {
|
async fn plugin_list_fetches_workspace_directory_kind_when_remote_plugin_disabled() -> Result<()> {
|
||||||
let codex_home = TempDir::new()?;
|
let codex_home = TempDir::new()?;
|
||||||
let server = MockServer::start().await;
|
let server = MockServer::start().await;
|
||||||
write_plugins_enabled_config_with_base_url(
|
write_remote_plugins_disabled_config_with_base_url(
|
||||||
codex_home.path(),
|
codex_home.path(),
|
||||||
&format!("{}/backend-api/", server.uri()),
|
&format!("{}/backend-api/", server.uri()),
|
||||||
)?;
|
)?;
|
||||||
@@ -2848,7 +2867,6 @@ async fn plugin_list_fetches_user_plugins_in_created_by_me_remote_marketplace()
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
plugin_sharing = false
|
plugin_sharing = false
|
||||||
"#,
|
"#,
|
||||||
server.uri()
|
server.uri()
|
||||||
@@ -4032,7 +4050,6 @@ chatgpt_base_url = "{base_url}"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2132,7 +2132,6 @@ chatgpt_base_url = "{base_url}"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -344,7 +344,6 @@ chatgpt_base_url = "{}/backend-api"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
plugin_sharing = false
|
plugin_sharing = false
|
||||||
"#,
|
"#,
|
||||||
server.uri()
|
server.uri()
|
||||||
@@ -1050,7 +1049,6 @@ chatgpt_base_url = "{}/backend-api"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
plugin_sharing = false
|
plugin_sharing = false
|
||||||
"#,
|
"#,
|
||||||
server.uri()
|
server.uri()
|
||||||
@@ -1204,7 +1202,6 @@ chatgpt_base_url = "{base_url}"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -622,7 +622,6 @@ chatgpt_base_url = "{base_url}"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -68,9 +68,7 @@ async fn first_turn_after_external_login_waits_for_recommended_plugins() -> Resu
|
|||||||
let config = std::fs::read_to_string(&config_path)?;
|
let config = std::fs::read_to_string(&config_path)?;
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
config_path,
|
config_path,
|
||||||
format!(
|
format!("{config}\n[features]\napps = true\nplugins = true\ntool_suggest = true\n"),
|
||||||
"{config}\n[features]\napps = true\nplugins = true\nremote_plugin = true\ntool_suggest = true\n"
|
|
||||||
),
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let sqlite_home = codex_home.path().to_string_lossy();
|
let sqlite_home = codex_home.path().to_string_lossy();
|
||||||
|
|||||||
@@ -79,23 +79,6 @@ plugins = true
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_remote_plugins_enabled_config_with_base_url(
|
|
||||||
codex_home: &std::path::Path,
|
|
||||||
base_url: &str,
|
|
||||||
) -> std::io::Result<()> {
|
|
||||||
std::fs::write(
|
|
||||||
codex_home.join("config.toml"),
|
|
||||||
format!(
|
|
||||||
r#"chatgpt_base_url = "{base_url}"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
plugins = true
|
|
||||||
remote_plugin = true
|
|
||||||
"#,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_plugin_with_skill(
|
fn write_plugin_with_skill(
|
||||||
repo_root: &std::path::Path,
|
repo_root: &std::path::Path,
|
||||||
plugin_name: &str,
|
plugin_name: &str,
|
||||||
@@ -175,7 +158,7 @@ fn write_cached_local_curated_plugin_with_skill(codex_home: &std::path::Path) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn runtime_remote_plugin_enablement_excludes_local_curated_plugin_skills() -> Result<()> {
|
async fn runtime_remote_plugin_toggle_updates_local_curated_plugin_skills() -> Result<()> {
|
||||||
let codex_home = TempDir::new()?;
|
let codex_home = TempDir::new()?;
|
||||||
let cwd = TempDir::new()?;
|
let cwd = TempDir::new()?;
|
||||||
let server = MockServer::start().await;
|
let server = MockServer::start().await;
|
||||||
@@ -206,6 +189,18 @@ enabled = true
|
|||||||
let mut mcp = TestAppServer::new(codex_home.path()).await?;
|
let mut mcp = TestAppServer::new(codex_home.path()).await?;
|
||||||
timeout(DEFAULT_TIMEOUT, mcp.initialize()).await??;
|
timeout(DEFAULT_TIMEOUT, mcp.initialize()).await??;
|
||||||
|
|
||||||
|
let disablement_request_id = mcp
|
||||||
|
.send_experimental_feature_enablement_set_request(ExperimentalFeatureEnablementSetParams {
|
||||||
|
enablement: BTreeMap::from([("remote_plugin".to_string(), false)]),
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
let disablement_response: JSONRPCResponse = timeout(
|
||||||
|
DEFAULT_TIMEOUT,
|
||||||
|
mcp.read_stream_until_response_message(RequestId::Integer(disablement_request_id)),
|
||||||
|
)
|
||||||
|
.await??;
|
||||||
|
let _: ExperimentalFeatureEnablementSetResponse = to_response(disablement_response)?;
|
||||||
|
|
||||||
let initial_skills_list_request_id = mcp
|
let initial_skills_list_request_id = mcp
|
||||||
.send_skills_list_request(SkillsListParams {
|
.send_skills_list_request(SkillsListParams {
|
||||||
cwds: vec![cwd.path().to_path_buf()],
|
cwds: vec![cwd.path().to_path_buf()],
|
||||||
@@ -266,7 +261,7 @@ async fn skills_list_loads_remote_installed_plugin_skills_from_cache() -> Result
|
|||||||
let server = MockServer::start().await;
|
let server = MockServer::start().await;
|
||||||
let expected_skill_path =
|
let expected_skill_path =
|
||||||
std::fs::canonicalize(write_cached_remote_plugin_with_skill(codex_home.path())?)?;
|
std::fs::canonicalize(write_cached_remote_plugin_with_skill(codex_home.path())?)?;
|
||||||
write_remote_plugins_enabled_config_with_base_url(
|
write_plugins_enabled_config_with_base_url(
|
||||||
codex_home.path(),
|
codex_home.path(),
|
||||||
&format!("{}/backend-api/", server.uri()),
|
&format!("{}/backend-api/", server.uri()),
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
@@ -37,6 +37,13 @@ use wiremock::matchers::query_param;
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn returns_fallback_plugins_when_remote_disabled_for_codex_auth() {
|
async fn returns_fallback_plugins_when_remote_disabled_for_codex_auth() {
|
||||||
let codex_home = tempdir().expect("tempdir should succeed");
|
let codex_home = tempdir().expect("tempdir should succeed");
|
||||||
|
write_file(
|
||||||
|
&codex_home.path().join(CONFIG_TOML_FILE),
|
||||||
|
r#"[features]
|
||||||
|
plugins = true
|
||||||
|
remote_plugin = false
|
||||||
|
"#,
|
||||||
|
);
|
||||||
let curated_root = curated_plugins_repo_path(codex_home.path());
|
let curated_root = curated_plugins_repo_path(codex_home.path());
|
||||||
write_openai_curated_marketplace(&curated_root, &["sample", "slack", "openai-developers"]);
|
write_openai_curated_marketplace(&curated_root, &["sample", "slack", "openai-developers"]);
|
||||||
|
|
||||||
@@ -69,8 +76,7 @@ async fn returns_api_curated_fallback_plugins_for_direct_provider_auth() {
|
|||||||
let curated_root = curated_plugins_repo_path(codex_home.path());
|
let curated_root = curated_plugins_repo_path(codex_home.path());
|
||||||
write_openai_api_curated_marketplace(&curated_root, &["sample", "slack", "openai-developers"]);
|
write_openai_api_curated_marketplace(&curated_root, &["sample", "slack", "openai-developers"]);
|
||||||
|
|
||||||
let mut plugins = load_plugins_config(codex_home.path(), codex_home.path()).await;
|
let plugins = load_plugins_config(codex_home.path(), codex_home.path()).await;
|
||||||
plugins.remote_plugin_enabled = true;
|
|
||||||
let plugins_manager = PluginsManager::new(codex_home.path().to_path_buf());
|
let plugins_manager = PluginsManager::new(codex_home.path().to_path_buf());
|
||||||
plugins_manager.set_auth_mode(Some(AuthMode::ApiKey));
|
plugins_manager.set_auth_mode(Some(AuthMode::ApiKey));
|
||||||
let auth = CodexAuth::from_api_key("test-api-key");
|
let auth = CodexAuth::from_api_key("test-api-key");
|
||||||
@@ -153,7 +159,6 @@ async fn omits_openai_curated_but_keeps_configured_marketplaces_for_remote_codex
|
|||||||
&format!(
|
&format!(
|
||||||
r#"[features]
|
r#"[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
|
|
||||||
[marketplaces.{bundled_marketplace_name}]
|
[marketplaces.{bundled_marketplace_name}]
|
||||||
source_type = "git"
|
source_type = "git"
|
||||||
@@ -188,8 +193,7 @@ async fn includes_openai_curated_when_remote_enabled_without_auth() {
|
|||||||
let curated_root = curated_plugins_repo_path(codex_home.path());
|
let curated_root = curated_plugins_repo_path(codex_home.path());
|
||||||
write_openai_curated_marketplace(&curated_root, &["slack"]);
|
write_openai_curated_marketplace(&curated_root, &["slack"]);
|
||||||
|
|
||||||
let mut plugins = load_plugins_config(codex_home.path(), codex_home.path()).await;
|
let plugins = load_plugins_config(codex_home.path(), codex_home.path()).await;
|
||||||
plugins.remote_plugin_enabled = true;
|
|
||||||
let plugins_manager = PluginsManager::new(codex_home.path().to_path_buf());
|
let plugins_manager = PluginsManager::new(codex_home.path().to_path_buf());
|
||||||
let discoverable_plugins = list_discoverable_plugins(
|
let discoverable_plugins = list_discoverable_plugins(
|
||||||
&plugins_manager,
|
&plugins_manager,
|
||||||
@@ -788,7 +792,6 @@ async fn expands_cached_remote_plugins_by_loaded_apps() {
|
|||||||
&codex_home.path().join(CONFIG_TOML_FILE),
|
&codex_home.path().join(CONFIG_TOML_FILE),
|
||||||
r#"[features]
|
r#"[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1062,7 +1062,6 @@ async fn remote_installed_cache_ignores_plugins_missing_local_cache() {
|
|||||||
&codex_home.path().join(CONFIG_TOML_FILE),
|
&codex_home.path().join(CONFIG_TOML_FILE),
|
||||||
r#"[features]
|
r#"[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1296,7 +1295,6 @@ async fn remote_global_catalog_ignores_local_curated_plugins() {
|
|||||||
&codex_home.path().join(CONFIG_TOML_FILE),
|
&codex_home.path().join(CONFIG_TOML_FILE),
|
||||||
r#"[features]
|
r#"[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
|
|
||||||
[plugins."linear@openai-curated"]
|
[plugins."linear@openai-curated"]
|
||||||
enabled = true
|
enabled = true
|
||||||
@@ -1347,7 +1345,6 @@ async fn remote_plugin_feature_keeps_local_curated_without_codex_backend() {
|
|||||||
&codex_home.path().join(CONFIG_TOML_FILE),
|
&codex_home.path().join(CONFIG_TOML_FILE),
|
||||||
r#"[features]
|
r#"[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
|
|
||||||
[plugins."linear@openai-curated"]
|
[plugins."linear@openai-curated"]
|
||||||
enabled = true
|
enabled = true
|
||||||
@@ -4878,7 +4875,6 @@ async fn remote_plugin_caches_refresh_warms_recommended_plugins_cache() {
|
|||||||
&tmp.path().join(CONFIG_TOML_FILE),
|
&tmp.path().join(CONFIG_TOML_FILE),
|
||||||
r#"[features]
|
r#"[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -4939,7 +4935,6 @@ async fn recommended_plugins_mode_deduplicates_concurrent_cache_misses() {
|
|||||||
&tmp.path().join(CONFIG_TOML_FILE),
|
&tmp.path().join(CONFIG_TOML_FILE),
|
||||||
r#"[features]
|
r#"[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -5017,7 +5012,6 @@ async fn recommended_plugin_candidates_filter_installed_and_disabled_plugins() {
|
|||||||
&tmp.path().join(CONFIG_TOML_FILE),
|
&tmp.path().join(CONFIG_TOML_FILE),
|
||||||
r#"[features]
|
r#"[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
let server = MockServer::start().await;
|
let server = MockServer::start().await;
|
||||||
@@ -5090,7 +5084,6 @@ async fn recommended_plugins_mode_caches_explicit_false() {
|
|||||||
&tmp.path().join(CONFIG_TOML_FILE),
|
&tmp.path().join(CONFIG_TOML_FILE),
|
||||||
r#"[features]
|
r#"[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -5130,7 +5123,6 @@ async fn recommended_plugins_mode_retries_after_fetch_failure() {
|
|||||||
&tmp.path().join(CONFIG_TOML_FILE),
|
&tmp.path().join(CONFIG_TOML_FILE),
|
||||||
r#"[features]
|
r#"[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ pub(crate) async fn load_plugins_config(codex_home: &Path, cwd: &Path) -> Plugin
|
|||||||
feature_enabled(
|
feature_enabled(
|
||||||
&effective_config,
|
&effective_config,
|
||||||
"remote_plugin",
|
"remote_plugin",
|
||||||
/*default_enabled*/ false,
|
/*default_enabled*/ true,
|
||||||
),
|
),
|
||||||
"https://chatgpt.com/backend-api/".to_string(),
|
"https://chatgpt.com/backend-api/".to_string(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ async fn list_tool_suggest_discoverable_plugins_includes_cached_remote_global_pl
|
|||||||
&codex_home.path().join(crate::config::CONFIG_TOML_FILE),
|
&codex_home.path().join(crate::config::CONFIG_TOML_FILE),
|
||||||
r#"[features]
|
r#"[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -306,7 +305,6 @@ remote_plugin = true
|
|||||||
&codex_home.path().join(crate::config::CONFIG_TOML_FILE),
|
&codex_home.path().join(crate::config::CONFIG_TOML_FILE),
|
||||||
r#"[features]
|
r#"[features]
|
||||||
plugins = true
|
plugins = true
|
||||||
remote_plugin = true
|
|
||||||
|
|
||||||
[tool_suggest]
|
[tool_suggest]
|
||||||
disabled_tools = [
|
disabled_tools = [
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ pub enum Feature {
|
|||||||
///
|
///
|
||||||
/// Requirements-only gate: this should be set from requirements, not user config.
|
/// Requirements-only gate: this should be set from requirements, not user config.
|
||||||
ComputerUse,
|
ComputerUse,
|
||||||
/// Temporary internal-only flag for PS-backed remote plugin catalog development.
|
/// Enable the PS-backed remote plugin catalog.
|
||||||
RemotePlugin,
|
RemotePlugin,
|
||||||
/// Enable remote plugin sharing flows.
|
/// Enable remote plugin sharing flows.
|
||||||
PluginSharing,
|
PluginSharing,
|
||||||
@@ -1145,8 +1145,8 @@ pub const FEATURES: &[FeatureSpec] = &[
|
|||||||
FeatureSpec {
|
FeatureSpec {
|
||||||
id: Feature::RemotePlugin,
|
id: Feature::RemotePlugin,
|
||||||
key: "remote_plugin",
|
key: "remote_plugin",
|
||||||
stage: Stage::UnderDevelopment,
|
stage: Stage::Stable,
|
||||||
default_enabled: false,
|
default_enabled: true,
|
||||||
},
|
},
|
||||||
FeatureSpec {
|
FeatureSpec {
|
||||||
id: Feature::PluginSharing,
|
id: Feature::PluginSharing,
|
||||||
|
|||||||
@@ -1200,9 +1200,10 @@ async fn plugins_popup_admin_disabled_available_plugin_has_view_only_hint() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn plugins_popup_remote_section_fallback_states_snapshot() {
|
async fn plugins_popup_remote_section_fallback_states_when_remote_plugin_disabled_snapshot() {
|
||||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||||
chat.set_feature_enabled(Feature::Plugins, /*enabled*/ true);
|
chat.set_feature_enabled(Feature::Plugins, /*enabled*/ true);
|
||||||
|
chat.set_feature_enabled(Feature::RemotePlugin, /*enabled*/ false);
|
||||||
|
|
||||||
let select_tab_containing = |chat: &mut ChatWidget, visible_text: &str| -> String {
|
let select_tab_containing = |chat: &mut ChatWidget, visible_text: &str| -> String {
|
||||||
for _ in 0..8 {
|
for _ in 0..8 {
|
||||||
@@ -1266,7 +1267,6 @@ async fn plugins_popup_remote_section_fallback_states_snapshot() {
|
|||||||
|
|
||||||
let (mut remote_chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
let (mut remote_chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||||
remote_chat.set_feature_enabled(Feature::Plugins, /*enabled*/ true);
|
remote_chat.set_feature_enabled(Feature::Plugins, /*enabled*/ true);
|
||||||
remote_chat.set_feature_enabled(Feature::RemotePlugin, /*enabled*/ true);
|
|
||||||
remote_chat.add_plugins_output();
|
remote_chat.add_plugins_output();
|
||||||
let remote_cwd = remote_chat.config.cwd.clone();
|
let remote_cwd = remote_chat.config.cwd.clone();
|
||||||
remote_chat.on_plugins_loaded(
|
remote_chat.on_plugins_loaded(
|
||||||
|
|||||||
Reference in new issue
Block a user