@bitkyc08/opencodex 2.38.0 → 2.39.0

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 (81) hide show
  1. package/bin/ocx.mjs +58 -6
  2. package/gui/dist/assets/index-D-lchsPw.js +112 -0
  3. package/gui/dist/assets/index-uvENYLin.css +1 -0
  4. package/gui/dist/index.html +2 -2
  5. package/gui/dist/provider-icons/baseten.svg +13 -0
  6. package/gui/dist/provider-icons/bizrouter.svg +41 -0
  7. package/gui/dist/provider-icons/cerebras.svg +26 -0
  8. package/gui/dist/provider-icons/deepinfra.svg +75 -0
  9. package/gui/dist/provider-icons/digitalocean.svg +10 -0
  10. package/gui/dist/provider-icons/featherless.svg +4 -0
  11. package/gui/dist/provider-icons/gajae-code.svg +410 -0
  12. package/gui/dist/provider-icons/hermes-agent.svg +207 -0
  13. package/gui/dist/provider-icons/hyperbolic.svg +18 -0
  14. package/gui/dist/provider-icons/kilo.svg +13 -0
  15. package/gui/dist/provider-icons/litellm.svg +1 -0
  16. package/gui/dist/provider-icons/minimax.svg +1 -0
  17. package/gui/dist/provider-icons/nanogpt.svg +74 -0
  18. package/gui/dist/provider-icons/nebius.svg +1 -0
  19. package/gui/dist/provider-icons/neuralwatt.svg +27 -0
  20. package/gui/dist/provider-icons/nous.svg +149 -0
  21. package/gui/dist/provider-icons/novita.svg +32 -0
  22. package/gui/dist/provider-icons/orcarouter.svg +175 -0
  23. package/gui/dist/provider-icons/parallel.svg +13 -0
  24. package/gui/dist/provider-icons/sambanova.svg +276 -0
  25. package/gui/dist/provider-icons/scaleway.svg +11 -0
  26. package/gui/dist/provider-icons/siliconflow.svg +18 -0
  27. package/gui/dist/provider-icons/synthetic.svg +12 -0
  28. package/gui/dist/provider-icons/together.svg +18 -0
  29. package/gui/dist/provider-icons/umans.svg +30 -0
  30. package/gui/dist/provider-icons/venice.svg +165 -0
  31. package/gui/dist/provider-icons/vultr.svg +15 -0
  32. package/gui/dist/provider-icons/zai.svg +218 -0
  33. package/gui/dist/provider-icons/zenmux.svg +1 -0
  34. package/package.json +1 -1
  35. package/src/adapters/cursor/live-models.ts +1 -0
  36. package/src/adapters/openai-responses.ts +72 -10
  37. package/src/bridge.ts +15 -15
  38. package/src/cli/dispatch.ts +54 -18
  39. package/src/cli/index.ts +420 -30
  40. package/src/cli/integrations.ts +24 -2
  41. package/src/cli/uninstall-plan.ts +86 -0
  42. package/src/codex/account-store.ts +121 -8
  43. package/src/codex/auth-api.ts +202 -33
  44. package/src/codex/catalog/provider-fetch.ts +76 -9
  45. package/src/codex/history-job.ts +10 -0
  46. package/src/codex/history-manifest.ts +35 -2
  47. package/src/codex/history-provider.ts +196 -19
  48. package/src/codex/history-worker.ts +3 -0
  49. package/src/codex/quota-401-recovery.ts +190 -0
  50. package/src/codex/quota-recovery-timing.ts +28 -0
  51. package/src/codex/quota.ts +6 -0
  52. package/src/codex/routing.ts +68 -16
  53. package/src/codex/subagent-model-fallback.ts +4 -1
  54. package/src/config/pending-teardown-names.d.mts +8 -0
  55. package/src/config/pending-teardown-names.mjs +69 -0
  56. package/src/config/pending-teardown.ts +286 -0
  57. package/src/generated/compatibility-version.json +84 -32
  58. package/src/integrations/journal.ts +12 -1
  59. package/src/integrations/writer.ts +82 -7
  60. package/src/lib/process-control.ts +30 -5
  61. package/src/lib/state-store-registrations.ts +8 -0
  62. package/src/oauth/index.ts +220 -13
  63. package/src/oauth/store.ts +220 -18
  64. package/src/responses/spill-store.ts +20 -0
  65. package/src/responses/state.ts +288 -2
  66. package/src/server/management/integration-routes.ts +36 -5
  67. package/src/server/management-api.ts +66 -12
  68. package/src/server/responses/encrypted-payload.ts +18 -1
  69. package/src/server/stop-teardown.ts +84 -0
  70. package/src/service.ts +155 -20
  71. package/src/update/index.ts +36 -4
  72. package/src/update/proxy-liveness-probe.d.mts +6 -0
  73. package/src/update/proxy-liveness-probe.mjs +84 -0
  74. package/src/update/stop-contract.d.mts +2 -0
  75. package/src/update/stop-contract.mjs +15 -0
  76. package/src/update/stop-decision.d.mts +10 -0
  77. package/src/update/stop-decision.mjs +34 -0
  78. package/src/vision/eligibility.ts +19 -1
  79. package/src/vision/index.ts +4 -18
  80. package/gui/dist/assets/index-C14iCj_Q.js +0 -112
  81. package/gui/dist/assets/index-D7PIz7_g.css +0 -1
@@ -12,7 +12,7 @@ import { CLI_COMMANDS } from "./registry";
12
12
  import { isValidProviderName } from "../config/provider-name";
13
13
  import type { CliHead } from "./root";
14
14
  import type { ReadyArgs } from "./ready";
15
- import type { LiveProxy } from "../server/proxy-liveness";
15
+ import type { LivenessIo, LiveProxy } from "../server/proxy-liveness";
16
16
  import type { OcxConfig } from "../types";
17
17
  import { hasHelpFlag, printSubcommandUsage, printUsage } from "./help";
18
18
  import { setIntegrationEnabled, shouldSyncCodexOnStart } from "../codex/desired-state";
@@ -29,7 +29,7 @@ export interface CliDispatchDeps {
29
29
  command: string | undefined;
30
30
  head: CliHead;
31
31
  loadConfig: () => OcxConfig;
32
- findLiveProxy: () => Promise<LiveProxy | null>;
32
+ findLiveProxy: (io?: LivenessIo) => Promise<LiveProxy | null>;
33
33
  probeHostname: (hostname: string | undefined) => string;
34
34
  waitForProxy: (timeoutMs?: number) => Promise<LiveProxy | null>;
35
35
  startArgv: (port?: number) => string[];
@@ -121,14 +121,31 @@ const commandRunners: Record<string, CommandRunner> = {
121
121
  if (desired.status === "unchanged") {
122
122
  const { classifyNativeRoutedResidue } = await import("../codex/native-residue");
123
123
  if (classifyNativeRoutedResidue().kind === "clean") {
124
- const alreadyOff = "Codex integration is already OFF and native; no Codex files changed.";
124
+ // The Codex half being a no-op says nothing about the Grok half. Returning here
125
+ // without stripping the fence meant `ocx restore` could report success while Grok
126
+ // still pointed at a stopped proxy — and the deferred-teardown recovery path
127
+ // (#3008) tells operators to run exactly this command before deleting a receipt,
128
+ // so the incomplete teardown would be signed off and the obligation erased.
129
+ let grokNote = "";
130
+ let grokCode = 0;
131
+ try {
132
+ const g = stripGrokConfig();
133
+ if (g.changed) grokNote = ` ${g.message}`;
134
+ else if (!g.ok) { grokNote = ` Grok config cleanup failed: ${g.message}`; grokCode = 1; }
135
+ } catch (err) {
136
+ grokNote = ` Grok config cleanup failed: ${err instanceof Error ? err.message : String(err)}`;
137
+ grokCode = 1;
138
+ }
139
+ const alreadyOff = `Codex integration is already OFF and native; no Codex files changed.${grokNote}`;
125
140
  if (restoreJson) {
126
141
  const { skippedRestoreEnvelope } = await import("../codex/inject");
127
- console.log(JSON.stringify(skippedRestoreEnvelope(true, alreadyOff)));
128
- } else {
142
+ console.log(JSON.stringify(skippedRestoreEnvelope(grokCode === 0, alreadyOff)));
143
+ } else if (grokCode === 0) {
129
144
  console.log(alreadyOff);
145
+ } else {
146
+ console.error(alreadyOff);
130
147
  }
131
- return 0;
148
+ return grokCode;
132
149
  }
133
150
  }
134
151
  let r: { success: boolean; message: string };
@@ -137,26 +154,40 @@ const commandRunners: Record<string, CommandRunner> = {
137
154
  } catch (err) {
138
155
  r = { success: false, message: err instanceof Error ? err.message : String(err) };
139
156
  }
157
+ // Grok BEFORE either output. The JSON path used to return here, so `ocx restore --json`
158
+ // (and `ocx eject --json`, the same runner) could report success while the fence still
159
+ // pointed at the stopped proxy — and the deferred-teardown recovery on this branch
160
+ // tells operators to run exactly this before deleting a receipt (#3008).
161
+ let grokFailure: string | null = null;
162
+ let grokChangedMessage: string | null = null;
163
+ try {
164
+ const g = stripGrokConfig();
165
+ if (g.changed) grokChangedMessage = g.message;
166
+ else if (!g.ok) grokFailure = g.message;
167
+ } catch (err) {
168
+ grokFailure = err instanceof Error ? err.message : String(err);
169
+ }
140
170
  if (restoreJson) {
141
171
  // Spawned callers need the artifact-level result to distinguish a busy
142
172
  // history worker from a successful native restore. Keep stdout machine
143
- // readable; human framing remains the default command contract.
144
- console.log(JSON.stringify(r));
145
- return r.success ? 0 : 1;
173
+ // readable the Codex artifact schema is unchanged; the Grok outcome is
174
+ // folded into success/message so a caller cannot read a half teardown as done.
175
+ const message = grokFailure
176
+ ? `${r.message} Grok config cleanup failed: ${grokFailure}`
177
+ : grokChangedMessage ? `${r.message} ${grokChangedMessage}` : r.message;
178
+ console.log(JSON.stringify({ ...r, success: r.success && !grokFailure, message }));
179
+ return r.success && !grokFailure ? 0 : 1;
146
180
  }
147
181
  if (r.success) console.log(`✅ ${r.message}`);
148
182
  else {
149
183
  console.error(`⚠️ ${r.message}`);
150
184
  }
151
185
  let code = r.success ? 0 : 1;
152
- try {
153
- const g = stripGrokConfig();
154
- if (g.changed) console.log(`✅ ${g.message}`);
155
- else if (!g.ok) {
156
- console.error(`⚠️ ${g.message}`);
157
- code = 1;
158
- }
159
- } catch { /* best-effort */ }
186
+ if (grokChangedMessage) console.log(`✅ ${grokChangedMessage}`);
187
+ if (grokFailure) {
188
+ console.error(`⚠️ ${grokFailure}`);
189
+ code = 1;
190
+ }
160
191
  if (r.success) {
161
192
  console.log("Codex integration is OFF and plain `codex` now runs natively. Switch back with: ocx restore back");
162
193
  } else {
@@ -542,7 +573,12 @@ const commandRunners: Record<string, CommandRunner> = {
542
573
  health: async deps => {
543
574
  const healthArgs = deps.args.slice(1);
544
575
  const wantsHealthJson = healthArgs.includes("--json");
545
- const live = await deps.findLiveProxy();
576
+ // A proxy that has only just bound can miss a single probe while its event loop
577
+ // is still settling startup work — the same just-started race the stop paths
578
+ // already retry for (#764, SERVICE_STOP_LIVENESS). Without this, `ocx health`
579
+ // run seconds after a service restart reports a false negative on a proxy that
580
+ // is in fact serving.
581
+ const live = await deps.findLiveProxy({ attempts: 3 });
546
582
  if (wantsHealthJson) {
547
583
  console.log(JSON.stringify({ ok: !!live, pid: live?.pid ?? null, port: live?.port ?? null }));
548
584
  } else {