@codexapi/codexclaude 2.0.23 → 2.0.25

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 CHANGED
@@ -1,13 +1,14 @@
1
- # Magnetapi Client Customizations
1
+ # MagnetAPI.org Codex CLI Customizations
2
2
 
3
- `codexclaude` tracks the managed coding runtime while keeping a thin Magnetapi Client launcher layer. Future upgrades must preserve this file's behavior before a package is published.
3
+ `codexclaude` tracks the managed coding runtime while keeping a thin MagnetAPI.org Codex CLI launcher layer. Future upgrades must preserve this file's behavior before a package is published.
4
4
 
5
5
  ## Runtime
6
6
 
7
- - Customer-facing app name: `Magnetapi Client`
8
- - Local launcher version: `2.0.23`
9
- - Bundled official runtime dependency: `@openai/codex@0.144.3`
10
- - Required install command: `npm install -g https://codexapi.pro/downloads/codexapi-codexclaude-2.0.23.tgz`
7
+ - Customer-facing app name: `MagnetAPI.org Codex CLI`
8
+ - Local launcher version: `2.0.25`
9
+ - Bundled official runtime dependency: `@openai/codex@0.145.0`
10
+ - Required install command: `npm install -g @codexapi/codexclaude@latest`
11
+ - Hosted fallback: `npm install -g https://codexapi.pro/downloads/codexapi-codexclaude-2.0.25.tgz`
11
12
  - Bundled runtime version is managed internally and must not be used for customer update prompts.
12
13
  - Launcher update checks may call the CodexAPI.pro version endpoint and `@codexapi/codexclaude` npm metadata only.
13
14
  - The launcher must never check `@openai/codex` npm metadata or OpenAI GitHub releases for update notices.
@@ -19,12 +20,15 @@
19
20
  - Rewrites `~/.codex/config.toml` before every launch.
20
21
  - Deletes stale `~/.codex/version.json` before writing managed config.
21
22
  - Launches the bundled platform-native runtime binary directly rather than the upstream npm wrapper.
22
- - Keeps launcher-owned output branded as `Magnetapi Client`; hardcoded native binary strings require a forked native runtime build if operations wants them removed across all platforms.
23
+ - Keeps launcher-owned output branded as `MagnetAPI.org Codex CLI`; hardcoded native binary strings require a forked native runtime build if operations wants them removed across all platforms.
23
24
  - Starts with `--search` by default.
24
25
  - Passes unknown commands directly to the bundled runtime after config is applied.
25
26
  - Provides `codexclaude changelog` using the managed version endpoint.
26
27
  - Does not expose separate `codexclaude status` or `codexclaude usage` commands; wallet information remains a compact pre-launch line.
27
- - Version `2.0.23` is forced by the backend minimum version and older clients must show an update-required message.
28
+ - Version `2.0.25` is forced by the backend minimum version and older clients must show an update-required message.
29
+ - Mandatory updates present `Upgrade Now` in an interactive terminal, invoke npm with an argument array and no shell interpolation, then relaunch the requested action automatically.
30
+ - The npm package exposes `codexclaude` and `codex` as managed launch commands.
31
+ - Global installation creates `claude` only when no existing command is present anywhere on `PATH`; native Claude Code must never be overwritten.
28
32
 
29
33
  ## Provider Config
30
34
 
@@ -42,13 +46,13 @@ The launcher writes a model provider named `codexapi`:
42
46
  ## Runtime Defaults
43
47
 
44
48
  - Default model: `gpt-5.6` displayed as `GPT-5.6`
45
- - Supported launcher choices: `gpt-5.6`, `gpt-5.6-sol-max`, `gpt-5.6-sol-ultra`, `gpt-5.6-sol`, `gpt-5.5`, `claude-opus-4-8`, `claude-sonnet-5`, and `claude-fable-5`
49
+ - Supported launcher choices: `gpt-5.6`, `gpt-5.6-sol-max`, `gpt-5.6-sol-ultra`, `gpt-5.6-sol`, `gpt-5.5`, `claude-opus-4-8`, `claude-sonnet-5`, `claude-fable-5`, and `gpt-5.6-terra`
46
50
  - Default reasoning effort displayed locally: `xhigh`; SOL Max and SOL Ultra retain their explicit premium labels.
47
51
  - Reasoning hint sent in launcher env: model-specific
48
52
  - Approval policy: `never`
49
53
  - Sandbox mode: `danger-full-access`
50
54
  - Display wording for permissions: `Full Access` in launcher-owned copy
51
- - Local model catalog: `~/.codexclaude/model_catalog.json`; this keeps the native `/model` picker limited to the supported choices and prevents fallback metadata warnings for GPT-5.6 SOL, SOL Max, SOL Ultra, Opus 4.8, Sonnet 5, and Fable 5.
55
+ - Local model catalog: `~/.codexclaude/model_catalog.json`; this keeps the native `/model` picker limited to the supported choices and prevents fallback metadata warnings for GPT-5.6 Terra, SOL, SOL Max, SOL Ultra, Opus 4.8, Sonnet 5, and Fable 5.
52
56
  - Service tier: omitted by default; `/fast` remains user-controlled and billed server-side when active.
53
57
  - TUI status line: `model-with-reasoning`, `fast-mode`, `current-dir`
54
58
  - Fable 5 stays visible to the user while the backend applies its server-managed route and billing policy.
@@ -61,7 +65,7 @@ Before launching the runtime, the launcher calls `/api/v1/wallet/status`, then `
61
65
  Expected status line:
62
66
 
63
67
  ```text
64
- Magnetapi Client v2.0.23 · gpt-5.6 xhigh · ~/project · Wallet $20.00
68
+ MagnetAPI.org Codex CLI v2.0.25 · gpt-5.6 xhigh · ~/project · Wallet $20.00
65
69
  ```
66
70
 
67
71
  ## Upgrade Checklist
@@ -71,7 +75,7 @@ When updating the bundled runtime:
71
75
  1. Update `CODEX_VERSION` in `bin/codexclaude.js`.
72
76
  2. Update `@openai/codex` in `package.json` and `package-lock.json`.
73
77
  3. Bump the launcher package version.
74
- 4. Keep `APP_DISPLAY_NAME = "Magnetapi Client"`.
78
+ 4. Keep `APP_DISPLAY_NAME = "MagnetAPI.org Codex CLI"`.
75
79
  5. Keep `DEFAULT_MODEL_ID = "gpt-5.6"`.
76
80
  6. Keep `reasoningEffortForModel()` and model-specific visible reasoning.
77
81
  7. Keep Full Access defaults: `approval_policy = "never"` and `sandbox_mode = "danger-full-access"`.
@@ -79,7 +83,9 @@ When updating the bundled runtime:
79
83
  9. Keep `clearUpstreamUpdateCache()` deleting `~/.codex/version.json`.
80
84
  10. Keep direct platform binary launch and do not fall back to the upstream npm wrapper.
81
85
  11. Keep update checks limited to `/api/v1/codexclaude/version` and `@codexapi/codexclaude` npm metadata.
82
- 12. Keep the managed `MODELS` map and local model catalog, including SOL Max and SOL Ultra.
83
- 13. Keep bearer username auth and the `X-CodexAPI-*` headers.
84
- 14. Update `README.md`, `CUSTOMIZATIONS.md`, and `codexclaude.md`.
85
- 15. Run `node --check bin/codexclaude.js`, a temporary-home setup test, `npm pack --dry-run`, and endpoint validation before publishing.
86
+ 12. Keep the interactive `Upgrade Now` flow installing `@codexapi/codexclaude@latest` without a shell and relaunching automatically.
87
+ 13. Keep `codex` as a package alias and the conditional, non-overwriting `claude` postinstall alias.
88
+ 14. Keep the managed `MODELS` map and local model catalog, including Terra, SOL Max, and SOL Ultra.
89
+ 15. Keep bearer username auth and the `X-CodexAPI-*` headers.
90
+ 16. Update `README.md`, `CUSTOMIZATIONS.md`, and `codexclaude.md`.
91
+ 17. Run syntax checks, temporary-home setup, alias-preservation tests, `npm pack --dry-run`, and endpoint validation before publishing.
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # codexclaude
2
2
 
3
- `codexclaude` installs the Magnetapi Client for customers who want one coding CLI that can use GPT-5.6, GPT-5.6 SOL, GPT-5.6 SOL Max, GPT-5.6 SOL Ultra, ChatGPT-5.5, Opus 4.8, Sonnet 5, or Fable 5 against the same Token Wallet.
3
+ `codexclaude` installs the MagnetAPI.org Codex CLI for customers who want one coding CLI that can use GPT-5.6, GPT-5.6 Terra, GPT-5.6 SOL, GPT-5.6 SOL Max, GPT-5.6 SOL Ultra, ChatGPT-5.5, Opus 4.8, Sonnet 5, or Fable 5 against the same Token Wallet.
4
4
 
5
- Version `2.0.23` is a required client sync release. It bundles official Codex runtime dependency `@openai/codex@0.144.3`, launches the platform-native runtime binary directly, disables upstream OpenAI update prompts, and applies account, wallet, model, Full Access, GPT-5.6/xhigh defaults, and managed model metadata before each coding session starts. Model menus no longer display wallet multiplier notices; billing remains managed by the server.
5
+ Version `2.0.25` is a required client sync release. It bundles official Codex runtime dependency `@openai/codex@0.145.0`, launches the platform-native runtime binary directly, disables upstream OpenAI update prompts, and applies account, wallet, model, Full Access, GPT-5.6/xhigh defaults, and managed model metadata before each coding session starts. Model menus no longer display wallet multiplier notices; billing remains managed by the server.
6
6
 
7
7
  ## Install Or Update
8
8
 
9
9
  ```bash
10
- npm install -g https://codexapi.pro/downloads/codexapi-codexclaude-2.0.23.tgz
10
+ npm install -g @codexapi/codexclaude@latest
11
11
  ```
12
12
 
13
13
  This does not delete local session history. The update replaces the `codexclaude` launcher package, refreshes the bundled runtime dependency, and rewrites the managed provider config the next time `codexclaude setup`, `codexclaude login`, or `codexclaude start` runs.
@@ -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
- Version `2.0.23` is currently enforced as the minimum supported version, so older launchers show a required update message with the exact hosted tarball command above.
19
+ Version `2.0.25` is currently enforced as the minimum supported version. A compatible older launcher presents `Upgrade Now`; selecting it installs `@codexapi/codexclaude@latest` and relaunches the requested action automatically. Non-interactive terminals print the same npm command instead of hanging for input.
20
20
 
21
21
  ## First Login
22
22
 
@@ -44,7 +44,17 @@ Switch model:
44
44
  codexclaude model
45
45
  ```
46
46
 
47
- Available model labels are `GPT-5.6`, `GPT-5.6 SOL Max`, `GPT-5.6 SOL Ultra`, `GPT-5.6 SOL`, `ChatGPT-5.5`, `Opus 4.8`, `Sonnet 5`, and `Fable 5`. All models use a Responses-compatible endpoint and the same customer Token Wallet.
47
+ Available model labels are `GPT-5.6`, `GPT-5.6 SOL Max`, `GPT-5.6 SOL Ultra`, `GPT-5.6 SOL`, `ChatGPT-5.5`, `Opus 4.8`, `Sonnet 5`, `Fable 5`, and `GPT-5.6 Terra`. All models use a Responses-compatible endpoint and the same customer Token Wallet.
48
+
49
+ ## Launch Commands
50
+
51
+ The managed package installs `codexclaude` and `codex` as equivalent launch commands. During a global install, it also creates a `claude` alias only when no existing `claude` command can be found. If official Claude Code is already installed, its native `claude` command is preserved.
52
+
53
+ ```bash
54
+ codexclaude
55
+ codex
56
+ claude
57
+ ```
48
58
 
49
59
  Show current launcher changes:
50
60
 
@@ -57,17 +67,17 @@ codexclaude changelog
57
67
  Before launching the coding runtime, the app prints a compact status line like:
58
68
 
59
69
  ```text
60
- Magnetapi Client v2.0.23 · gpt-5.6 xhigh · ~/project · Wallet $20.00
70
+ MagnetAPI.org Codex CLI v2.0.25 · gpt-5.6 xhigh · ~/project · Wallet $20.00
61
71
  ```
62
72
 
63
73
  ## Preserved Customizations
64
74
 
65
75
  - Dashboard Username or Email Address plus password login for CodexAPI.pro, ChatPlus.chat, MyAPI.world, and MagnetAPI.org.
66
- - GPT-5.6, GPT-5.6 SOL Max, GPT-5.6 SOL Ultra, GPT-5.6 SOL, ChatGPT-5.5, Opus 4.8, Sonnet 5, or Fable 5 model selection, with GPT-5.6/xhigh as the default.
76
+ - GPT-5.6, GPT-5.6 Terra, GPT-5.6 SOL Max, GPT-5.6 SOL Ultra, GPT-5.6 SOL, ChatGPT-5.5, Opus 4.8, Sonnet 5, or Fable 5 model selection, with GPT-5.6/xhigh as the default.
67
77
  - Service-specific Responses-compatible provider for the dashboard account that logged in.
68
78
  - Full Access defaults: approval policy `never` and sandbox mode `danger-full-access`.
69
79
  - Model-specific visible reasoning in the local UI while the API server keeps upstream runtime effort server-managed.
70
- - A local `~/.codexclaude/model_catalog.json` file so the native `/model` picker lists only the supported Magnetapi Client choices, including SOL Max and SOL Ultra.
80
+ - 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.
71
81
  - No default fast service tier. Fast mode is billed only when the user enables it inside the client.
72
82
  - Token Wallet balance lookup before launch without exposing separate `status` or `usage` launcher commands.
73
83
  - Backend-identifying request headers so the API can enforce account and plan rules server-side.
@@ -7,12 +7,14 @@ import { homedir } from "node:os";
7
7
  import path from "node:path";
8
8
  import readline from "node:readline/promises";
9
9
  import { stdin as input, stdout as output } from "node:process";
10
+ import { fileURLToPath } from "node:url";
11
+ import { installSafeClaudeAlias } from "../scripts/install-safe-aliases.js";
10
12
 
11
13
  const require = createRequire(import.meta.url);
12
14
 
13
- const APP_VERSION = "2.0.23";
14
- const CODEX_VERSION = "0.144.3";
15
- const APP_DISPLAY_NAME = "Magnetapi Client";
15
+ const APP_VERSION = "2.0.25";
16
+ const CODEX_VERSION = "0.145.0";
17
+ const APP_DISPLAY_NAME = "MagnetAPI.org Codex CLI";
16
18
  const DEFAULT_MODEL_ID = "gpt-5.6";
17
19
  const DEFAULT_DISPLAY_REASONING_EFFORT = "xhigh";
18
20
  const DEFAULT_SERVER_REASONING_EFFORT = "xhigh";
@@ -24,7 +26,8 @@ const VERSION_CHECK_PATH = "/api/v1/codexclaude/version";
24
26
  const NPM_PACKAGE_NAME = "@codexapi/codexclaude";
25
27
  const NPM_LATEST_URL = "https://registry.npmjs.org/@codexapi%2Fcodexclaude/latest";
26
28
  const HOSTED_TARBALL_URL = `https://codexapi.pro/downloads/codexapi-codexclaude-${APP_VERSION}.tgz`;
27
- const UPDATE_COMMAND = `npm install -g ${HOSTED_TARBALL_URL}`;
29
+ const UPDATE_COMMAND = `npm install -g ${NPM_PACKAGE_NAME}@latest`;
30
+ const HOSTED_UPDATE_COMMAND = `npm install -g ${HOSTED_TARBALL_URL}`;
28
31
  const CONFIG_DIR = path.join(homedir(), ".codexclaude");
29
32
  const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
30
33
  const MODEL_CATALOG_FILE = path.join(CONFIG_DIR, "model_catalog.json");
@@ -119,13 +122,20 @@ const MODELS = {
119
122
  aliases: ["8", "fable", "fable-5", "fabel", "fabel-5", "claude-fable-5", "claude-fabel-5"],
120
123
  premium: true,
121
124
  },
125
+ "gpt-5.6-terra": {
126
+ id: "gpt-5.6-terra",
127
+ label: "GPT-5.6 Terra",
128
+ aliases: ["9", "terra", "gpt-5.6-terra", "gpt56-terra"],
129
+ reasoningEffort: "xhigh",
130
+ },
122
131
  };
123
132
 
124
133
  async function main() {
125
134
  ensureExecutable();
135
+ ensureSafeCommandAliases();
126
136
  const [command = "start", ...args] = process.argv.slice(2);
127
137
  if (["-v", "--version", "version"].includes(command)) {
128
- console.log(`${APP_DISPLAY_NAME} ${APP_VERSION}`);
138
+ console.log(`${APP_DISPLAY_NAME} v${APP_VERSION}`);
129
139
  return;
130
140
  }
131
141
  if (["-h", "--help", "help"].includes(command)) {
@@ -136,7 +146,9 @@ async function main() {
136
146
  await printChangelog();
137
147
  return;
138
148
  }
139
- await enforceLauncherVersion();
149
+ if (await enforceLauncherVersion()) {
150
+ return;
151
+ }
140
152
  if (command === "login") {
141
153
  await loginFlow();
142
154
  return;
@@ -170,14 +182,14 @@ async function main() {
170
182
 
171
183
  function printHelp() {
172
184
  console.log(`
173
- ${APP_DISPLAY_NAME} ${APP_VERSION}
185
+ ${APP_DISPLAY_NAME} v${APP_VERSION}
174
186
 
175
187
  Commands:
176
188
  codexclaude login Login with dashboard username/email and password
177
- codexclaude model Select GPT-5.6, SOL modes, Opus 4.8, Sonnet 5, or Fable 5
189
+ codexclaude model Select GPT-5.6, Terra, SOL modes, Opus 4.8, Sonnet 5, or Fable 5
178
190
  codexclaude changelog Show the latest CodexAPI.pro launcher changes
179
191
  codexclaude setup Rewrite ~/.codex/config.toml with Full Access defaults
180
- codexclaude start Start Magnetapi Client with --search
192
+ codexclaude start Start ${APP_DISPLAY_NAME} with --search
181
193
  codexclaude resume Resume the latest coding session with --search
182
194
  codexclaude logout Remove saved codexclaude account state
183
195
 
@@ -187,7 +199,7 @@ Any other command is passed through to the bundled coding runtime after Magnetap
187
199
 
188
200
  async function printChangelog() {
189
201
  const metadata = await getJson(`${VERSION_CHECK_PATH}?current=${encodeURIComponent(APP_VERSION)}`);
190
- console.log(`codexclaude ${metadata?.latestVersion || APP_VERSION}`);
202
+ console.log(`${APP_DISPLAY_NAME} v${metadata?.latestVersion || APP_VERSION}`);
191
203
  console.log(`Required minimum: ${metadata?.minimumVersion || APP_VERSION}`);
192
204
  const changes = Array.isArray(metadata?.changes) ? metadata.changes : [];
193
205
  if (changes.length) {
@@ -268,7 +280,7 @@ async function loginWithServiceSelection({ username, password, selectedService,
268
280
  const loginBody = {
269
281
  username,
270
282
  password,
271
- deviceName: `codexclaude ${APP_VERSION}`,
283
+ deviceName: `${APP_DISPLAY_NAME} v${APP_VERSION}`,
272
284
  };
273
285
  if (selectedService) {
274
286
  return {
@@ -414,7 +426,7 @@ async function postJson(pathname, body, origin = API_ORIGIN) {
414
426
 
415
427
  async function enforceLauncherVersion() {
416
428
  if (isTruthy(process.env.CODEXCLAUDE_DISABLE_UPDATE_CHECK)) {
417
- return;
429
+ return false;
418
430
  }
419
431
  const params = new URLSearchParams({ current: APP_VERSION });
420
432
  let metadata = null;
@@ -424,12 +436,83 @@ async function enforceLauncherVersion() {
424
436
  metadata = null;
425
437
  }
426
438
  if (metadata?.updateRequired || isOlderVersion(APP_VERSION, metadata?.minimumVersion)) {
427
- throw new Error(updateRequiredMessage(metadata));
439
+ await runMandatoryUpgrade(metadata);
440
+ return true;
428
441
  }
429
442
  const updateMetadata = optionalUpdateMetadata(metadata, await npmLatestMetadata());
430
443
  if (updateMetadata) {
431
444
  printOptionalUpdateNotice(updateMetadata);
432
445
  }
446
+ return false;
447
+ }
448
+
449
+ async function runMandatoryUpgrade(metadata) {
450
+ const latest = metadata?.latestVersion || "latest";
451
+ const minimum = metadata?.minimumVersion || latest;
452
+ const changes = Array.isArray(metadata?.changes) ? metadata.changes.slice(0, 4) : [];
453
+ console.error(`\n${APP_DISPLAY_NAME} v${latest} is required before your next coding session.`);
454
+ console.error(`Installed: v${APP_VERSION} · Required: v${minimum}`);
455
+ for (const change of changes) {
456
+ console.error(`- ${change}`);
457
+ }
458
+ console.error("Your local project files and coding-session history will not be removed.\n");
459
+
460
+ let shouldUpgrade = isTruthy(process.env.CODEXCLAUDE_AUTO_UPDATE);
461
+ if (!shouldUpgrade) {
462
+ if (!input.isTTY || !output.isTTY) {
463
+ throw new Error(updateRequiredMessage(metadata));
464
+ }
465
+ const rl = readline.createInterface({ input, output });
466
+ try {
467
+ console.log(" 1. Upgrade Now");
468
+ console.log(" 2. Exit");
469
+ const answer = (await rl.question("Select [Upgrade Now]: ")).trim().toLowerCase();
470
+ shouldUpgrade = ["", "1", "upgrade", "upgrade now", "yes", "y"].includes(answer);
471
+ } finally {
472
+ rl.close();
473
+ }
474
+ }
475
+ if (!shouldUpgrade) {
476
+ throw new Error(`Upgrade cancelled. Run ${UPDATE_COMMAND} before starting codexclaude again.`);
477
+ }
478
+
479
+ console.log(`\nDownloading and installing ${NPM_PACKAGE_NAME}@latest...`);
480
+ const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
481
+ const exitCode = await spawnAndWait(npmCommand, ["install", "-g", `${NPM_PACKAGE_NAME}@latest`]);
482
+ if (exitCode !== 0) {
483
+ throw new Error(
484
+ `Automatic upgrade failed with exit code ${exitCode}. Run ${UPDATE_COMMAND}. ` +
485
+ `Hosted fallback: ${HOSTED_UPDATE_COMMAND}`,
486
+ );
487
+ }
488
+ console.log(`\nUpgrade complete. Restarting ${APP_DISPLAY_NAME} now...`);
489
+ const relaunchArgs = process.argv.slice(2);
490
+ const relaunchCommand = process.platform === "win32" ? "codexclaude.cmd" : "codexclaude";
491
+ try {
492
+ const relaunchExitCode = await spawnAndWait(relaunchCommand, relaunchArgs);
493
+ if (relaunchExitCode !== 0) {
494
+ throw new Error(`updated client exited with code ${relaunchExitCode}`);
495
+ }
496
+ } catch (error) {
497
+ throw new Error(
498
+ `The update installed successfully, but automatic restart failed: ${error.message}. ` +
499
+ "Run codexclaude to continue.",
500
+ );
501
+ }
502
+ }
503
+
504
+ async function spawnAndWait(command, args) {
505
+ return await new Promise((resolve, reject) => {
506
+ const child = spawn(command, args, { stdio: "inherit", env: process.env, shell: false });
507
+ child.once("error", reject);
508
+ child.once("exit", (code, signal) => {
509
+ if (signal) {
510
+ reject(new Error(`Upgrade process stopped by ${signal}.`));
511
+ return;
512
+ }
513
+ resolve(code ?? 1);
514
+ });
515
+ });
433
516
  }
434
517
 
435
518
  async function getJson(pathname) {
@@ -527,8 +610,8 @@ function updateRequiredMessage(metadata) {
527
610
  const latest = metadata?.latestVersion || "latest";
528
611
  const minimum = metadata?.minimumVersion || latest;
529
612
  return [
530
- `Update required: ${APP_DISPLAY_NAME} has updated to codexclaude ${latest}. This major release is required for all users so your local client stays synced with the managed model catalog, Full Access defaults, and provider config.`,
531
- `Installed codexclaude: ${APP_VERSION}. Required: ${minimum}. Latest: ${latest}.`,
613
+ `Update required: ${APP_DISPLAY_NAME} v${latest} is required so your local client stays synced with the managed model catalog, Full Access defaults, and provider config.`,
614
+ `Installed: v${APP_VERSION}. Required: v${minimum}. Latest: v${latest}.`,
532
615
  `Run: ${installCommand}`,
533
616
  "Your local session history will not be deleted. The update only replaces the codexclaude launcher and rewrites provider config backups.",
534
617
  ].join("\n");
@@ -562,7 +645,7 @@ function printOptionalUpdateNotice(metadata) {
562
645
  const border = "─".repeat(64);
563
646
  const line = (text) => `│ ${String(text)}`.slice(0, 65).padEnd(65) + "│";
564
647
  console.error(`\n┌${border}┐`);
565
- console.error(line(`codexclaude ${latest} is available. You can keep coding on ${APP_VERSION}.`));
648
+ console.error(line(`${APP_DISPLAY_NAME} v${latest} is available. You can keep coding on v${APP_VERSION}.`));
566
649
  console.error(line(`Update when ready: ${installCommand}`));
567
650
  for (const change of changes) {
568
651
  console.error(line(`• ${change}`));
@@ -713,6 +796,9 @@ function modelCatalogDescription(modelId) {
713
796
  if (modelId === "gpt-5.6-sol") {
714
797
  return "GPT-5.6 SOL native coding route with local coding tools and wallet billing.";
715
798
  }
799
+ if (modelId === "gpt-5.6-terra") {
800
+ return "GPT-5.6 Terra coding route with local coding tools and wallet billing.";
801
+ }
716
802
  if (modelId === "claude-opus-4-8") {
717
803
  return "Opus 4.8 coding route with local coding tools and wallet billing.";
718
804
  }
@@ -940,6 +1026,9 @@ function modelStatusName(model) {
940
1026
  if (model === "gpt-5.6-sol") {
941
1027
  return "gpt-5.6-sol";
942
1028
  }
1029
+ if (model === "gpt-5.6-terra") {
1030
+ return "gpt-5.6-terra";
1031
+ }
943
1032
  if (model === "claude-opus-4-8") {
944
1033
  return "opus-4.8";
945
1034
  }
@@ -979,6 +1068,9 @@ function normalizeConfig(config) {
979
1068
  if (["gpt-5-6-sol", "sol"].includes(normalized.model)) {
980
1069
  normalized.model = "gpt-5.6-sol";
981
1070
  }
1071
+ if (["gpt-5-6-terra", "gpt56-terra", "terra"].includes(normalized.model)) {
1072
+ normalized.model = "gpt-5.6-terra";
1073
+ }
982
1074
  if (["gpt-5-6", "gpt56", "chatgpt-5.6", "chatgpt-5-6"].includes(normalized.model)) {
983
1075
  normalized.model = "gpt-5.6";
984
1076
  }
@@ -1125,6 +1217,36 @@ function ensureExecutable() {
1125
1217
  }
1126
1218
  }
1127
1219
 
1220
+ function ensureSafeCommandAliases() {
1221
+ const prefix = installedGlobalPrefix();
1222
+ if (!prefix) {
1223
+ return;
1224
+ }
1225
+ installSafeClaudeAlias({
1226
+ isGlobalInstall: true,
1227
+ prefix,
1228
+ quiet: true,
1229
+ });
1230
+ }
1231
+
1232
+ function installedGlobalPrefix() {
1233
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
1234
+ const segments = packageRoot.split(path.sep);
1235
+ const nodeModulesIndex = segments.lastIndexOf("node_modules");
1236
+ if (nodeModulesIndex < 0 || nodeModulesIndex >= segments.length - 2) {
1237
+ return null;
1238
+ }
1239
+ const scope = segments[nodeModulesIndex + 1];
1240
+ if (scope !== "@codexapi") {
1241
+ return null;
1242
+ }
1243
+ const prefixSegments = process.platform === "win32"
1244
+ ? segments.slice(0, nodeModulesIndex)
1245
+ : segments.slice(0, Math.max(0, nodeModulesIndex - 1));
1246
+ const prefix = prefixSegments.join(path.sep) || path.parse(packageRoot).root;
1247
+ return prefix;
1248
+ }
1249
+
1128
1250
  main().catch((error) => {
1129
1251
  console.error(`codexclaude: ${error.message}`);
1130
1252
  process.exit(1);
package/codexclaude.md CHANGED
@@ -5,11 +5,12 @@ This file is the durable handoff for the `@codexapi/codexclaude` package in `/ro
5
5
  ## Current Release
6
6
 
7
7
  - Package name: `@codexapi/codexclaude`
8
- - Launcher version: `2.0.23`
9
- - Customer-facing app name: `Magnetapi Client`
10
- - Bundled runtime dependency: `@openai/codex@0.144.3`
11
- - Required install command: `npm install -g https://codexapi.pro/downloads/codexapi-codexclaude-2.0.23.tgz`
12
- - Backend minimum version: `2.0.23`
8
+ - Launcher version: `2.0.25`
9
+ - Customer-facing app name: `MagnetAPI.org Codex CLI`
10
+ - Bundled runtime dependency: `@openai/codex@0.145.0`
11
+ - Required install command: `npm install -g @codexapi/codexclaude@latest`
12
+ - Hosted fallback: `npm install -g https://codexapi.pro/downloads/codexapi-codexclaude-2.0.25.tgz`
13
+ - Backend minimum version: `2.0.25`
13
14
  - Default visible model: `GPT-5.6`
14
15
  - Default model slug: `gpt-5.6`
15
16
  - Default visible reasoning effort: `xhigh`; premium SOL Max and SOL Ultra retain their explicit `max` and `ultra` labels.
@@ -24,13 +25,13 @@ This file is the durable handoff for the `@codexapi/codexclaude` package in `/ro
24
25
  The launcher must present itself as:
25
26
 
26
27
  ```text
27
- Magnetapi Client v2.0.23
28
+ MagnetAPI.org Codex CLI v2.0.25
28
29
  ```
29
30
 
30
31
  Normal pre-launch status should look like:
31
32
 
32
33
  ```text
33
- Magnetapi Client v2.0.23 · gpt-5.6 xhigh · ~/project · Wallet $20.00
34
+ MagnetAPI.org Codex CLI v2.0.25 · gpt-5.6 xhigh · ~/project · Wallet $20.00
34
35
  ```
35
36
 
36
37
  Do not show OpenAI update notices, OpenAI npm install commands, OpenAI release links, or the upstream runtime version in launcher-owned output. The package still depends on the official runtime internally, but the customer update surface is ours.
@@ -45,6 +46,7 @@ The launcher command `codexclaude model` must list these customer-visible models
45
46
  - `claude-opus-4-8` displayed as `Opus 4.8`
46
47
  - `claude-sonnet-5` displayed as `Sonnet 5`
47
48
  - `claude-fable-5` displayed as `Fable 5`
49
+ - `gpt-5.6-terra` displayed as `GPT-5.6 Terra`
48
50
 
49
51
  GPT-5.6 must be the default when a new config is created or a legacy config contains an unsupported Gemini/Deepseek value. It is displayed with `xhigh` reasoning while the API servers execute Codex-family requests through the managed GPT-5.6 Terra/xhigh signed-in target. 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.
50
52
 
@@ -55,11 +57,13 @@ GPT-5.6 must be the default when a new config is created or a legacy config cont
55
57
  - `https://codexapi.pro/api/v1/codexclaude/version`
56
58
  - `https://registry.npmjs.org/@codexapi%2Fcodexclaude/latest`
57
59
 
58
- It must not check `@openai/codex` npm metadata, OpenAI GitHub releases, or any upstream OpenAI update endpoint. Version `2.0.23` is a forced release: the backend `minimumVersion` equals `2.0.23`, and older clients must show an update-required message with the hosted tarball command.
60
+ It must not check `@openai/codex` npm metadata, OpenAI GitHub releases, or any upstream OpenAI update endpoint. Version `2.0.25` is a forced release: the backend `minimumVersion` equals `2.0.25`. Compatible older launchers offer an interactive `Upgrade Now` action that invokes `npm install -g @codexapi/codexclaude@latest` without shell interpolation. 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.
61
+
62
+ The npm package owns `codexclaude` and `codex`. Its postinstall script may create a `claude` alias only during a global installation and only when neither the target npm prefix nor any directory on `PATH` already contains a Claude command. If native Claude Code exists, report that it was preserved and do not write any `claude` shim.
59
63
 
60
64
  The launcher writes `check_for_update_on_startup = false` and removes `~/.codex/version.json` so the bundled runtime does not display stale upstream update prompts. The launcher also resolves the platform-native runtime binary directly from the optional package (`@openai/codex-linux-x64`, `@openai/codex-darwin-arm64`, and so on). Do not fall back to the upstream npm wrapper, because that wrapper can re-enable upstream managed update behavior.
61
65
 
62
- The optional platform-native runtime packages can still contain upstream README files and hardcoded native strings inside the binary. Launcher-owned output must say `Magnetapi Client`; replacing native binary text itself requires a maintained forked native runtime build for every supported platform. Until such a fork exists, do not re-enable the upstream npm wrapper and do not present upstream update notices to customers.
66
+ The optional platform-native runtime packages can still contain upstream README files and hardcoded native strings inside the binary. Launcher-owned output must say `MagnetAPI.org Codex CLI`; replacing native binary text itself requires a maintained forked native runtime build for every supported platform. Until such a fork exists, do not re-enable the upstream npm wrapper and do not present upstream update notices to customers.
63
67
 
64
68
  ## Generated Config Contract
65
69
 
@@ -83,7 +87,7 @@ base_url = "<service Responses URL>"
83
87
  experimental_bearer_token = "<customer System Token/API username>"
84
88
  wire_api = "responses"
85
89
  supports_websockets = false
86
- http_headers = { "X-CodexAPI-Client" = "codexclaude", "X-CodexAPI-Client-Version" = "2.0.23", "X-CodexAPI-Selected-Model" = "<selected model>" }
90
+ http_headers = { "X-CodexAPI-Client" = "codexclaude", "X-CodexAPI-Client-Version" = "2.0.25", "X-CodexAPI-Selected-Model" = "<selected model>" }
87
91
 
88
92
  [tui]
89
93
  status_line = ["model-with-reasoning", "fast-mode", "current-dir"]
@@ -91,7 +95,7 @@ status_line_use_colors = true
91
95
  terminal_title = ["project-name", "model-with-reasoning", "run-state"]
92
96
  ```
93
97
 
94
- The generated model catalog must contain full metadata for every supported slug, including `gpt-5.6`, `gpt-5.6-sol-max`, and `gpt-5.6-sol-ultra`. This prevents fallback metadata warnings such as:
98
+ The generated model catalog must contain full metadata for every supported slug, including `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:
95
99
 
96
100
  ```text
97
101
  Model metadata for `claude-opus-4-8` not found. Defaulting to fallback metadata; this can degrade performance and cause issues.
@@ -125,17 +129,19 @@ When updating the bundled runtime dependency:
125
129
  2. Run `npm install @openai/codex@<version> --save-exact`.
126
130
  3. Bump `package.json` and `package-lock.json` to a new `@codexapi/codexclaude` version.
127
131
  4. Update `APP_VERSION` and `CODEX_VERSION` in `bin/codexclaude.js`.
128
- 5. Preserve `APP_DISPLAY_NAME = "Magnetapi Client"`.
132
+ 5. Preserve `APP_DISPLAY_NAME = "MagnetAPI.org Codex CLI"`.
129
133
  6. Preserve `DEFAULT_MODEL_ID = "gpt-5.6"`.
130
134
  7. Preserve `DISPLAY_REASONING_EFFORT = "xhigh"` and `SERVER_REASONING_EFFORT = "xhigh"` unless operations explicitly changes the launcher-visible contract.
131
135
  8. Preserve Full Access defaults and the local model catalog.
132
136
  9. Preserve direct platform-native binary launch.
133
137
  10. Preserve update checks through our version endpoint and `@codexapi/codexclaude` npm metadata only.
134
- 11. Preserve deletion of `~/.codex/version.json` and `check_for_update_on_startup = false`.
135
- 12. Update customer setup scripts on CodexAPI.pro, ChatPlus.chat, MyAPI.world, MagnetAPI.org, and VIP pages to use the exact hosted tarball command.
136
- 13. Update backend `CODEXCLAUDE_LATEST_VERSION`, `CODEXCLAUDE_MIN_VERSION`, and hosted tarball URL.
137
- 14. Update this file, `README.md`, and `CUSTOMIZATIONS.md`.
138
- 15. Run validation and publish.
138
+ 11. Preserve the interactive `Upgrade Now` flow, shell-free npm invocation, and automatic relaunch.
139
+ 12. Preserve `codex` as a package alias and the conditional native-Claude-safe postinstall alias.
140
+ 13. Preserve deletion of `~/.codex/version.json` and `check_for_update_on_startup = false`.
141
+ 14. Update customer setup scripts on CodexAPI.pro, ChatPlus.chat, MyAPI.world, MagnetAPI.org, and VIP pages to use the current release.
142
+ 15. Update backend `CODEXCLAUDE_LATEST_VERSION`, `CODEXCLAUDE_MIN_VERSION`, and hosted tarball URL.
143
+ 16. Update this file, `README.md`, and `CUSTOMIZATIONS.md`.
144
+ 17. Run validation and publish.
139
145
 
140
146
  ## Validation Commands
141
147
 
@@ -153,7 +159,7 @@ tmp_home="$(mktemp -d)"
153
159
  mkdir -p "$tmp_home/.codexclaude"
154
160
  cat > "$tmp_home/.codexclaude/config.json" <<'JSON'
155
161
  {
156
- "version": "2.0.23",
162
+ "version": "2.0.25",
157
163
  "serviceId": "codexapi",
158
164
  "serviceLabel": "CodexAPI.pro",
159
165
  "apiOrigin": "https://codexapi.pro",
@@ -185,15 +191,30 @@ Verify the generated model catalog contains only:
185
191
  - `claude-opus-4-8`
186
192
  - `claude-sonnet-5`
187
193
  - `claude-fable-5`
194
+ - `gpt-5.6-terra`
188
195
 
189
196
  After packaging, copy the tarball to the public downloads directories, restart the backend, and verify:
190
197
 
191
198
  ```bash
192
199
  curl -fsS "https://codexapi.pro/api/v1/codexclaude/version?current=2.0.17"
193
- curl -fsSI "https://codexapi.pro/downloads/codexapi-codexclaude-2.0.23.tgz"
200
+ curl -fsSI "https://codexapi.pro/downloads/codexapi-codexclaude-2.0.25.tgz"
194
201
  ```
195
202
 
196
- The version endpoint must report `latestVersion = 2.0.23`, `minimumVersion = 2.0.23`, and `updateRequired = true` for old clients.
203
+ The version endpoint must report `latestVersion = 2.0.25`, `minimumVersion = 2.0.25`, and `updateRequired = true` for old clients.
204
+
205
+ ## Version 2.0.25 Changes
206
+
207
+ - Updated the bundled runtime dependency to `@openai/codex@0.145.0`.
208
+ - Added `GPT-5.6 Terra` to the managed `/model` catalog.
209
+ - Added `codex` as a managed launch alias and a conditional `claude` alias that preserves native Claude Code.
210
+ - Changed mandatory updates to relaunch the requested action automatically after installation.
211
+
212
+ ## Version 2.0.24 Changes
213
+
214
+ - Updated the bundled runtime dependency to `@openai/codex@0.144.4`.
215
+ - Changed launcher-owned titles, help, status, terminal title, and version output to `MagnetAPI.org Codex CLI v2.0.24`.
216
+ - Added the interactive mandatory `Upgrade Now` action backed by `@codexapi/codexclaude@latest`.
217
+ - Preserved dashboard login, wallet status, Full Access, managed models, web search, local tools, and upstream update suppression.
197
218
 
198
219
  ## Version 2.0.23 Changes
199
220
 
package/package.json CHANGED
@@ -1,23 +1,28 @@
1
1
  {
2
2
  "name": "@codexapi/codexclaude",
3
- "version": "2.0.23",
4
- "description": "Magnetapi Client launcher for ChatGPT-5.5, Opus 4.8, Sonnet 5, and Fable 5.",
3
+ "version": "2.0.25",
4
+ "description": "MagnetAPI.org Codex CLI for GPT-5.6, Opus 4.8, Sonnet 5, and Fable 5.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "bin": {
8
- "codexclaude": "bin/codexclaude.js"
8
+ "codexclaude": "bin/codexclaude.js",
9
+ "codex": "bin/codexclaude.js"
9
10
  },
10
11
  "files": [
11
12
  "bin",
13
+ "scripts",
12
14
  "README.md",
13
15
  "CUSTOMIZATIONS.md",
14
16
  "codexclaude.md"
15
17
  ],
18
+ "scripts": {
19
+ "postinstall": "node scripts/install-safe-aliases.js"
20
+ },
16
21
  "engines": {
17
22
  "node": ">=20"
18
23
  },
19
24
  "dependencies": {
20
- "@openai/codex": "0.144.3"
25
+ "@openai/codex": "0.145.0"
21
26
  },
22
27
  "publishConfig": {
23
28
  "access": "public"
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {
4
+ chmodSync,
5
+ existsSync,
6
+ lstatSync,
7
+ mkdirSync,
8
+ symlinkSync,
9
+ writeFileSync,
10
+ } from "node:fs";
11
+ import path from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
15
+ const launcherPath = path.join(packageRoot, "bin", "codexclaude.js");
16
+
17
+ export function installSafeClaudeAlias(options = {}) {
18
+ const isGlobalInstall =
19
+ options.isGlobalInstall ??
20
+ String(process.env.npm_config_global || "").toLowerCase() === "true";
21
+ const quiet = Boolean(options.quiet);
22
+ if (!isGlobalInstall || isTruthy(process.env.CODEXCLAUDE_SKIP_COMMAND_ALIASES)) {
23
+ return { status: "skipped" };
24
+ }
25
+
26
+ const prefix = String(options.prefix || process.env.npm_config_prefix || "").trim();
27
+ if (!prefix) {
28
+ if (!quiet) {
29
+ console.warn("codexclaude: skipped the optional claude alias because npm did not provide its global prefix.");
30
+ }
31
+ return { status: "missing-prefix" };
32
+ }
33
+
34
+ const binDir = process.platform === "win32" ? prefix : path.join(prefix, "bin");
35
+ const aliasPaths = claudeAliasPaths(binDir);
36
+ const existingCommand = findCommandOnPath("claude", aliasPaths);
37
+ const existingAlias = aliasPaths.find((candidate) => existsSync(candidate));
38
+
39
+ if (existingCommand || existingAlias) {
40
+ const preserved = existingCommand || existingAlias;
41
+ if (!quiet) {
42
+ console.log(`codexclaude: preserved the existing native claude command at ${preserved}.`);
43
+ }
44
+ return { status: "preserved", path: preserved };
45
+ }
46
+
47
+ try {
48
+ mkdirSync(binDir, { recursive: true });
49
+ if (process.platform === "win32") {
50
+ installWindowsAliases(aliasPaths);
51
+ } else {
52
+ symlinkSync(launcherPath, aliasPaths[0]);
53
+ chmodSync(aliasPaths[0], 0o755);
54
+ }
55
+ if (!quiet) {
56
+ console.log("codexclaude: installed the optional claude launch alias; codex and codexclaude are also available.");
57
+ }
58
+ return { status: "installed", paths: aliasPaths.filter((candidate) => existsSync(candidate)) };
59
+ } catch (error) {
60
+ if (!quiet) {
61
+ console.warn(`codexclaude: could not install the optional claude alias (${error.message}).`);
62
+ }
63
+ return { status: "failed", error: error.message };
64
+ }
65
+ }
66
+
67
+ function claudeAliasPaths(directory) {
68
+ if (process.platform === "win32") {
69
+ return [
70
+ path.join(directory, "claude"),
71
+ path.join(directory, "claude.cmd"),
72
+ path.join(directory, "claude.ps1"),
73
+ path.join(directory, "claude.exe"),
74
+ ];
75
+ }
76
+ return [path.join(directory, "claude")];
77
+ }
78
+
79
+ function findCommandOnPath(command, ignoredPaths) {
80
+ const ignored = new Set(ignoredPaths.map(normalizePath));
81
+ const pathEntries = String(process.env.PATH || "")
82
+ .split(path.delimiter)
83
+ .map((entry) => entry.trim())
84
+ .filter(Boolean);
85
+ const names =
86
+ process.platform === "win32"
87
+ ? [command, `${command}.exe`, `${command}.cmd`, `${command}.bat`, `${command}.ps1`]
88
+ : [command];
89
+ for (const entry of pathEntries) {
90
+ for (const name of names) {
91
+ const candidate = path.resolve(entry, name);
92
+ if (ignored.has(normalizePath(candidate)) || !existsSync(candidate)) {
93
+ continue;
94
+ }
95
+ try {
96
+ if (lstatSync(candidate).isFile() || lstatSync(candidate).isSymbolicLink()) {
97
+ return candidate;
98
+ }
99
+ } catch {
100
+ // Ignore a path entry that disappears while npm is installing.
101
+ }
102
+ }
103
+ }
104
+ return null;
105
+ }
106
+
107
+ function installWindowsAliases(paths) {
108
+ const [shellPath, cmdPath, ps1Path] = paths;
109
+ const node = quoteForCmd(process.execPath);
110
+ const launcher = quoteForCmd(launcherPath);
111
+ writeFileSync(
112
+ shellPath,
113
+ `#!/bin/sh\nexec "${escapeForShell(process.execPath)}" "${escapeForShell(launcherPath)}" "$@"\n`,
114
+ { encoding: "utf8", mode: 0o755 },
115
+ );
116
+ writeFileSync(
117
+ cmdPath,
118
+ `@ECHO off\r\n${node} ${launcher} %*\r\n`,
119
+ { encoding: "utf8" },
120
+ );
121
+ writeFileSync(
122
+ ps1Path,
123
+ `& '${escapeForPowerShell(process.execPath)}' '${escapeForPowerShell(launcherPath)}' @args\nexit $LASTEXITCODE\n`,
124
+ { encoding: "utf8" },
125
+ );
126
+ }
127
+
128
+ function normalizePath(value) {
129
+ const resolved = path.resolve(value);
130
+ return process.platform === "win32" ? resolved.toLowerCase() : resolved;
131
+ }
132
+
133
+ function quoteForCmd(value) {
134
+ return `"${String(value).replaceAll('"', '""')}"`;
135
+ }
136
+
137
+ function escapeForPowerShell(value) {
138
+ return String(value).replaceAll("'", "''");
139
+ }
140
+
141
+ function escapeForShell(value) {
142
+ return String(value).replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("$", "\\$").replaceAll("`", "\\`");
143
+ }
144
+
145
+ function isTruthy(value) {
146
+ return ["1", "true", "yes", "on"].includes(String(value || "").trim().toLowerCase());
147
+ }
148
+
149
+ if (path.resolve(process.argv[1] || "") === fileURLToPath(import.meta.url)) {
150
+ installSafeClaudeAlias();
151
+ }