@bitkyc08/opencodex 2.7.29 → 2.7.31

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 (41) hide show
  1. package/README.ko.md +1 -1
  2. package/README.md +1 -1
  3. package/README.ru.md +479 -0
  4. package/README.zh-CN.md +1 -1
  5. package/gui/dist/assets/index-BPa0R6EN.js +46 -0
  6. package/gui/dist/assets/index-BY7KvJRB.css +1 -0
  7. package/gui/dist/index.html +2 -2
  8. package/package.json +1 -1
  9. package/src/adapters/cursor/cursor-errors.ts +7 -2
  10. package/src/adapters/cursor/discovery.ts +2 -2
  11. package/src/adapters/cursor/request-builder.ts +90 -6
  12. package/src/adapters/cursor/tool-definitions.ts +23 -6
  13. package/src/adapters/google.ts +7 -0
  14. package/src/codex/auth-api.ts +18 -0
  15. package/src/codex/catalog.ts +39 -11
  16. package/src/codex/routing.ts +85 -4
  17. package/src/combos/index.ts +1 -1
  18. package/src/combos/request.ts +26 -4
  19. package/src/combos/types.ts +4 -4
  20. package/src/lib/errors.ts +4 -0
  21. package/src/lib/upstream-retry.ts +21 -0
  22. package/src/lib/winsw.ts +7 -1
  23. package/src/oauth/anthropic.ts +23 -1
  24. package/src/oauth/index.ts +83 -4
  25. package/src/oauth/local-token-detect.ts +3 -0
  26. package/src/oauth/store.ts +32 -0
  27. package/src/providers/antigravity-models.ts +23 -12
  28. package/src/providers/base-url-choices.ts +18 -0
  29. package/src/providers/registry.ts +122 -7
  30. package/src/responses/parser.ts +11 -6
  31. package/src/router.ts +6 -1
  32. package/src/server/index.ts +3 -3
  33. package/src/server/relay.ts +31 -5
  34. package/src/server/request-log.ts +12 -0
  35. package/src/server/responses.ts +111 -27
  36. package/src/service.ts +12 -3
  37. package/src/storage/scanner.ts +18 -6
  38. package/src/types.ts +4 -2
  39. package/src/usage/expected-prices.ts +12 -9
  40. package/gui/dist/assets/index-CMKZnkG9.js +0 -40
  41. package/gui/dist/assets/index-DyBPh28A.css +0 -1
package/src/service.ts CHANGED
@@ -503,7 +503,7 @@ function installWindows(): void {
503
503
  throw new Error(`Cannot remove the native service before switching to Task Scheduler: ${err instanceof Error ? err.message : String(err)}. Remove it manually with 'sc delete ${WINSW_SERVICE_ID}' or retry.`);
504
504
  }
505
505
  if (statusWinswRaw() !== "nonexistent") {
506
- throw new Error("Native service still present after removal attempt — aborting switch. Remove it manually with 'sc delete opencodex-proxy-native'.");
506
+ throw new Error(`Native service registration could not be re-verified after the removal attempt — aborting switch. Check 'sc.exe query ${WINSW_SERVICE_ID}' and remove it manually if present.`);
507
507
  }
508
508
  }
509
509
  // End a running task BEFORE rewriting the assets it is executing — cmd.exe reading the
@@ -761,7 +761,9 @@ export function stopServiceIfInstalled(): boolean {
761
761
  const q = schtasks(["/query", "/tn", TASK]);
762
762
  if (q.includes(TASK)) { stopWindows(); stopped = true; }
763
763
  } catch { /* task not found */ }
764
- if (statusWinswRaw() !== "nonexistent") { stopWinswService(); stopped = true; }
764
+ if (statusWinswRaw() !== "nonexistent") {
765
+ try { stopWinswService(); stopped = true; } catch { /* best-effort */ }
766
+ }
765
767
  if (stopped) return true;
766
768
  } else if (process.platform === "linux" && isSystemd() && existsSync(unitPath())) {
767
769
  try { stopSystemd(); return true; } catch { return false; }
@@ -793,7 +795,14 @@ export function uninstallServiceIfInstalled(): boolean {
793
795
  const q = schtasks(["/query", "/tn", TASK]);
794
796
  if (q.includes(TASK)) { uninstallWindows(); removed = true; }
795
797
  } catch { /* task not found */ }
796
- if (statusWinswRaw() !== "nonexistent") { uninstallWinswService(); removed = true; }
798
+ if (statusWinswRaw() !== "nonexistent") {
799
+ try {
800
+ uninstallWinswService();
801
+ removed = true;
802
+ } catch (err) {
803
+ console.warn(`⚠️ Failed to remove native service: ${err instanceof Error ? err.message : String(err)}. Check 'sc.exe query ${WINSW_SERVICE_ID}'.`);
804
+ }
805
+ }
797
806
  if (removed) { removeServiceInstallState(); return true; }
798
807
  } else if (process.platform === "linux" && existsSync(unitPath())) {
799
808
  try { uninstallSystemd(); removeServiceInstallState(); return true; } catch {
@@ -1,8 +1,18 @@
1
1
  import { readdirSync, statSync } from "node:fs";
2
2
  import { join } from "node:path";
3
- import { Database } from "bun:sqlite";
3
+ import { pathToFileURL } from "node:url";
4
+ import { Database, constants } from "bun:sqlite";
4
5
  import { resolveCodexHomeDir } from "../codex/home";
5
6
 
7
+ // SQLITE_OPEN_READONLY alone is not filesystem-read-only for a WAL-mode DB: Bun's
8
+ // `{ readonly: true }` can still materialize *.sqlite-wal/-shm sidecars the first time a
9
+ // checkpointed WAL database (no live sidecars yet) is opened and queried. `immutable=1`
10
+ // (via a file: URI, which requires the SQLITE_OPEN_URI flag) tells SQLite the file will
11
+ // never change for this connection's lifetime, so it skips WAL/shm entirely — the
12
+ // tradeoff is reading the last-checkpointed snapshot instead of blocking on a live writer,
13
+ // which is the right tradeoff for a passive diagnostics scan that must never write.
14
+ const IMMUTABLE_READONLY_FLAGS = constants.SQLITE_OPEN_READONLY | constants.SQLITE_OPEN_URI;
15
+
6
16
  /**
7
17
  * Read-only CODEX_HOME storage scanner — Phase 1 of the Storage page epic
8
18
  * (devlog/_plan/500_storage-page-session-cleanup). Pure measurement: sizes via
@@ -121,15 +131,17 @@ function buildBucket(key: StorageBucketKey, files: FileEntry[]): StorageBucket {
121
131
  }
122
132
 
123
133
  /**
124
- * Row count via a lock-safe readonly open (the same secondary-reader contract as
125
- * codex/history-provider.ts): short busy timeout, and any lock/corruption/schema
126
- * error degrades to null — "unknown", never a crash and never a write.
134
+ * Row count via an immutable readonly open guarantees zero writes under CODEX_HOME even
135
+ * for a checkpointed WAL-mode DB with no sidecars yet. Any error (corruption, a file that
136
+ * vanished mid-scan, a future schema change) degrades to null — "unknown", never a crash.
127
137
  */
128
138
  function countRowsReadonly(dbPath: string, table: string): number | null {
129
139
  try {
130
- const db = new Database(dbPath, { readonly: true });
140
+ // pathToFileURL percent-encodes reserved characters (space, #, ?, %) that a naive
141
+ // `file:${dbPath}` concatenation would misparse as a URI fragment/query/escape.
142
+ const uri = `${pathToFileURL(dbPath).href}?immutable=1`;
143
+ const db = new Database(uri, IMMUTABLE_READONLY_FLAGS);
131
144
  try {
132
- db.exec("PRAGMA busy_timeout = 100");
133
145
  const row = db.query<{ n: number }, []>(`SELECT count(*) AS n FROM "${table}"`).get();
134
146
  return row?.n ?? null;
135
147
  } finally {
package/src/types.ts CHANGED
@@ -122,6 +122,8 @@ export interface OcxTool {
122
122
  freeform?: boolean;
123
123
  /** Client-executed tool discovery (tool_search): the model's call must be relayed as a tool_search_call. */
124
124
  toolSearch?: boolean;
125
+ /** Tool definition restored from a prior tool_search output; transports may prioritize it when catalogs are bounded. */
126
+ loadedFromToolSearch?: boolean;
125
127
  /** Synthetic web_search tool: the model's call is executed by the gpt-5.4-mini sidecar, not relayed to Codex. */
126
128
  webSearch?: boolean;
127
129
  }
@@ -496,8 +498,8 @@ export interface OcxComboConfig {
496
498
  strategy?: OcxComboStrategy;
497
499
  /** Successful requests retained on one RR selection batch. Default 1; range 1..100. */
498
500
  stickyLimit?: number;
499
- /** Used when the client omits reasoning.effort. Default medium. */
500
- defaultEffort?: OcxComboDefaultEffort;
501
+ /** Used when the client omits reasoning.effort. null/omitted leaves the target default unchanged. */
502
+ defaultEffort?: OcxComboDefaultEffort | null;
501
503
  }
502
504
 
503
505
  /**
@@ -30,8 +30,7 @@ export interface ExpectedPriceOverlay {
30
30
  }
31
31
 
32
32
  const GEMINI_31_PRO: Cost4 = { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 };
33
- const GEMINI_35_FLASH: Cost4 = { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 };
34
- const GEMINI_3_FLASH: Cost4 = { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0 };
33
+ const GEMINI_36_FLASH: Cost4 = { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 };
35
34
  const MINIMAX_M21_HIGHSPEED: Cost4 = { input: 0.6, output: 2.4, cacheRead: 0.03, cacheWrite: 0.375 };
36
35
  const KIMI_K3: Cost4 = { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3 };
37
36
  const KIMI_K27_CODE: Cost4 = { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0.95 };
@@ -39,7 +38,7 @@ const KIMI_K27_CODE_HIGHSPEED: Cost4 = { input: 1.9, output: 8, cacheRead: 0.38,
39
38
  const KIMI_K26: Cost4 = { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0.95 };
40
39
  const KIMI_K25: Cost4 = { input: 0.6, output: 3, cacheRead: 0.1, cacheWrite: 0.6 };
41
40
 
42
- const GEMINI_PRICING = "https://ai.google.dev/gemini-api/docs/pricing (2026-06-18); cacheWrite=0: storage is billed per-hour, not per-token";
41
+ const GEMINI_PRICING = "https://ai.google.dev/gemini-api/docs/pricing (2026-07-22); cacheWrite=0: storage is billed per-hour, not per-token";
43
42
  const MINIMAX_PRICING = "https://platform.minimax.io/docs/guides/pricing-paygo";
44
43
  const DEEPSEEK_PRICING = "https://api-docs.deepseek.com/quick_start/pricing-details-usd; V4 Flash alias transition scheduled 2026-07-24 — re-verify after";
45
44
  // Kimi official tables publish input/output/cache-hit only; cacheWrite is mapped to the
@@ -58,12 +57,16 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
58
57
  // base model's standard rate per the official Billing FAQ).
59
58
  { provider: "google-antigravity", modelId: "gemini-3.1-pro-low", cost4: GEMINI_31_PRO, source: `derived: gemini-3.1-pro (<=200k tier) ${GEMINI_PRICING}`, verifiedAt: "2026-07-20", status: "verified-derived" },
60
59
  { provider: "google-antigravity", modelId: "gemini-3.1-pro-high", cost4: GEMINI_31_PRO, source: `derived: gemini-3.1-pro (<=200k tier) ${GEMINI_PRICING}`, verifiedAt: "2026-07-20", status: "verified-derived" },
61
- { provider: "google-antigravity", modelId: "gemini-3.5-flash-extra-low", cost4: GEMINI_35_FLASH, source: `derived: gemini-3.5-flash ${GEMINI_PRICING}`, verifiedAt: "2026-07-20", status: "verified-derived" },
62
- { provider: "google-antigravity", modelId: "gemini-3.5-flash-low", cost4: GEMINI_35_FLASH, source: `derived: gemini-3.5-flash ${GEMINI_PRICING}`, verifiedAt: "2026-07-20", status: "verified-derived" },
63
- { provider: "google-antigravity", modelId: "gemini-3.5-flash-mid", cost4: GEMINI_35_FLASH, source: `derived: gemini-3.5-flash ${GEMINI_PRICING}`, verifiedAt: "2026-07-20", status: "verified-derived" },
64
- { provider: "google-antigravity", modelId: "gemini-3.5-flash-high", cost4: GEMINI_35_FLASH, source: `derived: gemini-3.5-flash ${GEMINI_PRICING}`, verifiedAt: "2026-07-20", status: "verified-derived" },
65
- { provider: "google-antigravity", modelId: "gemini-3-flash-agent", cost4: GEMINI_3_FLASH, source: `derived: gemini-3-flash + Agent billing principle ${GEMINI_PRICING}`, verifiedAt: "2026-07-20", status: "verified-derived" },
66
- // Google Vertex/Gemini API current model (verified published table).
60
+ { provider: "google-antigravity", modelId: "gemini-3.6-flash-low", cost4: GEMINI_36_FLASH, source: `derived: gemini-3.6-flash ${GEMINI_PRICING}`, verifiedAt: "2026-07-22", status: "verified-derived" },
61
+ { provider: "google-antigravity", modelId: "gemini-3.6-flash-medium", cost4: GEMINI_36_FLASH, source: `derived: gemini-3.6-flash ${GEMINI_PRICING}`, verifiedAt: "2026-07-22", status: "verified-derived" },
62
+ { provider: "google-antigravity", modelId: "gemini-3.6-flash-high", cost4: GEMINI_36_FLASH, source: `derived: gemini-3.6-flash ${GEMINI_PRICING}`, verifiedAt: "2026-07-22", status: "verified-derived" },
63
+ { provider: "google-antigravity", modelId: "gemini-3.5-flash-extra-low", cost4: GEMINI_36_FLASH, source: `compat alias -> gemini-3.6-flash-low ${GEMINI_PRICING}`, verifiedAt: "2026-07-22", status: "verified-derived" },
64
+ { provider: "google-antigravity", modelId: "gemini-3.5-flash-low", cost4: GEMINI_36_FLASH, source: `compat alias -> gemini-3.6-flash-medium ${GEMINI_PRICING}`, verifiedAt: "2026-07-22", status: "verified-derived" },
65
+ { provider: "google-antigravity", modelId: "gemini-3.5-flash-mid", cost4: GEMINI_36_FLASH, source: `compat alias -> gemini-3.6-flash-medium ${GEMINI_PRICING}`, verifiedAt: "2026-07-22", status: "verified-derived" },
66
+ { provider: "google-antigravity", modelId: "gemini-3.5-flash-high", cost4: GEMINI_36_FLASH, source: `compat alias -> gemini-3.6-flash-high ${GEMINI_PRICING}`, verifiedAt: "2026-07-22", status: "verified-derived" },
67
+ { provider: "google-antigravity", modelId: "gemini-3-flash-agent", cost4: GEMINI_36_FLASH, source: `compat alias -> gemini-3.6-flash-high ${GEMINI_PRICING}`, verifiedAt: "2026-07-22", status: "verified-derived" },
68
+ // Direct Google Gemini API current model (verified — published table).
69
+ { provider: "google", modelId: "gemini-3.6-flash", cost4: GEMINI_36_FLASH, source: GEMINI_PRICING, verifiedAt: "2026-07-22", status: "verified" },
67
70
  { provider: "google-antigravity", modelId: "gemini-3.1-pro-preview", cost4: GEMINI_31_PRO, source: GEMINI_PRICING, verifiedAt: "2026-07-20", status: "verified" },
68
71
  // Antigravity-bundled third-party models — derived from the underlying vendor's
69
72
  // official API price (Antigravity itself bills via subscription quota).