mirror of
https://github.com/openai/codex.git
synced 2026-09-11 20:36:49 +00:00
## Why `--worktree` previously supported only `codex exec` and `codex exec fork`. Interactive sessions need the same managed checkout support, with configuration and policy resolved for the destination before starting a turn. ## What changed - Enable `codex --worktree` and `codex fork --worktree <session-id>` behind the `worktrees` feature, restricted to local sessions. Interactive forks require an explicit session selector. - Resolve interactive and exec worktree forks from the session's latest saved working directory unless `--cd` is supplied. Keep relative `--add-dir` paths anchored to the invocation directory. - Load interactive destination configuration before telemetry and login policy initialization, and bind checkout ownership before the first turn. - Reject explicitly untrusted sources, including when destination cloud policy or refreshed configuration reveals distrust. Retain unbound interactive checkouts after startup failure and report manual recovery instructions. ## Testing Add CLI integration and TUI tests for startup and named forks, destination instructions and configuration, ownership before the first request, trust enforcement, and retained-checkout recovery. Extend exec coverage for saved fork directories, explicit `--cd`, relative writable roots, and cloud policy rejection. GitOrigin-RevId: 371583f7feca73b218a4ff188b2b85812c8439e6
83 lines
3.0 KiB
Rust
83 lines
3.0 KiB
Rust
//! Resolves managed fork sources through the existing name/ID lookup before final configuration.
|
|
//! The temporary app-server never starts a thread or executes a turn.
|
|
|
|
use super::*;
|
|
|
|
pub(super) async fn fork_source(
|
|
args: &mut crate::cli::ForkArgs,
|
|
config: &Config,
|
|
arg0_paths: &Arg0DispatchPaths,
|
|
cli_overrides: &[(String, codex_config::TomlValue)],
|
|
loader_overrides: &LoaderOverrides,
|
|
cloud_config_bundle: CloudConfigBundleLoader,
|
|
strict_config: bool,
|
|
) -> anyhow::Result<std::path::PathBuf> {
|
|
let state_db = codex_core::init_state_db(config).await;
|
|
let environment_manager = EnvironmentManager::from_codex_home(
|
|
config.codex_home.clone(),
|
|
Some(ExecServerRuntimePaths::from_optional_paths(
|
|
arg0_paths.codex_self_exe.clone(),
|
|
arg0_paths.codex_linux_sandbox_exe.clone(),
|
|
)?),
|
|
config.http_client_factory(),
|
|
)
|
|
.await?;
|
|
let client = InProcessAppServerClient::start(InProcessClientStartArgs {
|
|
arg0_paths: arg0_paths.clone(),
|
|
config: std::sync::Arc::new(config.clone()),
|
|
cli_overrides: cli_overrides.to_vec(),
|
|
loader_overrides: LoaderOverrides {
|
|
ignore_project_config: true,
|
|
..loader_overrides.clone()
|
|
},
|
|
strict_config,
|
|
cloud_config_bundle,
|
|
feedback: CodexFeedback::new(),
|
|
log_db: None,
|
|
state_db: state_db.clone(),
|
|
environment_manager: std::sync::Arc::new(environment_manager),
|
|
config_warnings: Vec::new(),
|
|
session_source: SessionSource::Exec,
|
|
enable_codex_api_key_env: true,
|
|
client_name: "codex_exec".to_string(),
|
|
client_version: env!("CARGO_PKG_VERSION").to_string(),
|
|
experimental_api: true,
|
|
mcp_server_openai_form_elicitation: false,
|
|
opt_out_notification_methods: Vec::new(),
|
|
channel_capacity: DEFAULT_IN_PROCESS_CHANNEL_CAPACITY,
|
|
})
|
|
.await?;
|
|
let result = async {
|
|
let lookup = crate::cli::ResumeArgs {
|
|
session_id: Some(args.session_id.clone()),
|
|
last: false,
|
|
all: true,
|
|
images: Vec::new(),
|
|
prompt: None,
|
|
};
|
|
let thread_id = resolve_resume_thread_id(&client, config, state_db.as_ref(), &lookup)
|
|
.await?
|
|
.ok_or_else(|| anyhow::anyhow!("Session not found: {}", args.session_id))?;
|
|
let source: ThreadReadResponse = send_request_with_response(
|
|
&client,
|
|
ClientRequest::ThreadRead {
|
|
request_id: RequestId::Integer(1),
|
|
params: ThreadReadParams {
|
|
thread_id: thread_id.clone(),
|
|
include_turns: false,
|
|
},
|
|
},
|
|
"thread/read",
|
|
)
|
|
.await
|
|
.map_err(anyhow::Error::msg)?;
|
|
args.session_id = thread_id;
|
|
Ok::<_, anyhow::Error>(latest_thread_cwd(&source.thread).await)
|
|
}
|
|
.await;
|
|
let shutdown = client.shutdown().await;
|
|
let source_cwd = result?;
|
|
shutdown?;
|
|
Ok(source_cwd)
|
|
}
|