mirror of
https://github.com/openai/codex.git
synced 2026-02-01 22:47:52 +00:00
feat: Add support for --add-dir to exec and TypeScript SDK (#6565)
## Summary Adds support for specifying additional directories in the TypeScript SDK through a new `additionalDirectories` option in `ThreadOptions`. ## Changes - Added `additionalDirectories` parameter to `ThreadOptions` interface - Updated `CodexExec` to accept and pass through additional directories via the `--config` flag for `sandbox_workspace_write.writable_roots` - Added comprehensive test coverage for the new functionality ## Test plan - Added test case that verifies `additionalDirectories` is correctly passed as repeated flags - Existing tests continue to pass --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -52,6 +52,10 @@ pub struct Cli {
|
||||
#[arg(long = "skip-git-repo-check", default_value_t = false)]
|
||||
pub skip_git_repo_check: bool,
|
||||
|
||||
/// Additional directories that should be writable alongside the primary workspace.
|
||||
#[arg(long = "add-dir", value_name = "DIR", value_hint = clap::ValueHint::DirPath)]
|
||||
pub add_dir: Vec<PathBuf>,
|
||||
|
||||
/// Path to a JSON Schema file describing the model's final response shape.
|
||||
#[arg(long = "output-schema", value_name = "FILE")]
|
||||
pub output_schema: Option<PathBuf>,
|
||||
|
||||
@@ -62,6 +62,7 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> any
|
||||
dangerously_bypass_approvals_and_sandbox,
|
||||
cwd,
|
||||
skip_git_repo_check,
|
||||
add_dir,
|
||||
color,
|
||||
last_message_file,
|
||||
json: json_mode,
|
||||
@@ -180,7 +181,7 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> any
|
||||
show_raw_agent_reasoning: oss.then_some(true),
|
||||
tools_web_search_request: None,
|
||||
experimental_sandbox_command_assessment: None,
|
||||
additional_writable_roots: Vec::new(),
|
||||
additional_writable_roots: add_dir,
|
||||
};
|
||||
// Parse `-c` overrides.
|
||||
let cli_kv_overrides = match config_overrides.parse_overrides() {
|
||||
|
||||
72
codex-rs/exec/tests/suite/add_dir.rs
Normal file
72
codex-rs/exec/tests/suite/add_dir.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
#![cfg(not(target_os = "windows"))]
|
||||
#![allow(clippy::expect_used, clippy::unwrap_used)]
|
||||
|
||||
use core_test_support::responses;
|
||||
use core_test_support::test_codex_exec::test_codex_exec;
|
||||
|
||||
/// Verify that the --add-dir flag is accepted and the command runs successfully.
|
||||
/// This test confirms the CLI argument is properly wired up.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn accepts_add_dir_flag() -> anyhow::Result<()> {
|
||||
let test = test_codex_exec();
|
||||
|
||||
let server = responses::start_mock_server().await;
|
||||
let body = responses::sse(vec![
|
||||
responses::ev_response_created("response_1"),
|
||||
responses::ev_assistant_message("response_1", "Task completed"),
|
||||
responses::ev_completed("response_1"),
|
||||
]);
|
||||
responses::mount_sse_once(&server, body).await;
|
||||
|
||||
// Create temporary directories to use with --add-dir
|
||||
let temp_dir1 = tempfile::tempdir()?;
|
||||
let temp_dir2 = tempfile::tempdir()?;
|
||||
|
||||
test.cmd_with_server(&server)
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("--sandbox")
|
||||
.arg("workspace-write")
|
||||
.arg("--add-dir")
|
||||
.arg(temp_dir1.path())
|
||||
.arg("--add-dir")
|
||||
.arg(temp_dir2.path())
|
||||
.arg("test with additional directories")
|
||||
.assert()
|
||||
.code(0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify that multiple --add-dir flags can be specified.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn accepts_multiple_add_dir_flags() -> anyhow::Result<()> {
|
||||
let test = test_codex_exec();
|
||||
|
||||
let server = responses::start_mock_server().await;
|
||||
let body = responses::sse(vec![
|
||||
responses::ev_response_created("response_1"),
|
||||
responses::ev_assistant_message("response_1", "Multiple directories accepted"),
|
||||
responses::ev_completed("response_1"),
|
||||
]);
|
||||
responses::mount_sse_once(&server, body).await;
|
||||
|
||||
let temp_dir1 = tempfile::tempdir()?;
|
||||
let temp_dir2 = tempfile::tempdir()?;
|
||||
let temp_dir3 = tempfile::tempdir()?;
|
||||
|
||||
test.cmd_with_server(&server)
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("--sandbox")
|
||||
.arg("workspace-write")
|
||||
.arg("--add-dir")
|
||||
.arg(temp_dir1.path())
|
||||
.arg("--add-dir")
|
||||
.arg(temp_dir2.path())
|
||||
.arg("--add-dir")
|
||||
.arg(temp_dir3.path())
|
||||
.arg("test with three directories")
|
||||
.assert()
|
||||
.code(0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
// Aggregates all former standalone integration tests as modules.
|
||||
mod add_dir;
|
||||
mod apply_patch;
|
||||
mod auth_env;
|
||||
mod originator;
|
||||
|
||||
@@ -18,6 +18,8 @@ export type CodexExecArgs = {
|
||||
sandboxMode?: SandboxMode;
|
||||
// --cd
|
||||
workingDirectory?: string;
|
||||
// --add-dir
|
||||
additionalDirectories?: string[];
|
||||
// --skip-git-repo-check
|
||||
skipGitRepoCheck?: boolean;
|
||||
// --output-schema
|
||||
@@ -58,6 +60,12 @@ export class CodexExec {
|
||||
commandArgs.push("--cd", args.workingDirectory);
|
||||
}
|
||||
|
||||
if (args.additionalDirectories?.length) {
|
||||
for (const dir of args.additionalDirectories) {
|
||||
commandArgs.push("--add-dir", dir);
|
||||
}
|
||||
}
|
||||
|
||||
if (args.skipGitRepoCheck) {
|
||||
commandArgs.push("--skip-git-repo-check");
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ export class Thread {
|
||||
networkAccessEnabled: options?.networkAccessEnabled,
|
||||
webSearchEnabled: options?.webSearchEnabled,
|
||||
approvalPolicy: options?.approvalPolicy,
|
||||
additionalDirectories: options?.additionalDirectories,
|
||||
});
|
||||
try {
|
||||
for await (const item of generator) {
|
||||
|
||||
@@ -13,4 +13,5 @@ export type ThreadOptions = {
|
||||
networkAccessEnabled?: boolean;
|
||||
webSearchEnabled?: boolean;
|
||||
approvalPolicy?: ApprovalMode;
|
||||
additionalDirectories?: string[];
|
||||
};
|
||||
|
||||
@@ -348,6 +348,48 @@ describe("Codex", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("passes additionalDirectories as repeated flags", async () => {
|
||||
const { url, close } = await startResponsesTestProxy({
|
||||
statusCode: 200,
|
||||
responseBodies: [
|
||||
sse(
|
||||
responseStarted("response_1"),
|
||||
assistantMessage("Additional directories applied", "item_1"),
|
||||
responseCompleted("response_1"),
|
||||
),
|
||||
],
|
||||
});
|
||||
|
||||
const { args: spawnArgs, restore } = codexExecSpy();
|
||||
|
||||
try {
|
||||
const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
|
||||
|
||||
const thread = client.startThread({
|
||||
additionalDirectories: ["../backend", "/tmp/shared"],
|
||||
});
|
||||
await thread.run("test additional dirs");
|
||||
|
||||
const commandArgs = spawnArgs[0];
|
||||
expect(commandArgs).toBeDefined();
|
||||
if (!commandArgs) {
|
||||
throw new Error("Command args missing");
|
||||
}
|
||||
|
||||
// Find the --add-dir flags
|
||||
const addDirArgs: string[] = [];
|
||||
for (let i = 0; i < commandArgs.length; i += 1) {
|
||||
if (commandArgs[i] === "--add-dir") {
|
||||
addDirArgs.push(commandArgs[i + 1] ?? "");
|
||||
}
|
||||
}
|
||||
expect(addDirArgs).toEqual(["../backend", "/tmp/shared"]);
|
||||
} finally {
|
||||
restore();
|
||||
await close();
|
||||
}
|
||||
});
|
||||
|
||||
it("writes output schema to a temporary file and forwards it", async () => {
|
||||
const { url, close, requests } = await startResponsesTestProxy({
|
||||
statusCode: 200,
|
||||
|
||||
Reference in New Issue
Block a user