@codexapi/codexclaude 2.0.36 → 2.0.39
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/CUSTOMIZATIONS.md +13 -11
- package/README.md +11 -8
- package/bin/codexclaude.js +108 -74
- package/bin/splash.js +36 -0
- package/bin/update.js +94 -0
- package/codexclaude.md +82 -12
- package/package.json +4 -3
package/CUSTOMIZATIONS.md
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
## Runtime
|
|
6
6
|
|
|
7
7
|
- Customer-facing app name: `MagnetAPI.org Codex CLI`
|
|
8
|
-
- Local launcher version: `2.0.
|
|
9
|
-
- Bundled official runtime dependency: `@openai/codex@0.
|
|
8
|
+
- Local launcher version: `2.0.39`
|
|
9
|
+
- Bundled official runtime dependency: `@openai/codex@0.154.0`
|
|
10
10
|
- Required install command: `npm install -g @codexapi/codexclaude@latest`
|
|
11
|
-
- Hosted fallback: `
|
|
11
|
+
- Hosted fallback archive: `https://codexapi.pro/downloads/codexapi-codexclaude-2.0.39.tgz`, with its SHA-256 sidecar. The updater installs a verified local copy, not an npm remote URL.
|
|
12
12
|
- Bundled runtime version is managed internally and must not be used for customer update prompts.
|
|
13
13
|
- Launcher update checks may call the CodexAPI.pro version endpoint and `@codexapi/codexclaude` npm metadata only.
|
|
14
14
|
- The launcher must never check `@openai/codex` npm metadata or OpenAI GitHub releases for update notices.
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
- Passes unknown commands directly to the bundled runtime after config is applied.
|
|
26
26
|
- Provides `codexclaude changelog` using the managed version endpoint.
|
|
27
27
|
- Does not expose separate `codexclaude status` or `codexclaude usage` commands; wallet information remains a compact pre-launch line.
|
|
28
|
-
-
|
|
29
|
-
- Mandatory updates present a press-Enter `Upgrade Now` action
|
|
28
|
+
- The backend minimum controls enforcement. Never require an unpublished or unverified archive.
|
|
29
|
+
- Mandatory updates present a press-Enter `Upgrade Now` action, install the exact managed version through npm-cli.js on Windows, verify npm's actual global package, fall back to a checksum-verified local archive and relaunch its verified entrypoint through Node. Do not weaken npm policies or rely on stale PATH aliases.
|
|
30
30
|
- The npm package manifest exposes only `codexclaude`, preventing npm from colliding with a native `codex` or `claude` command before postinstall runs.
|
|
31
31
|
- Global installation creates optional `codex` and `claude` aliases only when no existing command is present in the npm prefix or anywhere on `PATH`; native clients must never be overwritten.
|
|
32
32
|
- `codexclaude topup` and `codexclaude /topup` authenticate with the saved System Token, map the six fixed packages to the correct site-specific plan ids, and call only `/api/v1/wallet/stripe/checkout` and `/api/v1/wallet/stripe/confirm`.
|
|
@@ -48,17 +48,17 @@ The launcher writes a model provider named `codexapi`:
|
|
|
48
48
|
## Runtime Defaults
|
|
49
49
|
|
|
50
50
|
- Default model: `gpt-5.6-sol` displayed as `GPT-5.6 SOL`
|
|
51
|
-
-
|
|
51
|
+
- Picker order: `gpt-6-astra`, `claude-fable-5` (Fable 5.1), `claude-opus-5`, followed by current GPT-5.6, Daybreak and Sonnet variants. GPT-5.5 and Opus 4.8 are hidden compatibility entries, not deleted API identities. Numeric choices are derived from visible order, never stored as stale aliases.
|
|
52
52
|
- Default reasoning effort displayed locally: `Extra High`, stored as `xhigh`; SOL Max and SOL Ultra retain their explicit premium labels.
|
|
53
53
|
- Reasoning hint written to managed runtime config: model-specific
|
|
54
54
|
- Approval policy: `never`
|
|
55
55
|
- Sandbox mode: `danger-full-access`
|
|
56
56
|
- Display wording for permissions: `Full Access` in launcher-owned copy
|
|
57
|
-
- Local model catalog: `~/.codexclaude/model_catalog.json`; this keeps the native `/model` picker limited to the supported choices and prevents fallback metadata warnings for ChatGPT Daybreak Blue, GPT-5.6 Terra, SOL, SOL Max, SOL Ultra, Opus 5, Opus 4.8, Sonnet 5, and Fable 5.
|
|
57
|
+
- Local model catalog: `~/.codexclaude/model_catalog.json`; this keeps the native `/model` picker limited to the supported choices and prevents fallback metadata warnings for ChatGPT-6 Astra, ChatGPT Daybreak Blue, GPT-5.6 Terra, SOL, SOL Max, SOL Ultra, Opus 5, Opus 4.8, Sonnet 5, and Fable 5.
|
|
58
58
|
- Service tier: omitted by default; `/fast` remains user-controlled and billed server-side when active.
|
|
59
59
|
- TUI status line: `model-with-reasoning`, `fast-mode`, `current-dir`
|
|
60
60
|
- Fable 5 stays visible to the user while the backend applies its server-managed route and billing policy.
|
|
61
|
-
- Premium model billing remains server-managed
|
|
61
|
+
- Premium model billing remains server-managed. ChatGPT-6 Astra is the explicit exception: its native signed-in 2x usage notice is printed when the user selects it, without injecting billing text into a model prompt or assistant output.
|
|
62
62
|
|
|
63
63
|
## Wallet Display
|
|
64
64
|
|
|
@@ -67,10 +67,12 @@ Before launching the runtime, the launcher calls `/api/v1/wallet/status`, then `
|
|
|
67
67
|
Expected status line:
|
|
68
68
|
|
|
69
69
|
```text
|
|
70
|
-
MagnetAPI.org Codex CLI v2.0.
|
|
71
|
-
Fable 5 is now available in codexclaude
|
|
70
|
+
MagnetAPI.org Codex CLI v2.0.39 · GPT-5.6 SOL Extra High · ~/project · Wallet balance $20.00
|
|
71
|
+
Fable 5.1 is now available in codexclaude.
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
+
`bin/splash.js` owns the terminal-only binary graphic and launch classification. Preserve `codexclaude, powered by https://magnetapi.org`, own app version, responsive widths, NO_COLOR, TERM=dumb and explicit opt-outs. No sleeps, clearing, network calls or decorations in headless/JSON/server output. `test/frontier.test.js` checks ordering, legacy visibility, numeric selection and splash behavior. `test/update.test.js` covers local verified fallback and Windows npm resolution.
|
|
75
|
+
|
|
74
76
|
## Upgrade Checklist
|
|
75
77
|
|
|
76
78
|
When updating the bundled runtime:
|
|
@@ -88,7 +90,7 @@ When updating the bundled runtime:
|
|
|
88
90
|
11. Keep update checks limited to `/api/v1/codexclaude/version` and `@codexapi/codexclaude` npm metadata.
|
|
89
91
|
12. Keep the interactive `Upgrade Now` flow installing `@codexapi/codexclaude@latest` without a shell and relaunching automatically.
|
|
90
92
|
13. Keep `codexclaude` as the only manifest-owned command and preserve the conditional, non-overwriting `codex` and `claude` postinstall aliases.
|
|
91
|
-
14. Keep the managed `MODELS` map and local model catalog, including Terra, SOL Max, and SOL Ultra.
|
|
93
|
+
14. Keep the managed `MODELS` map and local model catalog, including Astra, Terra, SOL Max, and SOL Ultra.
|
|
92
94
|
15. Keep bearer username auth and the `X-CodexAPI-*` headers.
|
|
93
95
|
16. Update `README.md`, `CUSTOMIZATIONS.md`, and `codexclaude.md`.
|
|
94
96
|
17. Run syntax checks, temporary-home setup, alias-preservation tests, `npm pack --dry-run`, and endpoint validation before publishing.
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# codexclaude
|
|
2
2
|
|
|
3
|
-
`codexclaude` installs the MagnetAPI.org Codex CLI for customers who want one coding
|
|
3
|
+
`codexclaude` installs the MagnetAPI.org Codex CLI for customers who want one coding client for ChatGPT-6-Astra, Fable 5.1, Opus 5, Sonnet 5, Daybreak Blue and GPT-5.6 models, using the same Token Wallet.
|
|
4
4
|
|
|
5
|
-
Version `2.0.
|
|
5
|
+
Version `2.0.39` bundles the exact Codex runtime dependency `@openai/codex@0.154.0`. The model picker starts with ChatGPT-6-Astra, Fable 5.1 and Opus 5. GPT-5.6 SOL with Extra High reasoning remains the default; existing valid selections are preserved. The release retains four-site authentication, wallet integration, Full Access defaults, local tools, safe configuration merging and managed updates.
|
|
6
6
|
|
|
7
7
|
## Install Or Update
|
|
8
8
|
|
|
@@ -16,7 +16,7 @@ This does not delete local session history. The update replaces the `codexclaude
|
|
|
16
16
|
|
|
17
17
|
The launcher checks CodexAPI.pro's managed version endpoint and the `@codexapi/codexclaude` npm package metadata only. It must never check `@openai/codex` npm metadata or OpenAI GitHub releases for customer update prompts.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
The service's release metadata determines the minimum supported version. When an update is required, pressing Enter at `Upgrade Now` installs the exact managed release and restarts the requested action. If npm is unavailable or stale, this release downloads and verifies the hosted package before installing it as a local file. Native `codex` and `claude` commands are never overwritten. Non-interactive commands fail clearly rather than waiting for input.
|
|
20
20
|
|
|
21
21
|
## First Login
|
|
22
22
|
|
|
@@ -44,7 +44,7 @@ Switch model:
|
|
|
44
44
|
codexclaude model
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
The first three choices are `ChatGPT-6-Astra`, `Fable 5.1` and `Opus 5`, followed by GPT-5.6, Daybreak Blue, SOL Max, SOL Ultra, SOL, Sonnet 5 and Terra. `codexclaude model`, `models`, `/model` and `/models` open the same launcher selector; the native in-session command remains `/model`. Legacy GPT-5.5 and Opus 4.8 metadata is hidden from new selection but retained for existing configurations. Fable 5.1 uses the compatible API id `claude-fable-5`; billing remains server-managed.
|
|
48
48
|
|
|
49
49
|
## Launch Commands
|
|
50
50
|
|
|
@@ -80,18 +80,21 @@ Card numbers, CVCs, and bank authentication challenges are entered only on Strip
|
|
|
80
80
|
Before launching the coding runtime, the app prints a compact status line like:
|
|
81
81
|
|
|
82
82
|
```text
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
codexclaude, powered by https://magnetapi.org
|
|
84
|
+
MagnetAPI.org Codex CLI v2.0.39 · GPT-5.6 SOL Extra High · ~/project · Wallet balance $20.00
|
|
85
|
+
Fable 5.1 is now available in codexclaude.
|
|
85
86
|
```
|
|
86
87
|
|
|
88
|
+
Interactive startup includes a gold-and-cyan binary graphic. Narrow terminals use a compact design. `NO_COLOR` and `TERM=dumb` disable color; `CODEXCLAUDE_NO_SPLASH=1` hides the graphic, and `CODEXCLAUDE_QUIET_STATUS=1` hides all launcher startup decoration. Exec/JSON, completion, server protocols, pipes and version/help output never receive splash or wallet text.
|
|
89
|
+
|
|
87
90
|
## Preserved Customizations
|
|
88
91
|
|
|
89
92
|
- Dashboard Username or Email Address plus password login for CodexAPI.pro, ChatPlus.chat, MyAPI.world, and MagnetAPI.org.
|
|
90
|
-
-
|
|
93
|
+
- Frontier-first model selection, with GPT-5.6 SOL/Extra High as the default and legacy configuration compatibility.
|
|
91
94
|
- Service-specific Responses-compatible provider for the dashboard account that logged in.
|
|
92
95
|
- Full Access defaults: approval policy `never` and sandbox mode `danger-full-access`.
|
|
93
96
|
- Model-specific visible reasoning in the local UI while the API server keeps upstream runtime effort server-managed.
|
|
94
|
-
- A local `~/.codexclaude/model_catalog.json` file so the native `/model` picker lists only the supported MagnetAPI.org Codex CLI choices, including Terra, SOL Max, and SOL Ultra.
|
|
97
|
+
- A local `~/.codexclaude/model_catalog.json` file so the native `/model` picker lists only the supported MagnetAPI.org Codex CLI choices, including Astra, Terra, SOL Max, and SOL Ultra.
|
|
95
98
|
- No default fast service tier. Fast mode is billed only when the user enables it inside the client.
|
|
96
99
|
- Token Wallet balance lookup before launch without exposing separate `status` or `usage` launcher commands.
|
|
97
100
|
- Authenticated `topup` and `/topup` commands using fixed server-authoritative packages, idempotent Stripe fulfillment, and post-payment wallet refresh.
|
package/bin/codexclaude.js
CHANGED
|
@@ -2,18 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
import { spawn, spawnSync } from "node:child_process";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, chmodSync, unlinkSync } from "node:fs";
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, chmodSync, unlinkSync, renameSync } from "node:fs";
|
|
6
|
+
import TOML from "@iarna/toml";
|
|
6
7
|
import { homedir } from "node:os";
|
|
7
8
|
import path from "node:path";
|
|
8
9
|
import readline from "node:readline/promises";
|
|
9
10
|
import { stdin as input, stdout as output } from "node:process";
|
|
10
11
|
import { fileURLToPath } from "node:url";
|
|
11
12
|
import { installSafeCommandAliases } from "../scripts/install-safe-aliases.js";
|
|
13
|
+
import { renderSplash, isInteractiveLaunch } from "./splash.js";
|
|
14
|
+
import { installedPackage, npmInvocation, performUpdate, releaseTarget } from "./update.js";
|
|
12
15
|
|
|
13
16
|
const require = createRequire(import.meta.url);
|
|
14
17
|
|
|
15
|
-
const APP_VERSION = "2.0.
|
|
16
|
-
const CODEX_VERSION = "0.
|
|
18
|
+
const APP_VERSION = "2.0.39";
|
|
19
|
+
const CODEX_VERSION = "0.154.0";
|
|
17
20
|
const APP_DISPLAY_NAME = "MagnetAPI.org Codex CLI";
|
|
18
21
|
const DEFAULT_MODEL_ID = "gpt-5.6-sol";
|
|
19
22
|
const DEFAULT_DISPLAY_REASONING_EFFORT = "xhigh";
|
|
@@ -36,7 +39,7 @@ const CODEX_CONFIG_FILE = path.join(CODEX_DIR, "config.toml");
|
|
|
36
39
|
const CODEX_UPDATE_CACHE_FILE = path.join(CODEX_DIR, "version.json");
|
|
37
40
|
const PROVIDER_ID = "codexapi";
|
|
38
41
|
const MODEL_CATALOG_CONTEXT_WINDOW = 272000;
|
|
39
|
-
const FABLE_ANNOUNCEMENT = "Fable 5 is now available in codexclaude
|
|
42
|
+
const FABLE_ANNOUNCEMENT = "Fable 5.1 is now available in codexclaude.";
|
|
40
43
|
const ANSI_GREEN = "\x1b[32m";
|
|
41
44
|
const ANSI_RESET = "\x1b[0m";
|
|
42
45
|
const SERVICE_CATALOG = [
|
|
@@ -91,70 +94,84 @@ const TOPUP_POLL_INTERVAL_MS = positiveInteger(process.env.CODEXCLAUDE_TOPUP_POL
|
|
|
91
94
|
const TOPUP_TIMEOUT_MS = positiveInteger(process.env.CODEXCLAUDE_TOPUP_TIMEOUT_MS, 30 * 60 * 1000);
|
|
92
95
|
|
|
93
96
|
const MODELS = {
|
|
97
|
+
"gpt-6-astra": {
|
|
98
|
+
id: "gpt-6-astra",
|
|
99
|
+
label: "ChatGPT-6-Astra",
|
|
100
|
+
aliases: ["astra", "gpt-6", "gpt-6-astra", "gpt6-astra", "chatgpt-6-astra"],
|
|
101
|
+
reasoningEffort: "xhigh",
|
|
102
|
+
contextWindow: 1050000,
|
|
103
|
+
maxOutputTokens: 128000,
|
|
104
|
+
premium: true,
|
|
105
|
+
supportedReasoningLevels: SUPPORTED_REASONING_LEVELS.filter(({ effort }) => effort !== "ultra"),
|
|
106
|
+
},
|
|
107
|
+
"claude-fable-5": {
|
|
108
|
+
id: "claude-fable-5",
|
|
109
|
+
label: "Fable 5.1",
|
|
110
|
+
aliases: ["fable", "fable-5.1", "claude-fable-5.1", "fable-5", "fabel", "fabel-5", "claude-fable-5", "claude-fabel-5"],
|
|
111
|
+
premium: true,
|
|
112
|
+
},
|
|
94
113
|
"claude-opus-5": {
|
|
95
114
|
id: "claude-opus-5",
|
|
96
115
|
label: "Opus 5",
|
|
97
|
-
aliases: ["
|
|
116
|
+
aliases: ["opus", "opus-5", "claude", "claude-opus-5"],
|
|
98
117
|
},
|
|
99
118
|
"gpt-5.6": {
|
|
100
119
|
id: "gpt-5.6",
|
|
101
120
|
label: "GPT-5.6",
|
|
102
|
-
aliases: ["
|
|
121
|
+
aliases: ["gpt", "gpt-5.6", "chatgpt", "chatgpt-5.6", "gpt56"],
|
|
103
122
|
reasoningEffort: "xhigh",
|
|
104
123
|
},
|
|
105
124
|
"gpt-daybreak-blue-latest": {
|
|
106
125
|
id: "gpt-daybreak-blue-latest",
|
|
107
126
|
label: "ChatGPT Daybreak Blue",
|
|
108
|
-
aliases: ["
|
|
127
|
+
aliases: ["daybreak", "daybreak-blue", "chatgpt-daybreak-blue", "gpt-daybreak-blue-latest"],
|
|
109
128
|
reasoningEffort: "xhigh",
|
|
110
129
|
},
|
|
111
130
|
"gpt-5.6-sol-max": {
|
|
112
131
|
id: "gpt-5.6-sol-max",
|
|
113
132
|
label: "GPT-5.6 SOL Max",
|
|
114
|
-
aliases: ["
|
|
133
|
+
aliases: ["gpt-5.6-sol-max", "gpt-5.6-max", "gpt56-max", "sol-max", "max"],
|
|
115
134
|
reasoningEffort: "max",
|
|
116
135
|
},
|
|
117
136
|
"gpt-5.6-sol-ultra": {
|
|
118
137
|
id: "gpt-5.6-sol-ultra",
|
|
119
138
|
label: "GPT-5.6 SOL Ultra",
|
|
120
|
-
aliases: ["
|
|
139
|
+
aliases: ["gpt-5.6-sol-ultra", "gpt-5.6-ultra", "gpt56-ultra", "sol-ultra", "ultra"],
|
|
121
140
|
reasoningEffort: "ultra",
|
|
122
141
|
},
|
|
123
142
|
"gpt-5.6-sol": {
|
|
124
143
|
id: "gpt-5.6-sol",
|
|
125
144
|
label: "GPT-5.6 SOL",
|
|
126
|
-
aliases: ["
|
|
145
|
+
aliases: ["gpt-5.6-sol", "sol"],
|
|
127
146
|
reasoningEffort: "xhigh",
|
|
128
147
|
},
|
|
129
148
|
"gpt-5.5": {
|
|
130
149
|
id: "gpt-5.5",
|
|
131
150
|
label: "ChatGPT-5.5",
|
|
132
|
-
aliases: ["
|
|
151
|
+
aliases: ["gpt-5.5", "chatgpt-5.5"],
|
|
152
|
+
legacy: true,
|
|
133
153
|
},
|
|
134
154
|
"claude-opus-4-8": {
|
|
135
155
|
id: "claude-opus-4-8",
|
|
136
156
|
label: "Opus 4.8",
|
|
137
|
-
aliases: ["
|
|
157
|
+
aliases: ["opus-4.8", "opus-4.7", "claude-opus-4-8", "claude-opus-4-7"],
|
|
158
|
+
legacy: true,
|
|
138
159
|
},
|
|
139
160
|
"claude-sonnet-5": {
|
|
140
161
|
id: "claude-sonnet-5",
|
|
141
162
|
label: "Sonnet 5",
|
|
142
|
-
aliases: ["
|
|
143
|
-
},
|
|
144
|
-
"claude-fable-5": {
|
|
145
|
-
id: "claude-fable-5",
|
|
146
|
-
label: "Fable 5",
|
|
147
|
-
aliases: ["10", "fable", "fable-5", "fabel", "fabel-5", "claude-fable-5", "claude-fabel-5"],
|
|
148
|
-
premium: true,
|
|
163
|
+
aliases: ["sonnet", "sonnet-5", "sonnet-4.6", "sonnet-4-6", "claude-sonnet-5", "claude-sonnet-4-6", "claude-sonnet-4.6"],
|
|
149
164
|
},
|
|
150
165
|
"gpt-5.6-terra": {
|
|
151
166
|
id: "gpt-5.6-terra",
|
|
152
167
|
label: "GPT-5.6 Terra",
|
|
153
|
-
aliases: ["
|
|
168
|
+
aliases: ["terra", "gpt-5.6-terra", "gpt56-terra"],
|
|
154
169
|
reasoningEffort: "xhigh",
|
|
155
170
|
},
|
|
156
171
|
};
|
|
157
172
|
|
|
173
|
+
const PICKER_MODELS = Object.values(MODELS).filter((model) => !model.legacy);
|
|
174
|
+
|
|
158
175
|
async function main() {
|
|
159
176
|
ensureExecutable();
|
|
160
177
|
ensureSafeCommandAliases();
|
|
@@ -182,7 +199,7 @@ async function main() {
|
|
|
182
199
|
logout();
|
|
183
200
|
return;
|
|
184
201
|
}
|
|
185
|
-
if (
|
|
202
|
+
if (["model", "models", "/model", "/models"].includes(command)) {
|
|
186
203
|
await modelFlow();
|
|
187
204
|
return;
|
|
188
205
|
}
|
|
@@ -216,7 +233,7 @@ ${APP_DISPLAY_NAME} v${APP_VERSION}
|
|
|
216
233
|
|
|
217
234
|
Commands:
|
|
218
235
|
codexclaude login Login with dashboard username/email and password
|
|
219
|
-
codexclaude
|
|
236
|
+
codexclaude models Select ChatGPT-6-Astra, Fable 5.1, Opus 5, or another current model
|
|
220
237
|
codexclaude changelog Show the latest CodexAPI.pro launcher changes
|
|
221
238
|
codexclaude setup Rewrite ~/.codex/config.toml with Full Access defaults
|
|
222
239
|
codexclaude topup Select an API Coding Credit package and securely complete payment
|
|
@@ -554,20 +571,33 @@ async function ensureReady() {
|
|
|
554
571
|
async function askModel(rl, current) {
|
|
555
572
|
const currentLabel = MODELS[current]?.label || MODELS[DEFAULT_MODEL_ID].label;
|
|
556
573
|
console.log("\nChoose your coding model:");
|
|
557
|
-
|
|
574
|
+
PICKER_MODELS.forEach((model, index) => {
|
|
558
575
|
console.log(` ${index + 1}. ${model.label}`);
|
|
559
576
|
});
|
|
560
577
|
const answer = (await rl.question(`Model [${currentLabel}]: `)).trim().toLowerCase();
|
|
561
578
|
if (!answer) {
|
|
562
|
-
|
|
579
|
+
const selected = MODELS[current] ? current : DEFAULT_MODEL_ID;
|
|
580
|
+
printModelSelectionWarning(selected);
|
|
581
|
+
return selected;
|
|
563
582
|
}
|
|
564
|
-
const match =
|
|
583
|
+
const match = PICKER_MODELS.find((model, index) => String(index + 1) === answer || model.aliases.includes(answer));
|
|
565
584
|
if (!match) {
|
|
566
585
|
throw new Error("Unknown model choice. Run codexclaude model and choose one of the numbered options.");
|
|
567
586
|
}
|
|
587
|
+
printModelSelectionWarning(match.id);
|
|
568
588
|
return match.id;
|
|
569
589
|
}
|
|
570
590
|
|
|
591
|
+
function printModelSelectionWarning(modelId) {
|
|
592
|
+
if (modelId !== "gpt-6-astra") {
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
console.log(
|
|
596
|
+
"\nBilling notice: Native ChatGPT-6 Astra usage is charged at 2x the normal Codex rate. " +
|
|
597
|
+
"When the managed cross-model route serves the request, that route's normal billing applies.",
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
|
|
571
601
|
async function postJson(pathname, body, origin = API_ORIGIN) {
|
|
572
602
|
const response = await fetch(`${String(origin || API_ORIGIN).replace(/\/+$/, "")}${pathname}`, {
|
|
573
603
|
method: "POST",
|
|
@@ -618,7 +648,6 @@ async function enforceLauncherVersion() {
|
|
|
618
648
|
async function runMandatoryUpgrade(metadata) {
|
|
619
649
|
const latest = metadata?.latestVersion || "latest";
|
|
620
650
|
const minimum = metadata?.minimumVersion || latest;
|
|
621
|
-
const hostedTarballUrl = metadata?.hostedTarballUrl || HOSTED_TARBALL_URL;
|
|
622
651
|
const changes = Array.isArray(metadata?.changes) ? metadata.changes.slice(0, 4) : [];
|
|
623
652
|
console.error(`\n✨ Update now available · ${APP_DISPLAY_NAME} v${latest}`);
|
|
624
653
|
console.error(`${APP_DISPLAY_NAME} v${latest} is required before your next coding session.`);
|
|
@@ -648,28 +677,21 @@ async function runMandatoryUpgrade(metadata) {
|
|
|
648
677
|
}
|
|
649
678
|
|
|
650
679
|
console.log(`\nDownloading and installing ${NPM_PACKAGE_NAME}@latest...`);
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
if (exitCode !== 0 || isOlderVersion(installedVersion, minimum)) {
|
|
663
|
-
throw new Error(
|
|
664
|
-
`Automatic upgrade failed with exit code ${exitCode} and installed version ${installedVersion || "unknown"}. Run ${UPDATE_COMMAND}. ` +
|
|
665
|
-
`If npm is unavailable, use: npm install -g ${hostedTarballUrl}`,
|
|
666
|
-
);
|
|
667
|
-
}
|
|
680
|
+
const npm = npmInvocation();
|
|
681
|
+
const installed = await performUpdate({
|
|
682
|
+
release: releaseTarget(metadata, null),
|
|
683
|
+
runNpm: args => spawnAndWait(npm.command, [...npm.args, ...args]),
|
|
684
|
+
readInstalled: () => {
|
|
685
|
+
const result = spawnSync(npm.command, [...npm.args, "root", "-g"], {
|
|
686
|
+
encoding: "utf8", timeout: 30000, shell: false,
|
|
687
|
+
});
|
|
688
|
+
return result.status === 0 ? installedPackage(String(result.stdout || "")) : null;
|
|
689
|
+
},
|
|
690
|
+
});
|
|
668
691
|
console.log(`\nUpgrade complete. Restarting ${APP_DISPLAY_NAME} now...`);
|
|
669
692
|
const relaunchArgs = process.argv.slice(2);
|
|
670
|
-
const relaunchCommand = process.platform === "win32" ? "codexclaude.cmd" : "codexclaude";
|
|
671
693
|
try {
|
|
672
|
-
const relaunchExitCode = await spawnAndWait(
|
|
694
|
+
const relaunchExitCode = await spawnAndWait(process.execPath, [installed.entrypoint, ...relaunchArgs]);
|
|
673
695
|
if (relaunchExitCode !== 0) {
|
|
674
696
|
throw new Error(`updated client exited with code ${relaunchExitCode}`);
|
|
675
697
|
}
|
|
@@ -681,24 +703,6 @@ async function runMandatoryUpgrade(metadata) {
|
|
|
681
703
|
}
|
|
682
704
|
}
|
|
683
705
|
|
|
684
|
-
function installedLauncherVersion() {
|
|
685
|
-
const command = process.platform === "win32" ? "codexclaude.cmd" : "codexclaude";
|
|
686
|
-
const result = spawnSync(command, ["--version"], {
|
|
687
|
-
encoding: "utf8",
|
|
688
|
-
env: {
|
|
689
|
-
...process.env,
|
|
690
|
-
CODEXCLAUDE_DISABLE_UPDATE_CHECK: "1",
|
|
691
|
-
CODEXCLAUDE_SKIP_COMMAND_ALIASES: "1",
|
|
692
|
-
},
|
|
693
|
-
shell: false,
|
|
694
|
-
});
|
|
695
|
-
if (result.error || result.status !== 0) {
|
|
696
|
-
return null;
|
|
697
|
-
}
|
|
698
|
-
const match = String(result.stdout || "").match(/\bv(\d+(?:\.\d+){2})\b/i);
|
|
699
|
-
return match?.[1] || null;
|
|
700
|
-
}
|
|
701
|
-
|
|
702
706
|
async function spawnAndWait(command, args) {
|
|
703
707
|
return await new Promise((resolve, reject) => {
|
|
704
708
|
const child = spawn(command, args, { stdio: "inherit", env: process.env, shell: false });
|
|
@@ -922,6 +926,8 @@ function isTruthy(value) {
|
|
|
922
926
|
|
|
923
927
|
function writeCodexConfig(config) {
|
|
924
928
|
mkdirSync(CODEX_DIR, { recursive: true });
|
|
929
|
+
const existing = existsSync(CODEX_CONFIG_FILE)
|
|
930
|
+
? TOML.parse(readFileSync(CODEX_CONFIG_FILE, "utf8").replace(/^\uFEFF/, "")) : {};
|
|
925
931
|
if (existsSync(CODEX_CONFIG_FILE)) {
|
|
926
932
|
const backup = `${CODEX_CONFIG_FILE}.backup.${timestamp()}`;
|
|
927
933
|
copyFileSync(CODEX_CONFIG_FILE, backup);
|
|
@@ -958,7 +964,16 @@ function writeCodexConfig(config) {
|
|
|
958
964
|
'terminal_title = ["project-name", "model-with-reasoning", "run-state"]',
|
|
959
965
|
"",
|
|
960
966
|
].join("\n");
|
|
961
|
-
|
|
967
|
+
const managed = TOML.parse(toml);
|
|
968
|
+
const merged = {
|
|
969
|
+
...existing,
|
|
970
|
+
...managed,
|
|
971
|
+
model_providers: { ...existing.model_providers, ...managed.model_providers },
|
|
972
|
+
tui: { ...existing.tui, ...managed.tui },
|
|
973
|
+
};
|
|
974
|
+
const temporary = `${CODEX_CONFIG_FILE}.tmp.${process.pid}`;
|
|
975
|
+
writeFileSync(temporary, TOML.stringify(merged), { encoding: "utf8", mode: 0o600 });
|
|
976
|
+
renameSync(temporary, CODEX_CONFIG_FILE);
|
|
962
977
|
}
|
|
963
978
|
|
|
964
979
|
function clearUpstreamUpdateCache() {
|
|
@@ -974,7 +989,8 @@ function clearUpstreamUpdateCache() {
|
|
|
974
989
|
function writeModelCatalog() {
|
|
975
990
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
976
991
|
const catalog = {
|
|
977
|
-
models: Object.values(MODELS).
|
|
992
|
+
models: [...PICKER_MODELS, ...Object.values(MODELS).filter((model) => model.legacy)]
|
|
993
|
+
.map((model, index) => modelCatalogEntry(model, index)),
|
|
978
994
|
};
|
|
979
995
|
writeFileSync(MODEL_CATALOG_FILE, `${JSON.stringify(catalog, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
|
|
980
996
|
return MODEL_CATALOG_FILE;
|
|
@@ -991,8 +1007,9 @@ function modelCatalogEntry(model, index) {
|
|
|
991
1007
|
supports_image_detail_original: true,
|
|
992
1008
|
truncation_policy: { mode: "tokens", limit: 10000 },
|
|
993
1009
|
supports_parallel_tool_calls: true,
|
|
994
|
-
context_window: MODEL_CATALOG_CONTEXT_WINDOW,
|
|
995
|
-
max_context_window: MODEL_CATALOG_CONTEXT_WINDOW,
|
|
1010
|
+
context_window: model.contextWindow || MODEL_CATALOG_CONTEXT_WINDOW,
|
|
1011
|
+
max_context_window: model.contextWindow || MODEL_CATALOG_CONTEXT_WINDOW,
|
|
1012
|
+
max_output_tokens: model.maxOutputTokens || null,
|
|
996
1013
|
auto_compact_token_limit: null,
|
|
997
1014
|
reasoning_summary_format: "experimental",
|
|
998
1015
|
default_reasoning_summary: "none",
|
|
@@ -1000,9 +1017,9 @@ function modelCatalogEntry(model, index) {
|
|
|
1000
1017
|
display_name: model.label,
|
|
1001
1018
|
description: modelCatalogDescription(model.id),
|
|
1002
1019
|
default_reasoning_level: reasoningEffortForModel(model.id),
|
|
1003
|
-
supported_reasoning_levels: SUPPORTED_REASONING_LEVELS,
|
|
1020
|
+
supported_reasoning_levels: model.supportedReasoningLevels || SUPPORTED_REASONING_LEVELS,
|
|
1004
1021
|
shell_type: "shell_command",
|
|
1005
|
-
visibility: "list",
|
|
1022
|
+
visibility: model.legacy ? "hide" : "list",
|
|
1006
1023
|
minimal_client_version: "0.124.0",
|
|
1007
1024
|
supported_in_api: true,
|
|
1008
1025
|
availability_nux: null,
|
|
@@ -1019,6 +1036,9 @@ function modelCatalogEntry(model, index) {
|
|
|
1019
1036
|
}
|
|
1020
1037
|
|
|
1021
1038
|
function modelCatalogDescription(modelId) {
|
|
1039
|
+
if (modelId === "gpt-6-astra") {
|
|
1040
|
+
return "ChatGPT-6-Astra: coding tools, configurable reasoning, and image input.";
|
|
1041
|
+
}
|
|
1022
1042
|
if (modelId === "gpt-5.6") {
|
|
1023
1043
|
return "GPT-5.6 coding route with local coding tools and wallet billing.";
|
|
1024
1044
|
}
|
|
@@ -1047,7 +1067,7 @@ function modelCatalogDescription(modelId) {
|
|
|
1047
1067
|
return "Sonnet 5 coding route with local coding tools and wallet billing.";
|
|
1048
1068
|
}
|
|
1049
1069
|
if (modelId === "claude-fable-5") {
|
|
1050
|
-
return "Fable 5
|
|
1070
|
+
return "Fable 5.1: coding tools and image input, using the compatible Fable 5 API id.";
|
|
1051
1071
|
}
|
|
1052
1072
|
return "ChatGPT-5.5 coding route with local coding tools and wallet billing.";
|
|
1053
1073
|
}
|
|
@@ -1080,17 +1100,28 @@ function logout() {
|
|
|
1080
1100
|
|
|
1081
1101
|
async function runCodex(args) {
|
|
1082
1102
|
const config = requireConfig();
|
|
1103
|
+
const interactive = isInteractiveLaunch(args, {
|
|
1104
|
+
stdinTTY: input.isTTY, stdoutTTY: output.isTTY,
|
|
1105
|
+
quiet: isTruthy(process.env.CODEXCLAUDE_QUIET_STATUS),
|
|
1106
|
+
});
|
|
1107
|
+
if (interactive && !isTruthy(process.env.CODEXCLAUDE_NO_SPLASH)) {
|
|
1108
|
+
process.stderr.write(renderSplash({
|
|
1109
|
+
version: APP_VERSION, columns: output.columns,
|
|
1110
|
+
color: process.env.NO_COLOR === undefined && process.env.TERM !== "dumb",
|
|
1111
|
+
}));
|
|
1112
|
+
}
|
|
1083
1113
|
let wallet = null;
|
|
1084
1114
|
try {
|
|
1085
1115
|
wallet = await walletSnapshot(config);
|
|
1086
1116
|
} catch {
|
|
1087
1117
|
// Wallet lookup should never block the user from starting a local coding session.
|
|
1088
1118
|
}
|
|
1089
|
-
if (
|
|
1119
|
+
if (interactive) {
|
|
1090
1120
|
console.log(formatStatusLine(config, wallet, process.cwd()));
|
|
1091
|
-
|
|
1121
|
+
const color = process.env.NO_COLOR === undefined && process.env.TERM !== "dumb";
|
|
1122
|
+
console.log(color ? `${ANSI_GREEN}${FABLE_ANNOUNCEMENT}${ANSI_RESET}` : FABLE_ANNOUNCEMENT);
|
|
1123
|
+
if (color) process.stdout.write(`\x1b]0;${APP_DISPLAY_NAME} v${APP_VERSION}\x07`);
|
|
1092
1124
|
}
|
|
1093
|
-
process.stdout.write(`\x1b]0;${APP_DISPLAY_NAME} v${APP_VERSION}\x07`);
|
|
1094
1125
|
const launch = resolveCodexLaunch();
|
|
1095
1126
|
const env = {
|
|
1096
1127
|
...process.env,
|
|
@@ -1255,6 +1286,9 @@ function formatStatusLine(config, wallet, cwd) {
|
|
|
1255
1286
|
}
|
|
1256
1287
|
|
|
1257
1288
|
function modelStatusName(model) {
|
|
1289
|
+
if (model === "gpt-6-astra") {
|
|
1290
|
+
return "ChatGPT-6 Astra";
|
|
1291
|
+
}
|
|
1258
1292
|
if (model === "gpt-5.6") {
|
|
1259
1293
|
return "GPT-5.6";
|
|
1260
1294
|
}
|
|
@@ -1320,7 +1354,7 @@ function normalizeConfig(config) {
|
|
|
1320
1354
|
if (["claude-sonnet-4.6", "claude-sonnet-4-6", "sonnet-4.6", "sonnet-4-6", "sonnet-5"].includes(normalized.model)) {
|
|
1321
1355
|
normalized.model = "claude-sonnet-5";
|
|
1322
1356
|
}
|
|
1323
|
-
if (["claude-fabel-5", "fable-5", "fabel-5"].includes(normalized.model)) {
|
|
1357
|
+
if (["claude-fabel-5", "fable-5", "fabel-5", "fable-5.1", "claude-fable-5.1"].includes(normalized.model)) {
|
|
1324
1358
|
normalized.model = "claude-fable-5";
|
|
1325
1359
|
}
|
|
1326
1360
|
if (["gpt-5.6-sol-max", "gpt-5.6-max", "gpt56-max", "sol-max", "max"].includes(normalized.model)) {
|
package/bin/splash.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Terminal-only artwork. Never delay startup or mix it into machine-readable output.
|
|
2
|
+
export function isInteractiveLaunch(args, { stdinTTY, stdoutTTY, quiet = false }) {
|
|
3
|
+
if (!stdinTTY || !stdoutTTY || quiet) return false;
|
|
4
|
+
if (args.some((arg) => /^(?:--json(?:=|$)|--help$|-h$|--version$|-V$)/.test(arg))) return false;
|
|
5
|
+
return !["exec", "e", "review", "app-server", "mcp-server", "completion", "mcp", "debug", "features"].includes(args[0]);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function renderSplash({ version, columns = 80, color = true }) {
|
|
9
|
+
const width = Math.max(1, Math.min(Number(columns) || 80, 74));
|
|
10
|
+
const gold = color ? "\x1b[93m" : "";
|
|
11
|
+
const cyan = color ? "\x1b[36m" : "";
|
|
12
|
+
const bold = color ? "\x1b[1m" : "";
|
|
13
|
+
const reset = color ? "\x1b[0m" : "";
|
|
14
|
+
const lines = [];
|
|
15
|
+
const add = (value, style = "") => {
|
|
16
|
+
for (let offset = 0; offset < value.length; offset += width) {
|
|
17
|
+
lines.push(style + value.slice(offset, offset + width) + reset);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
add("-".repeat(width), cyan);
|
|
21
|
+
if (width >= 40) {
|
|
22
|
+
[
|
|
23
|
+
" 011110 011110 010 101 001",
|
|
24
|
+
" 01 01 101 010 110",
|
|
25
|
+
" 10 10 010 101 001",
|
|
26
|
+
" 01 01 101 010 110",
|
|
27
|
+
" 100111 100111 010 101 001",
|
|
28
|
+
].forEach((line) => add(line, gold));
|
|
29
|
+
} else {
|
|
30
|
+
add("0101 CODE + CREATE 1010", gold);
|
|
31
|
+
}
|
|
32
|
+
add(`codexclaude v${version}`, bold + gold);
|
|
33
|
+
add("codexclaude, powered by https://magnetapi.org", cyan);
|
|
34
|
+
add("-".repeat(width), cyan);
|
|
35
|
+
return "\n" + lines.join("\n") + "\n\n";
|
|
36
|
+
}
|
package/bin/update.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdtemp, writeFile, rm } from "node:fs/promises";
|
|
3
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
|
|
7
|
+
export const PACKAGE = "@codexapi/codexclaude";
|
|
8
|
+
const VERSION = /^\d+\.\d+\.\d+$/;
|
|
9
|
+
|
|
10
|
+
export function atLeast(actual, required) {
|
|
11
|
+
if (!VERSION.test(actual || "") || !VERSION.test(required || "")) return false;
|
|
12
|
+
const a = actual.split(".").map(Number), b = required.split(".").map(Number);
|
|
13
|
+
for (let i = 0; i < 3; i++) if (a[i] !== b[i]) return a[i] > b[i];
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function releaseTarget(service, registry) {
|
|
18
|
+
const versions = [service?.latestVersion, service?.minimumVersion, registry?.version].filter(v => VERSION.test(v || ""));
|
|
19
|
+
const version = versions.reduce((a, b) => atLeast(a, b) ? a : b, null);
|
|
20
|
+
if (!version) throw new Error("No valid managed release version is available. Please retry shortly.");
|
|
21
|
+
const hostedTarballUrl = `https://codexapi.pro/downloads/codexapi-codexclaude-${version}.tgz`;
|
|
22
|
+
return { version, hostedTarballUrl, sha256: service?.latestVersion === version ? service.hostedTarballSha256 : null };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function downloadVerified(release, fetchImpl = fetch) {
|
|
26
|
+
const expectedUrl = `https://codexapi.pro/downloads/codexapi-codexclaude-${release.version}.tgz`;
|
|
27
|
+
if (!VERSION.test(release.version) || release.hostedTarballUrl !== expectedUrl) throw new Error("Untrusted managed update location.");
|
|
28
|
+
const request = async url => {
|
|
29
|
+
const response = await fetchImpl(url, { redirect: "error", signal: AbortSignal.timeout(60000) });
|
|
30
|
+
if (!response.ok) throw new Error(`Managed update download failed (HTTP ${response.status}).`);
|
|
31
|
+
return response;
|
|
32
|
+
};
|
|
33
|
+
const hash = release.sha256 || (await (await request(`${expectedUrl}.sha256`)).text()).trim().split(/\s+/)[0];
|
|
34
|
+
if (!/^[a-f0-9]{64}$/i.test(hash || "")) throw new Error("Managed update checksum is unavailable. No package was installed.");
|
|
35
|
+
const response = await request(expectedUrl);
|
|
36
|
+
const chunks = [];
|
|
37
|
+
let size = 0;
|
|
38
|
+
for await (const chunk of response.body) {
|
|
39
|
+
size += chunk.length;
|
|
40
|
+
if (size > 25 * 1024 * 1024) throw new Error("Managed update exceeds the download size limit.");
|
|
41
|
+
chunks.push(chunk);
|
|
42
|
+
}
|
|
43
|
+
const contents = Buffer.concat(chunks);
|
|
44
|
+
if (createHash("sha256").update(contents).digest("hex") !== hash.toLowerCase()) throw new Error("Managed update checksum mismatch. No package was installed.");
|
|
45
|
+
const directory = await mkdtemp(path.join(tmpdir(), "codexclaude-update-"));
|
|
46
|
+
const file = path.join(directory, `codexclaude-${release.version}.tgz`);
|
|
47
|
+
try { await writeFile(file, contents, { mode: 0o600, flag: "wx" }); }
|
|
48
|
+
catch (error) { await rm(directory, { recursive: true, force: true }); throw error; }
|
|
49
|
+
return { file, cleanup: () => rm(directory, { recursive: true, force: true }) };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function npmInvocation(env = process.env, platform = process.platform, executable = process.execPath) {
|
|
53
|
+
const candidates = [env.npm_execpath, path.join(path.dirname(executable), "node_modules/npm/bin/npm-cli.js")].filter(Boolean);
|
|
54
|
+
if (platform === "win32" && env.APPDATA) candidates.push(path.join(env.APPDATA, "npm/node_modules/npm/bin/npm-cli.js"));
|
|
55
|
+
for (const directory of (env.PATH || env.Path || "").split(platform === "win32" ? ";" : ":")) {
|
|
56
|
+
if (!directory) continue;
|
|
57
|
+
candidates.push(path.join(directory, "node_modules/npm/bin/npm-cli.js"));
|
|
58
|
+
if (platform !== "win32") candidates.push(path.join(directory, "npm"));
|
|
59
|
+
}
|
|
60
|
+
for (const candidate of candidates) {
|
|
61
|
+
try {
|
|
62
|
+
const real = realpathSync(candidate);
|
|
63
|
+
if (path.basename(real) === "npm-cli.js") return { command: executable, args: [real] };
|
|
64
|
+
} catch {}
|
|
65
|
+
}
|
|
66
|
+
if (platform === "win32") throw new Error("npm could not be located. Repair your Node.js installation, then retry the update.");
|
|
67
|
+
return { command: "npm", args: [] };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function installedPackage(globalRoot) {
|
|
71
|
+
try {
|
|
72
|
+
const root = path.join(globalRoot.trim(), "@codexapi", "codexclaude");
|
|
73
|
+
const pkg = JSON.parse(readFileSync(path.join(root, "package.json"), "utf8"));
|
|
74
|
+
const entrypoint = path.join(root, "bin/codexclaude.js");
|
|
75
|
+
if (pkg.name !== PACKAGE || !VERSION.test(pkg.version) || !existsSync(entrypoint)) return null;
|
|
76
|
+
return { version: pkg.version, entrypoint };
|
|
77
|
+
} catch { return null; }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function performUpdate({ release, runNpm, readInstalled, download = downloadVerified }) {
|
|
81
|
+
let code = await runNpm(["install", "-g", `${PACKAGE}@${release.version}`]);
|
|
82
|
+
let installed = code === 0 ? await readInstalled() : null;
|
|
83
|
+
if (!installed || !atLeast(installed.version, release.version)) {
|
|
84
|
+
const artifact = await download(release);
|
|
85
|
+
try {
|
|
86
|
+
code = await runNpm(["install", "-g", artifact.file]);
|
|
87
|
+
installed = code === 0 ? await readInstalled() : null;
|
|
88
|
+
} finally { await artifact.cleanup(); }
|
|
89
|
+
}
|
|
90
|
+
if (code !== 0 || !installed || !atLeast(installed.version, release.version)) {
|
|
91
|
+
throw new Error(`Automatic update did not install v${release.version}. Run: npm install -g ${PACKAGE}@${release.version}`);
|
|
92
|
+
}
|
|
93
|
+
return installed;
|
|
94
|
+
}
|
package/codexclaude.md
CHANGED
|
@@ -4,13 +4,72 @@ This file is the durable handoff for the `@codexapi/codexclaude` package in `/ro
|
|
|
4
4
|
|
|
5
5
|
## Current Release
|
|
6
6
|
|
|
7
|
+
### 2026-09-10 Frontier Picker And Binary Splash: 2.0.39
|
|
8
|
+
|
|
9
|
+
This section supersedes older release snapshots below. Source/package version
|
|
10
|
+
is `2.0.39`, with exact `@openai/codex@0.154.0`. Release deployment state and npm
|
|
11
|
+
verification are recorded in `/root/codexapi/STATE.md`; never infer registry
|
|
12
|
+
publication or minimum enforcement from the source version alone.
|
|
13
|
+
|
|
14
|
+
The first three choices in the launcher selector and native catalog are
|
|
15
|
+
`ChatGPT-6-Astra` (`gpt-6-astra`), `Fable 5.1` (`claude-fable-5`) and `Opus 5`
|
|
16
|
+
(`claude-opus-5`). Remaining current choices retain their API ids. GPT-5.5 and
|
|
17
|
+
Opus 4.8 are compatibility-only: hidden from new selection, with full metadata
|
|
18
|
+
retained so upgrades do not change existing customer configurations or history.
|
|
19
|
+
Do not invent `claude-fable-5.1` upstream. A display alias normalizes to the stable
|
|
20
|
+
Fable id. Numeric choices are calculated from visible order to avoid selecting
|
|
21
|
+
the wrong model after reordering. `model`, `models`, `/model` and `/models` are
|
|
22
|
+
launcher aliases; the native interactive command remains `/model`.
|
|
23
|
+
|
|
24
|
+
Default model remains `gpt-5.6-sol`, Extra High. Full Access, four-site login,
|
|
25
|
+
customer wallet display, top-up, reasoning metadata, tool/image transport,
|
|
26
|
+
client headers and native-safe command aliases are preserved. Setup parses TOML,
|
|
27
|
+
backs up and atomically merges only owned fields. No runtime routing, billing,
|
|
28
|
+
provider credentials or regional native Codex installation is changed by this
|
|
29
|
+
launcher release.
|
|
30
|
+
|
|
31
|
+
`bin/splash.js` renders gold/cyan binary artwork and the exact line
|
|
32
|
+
`codexclaude, powered by https://magnetapi.org`, with app version 2.0.39.
|
|
33
|
+
It adapts to narrow terminals, has no animation delay and honors NO_COLOR,
|
|
34
|
+
TERM=dumb, CODEXCLAUDE_NO_SPLASH and CODEXCLAUDE_QUIET_STATUS. Launcher notices,
|
|
35
|
+
wallet text and terminal-title escapes are now excluded from exec/JSON, server
|
|
36
|
+
protocols, completions and pipes. Never pollute machine-readable stdout.
|
|
37
|
+
|
|
38
|
+
`bin/update.js` ports the tested claudecodex updater: exact registry target,
|
|
39
|
+
checksum-verified temporary local archive on fallback, bounded HTTPS downloads,
|
|
40
|
+
Windows npm-cli.js through Node, actual global package verification and direct
|
|
41
|
+
relaunch of that installed entrypoint. No npm --force/remote-policy override.
|
|
42
|
+
Only CodexAPI and our npm package may provide update metadata. Publish and verify
|
|
43
|
+
archives, SHA-256 sidecars, registry and dashboard scripts before raising the
|
|
44
|
+
minimum version. Preserve native binaries, local tools, providers and projects.
|
|
45
|
+
|
|
46
|
+
Run `npm test` for config preservation, frontier metadata, aliases, splash,
|
|
47
|
+
wallet/top-up and updater behavior. Then test the packed installation with actual
|
|
48
|
+
0.154.0 exec JSON, native model picker and bounded live test-account calls.
|
|
49
|
+
All four websites, VIP setup and generated wizard checksums must match the final
|
|
50
|
+
archive; do not repack changed files after publishing its hash.
|
|
51
|
+
|
|
52
|
+
### 2026-09-09 Configuration Safety Build
|
|
53
|
+
|
|
54
|
+
`2.0.38` is a hosted safety build for the MagnetAPI v2 Setup Wizard. npm `latest`
|
|
55
|
+
and the global mandatory minimum remain `2.0.37`; npm authentication must be
|
|
56
|
+
renewed before publishing `2.0.38` to the registry. Do not force a registry update
|
|
57
|
+
until that publication is verified. The wizard downloads the exact hosted archive,
|
|
58
|
+
verifies SHA-256, and installs the local file, avoiding npm remote-fetch restrictions.
|
|
59
|
+
The runtime remains Codex `0.153.4`; model, routing, authentication and billing
|
|
60
|
+
behavior are unchanged. `writeCodexConfig` now parses TOML with pinned
|
|
61
|
+
`@iarna/toml@2.2.5`, merges only managed root fields, the owned provider and owned
|
|
62
|
+
TUI fields, preserves other providers/MCP/projects, backs up the original, and
|
|
63
|
+
replaces the file atomically. Invalid existing TOML stops setup without changing it.
|
|
64
|
+
Run `npm test`, including the real-launcher configuration-preservation tests.
|
|
65
|
+
|
|
7
66
|
- Package name: `@codexapi/codexclaude`
|
|
8
|
-
- Launcher version: `2.0.
|
|
67
|
+
- Launcher version: `2.0.37`
|
|
9
68
|
- Customer-facing app name: `MagnetAPI.org Codex CLI`
|
|
10
|
-
- Bundled runtime dependency: `@openai/codex@0.
|
|
69
|
+
- Bundled runtime dependency: `@openai/codex@0.153.4`
|
|
11
70
|
- Required install command: `npm install -g @codexapi/codexclaude@latest`
|
|
12
|
-
- Hosted fallback: `npm install -g https://codexapi.pro/downloads/codexapi-codexclaude-2.0.
|
|
13
|
-
- Backend minimum version: `2.0.
|
|
71
|
+
- Hosted fallback: `npm install -g https://codexapi.pro/downloads/codexapi-codexclaude-2.0.37.tgz`
|
|
72
|
+
- Backend minimum version: `2.0.37`
|
|
14
73
|
- Default visible model: `GPT-5.6 SOL`
|
|
15
74
|
- Default model slug: `gpt-5.6-sol`
|
|
16
75
|
- Default visible reasoning effort: `Extra High`, stored as `xhigh`; premium SOL Max and SOL Ultra retain their explicit `max` and `ultra` labels.
|
|
@@ -25,13 +84,13 @@ This file is the durable handoff for the `@codexapi/codexclaude` package in `/ro
|
|
|
25
84
|
The launcher must present itself as:
|
|
26
85
|
|
|
27
86
|
```text
|
|
28
|
-
MagnetAPI.org Codex CLI v2.0.
|
|
87
|
+
MagnetAPI.org Codex CLI v2.0.37
|
|
29
88
|
```
|
|
30
89
|
|
|
31
90
|
Normal pre-launch status should look like:
|
|
32
91
|
|
|
33
92
|
```text
|
|
34
|
-
MagnetAPI.org Codex CLI v2.0.
|
|
93
|
+
MagnetAPI.org Codex CLI v2.0.37 · GPT-5.6 SOL Extra High · ~/project · Wallet balance $20.00
|
|
35
94
|
Fable 5 is now available in codexclaude, exclusively.
|
|
36
95
|
```
|
|
37
96
|
|
|
@@ -50,6 +109,9 @@ The launcher command `codexclaude model` must list these customer-visible models
|
|
|
50
109
|
- `claude-sonnet-5` displayed as `Sonnet 5`
|
|
51
110
|
- `claude-fable-5` displayed as `Fable 5`
|
|
52
111
|
- `gpt-5.6-terra` displayed as `GPT-5.6 Terra`
|
|
112
|
+
- `gpt-6-astra` displayed as `ChatGPT-6 Astra`
|
|
113
|
+
|
|
114
|
+
ChatGPT-6 Astra supports `low`, `medium`, `high`, `xhigh`, and `max` reasoning in the managed catalog, with a 1,050,000-token context window and 128,000 maximum output tokens. The launcher displays a billing notice when Astra is selected. Native signed-in Astra usage is charged at 2x the normal Codex rate; when the dedicated Astra route follows Global Cross-Model Routing, normal billing for that route applies.
|
|
53
115
|
|
|
54
116
|
GPT-5.6 SOL must be the default when a new config is created or a legacy config contains an unsupported model value. It is displayed as Extra High while the generated runtime config stores `xhigh`. A valid existing customer selection must remain unchanged across upgrades. The selected model slug must stay in `~/.codex/config.toml`; do not rewrite customer-facing model selections locally. `gpt-5.6-sol-max` and `gpt-5.6-sol-ultra` remain distinct for customer choice, usage display, and wallet billing.
|
|
55
117
|
|
|
@@ -60,7 +122,7 @@ GPT-5.6 SOL must be the default when a new config is created or a legacy config
|
|
|
60
122
|
- `https://codexapi.pro/api/v1/codexclaude/version`
|
|
61
123
|
- `https://registry.npmjs.org/@codexapi%2Fcodexclaude/latest`
|
|
62
124
|
|
|
63
|
-
It must not check `@openai/codex` npm metadata, OpenAI GitHub releases, or any upstream OpenAI update endpoint. Version `2.0.
|
|
125
|
+
It must not check `@openai/codex` npm metadata, OpenAI GitHub releases, or any upstream OpenAI update endpoint. Version `2.0.37` is both the enforced minimum and current latest release. Compatible older launchers offer an interactive `Upgrade Now` action; pressing Enter invokes `npm install -g @codexapi/codexclaude@latest` without shell interpolation. If that registry install fails, the launcher automatically tries the hosted tarball. Non-interactive terminals print the exact update command and exit instead of waiting for input. After a successful interactive update, the launcher starts the requested action again automatically.
|
|
64
126
|
|
|
65
127
|
The npm package manifest owns only `codexclaude`. This is deliberate: npm creates manifest binaries before postinstall, so claiming `codex` there causes an `EEXIST` upgrade failure on machines with native Codex CLI. During a global installation, postinstall may create optional `codex` and `claude` aliases only when neither the target npm prefix nor any directory on `PATH` already contains the command. Existing native clients are preserved and no install path requires `--force`.
|
|
66
128
|
|
|
@@ -96,7 +158,7 @@ base_url = "<service Responses URL>"
|
|
|
96
158
|
experimental_bearer_token = "<customer System Token/API username>"
|
|
97
159
|
wire_api = "responses"
|
|
98
160
|
supports_websockets = false
|
|
99
|
-
http_headers = { "X-CodexAPI-Client" = "codexclaude", "X-CodexAPI-Client-Version" = "2.0.
|
|
161
|
+
http_headers = { "X-CodexAPI-Client" = "codexclaude", "X-CodexAPI-Client-Version" = "2.0.37", "X-CodexAPI-Selected-Model" = "<selected model>" }
|
|
100
162
|
|
|
101
163
|
[tui]
|
|
102
164
|
status_line = ["model-with-reasoning", "fast-mode", "current-dir"]
|
|
@@ -104,7 +166,7 @@ status_line_use_colors = true
|
|
|
104
166
|
terminal_title = ["project-name", "model-with-reasoning", "run-state"]
|
|
105
167
|
```
|
|
106
168
|
|
|
107
|
-
The generated model catalog must contain full metadata for every supported slug, including `gpt-daybreak-blue-latest`, `gpt-5.6`, `gpt-5.6-terra`, `gpt-5.6-sol-max`, and `gpt-5.6-sol-ultra`. This prevents fallback metadata warnings such as:
|
|
169
|
+
The generated model catalog must contain full metadata for every supported slug, including `gpt-6-astra`, `gpt-daybreak-blue-latest`, `gpt-5.6`, `gpt-5.6-terra`, `gpt-5.6-sol-max`, and `gpt-5.6-sol-ultra`. This prevents fallback metadata warnings such as:
|
|
108
170
|
|
|
109
171
|
```text
|
|
110
172
|
Model metadata for `claude-opus-4-8` not found. Defaulting to fallback metadata; this can degrade performance and cause issues.
|
|
@@ -183,7 +245,7 @@ tmp_home="$(mktemp -d)"
|
|
|
183
245
|
mkdir -p "$tmp_home/.codexclaude"
|
|
184
246
|
cat > "$tmp_home/.codexclaude/config.json" <<'JSON'
|
|
185
247
|
{
|
|
186
|
-
"version": "2.0.
|
|
248
|
+
"version": "2.0.37",
|
|
187
249
|
"serviceId": "codexapi",
|
|
188
250
|
"serviceLabel": "CodexAPI.pro",
|
|
189
251
|
"apiOrigin": "https://codexapi.pro",
|
|
@@ -222,10 +284,18 @@ After packaging, copy the tarball to the public downloads directories, restart t
|
|
|
222
284
|
|
|
223
285
|
```bash
|
|
224
286
|
curl -fsS "https://codexapi.pro/api/v1/codexclaude/version?current=2.0.17"
|
|
225
|
-
curl -fsSI "https://codexapi.pro/downloads/codexapi-codexclaude-2.0.
|
|
287
|
+
curl -fsSI "https://codexapi.pro/downloads/codexapi-codexclaude-2.0.37.tgz"
|
|
226
288
|
```
|
|
227
289
|
|
|
228
|
-
The version endpoint must report `latestVersion = 2.0.
|
|
290
|
+
The version endpoint must report `latestVersion = 2.0.37`, `minimumVersion = 2.0.37`, and `updateRequired = true` for every older client.
|
|
291
|
+
|
|
292
|
+
## Version 2.0.37 Changes
|
|
293
|
+
|
|
294
|
+
- Updated the bundled coding runtime to exact `@openai/codex@0.153.4`.
|
|
295
|
+
- Added ChatGPT-6 Astra with complete context, output, image, search, tool, and reasoning metadata.
|
|
296
|
+
- Added a model-selection warning for Astra's native signed-in 2x usage rate while keeping cross-model billing route-aware.
|
|
297
|
+
- Preserved all MagnetAPI account login, wallet, top-up, Full Access, safe-alias, update, and model-selection customizations.
|
|
298
|
+
- Made `2.0.37` mandatory after npm and the hosted fallback package become available.
|
|
229
299
|
|
|
230
300
|
## Version 2.0.36 Changes
|
|
231
301
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codexapi/codexclaude",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"description": "MagnetAPI.org Codex CLI for ChatGPT
|
|
3
|
+
"version": "2.0.39",
|
|
4
|
+
"description": "MagnetAPI.org Codex CLI for ChatGPT-6-Astra, Fable 5.1, Opus 5, Sonnet 5, Daybreak Blue, and GPT-5.6.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"node": ">=20"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@
|
|
25
|
+
"@iarna/toml": "2.2.5",
|
|
26
|
+
"@openai/codex": "0.154.0"
|
|
26
27
|
},
|
|
27
28
|
"publishConfig": {
|
|
28
29
|
"access": "public"
|