@codexapi/codexclaude 2.0.16 → 2.0.19

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,54 +1,84 @@
1
- # CodexAPI.pro Customizations
1
+ # Magnetapi Client Customizations
2
2
 
3
- `codexclaude` intentionally tracks the managed coding runtime while keeping a thin CodexAPI.pro launcher layer.
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.
4
4
 
5
5
  ## Runtime
6
6
 
7
- - Customer-facing app name: `Magnetapi.org Coding Agent`
8
- - Local launcher version: `2.0.16`
9
- - Bundled official Codex dependency: `@openai/codex@0.143.0`
10
- - Bundled coding runtime is managed internally and must not be advertised in customer-facing startup text.
7
+ - Customer-facing app name: `Magnetapi Client`
8
+ - Local launcher version: `2.0.19`
9
+ - Bundled official runtime dependency: `@openai/codex@0.144.1`
10
+ - Required install command: `npm install -g https://codexapi.pro/downloads/codexapi-codexclaude-2.0.19.tgz`
11
+ - Bundled runtime version is managed internally and must not be used for customer update prompts.
12
+ - Launcher update checks may call the CodexAPI.pro version endpoint and `@codexapi/codexclaude` npm metadata only.
13
+ - The launcher must never check `@openai/codex` npm metadata or OpenAI GitHub releases for update notices.
11
14
 
12
15
  ## Launcher Behavior
13
16
 
14
- - Authenticates customers against `https://codexapi.pro/api/v1/auth/login`.
15
- - Saves the returned API username in `~/.codexclaude/config.json`.
17
+ - Authenticates customers against the selected or auto-detected dashboard service: CodexAPI.pro, ChatPlus.chat, MyAPI.world, or MagnetAPI.org.
18
+ - Saves the returned API username/System Token in `~/.codexclaude/config.json`.
16
19
  - Rewrites `~/.codex/config.toml` before every launch.
17
- - Starts official Codex with `--search` by default.
18
- - Passes all unknown commands directly to the bundled coding runtime.
19
- - Provides `codexclaude changelog` so users can see recommended or required update changes from the terminal.
20
+ - Deletes stale `~/.codex/version.json` before writing managed config.
21
+ - 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
+ - Starts with `--search` by default.
24
+ - Passes unknown commands directly to the bundled runtime after config is applied.
25
+ - Provides `codexclaude changelog` using the managed version endpoint.
20
26
  - Does not expose separate `codexclaude status` or `codexclaude usage` commands; wallet information remains a compact pre-launch line.
21
- - Shows a non-blocking update notice at startup when a newer recommended launcher is available. Only versions below the backend minimum may be blocked.
27
+ - Version `2.0.19` is forced by the backend minimum version and older clients must show an update-required message.
22
28
 
23
29
  ## Provider Config
24
30
 
25
- The launcher writes a Codex model provider named `codexapi`:
31
+ The launcher writes a model provider named `codexapi`:
26
32
 
27
- - `base_url = "https://codexapi.pro/v1"` for ChatGPT-5.5, or `https://api-chicago.codexapi.pro/v1` for Claude-family models.
33
+ - `base_url` uses the logged-in service origin. CodexAPI.pro and ChatPlus Claude-family models keep the Chicago Responses endpoint; MyAPI.world and MagnetAPI.org keep their own API endpoints.
28
34
  - `wire_api = "responses"`
29
35
  - `supports_websockets = false`
30
36
  - `experimental_bearer_token` set to the customer API username
31
- - `http_headers` identify launcher traffic to CodexAPI.pro for server-side plan enforcement
37
+ - `http_headers` identify launcher traffic to the backend for server-side plan enforcement
38
+ - `check_for_update_on_startup = false`
39
+ - `analytics_enabled = false`
40
+ - `feedback_enabled = false`
32
41
 
33
42
  ## Runtime Defaults
34
43
 
35
- - Model: selected by the user, defaulting to `gpt-5.5`; supported launcher choices are `gpt-5.5`, `claude-opus-4-8`, `claude-sonnet-5`, and `claude-fable-5`.
36
- - Reasoning effort displayed in Codex: `xhigh`
37
- - Server-side upstream reasoning effort: `high`, enforced by CodexAPI.pro regardless of client display.
38
- - Local model catalog: `~/.codexclaude/model_catalog.json`; this keeps native Codex `/model` limited to the four supported CodexAPI.pro choices and prevents fallback metadata warnings for Opus 4.8, Sonnet 5, and Fable 5.
39
- - Service tier: omitted by default; `/fast` remains a user-controlled Codex setting and is billed server-side when active.
44
+ - Default model: `claude-opus-4-8` displayed as `Opus 4.8`
45
+ - Supported launcher choices: `gpt-5.5`, `claude-opus-4-8`, `claude-sonnet-5`, and `claude-fable-5`
46
+ - Reasoning effort displayed locally: `xhigh`
47
+ - Reasoning hint sent in launcher env: `xhigh`
40
48
  - Approval policy: `never`
41
49
  - Sandbox mode: `danger-full-access`
50
+ - 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 four supported choices and prevents fallback metadata warnings for Opus 4.8, Sonnet 5, and Fable 5.
52
+ - Service tier: omitted by default; `/fast` remains user-controlled and billed server-side when active.
42
53
  - TUI status line: `model-with-reasoning`, `fast-mode`, `current-dir`
43
- - Claude-family Responses traffic uses the Claude-compatible CodexAPI.pro endpoint for CodexAPI.pro and ChatPlus accounts, while MyAPI.world accounts keep the MyAPI endpoint.
44
- - Fable 5 stays visible to the user while the backend applies the custom routed premium path and 2x billing multiplier.
45
-
46
- Current backend state verified on 2026-07-08: Admin Manage Models controls runtime routing server-side. This operational routing must not change the launcher-visible model ids, model catalog, or customer-facing labels.
54
+ - Fable 5 stays visible to the user while the backend applies its custom routed premium path and billing multiplier.
47
55
 
48
56
  ## Wallet Display
49
57
 
50
- Before launching Codex, the launcher calls `/api/v1/me` using the saved API username as a bearer token and prints a compact status line:
58
+ Before launching the runtime, the launcher calls `/api/v1/wallet/status`, then `/api/v1/me`, then `/api/me` as fallback using the saved API username as bearer token. Wallet lookup failures must not block a local coding session.
59
+
60
+ Expected status line:
51
61
 
52
62
  ```text
53
- gpt-5.5 xhigh · ~/project · Wallet $20.00
63
+ Magnetapi Client v2.0.19 · opus-4.8 xhigh · ~/project · Wallet $20.00
54
64
  ```
65
+
66
+ ## Upgrade Checklist
67
+
68
+ When updating the bundled runtime:
69
+
70
+ 1. Update `CODEX_VERSION` in `bin/codexclaude.js`.
71
+ 2. Update `@openai/codex` in `package.json` and `package-lock.json`.
72
+ 3. Bump the launcher package version.
73
+ 4. Keep `APP_DISPLAY_NAME = "Magnetapi Client"`.
74
+ 5. Keep `DEFAULT_MODEL_ID = "claude-opus-4-8"`.
75
+ 6. Keep `DISPLAY_REASONING_EFFORT = "xhigh"`.
76
+ 7. Keep Full Access defaults: `approval_policy = "never"` and `sandbox_mode = "danger-full-access"`.
77
+ 8. Keep `check_for_update_on_startup = false`.
78
+ 9. Keep `clearUpstreamUpdateCache()` deleting `~/.codex/version.json`.
79
+ 10. Keep direct platform binary launch and do not fall back to the upstream npm wrapper.
80
+ 11. Keep update checks limited to `/api/v1/codexclaude/version` and `@codexapi/codexclaude` npm metadata.
81
+ 12. Keep the four-model `MODELS` map and local model catalog.
82
+ 13. Keep bearer username auth and the `X-CodexAPI-*` headers.
83
+ 14. Update `README.md`, `CUSTOMIZATIONS.md`, and `codexclaude.md`.
84
+ 15. Run `node --check bin/codexclaude.js`, a temporary-home setup test, `npm pack --dry-run`, and endpoint validation before publishing.
package/README.md CHANGED
@@ -1,26 +1,22 @@
1
1
  # codexclaude
2
2
 
3
- `codexclaude` installs the Magnetapi.org Coding Agent for customers who want one coding CLI that can use ChatGPT-5.5, Opus 4.8, Sonnet 5, or Fable 5 against the same Token Wallet.
3
+ `codexclaude` installs the Magnetapi Client for customers who want one coding CLI that can use ChatGPT-5.5, Opus 4.8, Sonnet 5, or Fable 5 against the same Token Wallet.
4
4
 
5
- Version `2.0.16` applies account, wallet, model, and Full Access defaults before the coding session starts. It bundles official Codex `0.143.0`.
5
+ Version `2.0.19` is a required major sync release. It bundles official Codex runtime dependency `@openai/codex@0.144.1`, launches the platform-native runtime binary directly, disables upstream OpenAI update prompts, and applies account, wallet, model, Full Access, Opus 4.8 default, and xhigh visible reasoning before each coding session starts.
6
6
 
7
- ## Install
7
+ ## Install Or Update
8
8
 
9
9
  ```bash
10
- npm install -g @codexapi/codexclaude@latest
10
+ npm install -g https://codexapi.pro/downloads/codexapi-codexclaude-2.0.19.tgz
11
11
  ```
12
12
 
13
- This installs the current `codexclaude` launcher from npm.
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.
14
14
 
15
15
  ## Update Notices
16
16
 
17
- CodexAPI.pro checks the CodexAPI.pro API and npm at startup. If a newer recommended launcher is available, the app shows a clear update notice and the exact command, then lets you keep coding. Only versions below the backend minimum are blocked.
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
- ```bash
20
- npm install -g @codexapi/codexclaude@2.0.16
21
- ```
22
-
23
- This does not delete your local Codex session history. The update only replaces the `codexclaude` launcher and refreshes the CodexAPI.pro provider config.
19
+ Version `2.0.19` is currently enforced as the minimum supported version, so older launchers show a required update message with the exact hosted tarball command above.
24
20
 
25
21
  ## First Login
26
22
 
@@ -28,7 +24,7 @@ This does not delete your local Codex session history. The update only replaces
28
24
  codexclaude login
29
25
  ```
30
26
 
31
- Enter the dashboard username or email address and password. The launcher saves the API username locally, writes `~/.codex/config.toml`, sets Full Access defaults, and lets you choose the coding model.
27
+ Enter the Dashboard Username or Email Address and password. The launcher can log in to CodexAPI.pro, ChatPlus.chat, MyAPI.world, or MagnetAPI.org, then saves the correct System Token locally, writes `~/.codex/config.toml`, sets Full Access defaults, and lets the customer choose the coding model. If the customer presses Enter at the model prompt, Opus 4.8 is selected by default.
32
28
 
33
29
  ## Start Coding
34
30
 
@@ -56,25 +52,23 @@ Show current launcher changes:
56
52
  codexclaude changelog
57
53
  ```
58
54
 
59
- ## Wallet Status
55
+ ## Startup Status
60
56
 
61
- Before launching Codex, the app prints a compact status line like:
57
+ Before launching the coding runtime, the app prints a compact status line like:
62
58
 
63
59
  ```text
64
- gpt-5.5 xhigh · ~/codexapi · Wallet $20.00
60
+ Magnetapi Client v2.0.19 · opus-4.8 xhigh · ~/project · Wallet $20.00
65
61
  ```
66
62
 
67
- ## Preserved CodexAPI.pro Customizations
63
+ ## Preserved Customizations
68
64
 
69
- - Dashboard username or email plus password login.
70
- - ChatGPT-5.5, Opus 4.8, Sonnet 5, or Fable 5 model selection.
71
- - CodexAPI.pro Responses-compatible provider at `https://codexapi.pro/v1`.
65
+ - Dashboard Username or Email Address plus password login for CodexAPI.pro, ChatPlus.chat, MyAPI.world, and MagnetAPI.org.
66
+ - ChatGPT-5.5, Opus 4.8, Sonnet 5, or Fable 5 model selection, with Opus 4.8 as the default.
67
+ - Service-specific Responses-compatible provider for the dashboard account that logged in.
72
68
  - Full Access defaults: approval policy `never` and sandbox mode `danger-full-access`.
73
- - xhigh visible reasoning in the local Codex UI while CodexAPI.pro keeps upstream runtime effort server-managed.
74
- - A local `~/.codexclaude/model_catalog.json` file so native Codex `/model` lists only ChatGPT-5.5, Opus 4.8, Sonnet 5, and Fable 5.
75
- - No default fast service tier. Fast mode is billed only when the user enables it inside Codex.
76
- - Magnetapi.org Coding Agent `2.0.16` with the current profile-compatible config enabled.
69
+ - xhigh 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 ChatGPT-5.5, Opus 4.8, Sonnet 5, and Fable 5.
71
+ - No default fast service tier. Fast mode is billed only when the user enables it inside the client.
77
72
  - Token Wallet balance lookup before launch without exposing separate `status` or `usage` launcher commands.
78
- - Opus 4.8 tool-call compatibility through the Chicago CodexAPI.pro Responses gateway.
79
- - Backend-identifying request headers so CodexAPI.pro can enforce subscription plan rules server-side.
80
- - Non-blocking update notices before coding starts, with an explicit update command when a newer recommended launcher exists.
73
+ - Backend-identifying request headers so the API can enforce account and plan rules server-side.
74
+ - Direct platform binary launch so the upstream npm wrapper cannot emit OpenAI update prompts.
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { spawn } from "node:child_process";
4
4
  import { createRequire } from "node:module";
5
- import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, chmodSync } from "node:fs";
5
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, chmodSync, unlinkSync } from "node:fs";
6
6
  import { homedir } from "node:os";
7
7
  import path from "node:path";
8
8
  import readline from "node:readline/promises";
@@ -10,11 +10,12 @@ import { stdin as input, stdout as output } from "node:process";
10
10
 
11
11
  const require = createRequire(import.meta.url);
12
12
 
13
- const APP_VERSION = "2.0.16";
14
- const CODEX_VERSION = "0.143.0";
15
- const APP_DISPLAY_NAME = "Magnetapi.org Coding Agent";
13
+ const APP_VERSION = "2.0.19";
14
+ const CODEX_VERSION = "0.144.1";
15
+ const APP_DISPLAY_NAME = "Magnetapi Client";
16
+ const DEFAULT_MODEL_ID = "claude-opus-4-8";
16
17
  const DISPLAY_REASONING_EFFORT = "xhigh";
17
- const SERVER_REASONING_EFFORT = "high";
18
+ const SERVER_REASONING_EFFORT = "xhigh";
18
19
  const API_ORIGIN = (process.env.CODEXCLAUDE_API_ORIGIN || "https://codexapi.pro").replace(/\/+$/, "");
19
20
  const API_BASE_URL = `${API_ORIGIN}/v1`;
20
21
  const CHICAGO_API_ORIGIN = "https://api-chicago.codexapi.pro";
@@ -22,16 +23,44 @@ const CHICAGO_API_BASE_URL = `${CHICAGO_API_ORIGIN}/v1`;
22
23
  const VERSION_CHECK_PATH = "/api/v1/codexclaude/version";
23
24
  const NPM_PACKAGE_NAME = "@codexapi/codexclaude";
24
25
  const NPM_LATEST_URL = "https://registry.npmjs.org/@codexapi%2Fcodexclaude/latest";
25
- const UPDATE_COMMAND = `npm install -g ${NPM_PACKAGE_NAME}@latest`;
26
+ const HOSTED_TARBALL_URL = `https://codexapi.pro/downloads/codexapi-codexclaude-${APP_VERSION}.tgz`;
27
+ const UPDATE_COMMAND = `npm install -g ${HOSTED_TARBALL_URL}`;
26
28
  const CONFIG_DIR = path.join(homedir(), ".codexclaude");
27
29
  const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
28
30
  const MODEL_CATALOG_FILE = path.join(CONFIG_DIR, "model_catalog.json");
29
31
  const CODEX_DIR = path.join(homedir(), ".codex");
30
32
  const CODEX_CONFIG_FILE = path.join(CODEX_DIR, "config.toml");
33
+ const CODEX_UPDATE_CACHE_FILE = path.join(CODEX_DIR, "version.json");
31
34
  const PROVIDER_ID = "codexapi";
32
35
  const MODEL_CATALOG_CONTEXT_WINDOW = 272000;
36
+ const SERVICE_CATALOG = [
37
+ {
38
+ id: "codexapi",
39
+ label: "CodexAPI.pro",
40
+ apiOrigin: "https://codexapi.pro",
41
+ aliases: ["codexapi", "codex", "codexapi.pro", "api.codexapi.pro"],
42
+ },
43
+ {
44
+ id: "chatplus",
45
+ label: "ChatPlus.chat",
46
+ apiOrigin: "https://chatplus.chat",
47
+ aliases: ["chatplus", "chatplus.chat", "chat"],
48
+ },
49
+ {
50
+ id: "myapi",
51
+ label: "MyAPI.world",
52
+ apiOrigin: "https://api.myapi.world",
53
+ aliases: ["myapi", "myapi.world", "api.myapi.world"],
54
+ },
55
+ {
56
+ id: "magnetapi",
57
+ label: "MagnetAPI.org",
58
+ apiOrigin: "https://api.magnetapi.org",
59
+ aliases: ["magnetapi", "magnet", "magnetapi.org", "api.magnetapi.org"],
60
+ },
61
+ ];
33
62
  const MODEL_CATALOG_BASE_INSTRUCTIONS = [
34
- "You are Codex, a coding agent running in the user's terminal.",
63
+ "You are Magnetapi Client, a coding agent running in the user's terminal.",
35
64
  "You share the user's local workspace, use local tools when available, and complete coding tasks directly and carefully.",
36
65
  "Follow the tool schema supplied by the client and keep CodexAPI.pro provider details out of user-facing answers unless the user asks about setup or billing.",
37
66
  ].join(" ");
@@ -39,7 +68,7 @@ const SUPPORTED_REASONING_LEVELS = [
39
68
  { effort: "low", description: "Fast responses with lighter reasoning" },
40
69
  { effort: "medium", description: "Balances speed and reasoning depth for everyday coding" },
41
70
  { effort: "high", description: "Greater reasoning depth for complex work" },
42
- { effort: "xhigh", description: "Extra high visible reasoning setting for CodexAPI.pro sessions" },
71
+ { effort: "xhigh", description: "Extra high visible reasoning setting for managed sessions" },
43
72
  ];
44
73
 
45
74
  const MODELS = {
@@ -118,12 +147,12 @@ function printHelp() {
118
147
  ${APP_DISPLAY_NAME} ${APP_VERSION}
119
148
 
120
149
  Commands:
121
- codexclaude login Login with CodexAPI.pro username/email and password
150
+ codexclaude login Login with dashboard username/email and password
122
151
  codexclaude model Select ChatGPT-5.5, Opus 4.8, Sonnet 5, or Fable 5
123
152
  codexclaude changelog Show the latest CodexAPI.pro launcher changes
124
153
  codexclaude setup Rewrite ~/.codex/config.toml with Full Access defaults
125
- codexclaude start Start Codex with --search
126
- codexclaude resume Resume with codex resume --search
154
+ codexclaude start Start Magnetapi Client with --search
155
+ codexclaude resume Resume the latest coding session with --search
127
156
  codexclaude logout Remove saved codexclaude account state
128
157
 
129
158
  Any other command is passed through to the bundled coding runtime after Magnetapi.org account and model config is applied.
@@ -151,45 +180,144 @@ async function printChangelog() {
151
180
  async function loginFlow() {
152
181
  const rl = readline.createInterface({ input, output });
153
182
  try {
154
- const username = (await rl.question("CodexAPI.pro username or email: ")).trim();
183
+ const username = (await rl.question("Dashboard Username or Email Address: ")).trim();
155
184
  const password = await rl.question("Dashboard password: ");
156
185
  if (!username || !password) {
157
186
  throw new Error("Username/email and password are required.");
158
187
  }
159
- const response = await postJson("/api/v1/auth/login", {
188
+ const existing = readConfig();
189
+ const normalizedExisting = normalizeConfig(existing);
190
+ const selectedService = await askService(rl, normalizedExisting?.serviceId);
191
+ const loginResult = await loginWithServiceSelection({
160
192
  username,
161
193
  password,
162
- deviceName: `codexclaude ${APP_VERSION}`,
194
+ selectedService,
195
+ currentServiceId: normalizedExisting?.serviceId,
163
196
  });
164
- const apiUsername = response?.cliCredentials?.username || response?.user?.username;
197
+ const { response, service } = loginResult;
198
+ const apiUsername = extractApiUsername(response);
165
199
  if (!apiUsername) {
166
- throw new Error("Login succeeded but no API username was returned.");
200
+ throw new Error(`Login succeeded on ${service.label} but no System Token was returned.`);
167
201
  }
168
- const existing = readConfig();
169
- const normalizedExisting = normalizeConfig(existing);
170
- const selectedModel = await askModel(rl, normalizedExisting?.model || "gpt-5.5");
202
+ const selectedModel = await askModel(rl, normalizedExisting?.model || DEFAULT_MODEL_ID);
171
203
  const config = {
172
204
  version: APP_VERSION,
173
- apiOrigin: API_ORIGIN,
205
+ serviceId: service.id,
206
+ serviceLabel: service.label,
207
+ apiOrigin: service.apiOrigin,
174
208
  username: apiUsername,
175
- dashboardEmail: response?.user?.email || null,
209
+ dashboardEmail: response?.user?.email || response?.cliCredentials?.loginEmail || (username.includes("@") ? username : null),
176
210
  model: selectedModel,
177
211
  loggedInAt: new Date().toISOString(),
178
212
  };
179
213
  saveConfig(config);
180
214
  writeCodexConfig(config);
181
- console.log(`\nLogged in as ${apiUsername}. Model: ${MODELS[selectedModel].label}.`);
182
- console.log("Full Access permissions, xhigh visible reasoning, and CodexAPI.pro provider config were written.");
215
+ console.log(`\nLogged in to ${service.label} as ${apiUsername}. Model: ${MODELS[selectedModel].label}.`);
216
+ console.log("Full Access permissions, xhigh visible reasoning, and service-specific provider config were written.");
183
217
  } finally {
184
218
  rl.close();
185
219
  }
186
220
  }
187
221
 
222
+ async function askService(rl, currentServiceId) {
223
+ const current = serviceById(currentServiceId);
224
+ console.log("\nWhich dashboard is this account from?");
225
+ console.log(" 0. Auto-detect across all supported sites");
226
+ SERVICE_CATALOG.forEach((service, index) => {
227
+ const currentMarker = current?.id === service.id ? " (current)" : "";
228
+ console.log(` ${index + 1}. ${service.label}${currentMarker}`);
229
+ });
230
+ const answer = (await rl.question("Dashboard service [Auto-detect]: ")).trim().toLowerCase();
231
+ if (!answer || answer === "0" || answer === "auto" || answer === "detect") {
232
+ return null;
233
+ }
234
+ const service = serviceFromAnswer(answer);
235
+ if (!service) {
236
+ throw new Error("Unknown dashboard service. Choose 0, 1, 2, 3, or 4.");
237
+ }
238
+ return service;
239
+ }
240
+
241
+ async function loginWithServiceSelection({ username, password, selectedService, currentServiceId }) {
242
+ const loginBody = {
243
+ username,
244
+ password,
245
+ deviceName: `codexclaude ${APP_VERSION}`,
246
+ };
247
+ if (selectedService) {
248
+ return {
249
+ service: selectedService,
250
+ response: await postJson("/api/v1/auth/login", loginBody, selectedService.apiOrigin),
251
+ };
252
+ }
253
+ const candidates = orderedLoginServices(username, currentServiceId);
254
+ const successes = [];
255
+ const failures = [];
256
+ for (const service of candidates) {
257
+ try {
258
+ const response = await postJson("/api/v1/auth/login", loginBody, service.apiOrigin);
259
+ successes.push({ service, response });
260
+ } catch (error) {
261
+ failures.push({ service, error });
262
+ }
263
+ }
264
+ if (successes.length === 1) {
265
+ return successes[0];
266
+ }
267
+ if (successes.length > 1) {
268
+ return chooseBestSuccessfulLogin(username, successes);
269
+ }
270
+ const failureSummary = failures
271
+ .map(({ service, error }) => `${service.label}: ${error.message}`)
272
+ .join("; ");
273
+ throw new Error(`Login failed on all supported sites. ${failureSummary}`);
274
+ }
275
+
276
+ function orderedLoginServices(username, currentServiceId) {
277
+ const lower = String(username || "").trim().toLowerCase();
278
+ const preferred = [];
279
+ const current = serviceById(currentServiceId);
280
+ if (current) {
281
+ preferred.push(current);
282
+ }
283
+ if (lower.startsWith("myapi-")) {
284
+ preferred.push(serviceById("myapi"));
285
+ } else if (lower.startsWith("magnet-") || lower.startsWith("magnetapi-")) {
286
+ preferred.push(serviceById("magnetapi"));
287
+ } else if (lower.startsWith("g2g-codex-") || lower.startsWith("codex-")) {
288
+ preferred.push(serviceById("codexapi"), serviceById("chatplus"));
289
+ }
290
+ return dedupeServices([...preferred.filter(Boolean), ...SERVICE_CATALOG]);
291
+ }
292
+
293
+ function chooseBestSuccessfulLogin(username, successes) {
294
+ const lower = String(username || "").trim().toLowerCase();
295
+ const exactTokenMatch = successes.find(({ service }) => {
296
+ if (lower.startsWith("myapi-")) return service.id === "myapi";
297
+ if (lower.startsWith("magnet-") || lower.startsWith("magnetapi-")) return service.id === "magnetapi";
298
+ if (lower.startsWith("g2g-codex-") || lower.startsWith("codex-")) return service.id === "codexapi";
299
+ return false;
300
+ });
301
+ return exactTokenMatch || successes[0];
302
+ }
303
+
304
+ function extractApiUsername(response) {
305
+ return (
306
+ response?.cliCredentials?.apiToken ||
307
+ response?.cliCredentials?.username ||
308
+ response?.user?.apiToken ||
309
+ response?.user?.systemToken ||
310
+ response?.user?.username ||
311
+ response?.apiKey?.token ||
312
+ ""
313
+ );
314
+ }
315
+
188
316
  async function modelFlow() {
189
317
  const config = requireConfig();
190
318
  const rl = readline.createInterface({ input, output });
191
319
  try {
192
- config.model = await askModel(rl, config.model || "gpt-5.5");
320
+ config.model = await askModel(rl, config.model || DEFAULT_MODEL_ID);
193
321
  config.version = APP_VERSION;
194
322
  saveConfig(config);
195
323
  writeCodexConfig(config);
@@ -217,7 +345,7 @@ async function ensureReady() {
217
345
  }
218
346
 
219
347
  async function askModel(rl, current) {
220
- const currentLabel = MODELS[current]?.label || MODELS["gpt-5.5"].label;
348
+ const currentLabel = MODELS[current]?.label || MODELS[DEFAULT_MODEL_ID].label;
221
349
  console.log("\nChoose your coding model:");
222
350
  Object.values(MODELS).forEach((model, index) => {
223
351
  const premium = model.premium ? " (2x premium billing)" : "";
@@ -225,7 +353,7 @@ async function askModel(rl, current) {
225
353
  });
226
354
  const answer = (await rl.question(`Model [${currentLabel}]: `)).trim().toLowerCase();
227
355
  if (!answer) {
228
- return MODELS[current] ? current : "gpt-5.5";
356
+ return MODELS[current] ? current : DEFAULT_MODEL_ID;
229
357
  }
230
358
  const match = Object.values(MODELS).find((model) => model.aliases.includes(answer));
231
359
  if (!match) {
@@ -234,8 +362,8 @@ async function askModel(rl, current) {
234
362
  return match.id;
235
363
  }
236
364
 
237
- async function postJson(pathname, body) {
238
- const response = await fetch(`${API_ORIGIN}${pathname}`, {
365
+ async function postJson(pathname, body, origin = API_ORIGIN) {
366
+ const response = await fetch(`${String(origin || API_ORIGIN).replace(/\/+$/, "")}${pathname}`, {
239
367
  method: "POST",
240
368
  headers: {
241
369
  "content-type": "application/json",
@@ -374,10 +502,10 @@ function updateRequiredMessage(metadata) {
374
502
  const latest = metadata?.latestVersion || "latest";
375
503
  const minimum = metadata?.minimumVersion || latest;
376
504
  return [
377
- `Update required: CodexAPI.pro has updated to codexclaude ${latest}. Update your agent now to continue.`,
505
+ `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.`,
378
506
  `Installed codexclaude: ${APP_VERSION}. Required: ${minimum}. Latest: ${latest}.`,
379
507
  `Run: ${installCommand}`,
380
- "Your Codex session history will not be deleted. The update only replaces the codexclaude launcher and rewrites provider config backups.",
508
+ "Your local session history will not be deleted. The update only replaces the codexclaude launcher and rewrites provider config backups.",
381
509
  ].join("\n");
382
510
  }
383
511
 
@@ -456,7 +584,8 @@ function writeCodexConfig(config) {
456
584
  copyFileSync(CODEX_CONFIG_FILE, backup);
457
585
  }
458
586
  const normalized = normalizeConfig(config);
459
- const model = MODELS[normalized.model] ? normalized.model : "gpt-5.5";
587
+ clearUpstreamUpdateCache();
588
+ const model = MODELS[normalized.model] ? normalized.model : DEFAULT_MODEL_ID;
460
589
  const providerBaseUrl = providerBaseUrlForConfig(normalized);
461
590
  const modelCatalogFile = writeModelCatalog();
462
591
  const toml = [
@@ -465,11 +594,14 @@ function writeCodexConfig(config) {
465
594
  'preferred_auth_method = "apikey"',
466
595
  `model_provider = ${tomlString(PROVIDER_ID)}`,
467
596
  `model_reasoning_effort = ${tomlString(DISPLAY_REASONING_EFFORT)}`,
597
+ "check_for_update_on_startup = false",
598
+ "analytics_enabled = false",
599
+ "feedback_enabled = false",
468
600
  'approval_policy = "never"',
469
601
  'sandbox_mode = "danger-full-access"',
470
602
  "",
471
603
  `[model_providers.${PROVIDER_ID}]`,
472
- 'name = "CodexAPI.pro"',
604
+ `name = ${tomlString(normalized.serviceLabel || "CodexAPI.pro")}`,
473
605
  `base_url = ${tomlString(providerBaseUrl)}`,
474
606
  `experimental_bearer_token = ${tomlString(normalized.username)}`,
475
607
  'wire_api = "responses"',
@@ -485,6 +617,16 @@ function writeCodexConfig(config) {
485
617
  writeFileSync(CODEX_CONFIG_FILE, toml, { encoding: "utf8", mode: 0o600 });
486
618
  }
487
619
 
620
+ function clearUpstreamUpdateCache() {
621
+ try {
622
+ if (existsSync(CODEX_UPDATE_CACHE_FILE)) {
623
+ unlinkSync(CODEX_UPDATE_CACHE_FILE);
624
+ }
625
+ } catch {
626
+ // A stale upstream update cache should never block writing the managed config.
627
+ }
628
+ }
629
+
488
630
  function writeModelCatalog() {
489
631
  mkdirSync(CONFIG_DIR, { recursive: true });
490
632
  const catalog = {
@@ -534,15 +676,15 @@ function modelCatalogEntry(model, index) {
534
676
 
535
677
  function modelCatalogDescription(modelId) {
536
678
  if (modelId === "claude-opus-4-8") {
537
- return "CodexAPI.pro Opus 4.8 coding route with local Codex tools and wallet billing.";
679
+ return "Opus 4.8 coding route with local coding tools and wallet billing.";
538
680
  }
539
681
  if (modelId === "claude-sonnet-5") {
540
- return "CodexAPI.pro Sonnet 5 coding route with local Codex tools and wallet billing.";
682
+ return "Sonnet 5 coding route with local coding tools and wallet billing.";
541
683
  }
542
684
  if (modelId === "claude-fable-5") {
543
- return "CodexAPI.pro Fable 5 premium coding route with local Codex tools and wallet billing.";
685
+ return "Fable 5 premium coding route with local coding tools and wallet billing.";
544
686
  }
545
- return "CodexAPI.pro ChatGPT-5.5 coding route with local Codex tools and wallet billing.";
687
+ return "ChatGPT-5.5 coding route with local coding tools and wallet billing.";
546
688
  }
547
689
 
548
690
  function readConfig() {
@@ -568,7 +710,7 @@ function saveConfig(config) {
568
710
 
569
711
  function logout() {
570
712
  saveConfig({ version: APP_VERSION, loggedOutAt: new Date().toISOString() });
571
- console.log("codexclaude login state removed. Codex config was left untouched.");
713
+ console.log("codexclaude login state removed. Managed coding config was left untouched.");
572
714
  }
573
715
 
574
716
  async function runCodex(args) {
@@ -595,6 +737,11 @@ async function runCodex(args) {
595
737
  CODEXCLAUDE_SERVER_REASONING_EFFORT: SERVER_REASONING_EFFORT,
596
738
  CODEXCLAUDE_VERSION: APP_VERSION,
597
739
  };
740
+ delete env.CODEX_MANAGED_BY_NPM;
741
+ delete env.CODEX_MANAGED_BY_BUN;
742
+ delete env.CODEX_MANAGED_PACKAGE_ROOT;
743
+ env.CODEX_DISABLE_UPDATE_CHECK = "1";
744
+ env.CODEX_CHECK_FOR_UPDATE_ON_STARTUP = "0";
598
745
  if (wallet) {
599
746
  env.CODEXCLAUDE_WALLET_BALANCE_USD = String(wallet.balance);
600
747
  }
@@ -640,21 +787,38 @@ function resolveCodexLaunch() {
640
787
  if (bundled) {
641
788
  return bundled;
642
789
  }
643
- return {
644
- command: commandName("npx"),
645
- argsPrefix: ["-y", `@openai/codex@${CODEX_VERSION}`],
646
- };
790
+ throw new Error(
791
+ `Bundled runtime is missing. Reinstall ${APP_DISPLAY_NAME}: ${UPDATE_COMMAND}`,
792
+ );
647
793
  }
648
794
 
649
795
  function resolveBundledCodexLaunch() {
796
+ const platformBinary = resolveBundledCodexBinaryLaunch();
797
+ if (platformBinary) {
798
+ return platformBinary;
799
+ }
800
+ return null;
801
+ }
802
+
803
+ function resolveBundledCodexBinaryLaunch() {
804
+ const target = platformCodexTarget();
805
+ if (!target) {
806
+ return null;
807
+ }
650
808
  try {
651
- const packageJsonPath = require.resolve("@openai/codex/package.json");
809
+ const packageJsonPath = require.resolve(`${target.packageName}/package.json`);
652
810
  const packageRoot = path.dirname(packageJsonPath);
653
- const binPath = path.join(packageRoot, "bin", "codex.js");
811
+ const binPath = path.join(
812
+ packageRoot,
813
+ "vendor",
814
+ target.triple,
815
+ "bin",
816
+ process.platform === "win32" ? "codex.exe" : "codex",
817
+ );
654
818
  if (existsSync(binPath)) {
655
819
  return {
656
- command: process.execPath,
657
- argsPrefix: [binPath],
820
+ command: binPath,
821
+ argsPrefix: [],
658
822
  };
659
823
  }
660
824
  } catch {
@@ -663,6 +827,30 @@ function resolveBundledCodexLaunch() {
663
827
  return null;
664
828
  }
665
829
 
830
+ function platformCodexTarget() {
831
+ const platform = process.platform;
832
+ const arch = process.arch;
833
+ if ((platform === "linux" || platform === "android") && arch === "x64") {
834
+ return { triple: "x86_64-unknown-linux-musl", packageName: "@openai/codex-linux-x64" };
835
+ }
836
+ if ((platform === "linux" || platform === "android") && arch === "arm64") {
837
+ return { triple: "aarch64-unknown-linux-musl", packageName: "@openai/codex-linux-arm64" };
838
+ }
839
+ if (platform === "darwin" && arch === "x64") {
840
+ return { triple: "x86_64-apple-darwin", packageName: "@openai/codex-darwin-x64" };
841
+ }
842
+ if (platform === "darwin" && arch === "arm64") {
843
+ return { triple: "aarch64-apple-darwin", packageName: "@openai/codex-darwin-arm64" };
844
+ }
845
+ if (platform === "win32" && arch === "x64") {
846
+ return { triple: "x86_64-pc-windows-msvc", packageName: "@openai/codex-win32-x64" };
847
+ }
848
+ if (platform === "win32" && arch === "arm64") {
849
+ return { triple: "aarch64-pc-windows-msvc", packageName: "@openai/codex-win32-arm64" };
850
+ }
851
+ return null;
852
+ }
853
+
666
854
  async function walletSnapshot(config) {
667
855
  const payload =
668
856
  await tryGetJsonAuth("/api/v1/wallet/status", config, { timeoutMs: 10000 }) ||
@@ -740,13 +928,21 @@ function normalizeConfig(config) {
740
928
  "google-gemini-flash-3.5",
741
929
  ].includes(normalized.model)
742
930
  ) {
743
- normalized.model = "gpt-5.5";
931
+ normalized.model = DEFAULT_MODEL_ID;
744
932
  }
745
933
  if (!MODELS[normalized.model]) {
746
- normalized.model = "gpt-5.5";
934
+ normalized.model = DEFAULT_MODEL_ID;
747
935
  }
748
936
  normalized.version = APP_VERSION;
749
- normalized.apiOrigin = String(normalized.apiOrigin || API_ORIGIN).replace(/\/+$/, "");
937
+ const service = serviceById(normalized.serviceId) || serviceByOrigin(normalized.apiOrigin);
938
+ if (service) {
939
+ normalized.serviceId = service.id;
940
+ normalized.serviceLabel = service.label;
941
+ normalized.apiOrigin = service.apiOrigin;
942
+ } else {
943
+ normalized.apiOrigin = String(normalized.apiOrigin || API_ORIGIN).replace(/\/+$/, "");
944
+ normalized.serviceLabel = normalized.serviceLabel || serviceLabelForOrigin(normalized.apiOrigin);
945
+ }
750
946
  return normalized;
751
947
  }
752
948
 
@@ -775,6 +971,53 @@ function isCodexApiOrigin(origin) {
775
971
  }
776
972
  }
777
973
 
974
+ function serviceById(id) {
975
+ const normalized = String(id || "").trim().toLowerCase();
976
+ return SERVICE_CATALOG.find((service) => service.id === normalized) || null;
977
+ }
978
+
979
+ function serviceByOrigin(origin) {
980
+ const normalized = String(origin || "").trim().replace(/\/+$/, "").toLowerCase();
981
+ if (!normalized) {
982
+ return null;
983
+ }
984
+ return SERVICE_CATALOG.find((service) => service.apiOrigin.toLowerCase() === normalized) || null;
985
+ }
986
+
987
+ function serviceFromAnswer(answer) {
988
+ const normalized = String(answer || "").trim().toLowerCase();
989
+ const numbered = Number(normalized);
990
+ if (Number.isInteger(numbered) && numbered >= 1 && numbered <= SERVICE_CATALOG.length) {
991
+ return SERVICE_CATALOG[numbered - 1];
992
+ }
993
+ return SERVICE_CATALOG.find((service) => service.aliases.includes(normalized) || service.id === normalized) || null;
994
+ }
995
+
996
+ function dedupeServices(services) {
997
+ const seen = new Set();
998
+ const result = [];
999
+ for (const service of services) {
1000
+ if (!service || seen.has(service.id)) {
1001
+ continue;
1002
+ }
1003
+ seen.add(service.id);
1004
+ result.push(service);
1005
+ }
1006
+ return result;
1007
+ }
1008
+
1009
+ function serviceLabelForOrigin(origin) {
1010
+ const service = serviceByOrigin(origin);
1011
+ if (service) {
1012
+ return service.label;
1013
+ }
1014
+ try {
1015
+ return new URL(origin || API_ORIGIN).hostname;
1016
+ } catch {
1017
+ return "CodexAPI.pro";
1018
+ }
1019
+ }
1020
+
778
1021
  function formatUsd(value) {
779
1022
  return `$${Number(value || 0).toLocaleString("en-US", {
780
1023
  minimumFractionDigits: 2,
package/codexclaude.md CHANGED
@@ -1,137 +1,85 @@
1
1
  # codexclaude Customization Ledger
2
2
 
3
- This file records the CodexAPI.pro-specific behavior that must survive every
4
- upgrade of the bundled coding runtime dependency. Treat it as the handoff
5
- document for future maintainers. The launcher should remain a thin wrapper
6
- around official `@openai/codex`; do not patch the native Codex binary unless
7
- there is no supported configuration or API boundary that can solve the issue.
3
+ This file is the durable handoff for the `@codexapi/codexclaude` package in `/root/codexclaude`. Read it before updating the bundled coding runtime. The package is a managed launcher around the official runtime dependency, but customer-facing startup, update, model, auth, and setup behavior must stay under MagnetAPI control.
8
4
 
9
5
  ## Current Release
10
6
 
11
- - Launcher package: `@codexapi/codexclaude`
12
- - Launcher version: `2.0.16`
13
- - Customer-facing app name: `Magnetapi.org Coding Agent`
14
- - Bundled runtime dependency: official `@openai/codex@0.143.0`; do not print the upstream runtime version in customer-facing startup text.
15
- - Public update command for this optional release: `npm install -g @codexapi/codexclaude@2.0.16`
16
- - Default API origin: `https://codexapi.pro`
17
- - Normal Responses base URL: `https://codexapi.pro/v1`
18
- - Opus 4.8 Responses base URL: `https://api-chicago.codexapi.pro/v1`
7
+ - Package name: `@codexapi/codexclaude`
8
+ - Launcher version: `2.0.19`
9
+ - Customer-facing app name: `Magnetapi Client`
10
+ - Bundled runtime dependency: `@openai/codex@0.144.1`
11
+ - Required install command: `npm install -g https://codexapi.pro/downloads/codexapi-codexclaude-2.0.19.tgz`
12
+ - Backend minimum version: `2.0.19`
13
+ - Default visible model: `Opus 4.8`
14
+ - Default model slug: `claude-opus-4-8`
15
+ - Visible reasoning effort: `xhigh`
16
+ - Local permissions: Full Access, implemented as `approval_policy = "never"` and `sandbox_mode = "danger-full-access"`
19
17
  - Local launcher state: `~/.codexclaude/config.json`
20
- - Generated Codex config: `~/.codex/config.toml`
21
- - Generated Codex model catalog: `~/.codexclaude/model_catalog.json`
18
+ - Generated runtime config: `~/.codex/config.toml`
19
+ - Generated model catalog: `~/.codexclaude/model_catalog.json`
20
+ - Upstream update cache removed before setup: `~/.codex/version.json`
22
21
 
23
- State verified on 2026-07-08: the launcher presents itself as Magnetapi.org Coding Agent `2.0.16`. Backend routing is server-controlled by Admin Manage Models and must not collapse the launcher model list or rename customer-selected model ids.
22
+ ## Required Customer Behavior
24
23
 
25
- ## Required User-Facing Model Behavior
24
+ The launcher must present itself as:
26
25
 
27
- `codexclaude` supports exactly four visible model choices:
28
-
29
- - `gpt-5.5` displayed as `ChatGPT-5.5`
30
- - `claude-opus-4-8` displayed as `Opus 4.8`
31
- - `claude-sonnet-5` displayed as `Sonnet 5`
32
- - `claude-fable-5` displayed as `Fable 5`
33
-
34
- The launcher command `codexclaude model` must list only those four options.
35
- The native Codex `/model` picker must also list only those four options. This
36
- is enforced by writing `model_catalog_json` in `~/.codex/config.toml` and
37
- creating a complete Codex-compatible catalog at
38
- `~/.codexclaude/model_catalog.json`.
39
-
40
- Do not rely only on the wrapper prompt for model restrictions. Native Codex can
41
- render its own model picker from model metadata. If the generated catalog is
42
- removed, corrupted, or not referenced by `model_catalog_json`, Codex may fall
43
- back to its bundled OpenAI model list or may warn that metadata for
44
- `claude-opus-4-8` cannot be found.
45
-
46
- ## Opus 4.8 Metadata Warning Fix
26
+ ```text
27
+ Magnetapi Client v2.0.19
28
+ ```
47
29
 
48
- The warning:
30
+ Normal pre-launch status should look like:
49
31
 
50
32
  ```text
51
- Model metadata for `claude-opus-4-8` not found. Defaulting to fallback metadata; this can degrade performance and cause issues.
33
+ Magnetapi Client v2.0.19 · opus-4.8 xhigh · ~/project · Wallet $20.00
52
34
  ```
53
35
 
54
- comes from native Codex when the selected model slug does not exist in its
55
- model metadata catalog. The fix is not to rename Opus to GPT-5.5 locally,
56
- because the request body model is how CodexAPI.pro snapshots routing and
57
- billing before generation starts. The correct fix is to provide valid metadata
58
- for `claude-opus-4-8`.
59
-
60
- `bin/codexclaude.js` writes a local catalog with full metadata for all four
61
- supported slugs. Each entry must include, at minimum:
62
-
63
- - `slug`
64
- - `display_name`
65
- - `description`
66
- - `default_reasoning_level`
67
- - `supported_reasoning_levels`
68
- - `shell_type`
69
- - `visibility`
70
- - `supported_in_api`
71
- - `priority`
72
- - `base_instructions`
73
- - `truncation_policy`
74
- - `supports_parallel_tool_calls`
75
- - `supports_image_detail_original`
76
- - `input_modalities`
77
- - `additional_speed_tiers`
78
-
79
- Keep `visibility = "list"` for the four supported entries. Do not include any
80
- other list-visible models in this catalog.
81
-
82
- ## Reasoning Display Versus Server Runtime
83
-
84
- The user-facing Codex UI must show `xhigh` reasoning. The generated
85
- `~/.codex/config.toml` therefore writes:
36
+ 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.
86
37
 
87
- ```toml
88
- model_reasoning_effort = "xhigh"
89
- ```
38
+ The launcher command `codexclaude model` must list exactly four customer-visible models:
39
+
40
+ - `gpt-5.5` displayed as `ChatGPT-5.5`
41
+ - `claude-opus-4-8` displayed as `Opus 4.8`
42
+ - `claude-sonnet-5` displayed as `Sonnet 5`
43
+ - `claude-fable-5` displayed as `Fable 5`
90
44
 
91
- The API server must continue to enforce the Admin-selected server reasoning before upstream runtime.
92
- This is handled in the CodexAPI.pro backend by normalizing Responses requests
93
- to `settings.agent_default_effort`, currently `high`. Do not change the server
94
- setting just because the launcher displays `xhigh`.
45
+ Opus 4.8 must be the default when a new config is created or a legacy config contains an unsupported Gemini/Deepseek value. The selected model slug must stay in `~/.codex/config.toml`; do not rewrite Opus, Sonnet, or Fable to GPT locally just because the backend may route internally.
95
46
 
96
- The launcher keeps both concepts explicit:
47
+ ## Update Policy
97
48
 
98
- - `DISPLAY_REASONING_EFFORT = "xhigh"`
99
- - `SERVER_REASONING_EFFORT = "high"`
49
+ `bin/codexclaude.js` may check:
100
50
 
101
- The native Codex status line should show `xhigh`. The launcher no longer exposes separate `codexclaude status` or `codexclaude usage` commands, so normal launch status must not imply the user-visible model is downgraded.
51
+ - `https://codexapi.pro/api/v1/codexclaude/version`
52
+ - `https://registry.npmjs.org/@codexapi%2Fcodexclaude/latest`
102
53
 
103
- ## Fast Mode Behavior
54
+ It must not check `@openai/codex` npm metadata, OpenAI GitHub releases, or any upstream OpenAI update endpoint. Version `2.0.19` is a forced release: the backend `minimumVersion` equals `2.0.19`, and older clients must show an update-required message with the hosted tarball command.
104
55
 
105
- The local model catalog includes `additional_speed_tiers = ["fast"]` so native
106
- Codex can show `/fast` as active when the user enables it. CodexAPI.pro treats
107
- fast mode as a billing hint only. The backend must bill fast sessions at the
108
- configured multiplier, currently `6x`, while stripping fast mode and service
109
- tier controls before forwarding the request upstream.
56
+ 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.
110
57
 
111
- Do not write a default fast service tier in the launcher config. Fast must stay
112
- user-controlled.
58
+ 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.
113
59
 
114
60
  ## Generated Config Contract
115
61
 
116
- `bin/codexclaude.js` must rewrite `~/.codex/config.toml` before every coding
117
- session. Preserve this top-level shape:
62
+ `bin/codexclaude.js` must rewrite `~/.codex/config.toml` before every coding session. Preserve this top-level shape:
118
63
 
119
64
  ```toml
120
- model = "<selected-model>"
65
+ model = "claude-opus-4-8"
121
66
  model_catalog_json = "<absolute path to ~/.codexclaude/model_catalog.json>"
122
67
  preferred_auth_method = "apikey"
123
68
  model_provider = "codexapi"
124
69
  model_reasoning_effort = "xhigh"
70
+ check_for_update_on_startup = false
71
+ analytics_enabled = false
72
+ feedback_enabled = false
125
73
  approval_policy = "never"
126
74
  sandbox_mode = "danger-full-access"
127
75
 
128
76
  [model_providers.codexapi]
129
- name = "CodexAPI.pro"
130
- base_url = "<https://codexapi.pro/v1 or https://api-chicago.codexapi.pro/v1>"
131
- experimental_bearer_token = "<customer-api-username>"
77
+ name = "<logged-in service label>"
78
+ base_url = "<service Responses URL>"
79
+ experimental_bearer_token = "<customer System Token/API username>"
132
80
  wire_api = "responses"
133
81
  supports_websockets = false
134
- http_headers = { "X-CodexAPI-Client" = "codexclaude", "X-CodexAPI-Client-Version" = "<launcher-version>", "X-CodexAPI-Selected-Model" = "<selected-model>" }
82
+ http_headers = { "X-CodexAPI-Client" = "codexclaude", "X-CodexAPI-Client-Version" = "2.0.19", "X-CodexAPI-Selected-Model" = "<selected model>" }
135
83
 
136
84
  [tui]
137
85
  status_line = ["model-with-reasoning", "fast-mode", "current-dir"]
@@ -139,192 +87,115 @@ status_line_use_colors = true
139
87
  terminal_title = ["project-name", "model-with-reasoning", "run-state"]
140
88
  ```
141
89
 
142
- The selected model must remain the user's chosen slug. Do not force the local
143
- config model to `gpt-5.5` when Opus, Sonnet, or Fable is selected. The backend can
144
- route any selected model through GPT-5.5 or another upstream internally, but the
145
- client request must preserve the user-facing selected slug for display,
146
- snapshotting, and billing records.
147
-
148
- ## Routing Rules
149
-
150
- `gpt-5.5` uses the configured API origin, normally `https://codexapi.pro/v1`.
151
-
152
- Claude-family codexclaude models use the CodexAPI.pro Claude-compatible Responses endpoint for CodexAPI.pro and ChatPlus accounts. MyAPI.world accounts keep their own configured `api.myapi.world` Responses endpoint.
153
-
154
- `claude-fable-5` is a premium customer-visible model. The backend bills it at the configured 2x multiplier and routes it through the Admin-selected Fable 5 route while preserving `claude-fable-5` in client-visible status and usage records.
155
-
156
- The launcher must send these headers for every model:
90
+ The generated model catalog must contain full metadata for the four supported slugs. This prevents fallback metadata warnings such as:
157
91
 
158
- - `X-CodexAPI-Client: codexclaude`
159
- - `X-CodexAPI-Client-Version: <launcher version>`
160
- - `X-CodexAPI-Selected-Model: <selected model slug>`
161
-
162
- The backend uses these headers to enforce plan restrictions and to serve the
163
- codexclaude-specific model catalog from `/v1/models` if native Codex refreshes
164
- remote metadata.
165
-
166
- ## Authentication And Wallet
92
+ ```text
93
+ Model metadata for `claude-opus-4-8` not found. Defaulting to fallback metadata; this can degrade performance and cause issues.
94
+ ```
167
95
 
168
- Customers log in with:
96
+ Each model catalog entry must include a slug, display name, reasoning levels including `xhigh`, shell tool type, input modalities including images, web/search support, truncation policy, and `visibility = "list"`.
169
97
 
170
- ```bash
171
- codexclaude login
172
- ```
98
+ ## Service Login
173
99
 
174
- The launcher authenticates against:
100
+ The login prompt must ask for:
175
101
 
176
102
  ```text
177
- https://codexapi.pro/api/v1/auth/login
103
+ Dashboard Username or Email Address:
178
104
  ```
179
105
 
180
- The returned API username is saved in `~/.codexclaude/config.json` and written
181
- as `experimental_bearer_token` in `~/.codex/config.toml`. Preserve this
182
- behavior unless the backend auth contract is deliberately changed. The launcher
183
- must not ask customers for a separate OpenAI key.
106
+ The launcher supports CodexAPI.pro, ChatPlus.chat, MyAPI.world, and MagnetAPI.org. It can auto-detect by trying the supported dashboard auth endpoints. It saves `serviceId`, `serviceLabel`, `apiOrigin`, `username`, optional `dashboardEmail`, selected `model`, and `loggedInAt` in `~/.codexclaude/config.json`.
184
107
 
185
- Before launch, the wallet status should be read from:
108
+ The saved `username` is the System Token/API username returned by the service and is used as the bearer value. Do not store dashboard session tokens in the launcher config.
186
109
 
187
- ```text
188
- /api/v1/wallet/status
189
- ```
190
-
191
- If that endpoint fails, fall back to:
110
+ ## Routing Expectations
192
111
 
193
- ```text
194
- /api/v1/me
195
- ```
112
+ The launcher is not the source of truth for upstream runtime routing. Admin Manage Models controls execution routing server-side. The launcher must preserve the user-selected model slug and pass it through the Responses request so billing, logs, and the dashboard can record what the user chose.
196
113
 
197
- The launcher does not expose a separate usage command. Wallet lookup failures must not block a local coding session.
114
+ CodexAPI.pro and ChatPlus Claude-family models use the CodexAPI.pro Claude-compatible Responses endpoint. MyAPI.world and MagnetAPI.org accounts keep their own API origins. Fable 5 remains visible as `claude-fable-5` while the backend applies the premium model behavior and billing.
198
115
 
199
116
  ## Upgrade Checklist
200
117
 
201
- When upgrading official `@openai/codex`:
202
-
203
- 1. Update `CODEX_VERSION` in `bin/codexclaude.js`.
204
- 2. Update `package.json` and `package-lock.json` to the same official Codex version.
205
- 3. Keep the launcher package version higher than the last published version and keep customer-facing startup text on the Magnetapi.org Coding Agent version.
206
- 4. Preserve the four-model `MODELS` map and aliases.
207
- 5. Preserve `DISPLAY_REASONING_EFFORT = "xhigh"` and keep `SERVER_REASONING_EFFORT` aligned with the server default.
208
- 6. Preserve `writeModelCatalog()` and the `model_catalog_json` line in generated config.
209
- 7. Preserve Full Access defaults: `approval_policy = "never"` and `sandbox_mode = "danger-full-access"`.
210
- 8. Preserve `wire_api = "responses"` and `supports_websockets = false`.
211
- 9. Preserve bearer username auth with the CodexAPI.pro API username.
212
- 10. Preserve the `X-CodexAPI-*` headers.
213
- 11. Preserve Claude-family endpoint routing unless operations changes it.
214
- 12. Preserve update checks through `/api/v1/codexclaude/version` and npm metadata. Recommended releases must be non-blocking; only versions below the backend `minimumVersion` may be forced.
215
- 13. Update this file with a new release section explaining what changed.
216
- 14. Run the validation commands below before publishing.
118
+ When updating the bundled runtime dependency:
119
+
120
+ 1. Confirm the intended upstream package version with `npm view @openai/codex version`.
121
+ 2. Run `npm install @openai/codex@<version> --save-exact`.
122
+ 3. Bump `package.json` and `package-lock.json` to a new `@codexapi/codexclaude` version.
123
+ 4. Update `APP_VERSION` and `CODEX_VERSION` in `bin/codexclaude.js`.
124
+ 5. Preserve `APP_DISPLAY_NAME = "Magnetapi Client"`.
125
+ 6. Preserve `DEFAULT_MODEL_ID = "claude-opus-4-8"`.
126
+ 7. Preserve `DISPLAY_REASONING_EFFORT = "xhigh"` and `SERVER_REASONING_EFFORT = "xhigh"` unless operations explicitly changes the launcher-visible contract.
127
+ 8. Preserve Full Access defaults and the local model catalog.
128
+ 9. Preserve direct platform-native binary launch.
129
+ 10. Preserve update checks through our version endpoint and `@codexapi/codexclaude` npm metadata only.
130
+ 11. Preserve deletion of `~/.codex/version.json` and `check_for_update_on_startup = false`.
131
+ 12. Update customer setup scripts on CodexAPI.pro, ChatPlus.chat, MyAPI.world, MagnetAPI.org, and VIP pages to use the exact hosted tarball command.
132
+ 13. Update backend `CODEXCLAUDE_LATEST_VERSION`, `CODEXCLAUDE_MIN_VERSION`, and hosted tarball URL.
133
+ 14. Update this file, `README.md`, and `CUSTOMIZATIONS.md`.
134
+ 15. Run validation and publish.
217
135
 
218
136
  ## Validation Commands
219
137
 
220
- Run syntax validation:
138
+ Run from `/root/codexclaude`:
221
139
 
222
140
  ```bash
223
141
  node --check bin/codexclaude.js
142
+ npm pack --dry-run
224
143
  ```
225
144
 
226
- Create a temporary home, write config, and verify Codex can parse the four
227
- model catalog entries without making a model call:
145
+ Temporary-home config validation:
228
146
 
229
147
  ```bash
230
148
  tmp_home="$(mktemp -d)"
231
- HOME="$tmp_home" CODEXCLAUDE_DISABLE_UPDATE_CHECK=1 node bin/codexclaude.js --version
149
+ mkdir -p "$tmp_home/.codexclaude"
150
+ cat > "$tmp_home/.codexclaude/config.json" <<'JSON'
151
+ {
152
+ "version": "2.0.19",
153
+ "serviceId": "codexapi",
154
+ "serviceLabel": "CodexAPI.pro",
155
+ "apiOrigin": "https://codexapi.pro",
156
+ "username": "test-token",
157
+ "dashboardEmail": null,
158
+ "model": "claude-opus-4-8",
159
+ "loggedInAt": "2026-07-10T00:00:00.000Z"
160
+ }
161
+ JSON
162
+ HOME="$tmp_home" CODEXCLAUDE_DISABLE_UPDATE_CHECK=1 CODEXCLAUDE_QUIET_STATUS=1 node bin/codexclaude.js setup
232
163
  ```
233
164
 
234
- After a test config is generated, run:
165
+ Verify the generated config contains:
235
166
 
236
- ```bash
237
- HOME="$tmp_home" node node_modules/@openai/codex/bin/codex.js debug models
238
- ```
167
+ - `model = "claude-opus-4-8"`
168
+ - `model_reasoning_effort = "xhigh"`
169
+ - `check_for_update_on_startup = false`
170
+ - `approval_policy = "never"`
171
+ - `sandbox_mode = "danger-full-access"`
172
+ - no default fast service tier
239
173
 
240
- The JSON output must contain exactly:
174
+ Verify the generated model catalog contains only:
241
175
 
242
176
  - `gpt-5.5`
243
177
  - `claude-opus-4-8`
244
178
  - `claude-sonnet-5`
245
179
  - `claude-fable-5`
246
180
 
247
- The Opus entry must have `default_reasoning_level = "xhigh"` and must not use
248
- fallback metadata.
249
-
250
- Package validation:
181
+ After packaging, copy the tarball to the public downloads directories, restart the backend, and verify:
251
182
 
252
183
  ```bash
253
- npm pack --dry-run
254
- npm pack
255
- ```
256
-
257
- Backend validation after changing `/v1/models` or version metadata:
258
-
259
- ```bash
260
- python3 -m py_compile app/main.py app/openai_compat.py app/config.py app/postgres_admin.py
261
- /root/codexapi/.venv/bin/pytest -q tests/test_openai_compat.py tests/test_main_helpers.py
184
+ curl -fsS "https://codexapi.pro/api/v1/codexclaude/version?current=2.0.17"
185
+ curl -fsSI "https://codexapi.pro/downloads/codexapi-codexclaude-2.0.19.tgz"
262
186
  ```
263
187
 
264
- ## Version 2.0.16 Changes
265
-
266
- - Updated the bundled official Codex dependency to `@openai/codex@0.143.0`.
267
- - Kept the launcher model picker and native Codex `/model` catalog limited to ChatGPT-5.5, Opus 4.8, Sonnet 5, and Fable 5.
268
- - Kept the customer-facing startup identity as Magnetapi.org Coding Agent and continued hiding the upstream Codex runtime version in normal startup text.
269
- - Changed the update surface for this release to a recommended, non-blocking notice. Users should be shown the exact update command, but they must not be forced off `2.0.15` for this release.
270
- - Preserved Full Access defaults, xhigh visible reasoning, bearer username auth, Responses wire API, and the CodexAPI.pro identification headers.
271
-
272
- ## Version 2.0.15 Changes
273
-
274
- - Renamed the launcher-controlled startup/status surface to Magnetapi.org Coding Agent and now prints the app version instead of the upstream runtime version.
275
- - Removed Gemini Flash and Deepseek from the launcher model picker and generated native Codex model catalog.
276
- - Kept ChatGPT-5.5, Opus 4.8, Sonnet 5, and Fable 5 as the only visible codexclaude model choices.
277
- - Preserved Full Access defaults, xhigh visible reasoning, wallet auth, local model catalog metadata, and CodexAPI.pro identifying headers.
278
-
279
- ## Version 2.0.14 Changes
280
-
281
- - Updated the official OpenAI Codex runtime dependency to `@openai/codex@0.142.5`, the latest version currently published on npm.
282
- - Kept `claude-sonnet-5` and `claude-fable-5` as the live API slugs for Sonnet 5 and Fable 5 after verifying those names from the production model APIs.
283
- - Removed the standalone `codexclaude status` and `codexclaude usage` launcher commands while preserving the compact wallet status line printed before a coding session starts.
284
- - Preserved Full Access defaults, xhigh visible reasoning, server-managed high runtime effort, bearer username auth, local model catalog metadata, and CodexAPI.pro identifying headers.
285
-
286
- ## Version 2.0.13 Changes
287
-
288
- - Updated the official OpenAI Codex runtime dependency to `@openai/codex@0.142.2`.
289
- - Added Sonnet 5 and Fable 5 as visible launcher and native Codex `/model` choices.
290
- - Added `codexclaude usage`, which reads wallet and recent token usage from the signed-in account origin, including CodexAPI.pro, ChatPlus, or MyAPI.world compatible endpoints.
291
- - Kept Fable 5 customer-visible while the backend applies its custom routed premium path and 2x billing multiplier.
292
- - Preserved Full Access defaults, xhigh visible reasoning, server-managed high runtime effort, wallet auth, and local model catalog metadata.
293
-
294
- ## Version 2.0.12 Changes
295
-
296
- - Updated the official OpenAI Codex runtime dependency to `@openai/codex@0.141.0`.
297
- - Added Google Gemini Flash 3.5 as a fourth visible launcher and native Codex `/model` choice.
298
- - Kept Gemini visible in client config, response metadata, and usage records while the backend routes it through Sonnet 5 low effort.
299
- - Preserved the CodexAPI.pro launcher layer, Full Access defaults, xhigh visible reasoning, server-managed low runtime effort, wallet auth, and Opus 4.8 Chicago routing.
300
-
301
- ## Version 2.0.11 Changes
302
-
303
- - Updated the official OpenAI Codex runtime dependency to `@openai/codex@0.140.0`.
304
- - Re-applied the CodexAPI.pro launcher layer without changing the supported model list, local model catalog, Full Access defaults, xhigh visible reasoning, server-managed low runtime effort, fast-mode billing contract, wallet auth, or Opus 4.8 Chicago routing.
305
-
306
- ## Version 2.0.10 Changes
307
-
308
- - Added a generated local model catalog for native Codex.
309
- - Limited native Codex `/model` to ChatGPT-5.5, Opus 4.8, and Deepseek v4 Budget.
310
- - Added valid metadata for `claude-opus-4-8` and `deepseek-v4-pro`.
311
- - Changed the user-visible reasoning effort from `low` to `xhigh`.
312
- - Kept server-side upstream reasoning pinned to `low`.
313
- - Kept `/fast` client-visible by advertising the `fast` speed tier locally while relying on the backend to bill and strip it upstream.
314
-
315
- ## Older Release Notes
316
-
317
- Version 2.0.9 updated the official Codex runtime dependency to
318
- `@openai/codex@0.139.0` and re-applied the CodexAPI.pro launcher layer.
319
-
320
- Version 2.0.8 kept official Codex on `0.137.0`, changed generated config to low
321
- reasoning, and removed default fast service tier.
322
-
323
- Version 2.0.7 updated official Codex to `0.137.0`.
324
-
325
- Version 2.0.6 updated official Codex to `0.135.0`, migrated Opus 4.7 aliases to
326
- Opus 4.8, and pinned Opus 4.8 codexclaude sessions to Chicago.
188
+ The version endpoint must report `latestVersion = 2.0.19`, `minimumVersion = 2.0.19`, and `updateRequired = true` for old clients.
327
189
 
328
- Version 2.0.5 published the launcher as `@codexapi/codexclaude`.
190
+ ## Version 2.0.19 Changes
329
191
 
330
- Version 2.0.4 added Deepseek v4 Budget and introduced this customization ledger.
192
+ - Updated bundled runtime dependency to `@openai/codex@0.144.1`.
193
+ - Forced all older codexclaude clients to update by setting backend minimum version to `2.0.19`.
194
+ - Changed launcher-owned identity to `Magnetapi Client`.
195
+ - Changed the default selected model to Opus 4.8.
196
+ - Kept visible reasoning at xhigh.
197
+ - Preserved Full Access defaults.
198
+ - Disabled bundled runtime update checks through generated config and stale update-cache removal.
199
+ - Removed launcher fallback to the upstream npm wrapper so OpenAI update prompts are not emitted by codexclaude.
200
+ - Kept update monitoring limited to CodexAPI.pro version metadata and the `@codexapi/codexclaude` npm package.
201
+ - Updated setup scripts to install the exact hosted `2.0.19` tarball.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@codexapi/codexclaude",
3
- "version": "2.0.16",
4
- "description": "Magnetapi.org Coding Agent launcher for ChatGPT-5.5, Opus 4.8, Sonnet 5, and Fable 5.",
3
+ "version": "2.0.19",
4
+ "description": "Magnetapi Client launcher for ChatGPT-5.5, Opus 4.8, Sonnet 5, and Fable 5.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "bin": {
@@ -17,7 +17,7 @@
17
17
  "node": ">=20"
18
18
  },
19
19
  "dependencies": {
20
- "@openai/codex": "0.143.0"
20
+ "@openai/codex": "0.144.1"
21
21
  },
22
22
  "publishConfig": {
23
23
  "access": "public"