@openai/codex 0.16.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,11 +1,12 @@
1
1
  <h1 align="center">OpenAI Codex CLI</h1>
2
- <p align="center">Lightweight coding agent that runs in your terminal</p>
3
2
 
4
3
  <p align="center"><code>npm i -g @openai/codex</code><br />or <code>brew install codex</code></p>
5
4
 
6
- This is the home of the **Codex CLI**, which is a coding agent from OpenAI that runs locally on your computer. If you are looking for the _cloud-based agent_ from OpenAI, **Codex [Web]**, see <https://chatgpt.com/codex>.
5
+ <p align="center"><strong>Codex CLI</strong> is a coding agent from OpenAI that runs locally on your computer.</br>If you are looking for the <em>cloud-based agent</em> from OpenAI, <strong>Codex Web</strong>, see <a href="https://chatgpt.com/codex">chatgpt.com/codex</a>.</p>
7
6
 
8
- <!-- ![Codex demo GIF using: codex "explain this codebase to me"](./.github/demo.gif) -->
7
+ <p align="center">
8
+ <img src="./.github/codex-cli-splash.png" alt="Codex CLI splash" width="50%" />
9
+ </p>
9
10
 
10
11
  ---
11
12
 
@@ -14,22 +15,27 @@ This is the home of the **Codex CLI**, which is a coding agent from OpenAI that
14
15
 
15
16
  <!-- Begin ToC -->
16
17
 
17
- - [Experimental technology disclaimer](#experimental-technology-disclaimer)
18
18
  - [Quickstart](#quickstart)
19
- - [OpenAI API Users](#openai-api-users)
20
- - [OpenAI Plus/Pro Users](#openai-pluspro-users)
19
+ - [Installing and running Codex CLI](#installing-and-running-codex-cli)
20
+ - [Using Codex with your ChatGPT plan](#using-codex-with-your-chatgpt-plan)
21
+ - [Usage-based billing alternative: Use an OpenAI API key](#usage-based-billing-alternative-use-an-openai-api-key)
22
+ - [Choosing Codex's level of autonomy](#choosing-codexs-level-of-autonomy)
23
+ - [**1. Read/write**](#1-readwrite)
24
+ - [**2. Read-only**](#2-read-only)
25
+ - [**3. Advanced configuration**](#3-advanced-configuration)
26
+ - [Can I run without ANY approvals?](#can-i-run-without-any-approvals)
27
+ - [Fine-tuning in `config.toml`](#fine-tuning-in-configtoml)
28
+ - [Example prompts](#example-prompts)
29
+ - [Running with a prompt as input](#running-with-a-prompt-as-input)
21
30
  - [Using Open Source Models](#using-open-source-models)
22
- - [Why Codex?](#why-codex)
23
- - [Security model & permissions](#security-model--permissions)
24
31
  - [Platform sandboxing details](#platform-sandboxing-details)
32
+ - [Experimental technology disclaimer](#experimental-technology-disclaimer)
25
33
  - [System requirements](#system-requirements)
26
34
  - [CLI reference](#cli-reference)
27
35
  - [Memory & project docs](#memory--project-docs)
28
36
  - [Non-interactive / CI mode](#non-interactive--ci-mode)
29
37
  - [Model Context Protocol (MCP)](#model-context-protocol-mcp)
30
38
  - [Tracing / verbose logging](#tracing--verbose-logging)
31
- - [Recipes](#recipes)
32
- - [Installation](#installation)
33
39
  - [DotSlash](#dotslash)
34
40
  - [Configuration](#configuration)
35
41
  - [FAQ](#faq)
@@ -54,55 +60,159 @@ This is the home of the **Codex CLI**, which is a coding agent from OpenAI that
54
60
 
55
61
  ---
56
62
 
57
- ## Experimental technology disclaimer
58
-
59
- Codex CLI is an experimental project under active development. It is not yet stable, may contain bugs, incomplete features, or undergo breaking changes. We're building it in the open with the community and welcome:
60
-
61
- - Bug reports
62
- - Feature requests
63
- - Pull requests
64
- - Good vibes
65
-
66
- Help us improve by filing issues or submitting PRs (see the section below for how to contribute)!
67
-
68
63
  ## Quickstart
69
64
 
65
+ ### Installing and running Codex CLI
66
+
70
67
  Install globally with your preferred package manager:
71
68
 
72
69
  ```shell
73
70
  npm install -g @openai/codex # Alternatively: `brew install codex`
74
71
  ```
75
72
 
76
- Or go to the [latest GitHub Release](https://github.com/openai/codex/releases/latest) and download the appropriate binary for your platform.
73
+ Then simply run `codex` to get started:
74
+
75
+ ```shell
76
+ codex
77
+ ```
77
78
 
78
- ### OpenAI API Users
79
+ <details>
80
+ <summary>You can also go to the <a href="https://github.com/openai/codex/releases/latest">latest GitHub Release</a> and download the appropriate binary for your platform.</summary>
79
81
 
80
- Next, set your OpenAI API key as an environment variable:
82
+ Each GitHub Release contains many executables, but in practice, you likely want one of these:
83
+
84
+ - macOS
85
+ - Apple Silicon/arm64: `codex-aarch64-apple-darwin.tar.gz`
86
+ - x86_64 (older Mac hardware): `codex-x86_64-apple-darwin.tar.gz`
87
+ - Linux
88
+ - x86_64: `codex-x86_64-unknown-linux-musl.tar.gz`
89
+ - arm64: `codex-aarch64-unknown-linux-musl.tar.gz`
90
+
91
+ Each archive contains a single entry with the platform baked into the name (e.g., `codex-x86_64-unknown-linux-musl`), so you likely want to rename it to `codex` after extracting it.
92
+
93
+ </details>
94
+
95
+ ### Using Codex with your ChatGPT plan
96
+
97
+ <p align="center">
98
+ <img src="./.github/codex-cli-login.png" alt="Codex CLI login" width="50%" />
99
+ </p>
100
+
101
+ After you run `codex` select Sign in with ChatGPT. You'll need a Plus, Pro, or Team ChatGPT account, and will get access to our latest models, including `gpt-5`, at no extra cost to your plan. (Enterprise is coming soon.)
102
+
103
+ > Important: If you've used the Codex CLI before, you'll need to follow these steps to migrate from usage-based billing with your API key:
104
+ >
105
+ > 1. Update the CLI with `codex update` and ensure `codex --version` is greater than 0.13
106
+ > 2. Ensure that there is no `OPENAI_API_KEY` environment variable set. (Check that `env | grep 'OPENAI_API_KEY'` returns empty)
107
+ > 3. Run `codex login` again
108
+
109
+ If you encounter problems with the login flow, please comment on [this issue](https://github.com/openai/codex/issues/1243).
110
+
111
+ ### Usage-based billing alternative: Use an OpenAI API key
112
+
113
+ If you prefer to pay-as-you-go, you can still authenticate with your OpenAI API key by setting it as an environment variable:
81
114
 
82
115
  ```shell
83
116
  export OPENAI_API_KEY="your-api-key-here"
84
117
  ```
85
118
 
86
- > [!NOTE]
87
- > This command sets the key only for your current terminal session. You can add the `export` line to your shell's configuration file (e.g., `~/.zshrc`), but we recommend setting it for the session.
119
+ Notes:
120
+
121
+ - This command only sets the key for your current terminal session, which we recommend. To set it for all future sessions, you can also add the `export` line to your shell's configuration file (e.g., `~/.zshrc`).
122
+ - If you have signed in with ChatGPT, Codex will default to using your ChatGPT credits. If you wish to use your API key, use the `/logout` command to clear your ChatGPT authentication.
123
+
124
+ ### Choosing Codex's level of autonomy
125
+
126
+ We always recommend running Codex in its default sandbox that gives you strong guardrails around what the agent can do. The default sandbox prevents it from editing files outside its workspace, or from accessing the network.
127
+
128
+ When you launch Codex in a new folder, it detects whether the folder is version controlled and recommends one of two levels of autonomy:
88
129
 
89
- ### OpenAI Plus/Pro Users
130
+ #### **1. Read/write**
90
131
 
91
- If you have a paid OpenAI account, run the following to start the login process:
132
+ - Codex can run commands and write files in the workspace without approval.
133
+ - To write files in other folders, access network, update git or perform other actions protected by the sandbox, Codex will need your permission.
134
+ - By default, the workspace includes the current directory, as well as temporary directories like `/tmp`. You can see what directories are in the workspace with the `/status` command. See the docs for how to customize this behavior.
135
+ - Advanced: You can manually specify this configuration by running `codex --sandbox workspace-write --ask-for-approval on-request`
136
+ - This is the recommended default for version-controlled folders.
92
137
 
138
+ #### **2. Read-only**
139
+
140
+ - Codex can run read-only commands without approval.
141
+ - To edit files, access network, or perform other actions protected by the sandbox, Codex will need your permission.
142
+ - Advanced: You can manually specify this configuration by running `codex --sandbox read-only --ask-for-approval on-request`
143
+ - This is the recommended default non-version-controlled folders.
144
+
145
+ #### **3. Advanced configuration**
146
+
147
+ Codex gives you fine-grained control over the sandbox with the `--sandbox` option, and over when it requests approval with the `--ask-for-approval` option. Run `codex help` for more on these options.
148
+
149
+ #### Can I run without ANY approvals?
150
+
151
+ Yes, run codex non-interactively with `--ask-for-approval never`. This option works with all `--sandbox` options, so you still have full control over Codex's level of autonomy. It will make its best attempt with whatever contrainsts you provide. For example:
152
+
153
+ - Use `codex --ask-for-approval never --sandbox read-only` when you are running many agents to answer questions in parallel in the same workspace.
154
+ - Use `codex --ask-for-approval never --sandbox workspace-write` when you want the agent to non-interactively take time to produce the best outcome, with strong guardrails around its behavior.
155
+ - Use `codex --ask-for-approval never --sandbox danger-full-access` to dangerously give the agent full autonomy. Because this disables important safety mechanisms, we recommend against using this unless running Codex in an isolated environment.
156
+
157
+ #### Fine-tuning in `config.toml`
158
+
159
+ ```toml
160
+ # approval mode
161
+ approval_policy = "untrusted"
162
+ sandbox_mode = "read-only"
163
+
164
+ # full-auto mode
165
+ approval_policy = "on-request"
166
+ sandbox_mode = "workspace-write"
167
+
168
+ # Optional: allow network in workspace-write mode
169
+ [sandbox_workspace_write]
170
+ network_access = true
93
171
  ```
94
- codex login
172
+
173
+ You can also save presets as **profiles**:
174
+
175
+ ```toml
176
+ [profiles.full_auto]
177
+ approval_policy = "on-request"
178
+ sandbox_mode = "workspace-write"
179
+
180
+ [profiles.readonly_quiet]
181
+ approval_policy = "never"
182
+ sandbox_mode = "read-only"
95
183
  ```
96
184
 
97
- If you complete the process successfully, you should have a `~/.codex/auth.json` file that contains the credentials that Codex will use.
185
+ ### Example prompts
186
+
187
+ Below are a few bite-size examples you can copy-paste. Replace the text in quotes with your own task. See the [prompting guide](https://github.com/openai/codex/blob/main/codex-cli/examples/prompting_guide.md) for more tips and usage patterns.
188
+
189
+ | ✨ | What you type | What happens |
190
+ | --- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
191
+ | 1 | `codex "Refactor the Dashboard component to React Hooks"` | Codex rewrites the class component, runs `npm test`, and shows the diff. |
192
+ | 2 | `codex "Generate SQL migrations for adding a users table"` | Infers your ORM, creates migration files, and runs them in a sandboxed DB. |
193
+ | 3 | `codex "Write unit tests for utils/date.ts"` | Generates tests, executes them, and iterates until they pass. |
194
+ | 4 | `codex "Bulk-rename *.jpeg -> *.jpg with git mv"` | Safely renames files and updates imports/usages. |
195
+ | 5 | `codex "Explain what this regex does: ^(?=.*[A-Z]).{8,}$"` | Outputs a step-by-step human explanation. |
196
+ | 6 | `codex "Carefully review this repo, and propose 3 high impact well-scoped PRs"` | Suggests impactful PRs in the current codebase. |
197
+ | 7 | `codex "Look for vulnerabilities and create a security review report"` | Finds and explains security bugs. |
198
+
199
+ ## Running with a prompt as input
98
200
 
99
- To verify whether you are currently logged in, run:
201
+ You can also run Codex CLI with a prompt as input:
100
202
 
203
+ ```shell
204
+ codex "explain this codebase to me"
101
205
  ```
102
- codex login status
206
+
207
+ ```shell
208
+ codex --full-auto "create the fanciest todo-list app"
103
209
  ```
104
210
 
105
- If you encounter problems with the login flow, please comment on <https://github.com/openai/codex/issues/1243>.
211
+ That's it - Codex will scaffold a file, run it inside a sandbox, install any
212
+ missing dependencies, and show you the live result. Approve the changes and
213
+ they'll be committed to your working directory.
214
+
215
+ ## Using Open Source Models
106
216
 
107
217
  <details>
108
218
  <summary><strong>Use <code>--profile</code> to use other models</strong></summary>
@@ -163,31 +273,6 @@ model = "mistral"
163
273
  This way, you can specify one command-line argument (.e.g., `--profile o3`, `--profile mistral`) to override multiple settings together.
164
274
 
165
275
  </details>
166
- <br />
167
-
168
- Run interactively:
169
-
170
- ```shell
171
- codex
172
- ```
173
-
174
- Or, run with a prompt as input (and optionally in `Full Auto` mode):
175
-
176
- ```shell
177
- codex "explain this codebase to me"
178
- ```
179
-
180
- ```shell
181
- codex --full-auto "create the fanciest todo-list app"
182
- ```
183
-
184
- That's it - Codex will scaffold a file, run it inside a sandbox, install any
185
- missing dependencies, and show you the live result. Approve the changes and
186
- they'll be committed to your working directory.
187
-
188
- ---
189
-
190
- ## Using Open Source Models
191
276
 
192
277
  Codex can run fully locally against an OpenAI-compatible OSS host (like Ollama) using the `--oss` flag:
193
278
 
@@ -222,52 +307,27 @@ base_url = "http://my-ollama.example.com:11434/v1"
222
307
 
223
308
  ---
224
309
 
225
- ## Why Codex?
310
+ ### Platform sandboxing details
226
311
 
227
- Codex CLI is built for developers who already **live in the terminal** and want
228
- ChatGPT-level reasoning **plus** the power to actually run code, manipulate
229
- files, and iterate - all under version control. In short, it's _chat-driven
230
- development_ that understands and executes your repo.
312
+ The mechanism Codex uses to implement the sandbox policy depends on your OS:
231
313
 
232
- - **Zero setup** - bring your OpenAI API key and it just works!
233
- - **Full auto-approval, while safe + secure** by running network-disabled and directory-sandboxed
234
- - **Multimodal** - pass in screenshots or diagrams to implement features ✨
314
+ - **macOS 12+** uses **Apple Seatbelt** and runs commands using `sandbox-exec` with a profile (`-p`) that corresponds to the `--sandbox` that was specified.
315
+ - **Linux** uses a combination of Landlock/seccomp APIs to enforce the `sandbox` configuration.
235
316
 
236
- And it's **fully open-source** so you can see and contribute to how it develops!
317
+ Note that when running Linux in a containerized environment such as Docker, sandboxing may not work if the host/container configuration does not support the necessary Landlock/seccomp APIs. In such cases, we recommend configuring your Docker container so that it provides the sandbox guarantees you are looking for and then running `codex` with `--sandbox danger-full-access` (or, more simply, the `--dangerously-bypass-approvals-and-sandbox` flag) within your container.
237
318
 
238
319
  ---
239
320
 
240
- ## Security model & permissions
241
-
242
- Codex lets you decide _how much autonomy_ you want to grant the agent. The following options can be configured independently:
243
-
244
- - [`approval_policy`](./codex-rs/config.md#approval_policy) determines when you should be prompted to approve whether Codex can execute a command
245
- - [`sandbox`](./codex-rs/config.md#sandbox) determines the _sandbox policy_ that Codex uses to execute untrusted commands
246
-
247
- By default, Codex runs with `--ask-for-approval untrusted` and `--sandbox read-only`, which means that:
248
-
249
- - The user is prompted to approve every command not on the set of "trusted" commands built into Codex (`cat`, `ls`, etc.)
250
- - Approved commands are run outside of a sandbox because user approval implies "trust," in this case.
251
-
252
- Running Codex with the `--full-auto` convenience flag changes the configuration to `--ask-for-approval on-failure` and `--sandbox workspace-write`, which means that:
253
-
254
- - Codex does not initially ask for user approval before running an individual command.
255
- - Though when it runs a command, it is run under a sandbox in which:
256
- - It can read any file on the system.
257
- - It can only write files under the current directory (or the directory specified via `--cd`).
258
- - Network requests are completely disabled.
259
- - Only if the command exits with a non-zero exit code will it ask the user for approval. If granted, it will re-attempt the command outside of the sandbox. (A common case is when Codex cannot `npm install` a dependency because that requires network access.)
260
-
261
- Again, these two options can be configured independently. For example, if you want Codex to perform an "exploration" where you are happy for it to read anything it wants but you never want to be prompted, you could run Codex with `--ask-for-approval never` and `--sandbox read-only`.
262
-
263
- ### Platform sandboxing details
321
+ ## Experimental technology disclaimer
264
322
 
265
- The mechanism Codex uses to implement the sandbox policy depends on your OS:
323
+ Codex CLI is an experimental project under active development. It is not yet stable, may contain bugs, incomplete features, or undergo breaking changes. We're building it in the open with the community and welcome:
266
324
 
267
- - **macOS 12+** uses **Apple Seatbelt** and runs commands using `sandbox-exec` with a profile (`-p`) that corresponds to the `--sandbox` that was specified.
268
- - **Linux** uses a combination of Landlock/seccomp APIs to enforce the `sandbox` configuration.
325
+ - Bug reports
326
+ - Feature requests
327
+ - Pull requests
328
+ - Good vibes
269
329
 
270
- Note that when running Linux in a containerized environment such as Docker, sandboxing may not work if the host/container configuration does not support the necessary Landlock/seccomp APIs. In such cases, we recommend configuring your Docker container so that it provides the sandbox guarantees you are looking for and then running `codex` with `--sandbox danger-full-access` (or, more simply, the `--dangerously-bypass-approvals-and-sandbox` flag) within your container.
330
+ Help us improve by filing issues or submitting PRs (see the section below for how to contribute)!
271
331
 
272
332
  ---
273
333
 
@@ -346,52 +406,6 @@ See the Rust documentation on [`RUST_LOG`](https://docs.rs/env_logger/latest/env
346
406
 
347
407
  ---
348
408
 
349
- ## Recipes
350
-
351
- Below are a few bite-size examples you can copy-paste. Replace the text in quotes with your own task. See the [prompting guide](https://github.com/openai/codex/blob/main/codex-cli/examples/prompting_guide.md) for more tips and usage patterns.
352
-
353
- | ✨ | What you type | What happens |
354
- | --- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
355
- | 1 | `codex "Refactor the Dashboard component to React Hooks"` | Codex rewrites the class component, runs `npm test`, and shows the diff. |
356
- | 2 | `codex "Generate SQL migrations for adding a users table"` | Infers your ORM, creates migration files, and runs them in a sandboxed DB. |
357
- | 3 | `codex "Write unit tests for utils/date.ts"` | Generates tests, executes them, and iterates until they pass. |
358
- | 4 | `codex "Bulk-rename *.jpeg -> *.jpg with git mv"` | Safely renames files and updates imports/usages. |
359
- | 5 | `codex "Explain what this regex does: ^(?=.*[A-Z]).{8,}$"` | Outputs a step-by-step human explanation. |
360
- | 6 | `codex "Carefully review this repo, and propose 3 high impact well-scoped PRs"` | Suggests impactful PRs in the current codebase. |
361
- | 7 | `codex "Look for vulnerabilities and create a security review report"` | Finds and explains security bugs. |
362
-
363
- ---
364
-
365
- ## Installation
366
-
367
- <details open>
368
- <summary><strong>Install Codex CLI using your preferred package manager.</strong></summary>
369
-
370
- From `brew` (recommended, downloads only the binary for your platform):
371
-
372
- ```bash
373
- brew install codex
374
- ```
375
-
376
- From `npm` (generally more readily available, but downloads binaries for all supported platforms):
377
-
378
- ```bash
379
- npm i -g @openai/codex
380
- ```
381
-
382
- Or go to the [latest GitHub Release](https://github.com/openai/codex/releases/latest) and download the appropriate binary for your platform.
383
-
384
- Admittedly, each GitHub Release contains many executables, but in practice, you likely want one of these:
385
-
386
- - macOS
387
- - Apple Silicon/arm64: `codex-aarch64-apple-darwin.tar.gz`
388
- - x86_64 (older Mac hardware): `codex-x86_64-apple-darwin.tar.gz`
389
- - Linux
390
- - x86_64: `codex-x86_64-unknown-linux-musl.tar.gz`
391
- - arm64: `codex-aarch64-unknown-linux-musl.tar.gz`
392
-
393
- Each archive contains a single entry with the platform baked into the name (e.g., `codex-x86_64-unknown-linux-musl`), so you likely want to rename it to `codex` after extracting it.
394
-
395
409
  ### DotSlash
396
410
 
397
411
  The GitHub Release also contains a [DotSlash](https://dotslash-cli.com/) file for the Codex CLI named `codex`. Using a DotSlash file makes it possible to make a lightweight commit to source control to ensure all contributors use the same version of an executable, regardless of what platform they use for development.
Binary file
Binary file
Binary file
package/bin/codex.js CHANGED
@@ -1,154 +1,123 @@
1
1
  #!/usr/bin/env node
2
2
  // Unified entry point for the Codex CLI.
3
- /*
4
- * Behavior
5
- * =========
6
- * 1. By default we import the JavaScript implementation located in
7
- * dist/cli.js.
8
- *
9
- * 2. Developers can opt-in to a pre-compiled Rust binary by setting the
10
- * environment variable CODEX_RUST to a truthy value (`1`, `true`, etc.).
11
- * When that variable is present we resolve the correct binary for the
12
- * current platform / architecture and execute it via child_process.
13
- *
14
- * If the CODEX_RUST=1 is specified and there is no native binary for the
15
- * current platform / architecture, an error is thrown.
16
- */
17
3
 
18
- import fs from "fs";
19
4
  import path from "path";
20
- import { fileURLToPath, pathToFileURL } from "url";
21
-
22
- // Determine whether the user explicitly wants the Rust CLI.
5
+ import { fileURLToPath } from "url";
23
6
 
24
7
  // __dirname equivalent in ESM
25
8
  const __filename = fileURLToPath(import.meta.url);
26
9
  const __dirname = path.dirname(__filename);
27
10
 
28
- // For the @native release of the Node module, the `use-native` file is added,
29
- // indicating we should default to the native binary. For other releases,
30
- // setting CODEX_RUST=1 will opt-in to the native binary, if included.
31
- const wantsNative = fs.existsSync(path.join(__dirname, "use-native")) ||
32
- (process.env.CODEX_RUST != null
33
- ? ["1", "true", "yes"].includes(process.env.CODEX_RUST.toLowerCase())
34
- : false);
11
+ const { platform, arch } = process;
12
+
13
+ let targetTriple = null;
14
+ switch (platform) {
15
+ case "linux":
16
+ case "android":
17
+ switch (arch) {
18
+ case "x64":
19
+ targetTriple = "x86_64-unknown-linux-musl";
20
+ break;
21
+ case "arm64":
22
+ targetTriple = "aarch64-unknown-linux-musl";
23
+ break;
24
+ default:
25
+ break;
26
+ }
27
+ break;
28
+ case "darwin":
29
+ switch (arch) {
30
+ case "x64":
31
+ targetTriple = "x86_64-apple-darwin";
32
+ break;
33
+ case "arm64":
34
+ targetTriple = "aarch64-apple-darwin";
35
+ break;
36
+ default:
37
+ break;
38
+ }
39
+ break;
40
+ case "win32":
41
+ switch (arch) {
42
+ case "x64":
43
+ targetTriple = "x86_64-pc-windows-msvc.exe";
44
+ break;
45
+ case "arm64":
46
+ // We do not build this today, fall through...
47
+ default:
48
+ break;
49
+ }
50
+ break;
51
+ default:
52
+ break;
53
+ }
35
54
 
36
- // Try native binary if requested.
37
- if (wantsNative && process.platform !== 'win32') {
38
- const { platform, arch } = process;
55
+ if (!targetTriple) {
56
+ throw new Error(`Unsupported platform: ${platform} (${arch})`);
57
+ }
39
58
 
40
- let targetTriple = null;
41
- switch (platform) {
42
- case "linux":
43
- case "android":
44
- switch (arch) {
45
- case "x64":
46
- targetTriple = "x86_64-unknown-linux-musl";
47
- break;
48
- case "arm64":
49
- targetTriple = "aarch64-unknown-linux-musl";
50
- break;
51
- default:
52
- break;
53
- }
54
- break;
55
- case "darwin":
56
- switch (arch) {
57
- case "x64":
58
- targetTriple = "x86_64-apple-darwin";
59
- break;
60
- case "arm64":
61
- targetTriple = "aarch64-apple-darwin";
62
- break;
63
- default:
64
- break;
65
- }
66
- break;
67
- default:
68
- break;
59
+ const binaryPath = path.join(__dirname, "..", "bin", `codex-${targetTriple}`);
60
+
61
+ // Use an asynchronous spawn instead of spawnSync so that Node is able to
62
+ // respond to signals (e.g. Ctrl-C / SIGINT) while the native binary is
63
+ // executing. This allows us to forward those signals to the child process
64
+ // and guarantees that when either the child terminates or the parent
65
+ // receives a fatal signal, both processes exit in a predictable manner.
66
+ const { spawn } = await import("child_process");
67
+
68
+ const child = spawn(binaryPath, process.argv.slice(2), {
69
+ stdio: "inherit",
70
+ env: { ...process.env, CODEX_MANAGED_BY_NPM: "1" },
71
+ });
72
+
73
+ child.on("error", (err) => {
74
+ // Typically triggered when the binary is missing or not executable.
75
+ // Re-throwing here will terminate the parent with a non-zero exit code
76
+ // while still printing a helpful stack trace.
77
+ // eslint-disable-next-line no-console
78
+ console.error(err);
79
+ process.exit(1);
80
+ });
81
+
82
+ // Forward common termination signals to the child so that it shuts down
83
+ // gracefully. In the handler we temporarily disable the default behavior of
84
+ // exiting immediately; once the child has been signaled we simply wait for
85
+ // its exit event which will in turn terminate the parent (see below).
86
+ const forwardSignal = (signal) => {
87
+ if (child.killed) {
88
+ return;
69
89
  }
70
-
71
- if (!targetTriple) {
72
- throw new Error(`Unsupported platform: ${platform} (${arch})`);
90
+ try {
91
+ child.kill(signal);
92
+ } catch {
93
+ /* ignore */
73
94
  }
74
-
75
- const binaryPath = path.join(__dirname, "..", "bin", `codex-${targetTriple}`);
76
-
77
- // Use an asynchronous spawn instead of spawnSync so that Node is able to
78
- // respond to signals (e.g. Ctrl-C / SIGINT) while the native binary is
79
- // executing. This allows us to forward those signals to the child process
80
- // and guarantees that when either the child terminates or the parent
81
- // receives a fatal signal, both processes exit in a predictable manner.
82
- const { spawn } = await import("child_process");
83
-
84
- const child = spawn(binaryPath, process.argv.slice(2), {
85
- stdio: "inherit",
86
- env: { ...process.env, CODEX_MANAGED_BY_NPM: "1" },
87
- });
88
-
89
- child.on("error", (err) => {
90
- // Typically triggered when the binary is missing or not executable.
91
- // Re-throwing here will terminate the parent with a non-zero exit code
92
- // while still printing a helpful stack trace.
93
- // eslint-disable-next-line no-console
94
- console.error(err);
95
- process.exit(1);
96
- });
97
-
98
- // Forward common termination signals to the child so that it shuts down
99
- // gracefully. In the handler we temporarily disable the default behavior of
100
- // exiting immediately; once the child has been signaled we simply wait for
101
- // its exit event which will in turn terminate the parent (see below).
102
- const forwardSignal = (signal) => {
103
- if (child.killed) {
104
- return;
105
- }
106
- try {
107
- child.kill(signal);
108
- } catch {
109
- /* ignore */
95
+ };
96
+
97
+ ["SIGINT", "SIGTERM", "SIGHUP"].forEach((sig) => {
98
+ process.on(sig, () => forwardSignal(sig));
99
+ });
100
+
101
+ // When the child exits, mirror its termination reason in the parent so that
102
+ // shell scripts and other tooling observe the correct exit status.
103
+ // Wrap the lifetime of the child process in a Promise so that we can await
104
+ // its termination in a structured way. The Promise resolves with an object
105
+ // describing how the child exited: either via exit code or due to a signal.
106
+ const childResult = await new Promise((resolve) => {
107
+ child.on("exit", (code, signal) => {
108
+ if (signal) {
109
+ resolve({ type: "signal", signal });
110
+ } else {
111
+ resolve({ type: "code", exitCode: code ?? 1 });
110
112
  }
111
- };
112
-
113
- ["SIGINT", "SIGTERM", "SIGHUP"].forEach((sig) => {
114
- process.on(sig, () => forwardSignal(sig));
115
- });
116
-
117
- // When the child exits, mirror its termination reason in the parent so that
118
- // shell scripts and other tooling observe the correct exit status.
119
- // Wrap the lifetime of the child process in a Promise so that we can await
120
- // its termination in a structured way. The Promise resolves with an object
121
- // describing how the child exited: either via exit code or due to a signal.
122
- const childResult = await new Promise((resolve) => {
123
- child.on("exit", (code, signal) => {
124
- if (signal) {
125
- resolve({ type: "signal", signal });
126
- } else {
127
- resolve({ type: "code", exitCode: code ?? 1 });
128
- }
129
- });
130
113
  });
114
+ });
131
115
 
132
- if (childResult.type === "signal") {
133
- // Re-emit the same signal so that the parent terminates with the expected
134
- // semantics (this also sets the correct exit code of 128 + n).
135
- process.kill(process.pid, childResult.signal);
136
- } else {
137
- process.exit(childResult.exitCode);
138
- }
116
+ if (childResult.type === "signal") {
117
+ // Re-emit the same signal so that the parent terminates with the expected
118
+ // semantics (this also sets the correct exit code of 128 + n).
119
+ process.kill(process.pid, childResult.signal);
139
120
  } else {
140
- // Fallback: execute the original JavaScript CLI.
141
-
142
- // Resolve the path to the compiled CLI bundle
143
- const cliPath = path.resolve(__dirname, "../dist/cli.js");
144
- const cliUrl = pathToFileURL(cliPath).href;
145
-
146
- // Load and execute the CLI
147
- try {
148
- await import(cliUrl);
149
- } catch (err) {
150
- // eslint-disable-next-line no-console
151
- console.error(err);
152
- process.exit(1);
153
- }
121
+ process.exit(childResult.exitCode);
154
122
  }
123
+