mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
## Why The v2 app-server permission profile fields are experimental, but the previous migration kept a legacy object payload for profile selection. That made clients aware of server-owned `activePermissionProfile` metadata such as `extends`, and it kept a `legacy_additional_writable_roots` path even though `runtimeWorkspaceRoots` now owns runtime workspace-root selection. This PR makes the client contract match the intended model: clients select a permission profile by id, and the server resolves and reports active profile provenance in response payloads. Follow-up to #22611. ## What Changed - Changed `thread/start`, `thread/resume`, `thread/fork`, and `turn/start` permission profile selection to plain profile id strings. - Changed `command/exec.permissionProfile` to a plain profile id string for the same client/server ownership split. - Removed `PermissionProfileSelectionParams` and the legacy `{ type: "profile", modifications: [...] }` compatibility deserializer. - Updated app-server, TUI, and `codex exec` call sites to send only ids, while keeping `activePermissionProfile` as server response metadata. - Updated app-server docs and schema fixtures for the revised `command/exec.permissionProfile` shape. ## Verification - `cargo test -p codex-app-server-protocol` - `RUST_MIN_STACK=8388608 cargo test -p codex-app-server` - `cargo test -p codex-exec` - `RUST_MIN_STACK=8388608 cargo test -p codex-tui` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23360). * #23368 * __->__ #23360
214 lines
8.2 KiB
Rust
214 lines
8.2 KiB
Rust
use super::SandboxPolicy;
|
|
use codex_experimental_api_macros::ExperimentalApi;
|
|
use schemars::JsonSchema;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use std::collections::HashMap;
|
|
use std::path::PathBuf;
|
|
use ts_rs::TS;
|
|
|
|
/// PTY size in character cells for `command/exec` PTY sessions.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CommandExecTerminalSize {
|
|
/// Terminal height in character cells.
|
|
pub rows: u16,
|
|
/// Terminal width in character cells.
|
|
pub cols: u16,
|
|
}
|
|
|
|
/// Run a standalone command (argv vector) in the server sandbox without
|
|
/// creating a thread or turn.
|
|
///
|
|
/// The final `command/exec` response is deferred until the process exits and is
|
|
/// sent only after all `command/exec/outputDelta` notifications for that
|
|
/// connection have been emitted.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CommandExecParams {
|
|
/// Command argv vector. Empty arrays are rejected.
|
|
pub command: Vec<String>,
|
|
/// Optional client-supplied, connection-scoped process id.
|
|
///
|
|
/// Required for `tty`, `streamStdin`, `streamStdoutStderr`, and follow-up
|
|
/// `command/exec/write`, `command/exec/resize`, and
|
|
/// `command/exec/terminate` calls. When omitted, buffered execution gets an
|
|
/// internal id that is not exposed to the client.
|
|
#[ts(optional = nullable)]
|
|
pub process_id: Option<String>,
|
|
/// Enable PTY mode.
|
|
///
|
|
/// This implies `streamStdin` and `streamStdoutStderr`.
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub tty: bool,
|
|
/// Allow follow-up `command/exec/write` requests to write stdin bytes.
|
|
///
|
|
/// Requires a client-supplied `processId`.
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub stream_stdin: bool,
|
|
/// Stream stdout/stderr via `command/exec/outputDelta` notifications.
|
|
///
|
|
/// Streamed bytes are not duplicated into the final response and require a
|
|
/// client-supplied `processId`.
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub stream_stdout_stderr: bool,
|
|
/// Optional per-stream stdout/stderr capture cap in bytes.
|
|
///
|
|
/// When omitted, the server default applies. Cannot be combined with
|
|
/// `disableOutputCap`.
|
|
#[ts(type = "number | null")]
|
|
#[ts(optional = nullable)]
|
|
pub output_bytes_cap: Option<usize>,
|
|
/// Disable stdout/stderr capture truncation for this request.
|
|
///
|
|
/// Cannot be combined with `outputBytesCap`.
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub disable_output_cap: bool,
|
|
/// Disable the timeout entirely for this request.
|
|
///
|
|
/// Cannot be combined with `timeoutMs`.
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub disable_timeout: bool,
|
|
/// Optional timeout in milliseconds.
|
|
///
|
|
/// When omitted, the server default applies. Cannot be combined with
|
|
/// `disableTimeout`.
|
|
#[ts(type = "number | null")]
|
|
#[ts(optional = nullable)]
|
|
pub timeout_ms: Option<i64>,
|
|
/// Optional working directory. Defaults to the server cwd.
|
|
#[ts(optional = nullable)]
|
|
pub cwd: Option<PathBuf>,
|
|
/// Optional environment overrides merged into the server-computed
|
|
/// environment.
|
|
///
|
|
/// Matching names override inherited values. Set a key to `null` to unset
|
|
/// an inherited variable.
|
|
#[ts(optional = nullable)]
|
|
pub env: Option<HashMap<String, Option<String>>>,
|
|
/// Optional initial PTY size in character cells. Only valid when `tty` is
|
|
/// true.
|
|
#[ts(optional = nullable)]
|
|
pub size: Option<CommandExecTerminalSize>,
|
|
/// Optional sandbox policy for this command.
|
|
///
|
|
/// Uses the same shape as thread/turn execution sandbox configuration and
|
|
/// defaults to the user's configured policy when omitted. Cannot be
|
|
/// combined with `permissionProfile`.
|
|
#[ts(optional = nullable)]
|
|
pub sandbox_policy: Option<SandboxPolicy>,
|
|
/// Optional active permissions profile id for this command.
|
|
///
|
|
/// Defaults to the user's configured permissions when omitted. Cannot be
|
|
/// combined with `sandboxPolicy`.
|
|
#[experimental("command/exec.permissionProfile")]
|
|
#[ts(optional = nullable)]
|
|
pub permission_profile: Option<String>,
|
|
}
|
|
|
|
/// Final buffered result for `command/exec`.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CommandExecResponse {
|
|
/// Process exit code.
|
|
pub exit_code: i32,
|
|
/// Buffered stdout capture.
|
|
///
|
|
/// Empty when stdout was streamed via `command/exec/outputDelta`.
|
|
pub stdout: String,
|
|
/// Buffered stderr capture.
|
|
///
|
|
/// Empty when stderr was streamed via `command/exec/outputDelta`.
|
|
pub stderr: String,
|
|
}
|
|
|
|
/// Write stdin bytes to a running `command/exec` session, close stdin, or
|
|
/// both.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CommandExecWriteParams {
|
|
/// Client-supplied, connection-scoped `processId` from the original
|
|
/// `command/exec` request.
|
|
pub process_id: String,
|
|
/// Optional base64-encoded stdin bytes to write.
|
|
#[ts(optional = nullable)]
|
|
pub delta_base64: Option<String>,
|
|
/// Close stdin after writing `deltaBase64`, if present.
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub close_stdin: bool,
|
|
}
|
|
|
|
/// Empty success response for `command/exec/write`.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CommandExecWriteResponse {}
|
|
|
|
/// Terminate a running `command/exec` session.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CommandExecTerminateParams {
|
|
/// Client-supplied, connection-scoped `processId` from the original
|
|
/// `command/exec` request.
|
|
pub process_id: String,
|
|
}
|
|
|
|
/// Empty success response for `command/exec/terminate`.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CommandExecTerminateResponse {}
|
|
|
|
/// Resize a running PTY-backed `command/exec` session.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CommandExecResizeParams {
|
|
/// Client-supplied, connection-scoped `processId` from the original
|
|
/// `command/exec` request.
|
|
pub process_id: String,
|
|
/// New PTY size in character cells.
|
|
pub size: CommandExecTerminalSize,
|
|
}
|
|
|
|
/// Empty success response for `command/exec/resize`.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CommandExecResizeResponse {}
|
|
|
|
/// Stream label for `command/exec/outputDelta` notifications.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum CommandExecOutputStream {
|
|
/// stdout stream. PTY mode multiplexes terminal output here.
|
|
Stdout,
|
|
/// stderr stream.
|
|
Stderr,
|
|
}
|
|
/// Base64-encoded output chunk emitted for a streaming `command/exec` request.
|
|
///
|
|
/// These notifications are connection-scoped. If the originating connection
|
|
/// closes, the server terminates the process.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CommandExecOutputDeltaNotification {
|
|
/// Client-supplied, connection-scoped `processId` from the original
|
|
/// `command/exec` request.
|
|
pub process_id: String,
|
|
/// Output stream for this chunk.
|
|
pub stream: CommandExecOutputStream,
|
|
/// Base64-encoded output bytes.
|
|
pub delta_base64: String,
|
|
/// `true` on the final streamed chunk for a stream when `outputBytesCap`
|
|
/// truncated later output on that stream.
|
|
pub cap_reached: bool,
|
|
}
|