connectors: own app metadata types (#29723)

## Why

Connector metadata is consumed by connector discovery, ChatGPT
integration, core, and TUI code. Treating app-server's wire DTO as the
shared domain model reverses the intended dependency direction.

## What changed

- Added connector-owned app branding, review, screenshot, metadata, and
info types.
- Added explicit conversions in app-server and TUI while preserving
app-server's wire payloads.
- Removed production app-server-protocol dependencies from connectors
and ChatGPT connector code.

## Stack

This is PR 4 of 6, stacked on [PR
#29722](https://github.com/openai/codex/pull/29722). Review only the
delta from `codex/split-config-layer-types`. Next: [PR
#29724](https://github.com/openai/codex/pull/29724).

## Validation

- Connector and tools coverage passed.
- App-server app-list coverage passed: 13 tests.
This commit is contained in:
Adam Perry @ OpenAI
2026-06-23 22:08:23 -07:00
committed by GitHub
Unverified
parent 1d65ccabd5
commit e639e8c4bd
34 changed files with 400 additions and 32 deletions
+2 -2
View File
@@ -1976,6 +1976,7 @@ dependencies = [
"codex-chatgpt",
"codex-cloud-config",
"codex-config",
"codex-connectors",
"codex-core",
"codex-core-plugins",
"codex-exec-server",
@@ -2293,7 +2294,6 @@ version = "0.0.0"
dependencies = [
"anyhow",
"clap",
"codex-app-server-protocol",
"codex-connectors",
"codex-core",
"codex-git-utils",
@@ -2583,7 +2583,6 @@ name = "codex-connectors"
version = "0.0.0"
dependencies = [
"anyhow",
"codex-app-server-protocol",
"codex-config",
"pretty_assertions",
"serde",
@@ -4016,6 +4015,7 @@ version = "0.0.0"
dependencies = [
"codex-app-server-protocol",
"codex-code-mode",
"codex-connectors",
"codex-features",
"codex-file-system",
"codex-protocol",
+1
View File
@@ -33,6 +33,7 @@ codex-analytics = { workspace = true }
codex-arg0 = { workspace = true }
codex-cloud-config = { workspace = true }
codex-config = { workspace = true }
codex-connectors = { workspace = true }
codex-core = { workspace = true }
codex-core-plugins = { workspace = true }
codex-home = { workspace = true }
+118
View File
@@ -0,0 +1,118 @@
use codex_app_server_protocol::AppBranding as ApiAppBranding;
use codex_app_server_protocol::AppInfo as ApiAppInfo;
use codex_app_server_protocol::AppMetadata as ApiAppMetadata;
use codex_app_server_protocol::AppReview as ApiAppReview;
use codex_app_server_protocol::AppScreenshot as ApiAppScreenshot;
use codex_connectors::AppBranding;
use codex_connectors::AppInfo;
use codex_connectors::AppMetadata;
use codex_connectors::AppReview;
use codex_connectors::AppScreenshot;
/// Converts connector-domain app metadata owned by `codex-connectors` into the app-server wire
/// type owned by `codex-app-server-protocol`.
///
/// The types stay separate so app-server protocol ownership does not leak into the connector
/// domain crate. Because this crate owns neither type, Rust's orphan rules require an explicit
/// conversion function instead of a `From` implementation.
pub(crate) fn app_info_to_api(app: AppInfo) -> ApiAppInfo {
let AppInfo {
id,
name,
description,
logo_url,
logo_url_dark,
distribution_channel,
branding,
app_metadata,
labels,
install_url,
is_accessible,
is_enabled,
plugin_display_names,
} = app;
ApiAppInfo {
id,
name,
description,
logo_url,
logo_url_dark,
distribution_channel,
branding: branding.map(app_branding_to_api),
app_metadata: app_metadata.map(app_metadata_to_api),
labels,
install_url,
is_accessible,
is_enabled,
plugin_display_names,
}
}
fn app_branding_to_api(branding: AppBranding) -> ApiAppBranding {
let AppBranding {
category,
developer,
website,
privacy_policy,
terms_of_service,
is_discoverable_app,
} = branding;
ApiAppBranding {
category,
developer,
website,
privacy_policy,
terms_of_service,
is_discoverable_app,
}
}
fn app_review_to_api(review: AppReview) -> ApiAppReview {
let AppReview { status } = review;
ApiAppReview { status }
}
fn app_screenshot_to_api(screenshot: AppScreenshot) -> ApiAppScreenshot {
let AppScreenshot {
url,
file_id,
user_prompt,
} = screenshot;
ApiAppScreenshot {
url,
file_id,
user_prompt,
}
}
fn app_metadata_to_api(metadata: AppMetadata) -> ApiAppMetadata {
let AppMetadata {
review,
categories,
sub_categories,
seo_description,
screenshots,
developer,
version,
version_id,
version_notes,
first_party_type,
first_party_requires_install,
show_in_composer_when_unlinked,
} = metadata;
ApiAppMetadata {
review: review.map(app_review_to_api),
categories,
sub_categories,
seo_description,
screenshots: screenshots
.map(|screenshots| screenshots.into_iter().map(app_screenshot_to_api).collect()),
developer,
version,
version_id,
version_notes,
first_party_type,
first_party_requires_install,
show_in_composer_when_unlinked,
}
}
+1
View File
@@ -80,6 +80,7 @@ use tracing_subscriber::util::SubscriberInitExt;
const SQLITE_RECOVERY_CONFIG_WARNING_SUMMARY: &str = "Codex rebuilt its local database.";
mod analytics_utils;
mod app_info;
mod app_server_tracing;
mod attestation;
mod auth_mode;
@@ -29,7 +29,6 @@ use codex_app_server_protocol::AddCreditsNudgeCreditType;
use codex_app_server_protocol::AddCreditsNudgeEmailStatus;
use codex_app_server_protocol::AdditionalContextEntry;
use codex_app_server_protocol::AdditionalContextKind;
use codex_app_server_protocol::AppInfo;
use codex_app_server_protocol::AppListUpdatedNotification;
use codex_app_server_protocol::AppSummary;
use codex_app_server_protocol::AppTemplateSummary;
@@ -302,6 +301,7 @@ use codex_config::CloudConfigBundleLoadErrorCode;
use codex_config::ConfigLayerStack;
use codex_config::loader::project_trust_key;
use codex_config::types::McpServerTransportConfig;
use codex_connectors::AppInfo;
use codex_core::CodexThread;
use codex_core::CodexThreadSettingsOverrides;
use codex_core::ForkSnapshot;
@@ -1,4 +1,5 @@
use super::*;
use crate::app_info::app_info_to_api;
pub(crate) struct AppsRequestProcessor {
auth_manager: Arc<AuthManager>,
@@ -396,7 +397,11 @@ fn paginate_apps(
let effective_limit = limit.unwrap_or(total as u32).max(1) as usize;
let end = start.saturating_add(effective_limit).min(total);
let data = connectors[start..end].to_vec();
let data = connectors[start..end]
.iter()
.cloned()
.map(app_info_to_api)
.collect();
let next_cursor = if end < total {
Some(end.to_string())
} else {
@@ -410,6 +415,7 @@ async fn send_app_list_updated_notification(
outgoing: &Arc<OutgoingMessageSender>,
data: Vec<AppInfo>,
) {
let data = data.into_iter().map(app_info_to_api).collect();
outgoing
.send_server_notification(ServerNotification::AppListUpdated(
AppListUpdatedNotification { data },
-1
View File
@@ -10,7 +10,6 @@ workspace = true
[dependencies]
anyhow = { workspace = true }
clap = { workspace = true, features = ["derive"] }
codex-app-server-protocol = { workspace = true }
codex-connectors = { workspace = true }
codex-core = { workspace = true }
codex-git-utils = { workspace = true }
+1 -1
View File
@@ -4,7 +4,7 @@ use std::time::Duration;
use crate::chatgpt_client::chatgpt_get_request_with_timeout;
use codex_app_server_protocol::AppInfo;
use codex_connectors::AppInfo;
use codex_connectors::ConnectorDirectoryCacheContext;
use codex_connectors::ConnectorDirectoryCacheKey;
use codex_connectors::DirectoryListResponse;
-1
View File
@@ -9,7 +9,6 @@ workspace = true
[dependencies]
anyhow = { workspace = true }
codex-app-server-protocol = { workspace = true }
codex-config = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
+1 -1
View File
@@ -1,9 +1,9 @@
use std::collections::BTreeSet;
use std::collections::HashMap;
use crate::AppInfo;
use crate::metadata::connector_install_url;
use crate::normalize_connector_value;
use codex_app_server_protocol::AppInfo;
pub struct AccessibleConnectorTool {
pub connector_id: String,
+110
View File
@@ -0,0 +1,110 @@
//! Connector-domain app metadata used by directory discovery, caching, and tool selection.
//!
//! The Serde implementations decode connector-directory response metadata and persist normalized
//! app information in the connector-directory disk cache. They do not define the app-server wire
//! format; `codex-app-server-protocol` owns separate API types for that boundary.
use serde::Deserialize;
use serde::Serialize;
use std::collections::HashMap;
/// Branding supplied by the connector directory for an app.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AppBranding {
pub category: Option<String>,
pub developer: Option<String>,
pub website: Option<String>,
pub privacy_policy: Option<String>,
pub terms_of_service: Option<String>,
pub is_discoverable_app: bool,
}
/// Review state supplied by the connector directory for an app.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AppReview {
pub status: String,
}
/// Screenshot metadata supplied by the connector directory for an app.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AppScreenshot {
pub url: Option<String>,
#[serde(alias = "file_id")]
pub file_id: Option<String>,
#[serde(alias = "user_prompt")]
pub user_prompt: String,
}
/// Extended metadata supplied by the connector directory for an app.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AppMetadata {
pub review: Option<AppReview>,
pub categories: Option<Vec<String>>,
pub sub_categories: Option<Vec<String>>,
pub seo_description: Option<String>,
pub screenshots: Option<Vec<AppScreenshot>>,
pub developer: Option<String>,
pub version: Option<String>,
pub version_id: Option<String>,
pub version_notes: Option<String>,
pub first_party_type: Option<String>,
pub first_party_requires_install: Option<bool>,
pub show_in_composer_when_unlinked: Option<bool>,
}
/// Connector metadata used by connector discovery, caching, and tool selection.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AppInfo {
pub id: String,
pub name: String,
pub description: Option<String>,
pub logo_url: Option<String>,
pub logo_url_dark: Option<String>,
pub distribution_channel: Option<String>,
pub branding: Option<AppBranding>,
pub app_metadata: Option<AppMetadata>,
pub labels: Option<HashMap<String, String>>,
pub install_url: Option<String>,
#[serde(default)]
pub is_accessible: bool,
#[serde(default = "default_enabled")]
pub is_enabled: bool,
#[serde(default)]
pub plugin_display_names: Vec<String>,
}
impl AppInfo {
pub fn category(&self) -> Option<String> {
self.branding
.as_ref()
.and_then(|branding| non_empty_category(branding.category.as_deref()))
.or_else(|| {
self.app_metadata
.as_ref()
.and_then(|metadata| metadata.categories.as_ref())
.and_then(|categories| {
categories
.iter()
.find_map(|category| non_empty_category(Some(category.as_str())))
})
})
}
}
const fn default_enabled() -> bool {
true
}
fn non_empty_category(category: Option<&str>) -> Option<String> {
let category = category?.trim();
if category.is_empty() {
None
} else {
Some(category.to_string())
}
}
+1 -1
View File
@@ -1,12 +1,12 @@
use std::path::PathBuf;
use codex_app_server_protocol::AppInfo;
use serde::Deserialize;
use serde::Serialize;
use sha1::Digest;
use sha1::Sha1;
use tracing::warn;
use crate::AppInfo;
use crate::ConnectorDirectoryCacheKey;
pub(crate) const CONNECTOR_DIRECTORY_DISK_CACHE_SCHEMA_VERSION: u8 = 1;
+1 -1
View File
@@ -1,6 +1,6 @@
use std::collections::HashSet;
use codex_app_server_protocol::AppInfo;
use crate::AppInfo;
pub fn filter_tool_suggest_discoverable_connectors(
directory_connectors: Vec<AppInfo>,
+6 -3
View File
@@ -5,19 +5,22 @@ use std::sync::Mutex as StdMutex;
use std::time::Duration;
use std::time::Instant;
use codex_app_server_protocol::AppBranding;
use codex_app_server_protocol::AppInfo;
use codex_app_server_protocol::AppMetadata;
use serde::Deserialize;
use serde::Serialize;
pub mod accessible;
mod app_info;
mod app_tool_policy;
mod directory_cache;
pub mod filter;
pub mod merge;
pub mod metadata;
pub use app_info::AppBranding;
pub use app_info::AppInfo;
pub use app_info::AppMetadata;
pub use app_info::AppReview;
pub use app_info::AppScreenshot;
pub use app_tool_policy::AppToolPolicy;
pub use app_tool_policy::AppToolPolicyEvaluator;
pub use app_tool_policy::AppToolPolicyInput;
+1 -1
View File
@@ -1,9 +1,9 @@
use std::collections::HashMap;
use std::collections::HashSet;
use crate::AppInfo;
use crate::metadata::connector_install_url;
use crate::metadata::sort_connectors_by_accessibility_and_name;
use codex_app_server_protocol::AppInfo;
pub fn merge_connectors(
connectors: Vec<AppInfo>,
+1 -1
View File
@@ -1,4 +1,4 @@
use codex_app_server_protocol::AppInfo;
use crate::AppInfo;
pub fn connector_display_label(connector: &AppInfo) -> String {
connector.name.clone()
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::connectors::AppInfo;
use crate::context::AppsInstructions;
use crate::context::ContextualUserFragment;
use codex_app_server_protocol::AppInfo;
use codex_protocol::protocol::APPS_INSTRUCTIONS_CLOSE_TAG;
use codex_protocol::protocol::APPS_INSTRUCTIONS_OPEN_TAG;
+3 -3
View File
@@ -6,9 +6,9 @@ use std::time::Duration;
use std::time::Instant;
use async_channel::unbounded;
pub use codex_app_server_protocol::AppBranding;
pub use codex_app_server_protocol::AppInfo;
pub use codex_app_server_protocol::AppMetadata;
pub use codex_connectors::AppBranding;
pub use codex_connectors::AppInfo;
pub use codex_connectors::AppMetadata;
use codex_connectors::ConnectorDirectoryCacheContext;
use codex_connectors::ConnectorDirectoryCacheKey;
use codex_connectors::app_is_enabled;
@@ -1,4 +1,4 @@
use codex_app_server_protocol::AppInfo;
use crate::connectors::AppInfo;
use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
use codex_protocol::protocol::APPS_INSTRUCTIONS_CLOSE_TAG;
use codex_protocol::protocol::APPS_INSTRUCTIONS_OPEN_TAG;
+1 -1
View File
@@ -66,6 +66,7 @@ use codex_protocol::request_permissions::RequestPermissionProfile;
use codex_utils_path_uri::PathUri;
use tracing::Span;
use crate::connectors::AppInfo;
use crate::rollout::recorder::RolloutRecorder;
use crate::state::ActiveTurn;
use crate::state::TaskKind;
@@ -83,7 +84,6 @@ use crate::tools::handlers::ShellCommandHandler;
use crate::tools::registry::ToolExecutor;
use crate::tools::router::ToolCallSource;
use crate::turn_diff_tracker::TurnDiffTracker;
use codex_app_server_protocol::AppInfo;
use codex_app_server_protocol::McpElicitationSchema;
use codex_config::config_toml::ConfigToml;
use codex_config::config_toml::ProjectConfig;
@@ -1,6 +1,6 @@
use std::collections::HashSet;
use codex_app_server_protocol::AppInfo;
use crate::connectors::AppInfo;
use codex_config::types::ToolSuggestDisabledTool;
use codex_core_plugins::remote::REMOTE_GLOBAL_MARKETPLACE_NAME;
use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
+1
View File
@@ -10,6 +10,7 @@ workspace = true
[dependencies]
codex-app-server-protocol = { workspace = true }
codex-code-mode = { workspace = true }
codex-connectors = { workspace = true }
codex-features = { workspace = true }
codex-file-system = { workspace = true }
codex-protocol = { workspace = true }
+1 -1
View File
@@ -1,10 +1,10 @@
use std::collections::BTreeMap;
use codex_app_server_protocol::AppInfo;
use codex_app_server_protocol::McpElicitationObjectType;
use codex_app_server_protocol::McpElicitationSchema;
use codex_app_server_protocol::McpServerElicitationRequest;
use codex_app_server_protocol::McpServerElicitationRequestParams;
use codex_connectors::AppInfo;
use serde::Deserialize;
use serde::Serialize;
use serde_json::json;
+1 -1
View File
@@ -1,4 +1,4 @@
use codex_app_server_protocol::AppInfo;
use codex_connectors::AppInfo;
use serde::Deserialize;
use serde::Serialize;
+1 -1
View File
@@ -1,5 +1,5 @@
use super::*;
use codex_app_server_protocol::AppInfo;
use codex_connectors::AppInfo;
use pretty_assertions::assert_eq;
use serde_json::json;
+7 -1
View File
@@ -7,6 +7,7 @@ use super::app_server_event_targets::server_request_thread_id;
use crate::app_command::AppCommand;
use crate::app_event::AppEvent;
use crate::app_event::ConnectorsSnapshot;
use crate::app_info::app_info_from_api;
use crate::app_server_session::AppServerSession;
use crate::app_server_session::status_account_display_from_auth_mode;
use codex_app_server_client::AppServerEvent;
@@ -127,7 +128,12 @@ impl App {
ServerNotification::AppListUpdated(notification) => {
self.chat_widget.on_connectors_loaded(
Ok(ConnectorsSnapshot {
connectors: notification.data.clone(),
connectors: notification
.data
.iter()
.cloned()
.map(app_info_from_api)
.collect(),
}),
/*is_final*/ false,
);
+2 -1
View File
@@ -7,6 +7,7 @@
use super::plugin_mentions::fetch_plugin_mentions;
use super::*;
use crate::app_event::ConnectorsSnapshot;
use crate::app_info::app_info_from_api;
use crate::config_update::format_config_error;
use codex_app_server_protocol::AppsListParams;
use codex_app_server_protocol::AppsListResponse;
@@ -870,7 +871,7 @@ pub(super) async fn fetch_connectors_list(
.await
.wrap_err("app/list failed in TUI")?;
Ok(ConnectorsSnapshot {
connectors: response.data,
connectors: response.data.into_iter().map(app_info_from_api).collect(),
})
}
+1 -1
View File
@@ -12,7 +12,6 @@ use std::path::PathBuf;
use codex_app_server_protocol::AddCreditsNudgeCreditType;
use codex_app_server_protocol::AddCreditsNudgeEmailStatus;
use codex_app_server_protocol::AppInfo;
use codex_app_server_protocol::ConsumeAccountRateLimitResetCreditResponse;
use codex_app_server_protocol::GetAccountRateLimitsResponse;
use codex_app_server_protocol::GetAccountTokenUsageResponse;
@@ -29,6 +28,7 @@ use codex_app_server_protocol::PluginReadResponse;
use codex_app_server_protocol::PluginUninstallResponse;
use codex_app_server_protocol::SkillsListResponse;
use codex_app_server_protocol::ThreadGoalStatus;
use codex_connectors::AppInfo;
use codex_file_search::FileMatch;
use codex_protocol::ThreadId;
use codex_protocol::openai_models::ModelPreset;
+122
View File
@@ -0,0 +1,122 @@
use codex_app_server_protocol::AppBranding as ApiAppBranding;
use codex_app_server_protocol::AppInfo as ApiAppInfo;
use codex_app_server_protocol::AppMetadata as ApiAppMetadata;
use codex_app_server_protocol::AppReview as ApiAppReview;
use codex_app_server_protocol::AppScreenshot as ApiAppScreenshot;
use codex_connectors::AppBranding;
use codex_connectors::AppInfo;
use codex_connectors::AppMetadata;
use codex_connectors::AppReview;
use codex_connectors::AppScreenshot;
/// Converts the app-server wire type owned by `codex-app-server-protocol` into connector-domain
/// app metadata owned by `codex-connectors`.
///
/// The types stay separate so app-server protocol ownership does not leak into the connector
/// domain crate. Because this crate owns neither type, Rust's orphan rules require an explicit
/// conversion function instead of a `From` implementation.
pub(crate) fn app_info_from_api(app: ApiAppInfo) -> AppInfo {
let ApiAppInfo {
id,
name,
description,
logo_url,
logo_url_dark,
distribution_channel,
branding,
app_metadata,
labels,
install_url,
is_accessible,
is_enabled,
plugin_display_names,
} = app;
AppInfo {
id,
name,
description,
logo_url,
logo_url_dark,
distribution_channel,
branding: branding.map(app_branding_from_api),
app_metadata: app_metadata.map(app_metadata_from_api),
labels,
install_url,
is_accessible,
is_enabled,
plugin_display_names,
}
}
fn app_branding_from_api(branding: ApiAppBranding) -> AppBranding {
let ApiAppBranding {
category,
developer,
website,
privacy_policy,
terms_of_service,
is_discoverable_app,
} = branding;
AppBranding {
category,
developer,
website,
privacy_policy,
terms_of_service,
is_discoverable_app,
}
}
fn app_review_from_api(review: ApiAppReview) -> AppReview {
let ApiAppReview { status } = review;
AppReview { status }
}
fn app_screenshot_from_api(screenshot: ApiAppScreenshot) -> AppScreenshot {
let ApiAppScreenshot {
url,
file_id,
user_prompt,
} = screenshot;
AppScreenshot {
url,
file_id,
user_prompt,
}
}
fn app_metadata_from_api(metadata: ApiAppMetadata) -> AppMetadata {
let ApiAppMetadata {
review,
categories,
sub_categories,
seo_description,
screenshots,
developer,
version,
version_id,
version_notes,
first_party_type,
first_party_requires_install,
show_in_composer_when_unlinked,
} = metadata;
AppMetadata {
review: review.map(app_review_from_api),
categories,
sub_categories,
seo_description,
screenshots: screenshots.map(|screenshots| {
screenshots
.into_iter()
.map(app_screenshot_from_api)
.collect()
}),
developer,
version,
version_id,
version_notes,
first_party_type,
first_party_requires_install,
show_in_composer_when_unlinked,
}
}
@@ -241,7 +241,7 @@ use crate::history_cell;
use crate::skills_helpers::skill_display_name;
use crate::tui::FrameRequester;
use crate::ui_consts::LIVE_PREFIX_COLS;
use codex_app_server_protocol::AppInfo;
use codex_connectors::AppInfo;
#[cfg(test)]
use codex_core_skills::model::SkillInterface;
use codex_core_skills::model::SkillMetadata;
+1 -1
View File
@@ -80,7 +80,6 @@ use crate::token_usage::TokenUsageInfo;
use crate::version::CODEX_CLI_VERSION;
use codex_app_server_protocol::AddCreditsNudgeCreditType;
use codex_app_server_protocol::AddCreditsNudgeEmailStatus;
use codex_app_server_protocol::AppInfo;
use codex_app_server_protocol::AppSummary;
use codex_app_server_protocol::CodexErrorInfo as AppServerCodexErrorInfo;
use codex_app_server_protocol::CollabAgentTool;
@@ -123,6 +122,7 @@ use codex_config::ConstraintResult;
use codex_config::types::ApprovalsReviewer;
use codex_config::types::Notifications;
use codex_config::types::WindowsSandboxModeToml;
use codex_connectors::AppInfo;
use codex_core_skills::model::SkillMetadata;
use codex_features::FEATURES;
use codex_features::Feature;
+1 -1
View File
@@ -10,10 +10,10 @@ use crate::bottom_pane::SkillsToggleView;
use crate::bottom_pane::popup_consts::standard_popup_hint_line;
use crate::skills_helpers::skill_description;
use crate::skills_helpers::skill_display_name;
use codex_app_server_protocol::AppInfo;
use codex_app_server_protocol::SkillMetadata as ProtocolSkillMetadata;
use codex_app_server_protocol::SkillsListEntry;
use codex_app_server_protocol::SkillsListResponse;
use codex_connectors::AppInfo;
use codex_core_skills::model::SkillDependencies;
use codex_core_skills::model::SkillInterface;
use codex_core_skills::model::SkillMetadata;
@@ -1,7 +1,6 @@
use super::*;
use crate::app_event::ConnectorsSnapshot;
use crate::chatwidget::connectors::ConnectorsCacheState;
use codex_app_server_protocol::AppInfo;
use codex_app_server_protocol::HookErrorInfo;
use codex_app_server_protocol::HooksListEntry;
use codex_app_server_protocol::HooksListResponse;
@@ -11,6 +10,7 @@ use codex_app_server_protocol::PluginAvailability;
use codex_app_server_protocol::PluginShareContext;
use codex_app_server_protocol::PluginShareDiscoverability;
use codex_app_server_protocol::PluginSource;
use codex_connectors::AppInfo;
use codex_features::Stage;
use pretty_assertions::assert_eq;
+1
View File
@@ -91,6 +91,7 @@ mod app_backtrack;
mod app_command;
mod app_event;
mod app_event_sender;
mod app_info;
mod app_server_approval_conversions;
mod app_server_session;
mod approval_events;