mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
b9dc3b7a8b
## Why Managed deployments need a reliable deny gate for remote control. Persisted enablement and explicit startup requests currently remain able to start the transport, while the removed `features.remote_control` key is intentionally only a compatibility no-op. This adds a dedicated requirement that administrators can use to force remote control off without deleting the user's persisted preference. Removing the requirement and restarting restores the prior choice. ## What Changed - Added top-level `allow_remote_control` requirements parsing, sourced layer precedence, debug output, and `configRequirements/read` exposure as `allowRemoteControl`. - Added a typed transport policy captured from the startup requirements snapshot. Managed disable forces the initial state to disabled and prevents enrollment, refresh, connection, and persisted-preference mutation. - Rejected every `remoteControl/*` RPC before parameter deserialization with JSON-RPC `-32600` and `remote control is disabled by managed requirements`. - Preserved the existing disabled status notification and the previous behavior when the requirement is `true` or omitted. - Regenerated app-server protocol schemas and documented the new requirement. ## Verification - Confirmed all remote-control RPCs, including a malformed request, return the managed-policy error while the initial status notification remains `disabled`. - Confirmed explicit ephemeral startup and persisted enablement make no backend connection and leave the SQLite preference unchanged. - Confirmed `allow_remote_control = true` does not enable or block remote control and `configRequirements/read` returns `allowRemoteControl: false` for the deny policy. Related issue: N/A (managed-policy hardening).
751 lines
26 KiB
Rust
751 lines
26 KiB
Rust
use super::ApprovalsReviewer;
|
|
use super::AskForApproval;
|
|
use super::SandboxMode;
|
|
use super::WindowsSandboxSetupMode;
|
|
use super::shared::default_enabled;
|
|
use codex_experimental_api_macros::ExperimentalApi;
|
|
use codex_protocol::config_types::AutoCompactTokenLimitScope;
|
|
use codex_protocol::config_types::ForcedLoginMethod;
|
|
use codex_protocol::config_types::ReasoningSummary;
|
|
use codex_protocol::config_types::Verbosity;
|
|
use codex_protocol::config_types::WebSearchMode;
|
|
use codex_protocol::config_types::WebSearchToolConfig;
|
|
use codex_protocol::openai_models::ReasoningEffort;
|
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
|
use schemars::JsonSchema;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use serde_json::Value as JsonValue;
|
|
use std::collections::BTreeMap;
|
|
use std::collections::HashMap;
|
|
use std::path::PathBuf;
|
|
use ts_rs::TS;
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(tag = "type", rename_all = "camelCase")]
|
|
#[ts(tag = "type")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum ConfigLayerSource {
|
|
/// Managed preferences layer delivered by MDM (macOS only).
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(rename_all = "camelCase")]
|
|
Mdm {
|
|
domain: String,
|
|
key: String,
|
|
},
|
|
|
|
/// Managed config layer from a file (usually `managed_config.toml`).
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(rename_all = "camelCase")]
|
|
System {
|
|
/// This is the path to the system config.toml file, though it is not
|
|
/// guaranteed to exist.
|
|
file: AbsolutePathBuf,
|
|
},
|
|
|
|
/// Enterprise-managed config layer delivered by the cloud config bundle.
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(rename_all = "camelCase")]
|
|
EnterpriseManaged {
|
|
/// Stable identifier for the delivered layer.
|
|
id: String,
|
|
|
|
/// Admin-facing name for the delivered layer. This is surfaced in
|
|
/// diagnostics so users know which cloud layer needs administrator
|
|
/// attention.
|
|
name: String,
|
|
},
|
|
|
|
/// User config layer from $CODEX_HOME/config.toml. This layer is special
|
|
/// in that it is expected to be:
|
|
/// - writable by the user
|
|
/// - generally outside the workspace directory
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(rename_all = "camelCase")]
|
|
User {
|
|
/// This is the path to the user's config.toml file, though it is not
|
|
/// guaranteed to exist.
|
|
file: AbsolutePathBuf,
|
|
|
|
/// Name of the selected profile-v2 config layered on top of the base
|
|
/// user config, when this layer represents one.
|
|
profile: Option<String>,
|
|
},
|
|
|
|
/// Path to a .codex/ folder within a project. There could be multiple of
|
|
/// these between `cwd` and the project/repo root.
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(rename_all = "camelCase")]
|
|
Project {
|
|
dot_codex_folder: AbsolutePathBuf,
|
|
},
|
|
|
|
/// Session-layer overrides supplied via `-c`/`--config`.
|
|
SessionFlags,
|
|
|
|
/// `managed_config.toml` was designed to be a config that was loaded
|
|
/// as the last layer on top of everything else. This scheme did not quite
|
|
/// work out as intended, but we keep this variant as a "best effort" while
|
|
/// we phase out `managed_config.toml` in favor of `requirements.toml`.
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(rename_all = "camelCase")]
|
|
LegacyManagedConfigTomlFromFile {
|
|
file: AbsolutePathBuf,
|
|
},
|
|
|
|
LegacyManagedConfigTomlFromMdm,
|
|
}
|
|
|
|
impl ConfigLayerSource {
|
|
/// A settings from a layer with a higher precedence will override a setting
|
|
/// from a layer with a lower precedence.
|
|
pub fn precedence(&self) -> i16 {
|
|
match self {
|
|
ConfigLayerSource::Mdm { .. } => 0,
|
|
ConfigLayerSource::System { .. } => 10,
|
|
ConfigLayerSource::EnterpriseManaged { .. } => 15,
|
|
ConfigLayerSource::User { profile, .. } => {
|
|
if profile.is_some() {
|
|
21
|
|
} else {
|
|
20
|
|
}
|
|
}
|
|
ConfigLayerSource::Project { .. } => 25,
|
|
ConfigLayerSource::SessionFlags => 30,
|
|
ConfigLayerSource::LegacyManagedConfigTomlFromFile { .. } => 40,
|
|
ConfigLayerSource::LegacyManagedConfigTomlFromMdm => 50,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Compares [ConfigLayerSource] by precedence, so `A < B` means settings from
|
|
/// layer `A` will be overridden by settings from layer `B`.
|
|
impl PartialOrd for ConfigLayerSource {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
Some(self.precedence().cmp(&other.precedence()))
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct SandboxWorkspaceWrite {
|
|
#[serde(default)]
|
|
pub writable_roots: Vec<PathBuf>,
|
|
#[serde(default)]
|
|
pub network_access: bool,
|
|
#[serde(default)]
|
|
pub exclude_tmpdir_env_var: bool,
|
|
#[serde(default)]
|
|
pub exclude_slash_tmp: bool,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ToolsV2 {
|
|
pub web_search: Option<WebSearchToolConfig>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AnalyticsConfig {
|
|
pub enabled: Option<bool>,
|
|
#[serde(default, flatten)]
|
|
pub additional: HashMap<String, JsonValue>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum AppToolApproval {
|
|
Auto,
|
|
Prompt,
|
|
Approve,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AppsDefaultConfig {
|
|
#[serde(default = "default_enabled")]
|
|
pub enabled: bool,
|
|
pub approvals_reviewer: Option<ApprovalsReviewer>,
|
|
#[serde(default = "default_enabled")]
|
|
pub destructive_enabled: bool,
|
|
#[serde(default = "default_enabled")]
|
|
pub open_world_enabled: bool,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AppToolConfig {
|
|
pub enabled: Option<bool>,
|
|
pub approval_mode: Option<AppToolApproval>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AppToolsConfig {
|
|
#[serde(default, flatten)]
|
|
pub tools: HashMap<String, AppToolConfig>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AppConfig {
|
|
#[serde(default = "default_enabled")]
|
|
pub enabled: bool,
|
|
pub approvals_reviewer: Option<ApprovalsReviewer>,
|
|
pub destructive_enabled: Option<bool>,
|
|
pub open_world_enabled: Option<bool>,
|
|
pub default_tools_approval_mode: Option<AppToolApproval>,
|
|
pub default_tools_enabled: Option<bool>,
|
|
pub tools: Option<AppToolsConfig>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AppsConfig {
|
|
#[serde(default, rename = "_default")]
|
|
pub default: Option<AppsDefaultConfig>,
|
|
#[serde(default, flatten)]
|
|
pub apps: HashMap<String, AppConfig>,
|
|
}
|
|
|
|
/// Backward-compatible API shape for ChatGPT workspace login restrictions.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(untagged)]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum ForcedChatgptWorkspaceIds {
|
|
Single(String),
|
|
Multiple(Vec<String>),
|
|
}
|
|
|
|
impl ForcedChatgptWorkspaceIds {
|
|
pub fn into_vec(self) -> Vec<String> {
|
|
match self {
|
|
Self::Single(value) => vec![value],
|
|
Self::Multiple(values) => values,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct Config {
|
|
pub model: Option<String>,
|
|
pub review_model: Option<String>,
|
|
pub model_context_window: Option<i64>,
|
|
pub model_auto_compact_token_limit: Option<i64>,
|
|
pub model_auto_compact_token_limit_scope: Option<AutoCompactTokenLimitScope>,
|
|
pub model_provider: Option<String>,
|
|
#[experimental(nested)]
|
|
pub approval_policy: Option<AskForApproval>,
|
|
/// [UNSTABLE] Optional default for where approval requests are routed for
|
|
/// review.
|
|
#[experimental("config/read.approvalsReviewer")]
|
|
pub approvals_reviewer: Option<ApprovalsReviewer>,
|
|
pub sandbox_mode: Option<SandboxMode>,
|
|
pub sandbox_workspace_write: Option<SandboxWorkspaceWrite>,
|
|
pub forced_chatgpt_workspace_id: Option<ForcedChatgptWorkspaceIds>,
|
|
pub forced_login_method: Option<ForcedLoginMethod>,
|
|
pub web_search: Option<WebSearchMode>,
|
|
pub tools: Option<ToolsV2>,
|
|
pub instructions: Option<String>,
|
|
pub developer_instructions: Option<String>,
|
|
pub compact_prompt: Option<String>,
|
|
pub model_reasoning_effort: Option<ReasoningEffort>,
|
|
pub model_reasoning_summary: Option<ReasoningSummary>,
|
|
pub model_verbosity: Option<Verbosity>,
|
|
pub service_tier: Option<String>,
|
|
pub analytics: Option<AnalyticsConfig>,
|
|
#[experimental("config/read.apps")]
|
|
#[serde(default)]
|
|
pub apps: Option<AppsConfig>,
|
|
pub desktop: Option<HashMap<String, JsonValue>>,
|
|
#[serde(default, flatten)]
|
|
pub additional: HashMap<String, JsonValue>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConfigLayerMetadata {
|
|
pub name: ConfigLayerSource,
|
|
pub version: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConfigLayer {
|
|
pub name: ConfigLayerSource,
|
|
pub version: String,
|
|
pub config: JsonValue,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub disabled_reason: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum MergeStrategy {
|
|
Replace,
|
|
Upsert,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum WriteStatus {
|
|
Ok,
|
|
OkOverridden,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct OverriddenMetadata {
|
|
pub message: String,
|
|
pub overriding_layer: ConfigLayerMetadata,
|
|
pub effective_value: JsonValue,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConfigWriteResponse {
|
|
pub status: WriteStatus,
|
|
pub version: String,
|
|
/// Canonical path to the config file that was written.
|
|
pub file_path: AbsolutePathBuf,
|
|
pub overridden_metadata: Option<OverriddenMetadata>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum ConfigWriteErrorCode {
|
|
ConfigLayerReadonly,
|
|
ConfigVersionConflict,
|
|
ConfigValidationError,
|
|
ConfigPathNotFound,
|
|
ConfigSchemaUnknownKey,
|
|
UserLayerNotFound,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConfigReadParams {
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub include_layers: bool,
|
|
/// Optional working directory to resolve project config layers. If specified,
|
|
/// return the effective config as seen from that directory (i.e., including any
|
|
/// project layers between `cwd` and the project/repo root).
|
|
#[ts(optional = nullable)]
|
|
pub cwd: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConfigReadResponse {
|
|
#[experimental(nested)]
|
|
pub config: Config,
|
|
pub origins: HashMap<String, ConfigLayerMetadata>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub layers: Option<Vec<ConfigLayer>>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConfigRequirements {
|
|
#[experimental(nested)]
|
|
pub allowed_approval_policies: Option<Vec<AskForApproval>>,
|
|
#[experimental("configRequirements/read.allowedApprovalsReviewers")]
|
|
pub allowed_approvals_reviewers: Option<Vec<ApprovalsReviewer>>,
|
|
pub allowed_sandbox_modes: Option<Vec<SandboxMode>>,
|
|
pub allowed_windows_sandbox_implementations: Option<Vec<WindowsSandboxSetupMode>>,
|
|
pub allowed_permission_profiles: Option<BTreeMap<String, bool>>,
|
|
pub default_permissions: Option<String>,
|
|
pub allowed_web_search_modes: Option<Vec<WebSearchMode>>,
|
|
pub allow_managed_hooks_only: Option<bool>,
|
|
pub allow_appshots: Option<bool>,
|
|
pub allow_remote_control: Option<bool>,
|
|
pub computer_use: Option<ComputerUseRequirements>,
|
|
pub feature_requirements: Option<BTreeMap<String, bool>>,
|
|
#[experimental("configRequirements/read.hooks")]
|
|
pub hooks: Option<ManagedHooksRequirements>,
|
|
pub enforce_residency: Option<ResidencyRequirement>,
|
|
#[experimental("configRequirements/read.network")]
|
|
pub network: Option<NetworkRequirements>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ComputerUseRequirements {
|
|
pub allow_locked_computer_use: Option<bool>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ManagedHooksRequirements {
|
|
pub managed_dir: Option<PathBuf>,
|
|
pub windows_managed_dir: Option<PathBuf>,
|
|
#[serde(rename = "PreToolUse")]
|
|
#[ts(rename = "PreToolUse")]
|
|
pub pre_tool_use: Vec<ConfiguredHookMatcherGroup>,
|
|
#[serde(rename = "PermissionRequest")]
|
|
#[ts(rename = "PermissionRequest")]
|
|
pub permission_request: Vec<ConfiguredHookMatcherGroup>,
|
|
#[serde(rename = "PostToolUse")]
|
|
#[ts(rename = "PostToolUse")]
|
|
pub post_tool_use: Vec<ConfiguredHookMatcherGroup>,
|
|
#[serde(rename = "PreCompact")]
|
|
#[ts(rename = "PreCompact")]
|
|
pub pre_compact: Vec<ConfiguredHookMatcherGroup>,
|
|
#[serde(rename = "PostCompact")]
|
|
#[ts(rename = "PostCompact")]
|
|
pub post_compact: Vec<ConfiguredHookMatcherGroup>,
|
|
#[serde(rename = "SessionStart")]
|
|
#[ts(rename = "SessionStart")]
|
|
pub session_start: Vec<ConfiguredHookMatcherGroup>,
|
|
#[serde(rename = "UserPromptSubmit")]
|
|
#[ts(rename = "UserPromptSubmit")]
|
|
pub user_prompt_submit: Vec<ConfiguredHookMatcherGroup>,
|
|
#[serde(rename = "SubagentStart")]
|
|
#[ts(rename = "SubagentStart")]
|
|
pub subagent_start: Vec<ConfiguredHookMatcherGroup>,
|
|
#[serde(rename = "SubagentStop")]
|
|
#[ts(rename = "SubagentStop")]
|
|
pub subagent_stop: Vec<ConfiguredHookMatcherGroup>,
|
|
#[serde(rename = "Stop")]
|
|
#[ts(rename = "Stop")]
|
|
pub stop: Vec<ConfiguredHookMatcherGroup>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConfiguredHookMatcherGroup {
|
|
pub matcher: Option<String>,
|
|
pub hooks: Vec<ConfiguredHookHandler>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(tag = "type")]
|
|
#[ts(tag = "type", export_to = "v2/")]
|
|
pub enum ConfiguredHookHandler {
|
|
#[serde(rename = "command")]
|
|
#[ts(rename = "command")]
|
|
Command {
|
|
command: String,
|
|
#[serde(rename = "commandWindows")]
|
|
#[ts(rename = "commandWindows")]
|
|
command_windows: Option<String>,
|
|
#[serde(rename = "timeoutSec")]
|
|
#[ts(rename = "timeoutSec")]
|
|
timeout_sec: Option<u64>,
|
|
r#async: bool,
|
|
#[serde(rename = "statusMessage")]
|
|
#[ts(rename = "statusMessage")]
|
|
status_message: Option<String>,
|
|
},
|
|
#[serde(rename = "prompt")]
|
|
#[ts(rename = "prompt")]
|
|
Prompt {},
|
|
#[serde(rename = "agent")]
|
|
#[ts(rename = "agent")]
|
|
Agent {},
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct NetworkRequirements {
|
|
pub enabled: Option<bool>,
|
|
pub http_port: Option<u16>,
|
|
pub socks_port: Option<u16>,
|
|
pub allow_upstream_proxy: Option<bool>,
|
|
pub dangerously_allow_non_loopback_proxy: Option<bool>,
|
|
pub dangerously_allow_all_unix_sockets: Option<bool>,
|
|
/// Canonical network permission map for `experimental_network`.
|
|
pub domains: Option<BTreeMap<String, NetworkDomainPermission>>,
|
|
/// When true, only managed allowlist entries are respected while managed
|
|
/// network enforcement is active.
|
|
pub managed_allowed_domains_only: Option<bool>,
|
|
/// Legacy compatibility view derived from `domains`.
|
|
pub allowed_domains: Option<Vec<String>>,
|
|
/// Legacy compatibility view derived from `domains`.
|
|
pub denied_domains: Option<Vec<String>>,
|
|
/// Canonical unix socket permission map for `experimental_network`.
|
|
pub unix_sockets: Option<BTreeMap<String, NetworkUnixSocketPermission>>,
|
|
/// Legacy compatibility view derived from `unix_sockets`.
|
|
pub allow_unix_sockets: Option<Vec<String>>,
|
|
pub allow_local_binding: Option<bool>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "lowercase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum NetworkDomainPermission {
|
|
Allow,
|
|
Deny,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "lowercase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum NetworkUnixSocketPermission {
|
|
Allow,
|
|
Deny,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum ResidencyRequirement {
|
|
Us,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConfigRequirementsReadResponse {
|
|
/// Null if no requirements are configured (e.g. no requirements.toml/MDM entries).
|
|
#[experimental(nested)]
|
|
pub requirements: Option<ConfigRequirements>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, JsonSchema, TS)]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum ExternalAgentConfigMigrationItemType {
|
|
#[serde(rename = "AGENTS_MD")]
|
|
#[ts(rename = "AGENTS_MD")]
|
|
AgentsMd,
|
|
#[serde(rename = "CONFIG")]
|
|
#[ts(rename = "CONFIG")]
|
|
Config,
|
|
#[serde(rename = "SKILLS")]
|
|
#[ts(rename = "SKILLS")]
|
|
Skills,
|
|
#[serde(rename = "PLUGINS")]
|
|
#[ts(rename = "PLUGINS")]
|
|
Plugins,
|
|
#[serde(rename = "MCP_SERVER_CONFIG")]
|
|
#[ts(rename = "MCP_SERVER_CONFIG")]
|
|
McpServerConfig,
|
|
#[serde(rename = "SUBAGENTS")]
|
|
#[ts(rename = "SUBAGENTS")]
|
|
Subagents,
|
|
#[serde(rename = "HOOKS")]
|
|
#[ts(rename = "HOOKS")]
|
|
Hooks,
|
|
#[serde(rename = "COMMANDS")]
|
|
#[ts(rename = "COMMANDS")]
|
|
Commands,
|
|
#[serde(rename = "SESSIONS")]
|
|
#[ts(rename = "SESSIONS")]
|
|
Sessions,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct PluginsMigration {
|
|
#[serde(rename = "marketplaceName")]
|
|
#[ts(rename = "marketplaceName")]
|
|
pub marketplace_name: String,
|
|
#[serde(rename = "pluginNames")]
|
|
#[ts(rename = "pluginNames")]
|
|
pub plugin_names: Vec<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct SessionMigration {
|
|
pub path: PathBuf,
|
|
pub cwd: PathBuf,
|
|
pub title: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct McpServerMigration {
|
|
pub name: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct HookMigration {
|
|
pub name: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct SubagentMigration {
|
|
pub name: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CommandMigration {
|
|
pub name: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct MigrationDetails {
|
|
#[serde(default)]
|
|
pub plugins: Vec<PluginsMigration>,
|
|
#[serde(default)]
|
|
pub sessions: Vec<SessionMigration>,
|
|
#[serde(default)]
|
|
pub mcp_servers: Vec<McpServerMigration>,
|
|
#[serde(default)]
|
|
pub hooks: Vec<HookMigration>,
|
|
#[serde(default)]
|
|
pub subagents: Vec<SubagentMigration>,
|
|
#[serde(default)]
|
|
pub commands: Vec<CommandMigration>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ExternalAgentConfigMigrationItem {
|
|
pub item_type: ExternalAgentConfigMigrationItemType,
|
|
pub description: String,
|
|
/// Null or empty means home-scoped migration; non-empty means repo-scoped migration.
|
|
pub cwd: Option<PathBuf>,
|
|
pub details: Option<MigrationDetails>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ExternalAgentConfigDetectResponse {
|
|
pub items: Vec<ExternalAgentConfigMigrationItem>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ExternalAgentConfigDetectParams {
|
|
/// If true, include detection under the user's home (~/.claude, ~/.codex, etc.).
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub include_home: bool,
|
|
/// Zero or more working directories to include for repo-scoped detection.
|
|
#[ts(optional = nullable)]
|
|
pub cwds: Option<Vec<PathBuf>>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ExternalAgentConfigImportParams {
|
|
pub migration_items: Vec<ExternalAgentConfigMigrationItem>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ExternalAgentConfigImportResponse {}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ExternalAgentConfigImportCompletedNotification {}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConfigValueWriteParams {
|
|
pub key_path: String,
|
|
pub value: JsonValue,
|
|
pub merge_strategy: MergeStrategy,
|
|
/// Path to the config file to write; defaults to the user's `config.toml` when omitted.
|
|
#[ts(optional = nullable)]
|
|
pub file_path: Option<String>,
|
|
#[ts(optional = nullable)]
|
|
pub expected_version: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConfigBatchWriteParams {
|
|
pub edits: Vec<ConfigEdit>,
|
|
/// Path to the config file to write; defaults to the user's `config.toml` when omitted.
|
|
#[ts(optional = nullable)]
|
|
pub file_path: Option<String>,
|
|
#[ts(optional = nullable)]
|
|
pub expected_version: Option<String>,
|
|
/// When true, hot-reload the updated user config into all loaded threads after writing.
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub reload_user_config: bool,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConfigEdit {
|
|
pub key_path: String,
|
|
pub value: JsonValue,
|
|
pub merge_strategy: MergeStrategy,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TextPosition {
|
|
/// 1-based line number.
|
|
pub line: usize,
|
|
/// 1-based column number (in Unicode scalar values).
|
|
pub column: usize,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TextRange {
|
|
pub start: TextPosition,
|
|
pub end: TextPosition,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConfigWarningNotification {
|
|
/// Concise summary of the warning.
|
|
pub summary: String,
|
|
/// Optional extra guidance or error details.
|
|
pub details: Option<String>,
|
|
/// Optional path to the config file that triggered the warning.
|
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
#[ts(optional)]
|
|
pub path: Option<String>,
|
|
/// Optional range for the error location inside the config file.
|
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
#[ts(optional)]
|
|
pub range: Option<TextRange>,
|
|
}
|