@openai/codex 0.19.0 → 0.21.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 +52 -5
- package/bin/codex-aarch64-apple-darwin +0 -0
- package/bin/codex-aarch64-unknown-linux-musl +0 -0
- package/bin/codex-x86_64-apple-darwin +0 -0
- package/bin/codex-x86_64-pc-windows-msvc.exe +0 -0
- package/bin/codex-x86_64-unknown-linux-musl +0 -0
- package/bin/codex.js +105 -136
- package/package.json +2 -71
- package/bin/codex-linux-sandbox-arm64 +0 -0
- package/bin/codex-linux-sandbox-x64 +0 -0
- package/bin/use-native +0 -0
- package/dist/cli.js +0 -1582
- package/dist/cli.js.map +0 -7
package/README.md
CHANGED
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
- [Quickstart](#quickstart)
|
|
19
19
|
- [Installing and running Codex CLI](#installing-and-running-codex-cli)
|
|
20
20
|
- [Using Codex with your ChatGPT plan](#using-codex-with-your-chatgpt-plan)
|
|
21
|
+
- [Connecting on a "Headless" Machine](#connecting-on-a-headless-machine)
|
|
22
|
+
- [Authenticate locally and copy your credentials to the "headless" machine](#authenticate-locally-and-copy-your-credentials-to-the-headless-machine)
|
|
23
|
+
- [Connecting through VPS or remote](#connecting-through-vps-or-remote)
|
|
21
24
|
- [Usage-based billing alternative: Use an OpenAI API key](#usage-based-billing-alternative-use-an-openai-api-key)
|
|
22
25
|
- [Choosing Codex's level of autonomy](#choosing-codexs-level-of-autonomy)
|
|
23
26
|
- [**1. Read/write**](#1-readwrite)
|
|
@@ -98,16 +101,57 @@ Each archive contains a single entry with the platform baked into the name (e.g.
|
|
|
98
101
|
<img src="./.github/codex-cli-login.png" alt="Codex CLI login" width="50%" />
|
|
99
102
|
</p>
|
|
100
103
|
|
|
101
|
-
|
|
104
|
+
Run `codex` and 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
105
|
|
|
103
|
-
> Important: If you've used the Codex CLI before,
|
|
106
|
+
> Important: If you've used the Codex CLI before, follow these steps to migrate from usage-based billing with your API key:
|
|
104
107
|
>
|
|
105
|
-
> 1. Update the CLI
|
|
106
|
-
> 2.
|
|
108
|
+
> 1. Update the CLI and ensure `codex --version` is `0.20.0` or later
|
|
109
|
+
> 2. Delete `~/.codex/auth.json` (this should be `C:\Users\USERNAME\.codex\auth.json` on Windows)
|
|
107
110
|
> 3. Run `codex login` again
|
|
108
111
|
|
|
109
112
|
If you encounter problems with the login flow, please comment on [this issue](https://github.com/openai/codex/issues/1243).
|
|
110
113
|
|
|
114
|
+
### Connecting on a "Headless" Machine
|
|
115
|
+
|
|
116
|
+
Today, the login process entails running a server on `localhost:1455`. If you are on a "headless" server, such as a Docker container or are `ssh`'d into a remote machine, loading `localhost:1455` in the browser on your local machine will not automatically connect to the webserver running on the _headless_ machine, so you must use one of the following workarounds:
|
|
117
|
+
|
|
118
|
+
#### Authenticate locally and copy your credentials to the "headless" machine
|
|
119
|
+
|
|
120
|
+
The easiest solution is likely to run through the `codex login` process on your local machine such that `localhost:1455` _is_ accessible in your web browser. When you complete the authentication process, an `auth.json` file should be available at `$CODEX_HOME/auth.json` (on Mac/Linux, `$CODEX_HOME` defaults to `~/.codex` whereas on Windows, it defaults to `%USERPROFILE%\.codex`).
|
|
121
|
+
|
|
122
|
+
Because the `auth.json` file is not tied to a specific host, once you complete the authentication flow locally, you can copy the `$CODEX_HOME/auth.json` file to the headless machine and then `codex` should "just work" on that machine. Note to copy a file to a Docker container, you can do:
|
|
123
|
+
|
|
124
|
+
```shell
|
|
125
|
+
# substitute MY_CONTAINER with the name or id of your Docker container:
|
|
126
|
+
CONTAINER_HOME=$(docker exec MY_CONTAINER printenv HOME)
|
|
127
|
+
docker exec MY_CONTAINER mkdir -p "$CONTAINER_HOME/.codex"
|
|
128
|
+
docker cp auth.json MY_CONTAINER:"$CONTAINER_HOME/.codex/auth.json"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
whereas if you are `ssh`'d into a remote machine, you likely want to use [`scp`](https://en.wikipedia.org/wiki/Secure_copy_protocol):
|
|
132
|
+
|
|
133
|
+
```shell
|
|
134
|
+
ssh user@remote 'mkdir -p ~/.codex'
|
|
135
|
+
scp ~/.codex/auth.json user@remote:~/.codex/auth.json
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
or try this one-liner:
|
|
139
|
+
|
|
140
|
+
```shell
|
|
141
|
+
ssh user@remote 'mkdir -p ~/.codex && cat > ~/.codex/auth.json' < ~/.codex/auth.json
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### Connecting through VPS or remote
|
|
145
|
+
|
|
146
|
+
If you run Codex on a remote machine (VPS/server) without a local browser, the login helper starts a server on `localhost:1455` on the remote host. To complete login in your local browser, forward that port to your machine before starting the login flow:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# From your local machine
|
|
150
|
+
ssh -L 1455:localhost:1455 <user>@<remote-host>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Then, in that SSH session, run `codex` and select "Sign in with ChatGPT". When prompted, open the printed URL (it will be `http://localhost:1455/...`) in your local browser. The traffic will be tunneled to the remote server.
|
|
154
|
+
|
|
111
155
|
### Usage-based billing alternative: Use an OpenAI API key
|
|
112
156
|
|
|
113
157
|
If you prefer to pay-as-you-go, you can still authenticate with your OpenAI API key by setting it as an environment variable:
|
|
@@ -116,7 +160,10 @@ If you prefer to pay-as-you-go, you can still authenticate with your OpenAI API
|
|
|
116
160
|
export OPENAI_API_KEY="your-api-key-here"
|
|
117
161
|
```
|
|
118
162
|
|
|
119
|
-
|
|
163
|
+
Notes:
|
|
164
|
+
|
|
165
|
+
- 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`).
|
|
166
|
+
- 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.
|
|
120
167
|
|
|
121
168
|
### Choosing Codex's level of autonomy
|
|
122
169
|
|
|
Binary file
|
|
Binary file
|
|
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
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
55
|
+
if (!targetTriple) {
|
|
56
|
+
throw new Error(`Unsupported platform: ${platform} (${arch})`);
|
|
57
|
+
}
|
|
39
58
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
72
|
-
|
|
90
|
+
try {
|
|
91
|
+
child.kill(signal);
|
|
92
|
+
} catch {
|
|
93
|
+
/* ignore */
|
|
73
94
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
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
|
+
|
package/package.json
CHANGED
|
@@ -1,87 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openai/codex",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"bin": {
|
|
6
6
|
"codex": "bin/codex.js"
|
|
7
7
|
},
|
|
8
8
|
"type": "module",
|
|
9
9
|
"engines": {
|
|
10
|
-
"node": ">=
|
|
11
|
-
},
|
|
12
|
-
"scripts": {
|
|
13
|
-
"format": "prettier --check src tests",
|
|
14
|
-
"format:fix": "prettier --write src tests",
|
|
15
|
-
"dev": "tsc --watch",
|
|
16
|
-
"lint": "eslint src tests --ext ts --ext tsx --report-unused-disable-directives --max-warnings 0",
|
|
17
|
-
"lint:fix": "eslint src tests --ext ts --ext tsx --fix",
|
|
18
|
-
"test": "vitest run",
|
|
19
|
-
"test:watch": "vitest --watch",
|
|
20
|
-
"typecheck": "tsc --noEmit",
|
|
21
|
-
"build": "node build.mjs",
|
|
22
|
-
"build:dev": "NODE_ENV=development node build.mjs --dev && NODE_OPTIONS=--enable-source-maps node dist/cli-dev.js",
|
|
23
|
-
"stage-release": "./scripts/stage_release.sh"
|
|
10
|
+
"node": ">=20"
|
|
24
11
|
},
|
|
25
12
|
"files": [
|
|
26
13
|
"bin",
|
|
27
14
|
"dist"
|
|
28
15
|
],
|
|
29
|
-
"dependencies": {
|
|
30
|
-
"@inkjs/ui": "^2.0.0",
|
|
31
|
-
"chalk": "^5.2.0",
|
|
32
|
-
"diff": "^7.0.0",
|
|
33
|
-
"dotenv": "^16.1.4",
|
|
34
|
-
"express": "^5.1.0",
|
|
35
|
-
"fast-deep-equal": "^3.1.3",
|
|
36
|
-
"fast-npm-meta": "^0.4.2",
|
|
37
|
-
"figures": "^6.1.0",
|
|
38
|
-
"file-type": "^20.1.0",
|
|
39
|
-
"https-proxy-agent": "^7.0.6",
|
|
40
|
-
"ink": "^5.2.0",
|
|
41
|
-
"js-yaml": "^4.1.0",
|
|
42
|
-
"marked": "^15.0.7",
|
|
43
|
-
"marked-terminal": "^7.3.0",
|
|
44
|
-
"meow": "^13.2.0",
|
|
45
|
-
"open": "^10.1.0",
|
|
46
|
-
"openai": "^4.95.1",
|
|
47
|
-
"package-manager-detector": "^1.2.0",
|
|
48
|
-
"react": "^18.2.0",
|
|
49
|
-
"shell-quote": "^1.8.2",
|
|
50
|
-
"strip-ansi": "^7.1.0",
|
|
51
|
-
"to-rotated": "^1.0.0",
|
|
52
|
-
"use-interval": "1.4.0",
|
|
53
|
-
"zod": "^3.24.3"
|
|
54
|
-
},
|
|
55
|
-
"devDependencies": {
|
|
56
|
-
"@eslint/js": "^9.22.0",
|
|
57
|
-
"@types/diff": "^7.0.2",
|
|
58
|
-
"@types/express": "^5.0.1",
|
|
59
|
-
"@types/js-yaml": "^4.0.9",
|
|
60
|
-
"@types/marked-terminal": "^6.1.1",
|
|
61
|
-
"@types/react": "^18.0.32",
|
|
62
|
-
"@types/semver": "^7.7.0",
|
|
63
|
-
"@types/shell-quote": "^1.7.5",
|
|
64
|
-
"@types/which": "^3.0.4",
|
|
65
|
-
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
66
|
-
"@typescript-eslint/parser": "^7.18.0",
|
|
67
|
-
"boxen": "^8.0.1",
|
|
68
|
-
"esbuild": "^0.25.2",
|
|
69
|
-
"eslint-plugin-import": "^2.31.0",
|
|
70
|
-
"eslint-plugin-react": "^7.32.2",
|
|
71
|
-
"eslint-plugin-react-hooks": "^4.6.0",
|
|
72
|
-
"eslint-plugin-react-refresh": "^0.4.19",
|
|
73
|
-
"husky": "^9.1.7",
|
|
74
|
-
"ink-testing-library": "^3.0.0",
|
|
75
|
-
"prettier": "^3.5.3",
|
|
76
|
-
"punycode": "^2.3.1",
|
|
77
|
-
"semver": "^7.7.1",
|
|
78
|
-
"ts-node": "^10.9.1",
|
|
79
|
-
"typescript": "^5.0.3",
|
|
80
|
-
"vite": "^6.3.4",
|
|
81
|
-
"vitest": "^3.1.2",
|
|
82
|
-
"whatwg-url": "^14.2.0",
|
|
83
|
-
"which": "^5.0.0"
|
|
84
|
-
},
|
|
85
16
|
"repository": {
|
|
86
17
|
"type": "git",
|
|
87
18
|
"url": "git+https://github.com/openai/codex.git"
|
|
Binary file
|
|
Binary file
|
package/bin/use-native
DELETED
|
File without changes
|