From 94d5408875d4b4739b8c735463ec6eb7174c184c Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 22 Apr 2025 09:43:10 -0700 Subject: [PATCH 1/5] add instructions for connecting to a visual debugger under Contributing (#496) While here, I also moved the Nix stuff to the end of the **Contributing** section and replaced some examples with `npm` to use `pnpm`. --- README.md | 61 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index ed8d3ff84c..ab4701bf7d 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ - [Contributing](#contributing) - [Development workflow](#development-workflow) - [Git Hooks with Husky](#git-hooks-with-husky) - - [Nix Flake Development](#nix-flake-development) + - [Debugging](#debugging) - [Writing high-impact code changes](#writing-high-impact-code-changes) - [Opening a pull request](#opening-a-pull-request) - [Review process](#review-process) @@ -40,6 +40,8 @@ - [Contributor License Agreement (CLA)](#contributor-license-agreement-cla) - [Quick fixes](#quick-fixes) - [Releasing `codex`](#releasing-codex) + - [Alternative Build Options](#alternative-build-options) + - [Nix Flake Development](#nix-flake-development) - [Security & Responsible AI](#security--responsible-ai) - [License](#license) @@ -433,7 +435,7 @@ This project uses [Husky](https://typicode.github.io/husky/) to enforce code qua These hooks help maintain code quality and prevent pushing code with failing tests. For more details, see [HUSKY.md](./codex-cli/HUSKY.md). ```bash -npm test && npm run lint && npm run typecheck +pnpm test && pnpm run lint && pnpm run typecheck ``` - If you have **not** yet signed the Contributor License Agreement (CLA), add a PR comment containing the exact text @@ -456,30 +458,14 @@ pnpm lint:fix pnpm format:fix ``` -#### Nix Flake Development +### Debugging -Prerequisite: Nix >= 2.4 with flakes enabled (`experimental-features = nix-command flakes` in `~/.config/nix/nix.conf`). +To debug the CLI with a visual debugger, do the following in the `codex-cli` folder: -Enter a Nix development shell: - -```bash -nix develop -``` - -This shell includes Node.js, installs dependencies, builds the CLI, and provides a `codex` command alias. - -Build and run the CLI directly: - -```bash -nix build -./result/bin/codex --help -``` - -Run the CLI via the flake app: - -```bash -nix run .#codex -``` +- Run `pnpm run build` to build the CLI, which will generate `cli.js.map` alongside `cli.js` in the `dist` folder. +- Run the CLI with `node --inspect-brk ./dist/cli.js` The program then waits until a debugger is attached before proceeding. Options: + - In VS Code, choose **Debug: Attach to Node Process** from the command palette and choose the option in the dropdown with debug port `9229` (likely the first option) + - Go to in Chrome and find **localhost:9229** and click **trace** ### Writing high-impact code changes @@ -551,6 +537,33 @@ To publish a new version of the CLI, run the release scripts defined in `codex-c 5. Copy README, build, and publish to npm: `pnpm release` 6. Push to branch: `git push origin HEAD` +### Alternative Build Options + +#### Nix Flake Development + +Prerequisite: Nix >= 2.4 with flakes enabled (`experimental-features = nix-command flakes` in `~/.config/nix/nix.conf`). + +Enter a Nix development shell: + +```bash +nix develop +``` + +This shell includes Node.js, installs dependencies, builds the CLI, and provides a `codex` command alias. + +Build and run the CLI directly: + +```bash +nix build +./result/bin/codex --help +``` + +Run the CLI via the flake app: + +```bash +nix run .#codex +``` + --- ## Security & Responsible AI From fcd1d4bdf9b793eda003aa3675ec64db4de8cd27 Mon Sep 17 00:00:00 2001 From: Naveen Kumar Battula Date: Tue, 22 Apr 2025 22:25:08 +0530 Subject: [PATCH 2/5] feat: show actionable errors when api keys are missing (#523) Change errors on missing api key of other providers from image (missing deepseek key but still throws error for openai) to image This should help new users figure out the issue easier and go to the right place to get api keys OpenAI key missing would popup with the right link image --- codex-cli/src/cli.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/codex-cli/src/cli.tsx b/codex-cli/src/cli.tsx index 6220128f8d..2872cf0cf9 100644 --- a/codex-cli/src/cli.tsx +++ b/codex-cli/src/cli.tsx @@ -258,11 +258,19 @@ if (!apiKey) { // eslint-disable-next-line no-console console.error( `\n${chalk.red(`Missing ${provider} API key.`)}\n\n` + - `Set the environment variable ${chalk.bold("OPENAI_API_KEY")} ` + + `Set the environment variable ${chalk.bold( + `${provider.toUpperCase()}_API_KEY`, + )} ` + `and re-run this command.\n` + - `You can create a key here: ${chalk.bold( - chalk.underline("https://platform.openai.com/account/api-keys"), - )}\n`, + `${ + provider.toLowerCase() === "openai" + ? `You can create a key here: ${chalk.bold( + chalk.underline("https://platform.openai.com/account/api-keys"), + )}\n` + : `You can create a ${chalk.bold( + `${provider.toUpperCase()}_API_KEY`, + )} ` + `in the ${chalk.bold(`${provider}`)} dashboard.\n` + }`, ); process.exit(1); } From 549fc650c312b52960311dea1dd85f84ae06584e Mon Sep 17 00:00:00 2001 From: moppywhip <48742547+moppywhip@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:59:31 -0400 Subject: [PATCH 3/5] fix: remove requirement for api key for ollama (#546) Fixes #540 # Skip API key validation for Ollama provider ## Description This PR modifies the CLI to not require an API key when using Ollama as the provider ## Changes - Modified the validation logic to skip API key checks for these providers - Updated the README to clarify that Ollama doesn't require an API key --- codex-cli/src/cli.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/codex-cli/src/cli.tsx b/codex-cli/src/cli.tsx index 2872cf0cf9..d4982fb161 100644 --- a/codex-cli/src/cli.tsx +++ b/codex-cli/src/cli.tsx @@ -254,7 +254,11 @@ const imagePaths = cli.flags.image; const provider = cli.flags.provider ?? config.provider ?? "openai"; const apiKey = getApiKey(provider); -if (!apiKey) { +// Set of providers that don't require API keys +const NO_API_KEY_REQUIRED = new Set(["ollama"]); + +// Skip API key validation for providers that don't require an API key +if (!apiKey && !NO_API_KEY_REQUIRED.has(provider.toLowerCase())) { // eslint-disable-next-line no-console console.error( `\n${chalk.red(`Missing ${provider} API key.`)}\n\n` + From f99c9080fd751c5ed03a0ae7c9215685d57b22db Mon Sep 17 00:00:00 2001 From: Daniil Davydov <46081038+dan0102dan@users.noreply.github.com> Date: Tue, 22 Apr 2025 22:05:48 +0300 Subject: [PATCH 4/5] fix: support [provider]_BASE_URL (#542) Resolved issue where an OLLAMA_BASE_URL was not properly handled (openai/codex#516). --- codex-cli/src/utils/config.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/codex-cli/src/utils/config.ts b/codex-cli/src/utils/config.ts index 0c9cffa480..91b35956e3 100644 --- a/codex-cli/src/utils/config.ts +++ b/codex-cli/src/utils/config.ts @@ -47,6 +47,13 @@ export function getBaseUrl(provider: string = "openai"): string | undefined { return OPENAI_BASE_URL; } + // Check for a PROVIDER-specific override: e.g. OLLAMA_BASE_URL + const envKey = `${provider.toUpperCase()}_BASE_URL`; + if (process.env[envKey]) { + return process.env[envKey]; + } + + // Use the default URL from providers if available const providerInfo = providers[provider.toLowerCase()]; if (providerInfo) { return providerInfo.baseURL; From 012ad7e69ebcf2d46a4a6ee17f6bac8cc492f624 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 22 Apr 2025 12:56:07 -0700 Subject: [PATCH 5/5] when a shell tool call invokes apply_patch, resolve relative paths against workdir, if specified --- codex-cli/src/approvals.ts | 36 ++++++++++++++++--- .../src/utils/agent/handle-exec-command.ts | 4 +-- codex-cli/tests/approvals.test.ts | 8 ++++- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/codex-cli/src/approvals.ts b/codex-cli/src/approvals.ts index ff37a8903f..e962d548df 100644 --- a/codex-cli/src/approvals.ts +++ b/codex-cli/src/approvals.ts @@ -71,13 +71,14 @@ export type ApprovalPolicy = */ export function canAutoApprove( command: ReadonlyArray, + workdir: string | undefined, policy: ApprovalPolicy, writableRoots: ReadonlyArray, env: NodeJS.ProcessEnv = process.env, ): SafetyAssessment { if (command[0] === "apply_patch") { return command.length === 2 && typeof command[1] === "string" - ? canAutoApproveApplyPatch(command[1], writableRoots, policy) + ? canAutoApproveApplyPatch(command[1], workdir, writableRoots, policy) : { type: "reject", reason: "Invalid apply_patch command", @@ -103,7 +104,12 @@ export function canAutoApprove( ) { const applyPatchArg = tryParseApplyPatch(command[2]); if (applyPatchArg != null) { - return canAutoApproveApplyPatch(applyPatchArg, writableRoots, policy); + return canAutoApproveApplyPatch( + applyPatchArg, + workdir, + writableRoots, + policy, + ); } let bashCmd; @@ -162,6 +168,7 @@ export function canAutoApprove( function canAutoApproveApplyPatch( applyPatchArg: string, + workdir: string | undefined, writableRoots: ReadonlyArray, policy: ApprovalPolicy, ): SafetyAssessment { @@ -179,7 +186,13 @@ function canAutoApproveApplyPatch( break; } - if (isWritePatchConstrainedToWritablePaths(applyPatchArg, writableRoots)) { + if ( + isWritePatchConstrainedToWritablePaths( + applyPatchArg, + workdir, + writableRoots, + ) + ) { return { type: "auto-approve", reason: "apply_patch command is constrained to writable paths", @@ -208,6 +221,7 @@ function canAutoApproveApplyPatch( */ function isWritePatchConstrainedToWritablePaths( applyPatchArg: string, + workdir: string | undefined, writableRoots: ReadonlyArray, ): boolean { // `identify_files_needed()` returns a list of files that will be modified or @@ -222,10 +236,12 @@ function isWritePatchConstrainedToWritablePaths( return ( allPathsConstrainedTowritablePaths( identify_files_needed(applyPatchArg), + workdir, writableRoots, ) && allPathsConstrainedTowritablePaths( identify_files_added(applyPatchArg), + workdir, writableRoots, ) ); @@ -233,19 +249,29 @@ function isWritePatchConstrainedToWritablePaths( function allPathsConstrainedTowritablePaths( candidatePaths: ReadonlyArray, + workdir: string | undefined, writableRoots: ReadonlyArray, ): boolean { return candidatePaths.every((candidatePath) => - isPathConstrainedTowritablePaths(candidatePath, writableRoots), + isPathConstrainedTowritablePaths(candidatePath, workdir, writableRoots), ); } /** If candidatePath is relative, it will be resolved against cwd. */ function isPathConstrainedTowritablePaths( candidatePath: string, + workdir: string | undefined, writableRoots: ReadonlyArray, ): boolean { - const candidateAbsolutePath = path.resolve(candidatePath); + let candidateAbsolutePath: string; + if (path.isAbsolute(candidatePath)) { + candidateAbsolutePath = candidatePath; + } else if (workdir != null) { + candidateAbsolutePath = path.resolve(workdir, candidatePath); + } else { + candidateAbsolutePath = path.resolve(candidatePath); + } + return writableRoots.some((writablePath) => pathContains(writablePath, candidateAbsolutePath), ); diff --git a/codex-cli/src/utils/agent/handle-exec-command.ts b/codex-cli/src/utils/agent/handle-exec-command.ts index aea2c3a707..1932ab9840 100644 --- a/codex-cli/src/utils/agent/handle-exec-command.ts +++ b/codex-cli/src/utils/agent/handle-exec-command.ts @@ -81,7 +81,7 @@ export async function handleExecCommand( ) => Promise, abortSignal?: AbortSignal, ): Promise { - const { cmd: command } = args; + const { cmd: command, workdir } = args; const key = deriveCommandKey(command); @@ -103,7 +103,7 @@ export async function handleExecCommand( // working directory so that edits are constrained to the project root. If // the caller wishes to broaden or restrict the set it can be made // configurable in the future. - const safety = canAutoApprove(command, policy, [process.cwd()]); + const safety = canAutoApprove(command, workdir, policy, [process.cwd()]); let runInSandbox: boolean; switch (safety.type) { diff --git a/codex-cli/tests/approvals.test.ts b/codex-cli/tests/approvals.test.ts index a90abad6eb..94daacce00 100644 --- a/codex-cli/tests/approvals.test.ts +++ b/codex-cli/tests/approvals.test.ts @@ -11,7 +11,13 @@ describe("canAutoApprove()", () => { const writeablePaths: Array = []; const check = (command: ReadonlyArray): SafetyAssessment => - canAutoApprove(command, "suggest", writeablePaths, env); + canAutoApprove( + command, + /* workdir */ undefined, + "suggest", + writeablePaths, + env, + ); test("simple safe commands", () => { expect(check(["ls"])).toEqual({