@bitkyc08/opencodex 2.6.32 → 2.7.1-preview.20260710

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.
Files changed (61) hide show
  1. package/README.ko.md +9 -5
  2. package/README.md +7 -4
  3. package/README.zh-CN.md +8 -4
  4. package/gui/dist/assets/index-BUAMcKFd.css +1 -0
  5. package/gui/dist/assets/index-KorpEKW8.js +34 -0
  6. package/gui/dist/index.html +2 -2
  7. package/package.json +1 -1
  8. package/src/adapters/anthropic.ts +62 -1
  9. package/src/adapters/cursor/cursor-errors.ts +28 -1
  10. package/src/adapters/cursor/discovery.ts +60 -10
  11. package/src/adapters/cursor/effort-map.ts +38 -7
  12. package/src/adapters/cursor/live-models.ts +3 -0
  13. package/src/adapters/cursor/live-transport.ts +136 -7
  14. package/src/adapters/cursor/protobuf-request.ts +24 -1
  15. package/src/adapters/cursor/request-builder.ts +6 -5
  16. package/src/adapters/cursor/transport-retry.ts +22 -3
  17. package/src/adapters/cursor.ts +2 -1
  18. package/src/adapters/openai-chat.ts +75 -26
  19. package/src/bridge.ts +42 -3
  20. package/src/cli/debug.ts +203 -0
  21. package/src/cli/doctor.ts +11 -0
  22. package/src/cli/help.ts +11 -0
  23. package/src/cli/index.ts +10 -0
  24. package/src/cli/v2.ts +131 -0
  25. package/src/codex/auth-api.ts +7 -3
  26. package/src/codex/catalog.ts +334 -31
  27. package/src/codex/data/upstream-models.json +830 -0
  28. package/src/codex/features.ts +178 -0
  29. package/src/codex/project-config-warnings.ts +388 -0
  30. package/src/codex/sync.ts +8 -0
  31. package/src/codex/warmup.ts +62 -7
  32. package/src/config.ts +7 -5
  33. package/src/lib/debug-log-buffer.ts +42 -0
  34. package/src/lib/debug-settings.ts +84 -0
  35. package/src/lib/debug.ts +18 -9
  36. package/src/lib/errors.ts +104 -1
  37. package/src/oauth/cursor.ts +35 -12
  38. package/src/oauth/store.ts +4 -3
  39. package/src/providers/derive.ts +8 -0
  40. package/src/providers/registry.ts +56 -21
  41. package/src/reasoning-effort.ts +37 -9
  42. package/src/responses/parser.ts +7 -2
  43. package/src/router.ts +5 -0
  44. package/src/server/adapter-resolve.ts +1 -1
  45. package/src/server/index.ts +27 -3
  46. package/src/server/management-api.ts +189 -7
  47. package/src/server/relay.ts +2 -2
  48. package/src/server/request-decompress.ts +8 -2
  49. package/src/server/request-log.ts +78 -0
  50. package/src/server/responses.ts +241 -9
  51. package/src/types.ts +34 -1
  52. package/src/usage/debug.ts +32 -5
  53. package/src/usage/summary.ts +6 -6
  54. package/src/vision/describe.ts +4 -0
  55. package/src/web-search/executor.ts +4 -0
  56. package/src/web-search/format-result.ts +11 -3
  57. package/src/web-search/index.ts +31 -2
  58. package/src/web-search/loop.ts +112 -61
  59. package/src/web-search/parse.ts +4 -1
  60. package/gui/dist/assets/index-ByGC8-Bm.css +0 -1
  61. package/gui/dist/assets/index-D_JZzI0r.js +0 -15
package/src/cli/doctor.ts CHANGED
@@ -15,6 +15,7 @@ import { readCodexTokens } from "../codex/auth-collision";
15
15
  import { resolveCodexHomeDir as resolveCodexHomeDirImpl, isWslRuntime, listWslWindowsCodexHomes, wslAutomountRoot, type CodexHomeDeps } from "../codex/home";
16
16
  import { findCodexOnPath, isWindowsInteropDir } from "../codex/shim";
17
17
  import { countPendingOpencodexHistory } from "../codex/history-provider";
18
+ import { collectProjectCodexConfigWarnings, formatProjectCodexConfigWarningsForDoctor } from "../codex/project-config-warnings";
18
19
  export { resolveCodexHomeDir } from "../codex/home";
19
20
 
20
21
  const WHAM_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
@@ -373,6 +374,16 @@ export async function runDoctor(): Promise<void> {
373
374
  console.log(` -- ${pending.pendingRows} thread(s) still tagged opencodex, ${pending.backupEntries} backup manifest entr${pending.backupEntries === 1 ? "y" : "ies"}`);
374
375
  }
375
376
 
377
+ console.log("\nProject Codex configs");
378
+ const projectWarnings = collectProjectCodexConfigWarnings();
379
+ if (projectWarnings.length === 0) {
380
+ console.log(" ok no project-local provider bypass detected");
381
+ } else {
382
+ for (const line of formatProjectCodexConfigWarningsForDoctor(projectWarnings)) {
383
+ console.log(line);
384
+ }
385
+ }
386
+
376
387
  const dual = collectWslDualInstall();
377
388
  if (dual.wsl) {
378
389
  console.log("\nWSL Codex installs");
package/src/cli/help.ts CHANGED
@@ -54,6 +54,15 @@ const helpEntries: Record<string, HelpEntry> = {
54
54
  "sync-cache": { usage: "ocx sync-cache", summary: "Refresh Codex's model cache from the active catalog." },
55
55
  status: { usage: "ocx status", summary: "Check proxy server status." },
56
56
  doctor: { usage: "ocx doctor", summary: "Diagnose environment/network issues (paths, WSL /mnt, proxy env, ChatGPT reachability)." },
57
+ debug: {
58
+ usage: "ocx debug [provider on|off|status|reset|logs [-f]|usage on|off|status|reset|logs [-f]]",
59
+ summary: "Show or toggle runtime provider debug logging on the running proxy.",
60
+ details: [
61
+ "Provider: ocx debug provider on | off | status | reset | logs [-f]",
62
+ "Usage JSONL: ocx debug usage on | off | status | reset | logs [-f]",
63
+ "Env default: OCX_DEBUG=1 (legacy OCX_DEBUG_FRAMES still works)",
64
+ ],
65
+ },
57
66
  login: { usage: "ocx login <provider>", summary: "OAuth or API-key login for a provider." },
58
67
  logout: { usage: "ocx logout <provider>", summary: "Remove a stored provider login." },
59
68
  gui: { usage: "ocx gui", summary: "Open the opencodex dashboard." },
@@ -115,6 +124,8 @@ Usage:
115
124
  ocx sync-cache Refresh Codex's model cache from the active catalog
116
125
  ocx status Check proxy server status
117
126
  ocx doctor Diagnose environment/network issues (WSL, proxy, ChatGPT reachability)
127
+ ocx debug [provider|usage ...]
128
+ provider/usage on|off|status|reset|logs [-f]
118
129
  ocx login <provider> OAuth login (xai) — opens browser, stores token in ~/.opencodex/auth.json
119
130
  ocx logout <provider> Remove a stored OAuth login
120
131
  ocx gui Open the opencodex dashboard
package/src/cli/index.ts CHANGED
@@ -449,6 +449,11 @@ switch (command) {
449
449
  await runDoctor();
450
450
  break;
451
451
  }
452
+ case "debug": {
453
+ const { handleDebugCommand } = await import("./debug");
454
+ await handleDebugCommand(args.slice(1));
455
+ break;
456
+ }
452
457
  case "ensure":
453
458
  await handleEnsure();
454
459
  break;
@@ -468,6 +473,11 @@ switch (command) {
468
473
  await syncModelsToCodex((await findLiveProxy())?.port);
469
474
  break;
470
475
  }
476
+ case "v2": {
477
+ const { cmdV2 } = await import("./v2");
478
+ process.exitCode = await cmdV2(args.slice(1), {}, async () => (await findLiveProxy())?.port);
479
+ break;
480
+ }
471
481
  case "sync-cache": {
472
482
  const { invalidateCodexModelsCache } = await import("../codex/catalog");
473
483
  invalidateCodexModelsCache();
package/src/cli/v2.ts ADDED
@@ -0,0 +1,131 @@
1
+ /**
2
+ * `ocx v2 status|on|off` — toggle/report the codex `multi_agent_v2` feature that
3
+ * controls the multi-agent surface (v1 vs v2 collab mode).
4
+ *
5
+ * Contract:
6
+ * - config.toml writes go through the official `codex features enable|disable`
7
+ * CLI only (format-preserving TOML edit stays upstream-owned).
8
+ * - after a successful flip the catalog is RESYNCED so model metadata stays fresh.
9
+ * - `on` warns when [agents] max_threads is still present (codex-rs refuses to
10
+ * boot with it while v2 is enabled) — ocx never edits that key itself.
11
+ * - nothing in the catalog build path calls this module; no auto-flip exists.
12
+ */
13
+ import { execFileSync } from "node:child_process";
14
+ import { getMaxConcurrentThreads, hasAgentsMaxThreads, isMultiAgentV2Enabled, setMaxConcurrentThreads } from "../codex/features";
15
+
16
+ import { loadConfig, saveConfig } from "../config";
17
+
18
+ export interface V2CliDeps {
19
+ execFile?: (file: string, args: string[]) => void;
20
+ isEnabled?: typeof isMultiAgentV2Enabled;
21
+ hasMaxThreads?: typeof hasAgentsMaxThreads;
22
+ sync?: (port?: number) => Promise<unknown>;
23
+ log?: Pick<Console, "log" | "error">;
24
+ }
25
+
26
+ function runCodexFeatures(action: "enable" | "disable", deps: V2CliDeps): void {
27
+ const exec = deps.execFile ?? ((file: string, args: string[]) => {
28
+ execFileSync(file, args, { stdio: ["ignore", "pipe", "pipe"], timeout: 15_000, windowsHide: true });
29
+ });
30
+ const command = process.env.CODEX_CLI_PATH?.trim() || "codex";
31
+ exec(command, ["features", action, "multi_agent_v2"]);
32
+ }
33
+
34
+ export function v2StatusLine(enabled: boolean): string {
35
+ return enabled
36
+ ? "multi_agent_v2: ON — v2 multi-agent surface active"
37
+ : "multi_agent_v2: OFF — v1 multi-agent surface (default install)";
38
+ }
39
+
40
+ export function multiAgentModeLine(mode: string): string {
41
+ switch (mode) {
42
+ case "v1": return "multi_agent_mode: v1 — ALL models forced to v1 surface (upstream pins overridden)";
43
+ case "v2": return "multi_agent_mode: v2 — ALL models forced to v2 surface (upstream pins overridden)";
44
+ default: return "multi_agent_mode: default — upstream model pins respected (sol/terra=v2, luna=v1, rest=codex flag)";
45
+ }
46
+ }
47
+
48
+ export async function cmdV2(args: string[], deps: V2CliDeps = {}, findPort?: () => Promise<number | undefined>): Promise<number> {
49
+ const log = deps.log ?? console;
50
+ const isEnabled = deps.isEnabled ?? isMultiAgentV2Enabled;
51
+ const hasMaxThreads = deps.hasMaxThreads ?? hasAgentsMaxThreads;
52
+ const verb = (args[0] ?? "status").trim().toLowerCase();
53
+
54
+ if (verb === "status") {
55
+ log.log(v2StatusLine(isEnabled()));
56
+ const cfg = loadConfig();
57
+ log.log(multiAgentModeLine(cfg.multiAgentMode ?? "default"));
58
+ const threads = getMaxConcurrentThreads();
59
+ log.log(`max_concurrent_threads_per_session: ${threads ?? "(unset — codex default)"}`);
60
+ if (isEnabled() && hasMaxThreads()) {
61
+ log.log("WARNING: [agents] max_threads is set — codex refuses to start while multi_agent_v2 is enabled. Remove it from config.toml (concurrency lives in features.multi_agent_v2.max_concurrent_threads_per_session).");
62
+ }
63
+ return 0;
64
+ }
65
+ if (verb === "threads") {
66
+ const value = Number((args[1] ?? "").trim());
67
+ if (!Number.isInteger(value) || value < 1) {
68
+ log.error("v2 threads: pass an integer >= 1 (features.multi_agent_v2.max_concurrent_threads_per_session)");
69
+ return 1;
70
+ }
71
+ const result = setMaxConcurrentThreads(value);
72
+ if (!result.ok) { log.error(`v2 threads: ${result.error}`); return 1; }
73
+ log.log(result.changed
74
+ ? `max_concurrent_threads_per_session = ${value} — applies to new sessions.`
75
+ : `max_concurrent_threads_per_session already ${value} — nothing to do.`);
76
+ return 0;
77
+ }
78
+ if (verb === "mode") {
79
+ const modeArg = (args[1] ?? "").trim().toLowerCase();
80
+ if (modeArg !== "v1" && modeArg !== "default" && modeArg !== "v2") {
81
+ log.error("v2 mode: expected v1|default|v2");
82
+ return 1;
83
+ }
84
+ const cfg = loadConfig();
85
+ if (modeArg === "default") delete cfg.multiAgentMode;
86
+ else cfg.multiAgentMode = modeArg as "v1" | "v2";
87
+ saveConfig(cfg);
88
+ try {
89
+ const sync = deps.sync ?? (await import("../codex/sync")).syncModelsToCodex;
90
+ await sync(findPort ? await findPort() : undefined);
91
+ } catch (err) {
92
+ log.error(`catalog resync failed: ${err instanceof Error ? err.message : String(err)} — run 'ocx sync' manually.`);
93
+ return 1;
94
+ }
95
+ log.log(multiAgentModeLine(modeArg));
96
+ log.log("Applies to NEW sessions; running sessions keep their pinned multi-agent version.");
97
+ return 0;
98
+ }
99
+ if (verb !== "on" && verb !== "off") {
100
+ log.error(`v2: unknown verb '${verb}' (expected status|on|off|mode <v1|default|v2>|threads <n>)`);
101
+ return 1;
102
+ }
103
+
104
+ const want = verb === "on";
105
+ if (isEnabled() === want) {
106
+ log.log(`multi_agent_v2 already ${want ? "ON" : "OFF"} — nothing to do.`);
107
+ return 0;
108
+ }
109
+ try {
110
+ runCodexFeatures(want ? "enable" : "disable", deps);
111
+ } catch (err) {
112
+ log.error(`codex features ${want ? "enable" : "disable"} multi_agent_v2 failed: ${err instanceof Error ? err.message : String(err)}`);
113
+ return 1;
114
+ }
115
+ if (want && hasMaxThreads()) {
116
+ log.log("WARNING: [agents] max_threads is still set — codex will REFUSE to start until you remove it (features.multi_agent_v2.max_concurrent_threads_per_session replaces it).");
117
+ }
118
+
119
+ // Resync catalog so multi-agent surface metadata stays fresh in both the
120
+ // on-disk catalog and models_cache.json after the toggle flip.
121
+ try {
122
+ const sync = deps.sync ?? (await import("../codex/sync")).syncModelsToCodex;
123
+ await sync(findPort ? await findPort() : undefined);
124
+ } catch (err) {
125
+ log.error(`catalog resync failed (flag IS flipped): ${err instanceof Error ? err.message : String(err)} — run 'ocx sync' manually.`);
126
+ return 1;
127
+ }
128
+ log.log(v2StatusLine(want));
129
+ log.log("Applies to NEW sessions; running sessions keep their pinned multi-agent version. Restart the Codex app (or wait out its picker cache) to see the ladder change.");
130
+ return 0;
131
+ }
@@ -27,7 +27,7 @@ export { clearAccountQuota, getAccountQuota, parseUsageQuota, updateAccountQuota
27
27
  import { extractAccountId, decodeJwtPayload } from "../oauth/chatgpt";
28
28
  import { MAIN_CODEX_ACCOUNT_ID, setMainAccountPlan } from "./main-account";
29
29
  import { maskEmail } from "../lib/privacy";
30
- import { codexWarmupFailureReason, warmCodexAccount } from "./warmup";
30
+ import { CodexWarmupError, codexWarmupFailureReason, warmCodexAccount } from "./warmup";
31
31
  export { maskEmail } from "../lib/privacy";
32
32
  import type { CodexAccount, OcxConfig } from "../types";
33
33
 
@@ -149,12 +149,16 @@ async function verifyCodexAccountWarmup(
149
149
  await warmCodexAccount({ accessToken, chatgptAccountId });
150
150
  return { ok: true, validatedAt: Date.now() };
151
151
  } catch (err) {
152
+ const reason = codexWarmupFailureReason(err);
153
+ const upstream = err instanceof CodexWarmupError ? err.upstreamDetail : undefined;
152
154
  return {
153
155
  ok: false,
154
156
  response: jsonResponse({
155
- error: "Codex account warmup failed. Reauthenticate the account and try again.",
157
+ error: upstream
158
+ ? `Codex account warmup failed: ${upstream}`
159
+ : "Codex account warmup failed. Reauthenticate the account and try again.",
156
160
  code: "codex_warmup_failed",
157
- reason: codexWarmupFailureReason(err),
161
+ reason,
158
162
  accountId,
159
163
  }, 401),
160
164
  };