@bitkyc08/opencodex 2.37.0 → 2.39.0-preview.20260901
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/bin/ocx.mjs +127 -16
- package/gui/dist/assets/index-6HZDkIpX.js +112 -0
- package/gui/dist/assets/index-uvENYLin.css +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/aside.svg +3 -0
- package/gui/dist/provider-icons/baseten.svg +13 -0
- package/gui/dist/provider-icons/bizrouter.svg +41 -0
- package/gui/dist/provider-icons/cerebras.svg +26 -0
- package/gui/dist/provider-icons/deepinfra.svg +75 -0
- package/gui/dist/provider-icons/deepseek-harness.svg +3 -0
- package/gui/dist/provider-icons/digitalocean.svg +10 -0
- package/gui/dist/provider-icons/featherless.svg +4 -0
- package/gui/dist/provider-icons/gajae-code.svg +410 -0
- package/gui/dist/provider-icons/hermes-agent.svg +207 -0
- package/gui/dist/provider-icons/hyperbolic.svg +18 -0
- package/gui/dist/provider-icons/kilo.svg +13 -0
- package/gui/dist/provider-icons/litellm.svg +1 -0
- package/gui/dist/provider-icons/minimax.svg +1 -0
- package/gui/dist/provider-icons/nanogpt.svg +74 -0
- package/gui/dist/provider-icons/nebius.svg +1 -0
- package/gui/dist/provider-icons/neuralwatt.svg +27 -0
- package/gui/dist/provider-icons/nous.svg +149 -0
- package/gui/dist/provider-icons/novita.svg +32 -0
- package/gui/dist/provider-icons/oh-my-pi.svg +11 -0
- package/gui/dist/provider-icons/openclaw.svg +54 -0
- package/gui/dist/provider-icons/orcarouter.svg +175 -0
- package/gui/dist/provider-icons/parallel.svg +13 -0
- package/gui/dist/provider-icons/prime-agent.svg +21 -0
- package/gui/dist/provider-icons/sambanova.svg +276 -0
- package/gui/dist/provider-icons/scaleway.svg +11 -0
- package/gui/dist/provider-icons/siliconflow.svg +18 -0
- package/gui/dist/provider-icons/synthetic.svg +12 -0
- package/gui/dist/provider-icons/together.svg +18 -0
- package/gui/dist/provider-icons/umans.svg +30 -0
- package/gui/dist/provider-icons/venice.svg +165 -0
- package/gui/dist/provider-icons/vultr.svg +15 -0
- package/gui/dist/provider-icons/zai.svg +218 -0
- package/gui/dist/provider-icons/zcode.svg +219 -0
- package/gui/dist/provider-icons/zenmux.svg +1 -0
- package/package.json +1 -1
- package/src/adapters/cursor/live-models.ts +1 -0
- package/src/adapters/cursor/protobuf-request.ts +4 -1
- package/src/adapters/cursor/tool-definitions.ts +36 -4
- package/src/adapters/openai-responses.ts +72 -10
- package/src/bridge.ts +15 -15
- package/src/cli/capabilities.ts +14 -0
- package/src/cli/codex-cli-update.ts +96 -0
- package/src/cli/codex-shim-autorestore.ts +3 -0
- package/src/cli/dispatch.ts +54 -18
- package/src/cli/export-command.ts +18 -17
- package/src/cli/help.ts +2 -2
- package/src/cli/index.ts +423 -32
- package/src/cli/integrations.ts +24 -2
- package/src/cli/launcher-context.ts +53 -2
- package/src/cli/opencode.ts +126 -33
- package/src/cli/registry.ts +16 -10
- package/src/cli/system-command.ts +6 -1
- package/src/cli/uninstall-plan.ts +86 -0
- package/src/clients/config-export.ts +293 -28
- package/src/codex/account-store.ts +131 -12
- package/src/codex/auth-api.ts +202 -33
- package/src/codex/autostart-health.ts +3 -3
- package/src/codex/catalog/provider-fetch.ts +96 -10
- package/src/codex/catalog/sync.ts +4 -3
- package/src/codex/cli-install-provenance.ts +795 -0
- package/src/codex/convergence.ts +4 -3
- package/src/codex/credential-mutation-epoch.ts +11 -0
- package/src/codex/history-job.ts +10 -0
- package/src/codex/history-manifest.ts +35 -2
- package/src/codex/history-provider.ts +196 -19
- package/src/codex/history-worker.ts +3 -0
- package/src/codex/main-account.ts +2 -0
- package/src/codex/model-entitlements.ts +430 -27
- package/src/codex/native-profile-manager.ts +4 -0
- package/src/codex/quota-401-recovery.ts +190 -0
- package/src/codex/quota-recovery-timing.ts +28 -0
- package/src/codex/quota.ts +6 -0
- package/src/codex/reset-credit-operation-ledger.ts +1411 -0
- package/src/codex/reset-credit-recovery.ts +20 -2
- package/src/codex/routing.ts +68 -16
- package/src/codex/shim.ts +204 -18
- package/src/codex/subagent-model-fallback.ts +4 -1
- package/src/codex/user-identity.ts +2 -1
- package/src/config/paths.ts +18 -3
- package/src/config/pending-teardown-names.d.mts +8 -0
- package/src/config/pending-teardown-names.mjs +69 -0
- package/src/config/pending-teardown.ts +286 -0
- package/src/config.ts +23 -0
- package/src/generated/compatibility-version.json +155 -67
- package/src/integrations/journal.ts +12 -1
- package/src/integrations/registry.ts +112 -0
- package/src/integrations/state.ts +67 -5
- package/src/integrations/writer.ts +107 -16
- package/src/lib/bounded-subprocess.ts +36 -0
- package/src/lib/process-control.ts +30 -5
- package/src/lib/state-store-registrations.ts +8 -0
- package/src/lib/strict-semver.ts +47 -0
- package/src/lib/windows-elevation.ts +32 -1
- package/src/lib/windows-secret-acl.ts +47 -25
- package/src/lib/windows-service-mutation-lock.ts +133 -0
- package/src/lib/windows-user-principal.ts +15 -17
- package/src/oauth/index.ts +220 -13
- package/src/oauth/store.ts +220 -18
- package/src/responses/spill-store.ts +354 -29
- package/src/responses/state.ts +775 -8
- package/src/server/index.ts +4 -3
- package/src/server/lifecycle.ts +5 -1
- package/src/server/management/integration-routes.ts +36 -5
- package/src/server/management/model-rows.ts +11 -2
- package/src/server/management/provider-routes.ts +4 -0
- package/src/server/management/system-restart.ts +5 -5
- package/src/server/management-api.ts +72 -13
- package/src/server/responses/encrypted-payload.ts +18 -1
- package/src/server/startup-action-control.ts +3 -2
- package/src/server/stop-teardown.ts +84 -0
- package/src/service.ts +749 -53
- package/src/sidecar/candidates.ts +1 -1
- package/src/update/codex-cli-update-launch-policy.d.mts +18 -0
- package/src/update/codex-cli-update-launch-policy.mjs +30 -0
- package/src/update/index.ts +39 -6
- package/src/update/job.ts +10 -11
- package/src/update/proxy-liveness-probe.d.mts +6 -0
- package/src/update/proxy-liveness-probe.mjs +84 -0
- package/src/update/stop-contract.d.mts +2 -0
- package/src/update/stop-contract.mjs +15 -0
- package/src/update/stop-decision.d.mts +10 -0
- package/src/update/stop-decision.mjs +34 -0
- package/src/vision/eligibility.ts +19 -1
- package/src/vision/index.ts +4 -18
- package/gui/dist/assets/index-CowztZdo.js +0 -112
- package/gui/dist/assets/index-jqE_VOKI.css +0 -1
package/bin/ocx.mjs
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
* src/cli/index.ts — only the published npm `bin` routes through here.)
|
|
10
10
|
*/
|
|
11
11
|
import { spawn, spawnSync } from "node:child_process";
|
|
12
|
+
import { STOP_HISTORY_INCOMPLETE_EXIT_CODE } from "../src/update/stop-contract.mjs";
|
|
13
|
+
import { probeProxyLiveness } from "../src/update/proxy-liveness-probe.mjs";
|
|
14
|
+
import { decidePostStopUpdate } from "../src/update/stop-decision.mjs";
|
|
12
15
|
import { randomBytes } from "node:crypto";
|
|
13
16
|
import { createRequire } from "node:module";
|
|
14
17
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
@@ -17,12 +20,17 @@ import { dirname, join, resolve } from "node:path";
|
|
|
17
20
|
import { fileURLToPath } from "node:url";
|
|
18
21
|
import { isRealBunBinary } from "../src/lib/bun-binary-validator.mjs";
|
|
19
22
|
import { npmInvocation } from "../src/update/npm-invocation.mjs";
|
|
23
|
+
import { hasPendingTeardownIn } from "../src/config/pending-teardown-names.mjs";
|
|
20
24
|
import {
|
|
21
25
|
npmCachePreflightFailureMessage,
|
|
22
26
|
runNpmCachePreflight,
|
|
23
27
|
} from "../src/update/npm-cache-preflight.mjs";
|
|
24
28
|
import { handoffWindowsTrayForUpdate, planWindowsTrayUpdate } from "../src/update/tray-update-plan.mjs";
|
|
25
29
|
import { bootRestoreProbe, transactionalNpmUpdate } from "../src/update/transactional-install.mjs";
|
|
30
|
+
import {
|
|
31
|
+
CODEX_CLI_VERSION_MANAGER_ROOT_ENV_SLOTS,
|
|
32
|
+
isCodexCliUpdateInspectionArgv,
|
|
33
|
+
} from "../src/update/codex-cli-update-launch-policy.mjs";
|
|
26
34
|
|
|
27
35
|
const PKG = "@bitkyc08/opencodex";
|
|
28
36
|
const require = createRequire(import.meta.url);
|
|
@@ -155,10 +163,9 @@ function runNpmSelfUpdate() {
|
|
|
155
163
|
process.platform === "win32" ? trayInstallState() : { installed: false, running: false },
|
|
156
164
|
);
|
|
157
165
|
/**
|
|
158
|
-
* Refresh the existing service
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* non-admin `ocx update` does not have.
|
|
166
|
+
* Refresh the existing service in place. `service repair` discovers the installed backend;
|
|
167
|
+
* healthy Windows scheduler registrations avoid `schtasks /create`, while stale definitions
|
|
168
|
+
* may be re-registered and require elevation.
|
|
162
169
|
*/
|
|
163
170
|
function serviceRefreshArgs() {
|
|
164
171
|
return [launcher, "service", "repair"];
|
|
@@ -199,7 +206,12 @@ function runNpmSelfUpdate() {
|
|
|
199
206
|
// Capture listen target before stop clears runtime-port.json (mirrors GUI/CLI update worker).
|
|
200
207
|
// Do not treat a live runtime port of 10100 as "missing" — track whether the read succeeded.
|
|
201
208
|
let bakePort = 10100;
|
|
209
|
+
// The hostname travels with the port: a proxy bound to ::1 or a specific interface is
|
|
210
|
+
// invisible to a probe that assumes 127.0.0.1, and "no answer" would then read as
|
|
211
|
+
// "stopped" for exactly the proxy the probe exists to find.
|
|
212
|
+
let bakeHostname = "127.0.0.1";
|
|
202
213
|
let sawRuntimePort = false;
|
|
214
|
+
let sawRuntimeHostname = false;
|
|
203
215
|
try {
|
|
204
216
|
const rt = JSON.parse(readFileSync(join(configDir(), "runtime-port.json"), "utf8"));
|
|
205
217
|
if (Number.isFinite(rt?.port) && rt.port > 0 && rt.port <= 65535) {
|
|
@@ -216,16 +228,29 @@ function runNpmSelfUpdate() {
|
|
|
216
228
|
}
|
|
217
229
|
if (runtimeLive) {
|
|
218
230
|
bakePort = Math.trunc(rt.port);
|
|
231
|
+
if (typeof rt?.hostname === "string" && rt.hostname.trim() !== "") {
|
|
232
|
+
bakeHostname = rt.hostname.trim();
|
|
233
|
+
sawRuntimeHostname = true;
|
|
234
|
+
}
|
|
219
235
|
sawRuntimePort = true;
|
|
220
236
|
}
|
|
221
237
|
}
|
|
222
238
|
} catch { /* fall through to config */ }
|
|
223
|
-
|
|
239
|
+
// Port and hostname resolve INDEPENDENTLY: a legacy runtime record carries a port and no
|
|
240
|
+
// hostname, and skipping config in that case probed 127.0.0.1 for a proxy bound to ::1.
|
|
241
|
+
if (!sawRuntimePort || bakeHostname === "127.0.0.1") {
|
|
224
242
|
try {
|
|
225
243
|
const cfg = JSON.parse(readFileSync(join(configDir(), "config.json"), "utf8"));
|
|
226
|
-
if (Number.isFinite(cfg?.port) && cfg.port > 0 && cfg.port <= 65535)
|
|
244
|
+
if (!sawRuntimePort && Number.isFinite(cfg?.port) && cfg.port > 0 && cfg.port <= 65535) {
|
|
245
|
+
bakePort = Math.trunc(cfg.port);
|
|
246
|
+
}
|
|
247
|
+
if (!sawRuntimeHostname && typeof cfg?.hostname === "string" && cfg.hostname.trim() !== "") {
|
|
248
|
+
bakeHostname = cfg.hostname.trim();
|
|
249
|
+
}
|
|
227
250
|
} catch { /* keep default */ }
|
|
228
251
|
}
|
|
252
|
+
// Wildcard and bracketed-IPv6 normalization lives in probeProxyLiveness, so both lanes
|
|
253
|
+
// get it from one place.
|
|
229
254
|
|
|
230
255
|
const launcher = fileURLToPath(import.meta.url);
|
|
231
256
|
|
|
@@ -290,7 +315,8 @@ function runNpmSelfUpdate() {
|
|
|
290
315
|
}
|
|
291
316
|
}
|
|
292
317
|
if (needDirectStart) {
|
|
293
|
-
//
|
|
318
|
+
// Repair normally avoids elevation for a healthy registration, but a stale Windows
|
|
319
|
+
// scheduler definition can require it. It can also fail — or exit 0 while leaving
|
|
294
320
|
// a non-viable manager. Fall back to a direct detached proxy start so the
|
|
295
321
|
// update never leaves the user without a running proxy.
|
|
296
322
|
console.warn(
|
|
@@ -339,17 +365,47 @@ function runNpmSelfUpdate() {
|
|
|
339
365
|
}
|
|
340
366
|
}
|
|
341
367
|
|
|
342
|
-
|
|
368
|
+
// An outstanding pending-teardown receipt is a fourth reason to run the stop. After a
|
|
369
|
+
// parent crashed mid-deferral the service, pid and runtime records can all be absent
|
|
370
|
+
// while the shared client config still points at a proxy that is gone; installing over
|
|
371
|
+
// that silently skips the recovery the receipt was written to trigger (#3008). Presence
|
|
372
|
+
// is the whole test here — the launcher cannot parse it, and `ocx stop` is what decides
|
|
373
|
+
// whether the obligation is safe to finish.
|
|
374
|
+
const hasPendingTeardown = hasPendingTeardownIn(readdirSync, configDir());
|
|
375
|
+
if (serviceWasInstalled || hasRuntimeState || hasPendingTeardown) {
|
|
343
376
|
console.log("⏹ Stopping the running proxy before updating...");
|
|
344
377
|
const stopRes = spawnSync(process.execPath, [launcher, "stop"], { stdio: "inherit", windowsHide: true });
|
|
345
378
|
const stillHasRuntimeState =
|
|
346
379
|
existsSync(join(configDir(), "ocx.pid")) || existsSync(join(configDir(), "runtime-port.json"));
|
|
347
|
-
|
|
380
|
+
// A history-only failure means teardown succeeded and a backup manifest is waiting for
|
|
381
|
+
// review: the proxy is down and replacing package files is safe. Every other nonzero
|
|
382
|
+
// status is a stop that did not finish, and a signal kill (status null) says nothing
|
|
383
|
+
// about whether it did - both abort, because replacing files under a live server
|
|
384
|
+
// leaves it running mixed old and new modules (#3008).
|
|
385
|
+
// The same decision the Bun updater makes, from the same module (#3008). Absent PID and
|
|
386
|
+
// runtime files are weak evidence, so the captured endpoint is asked; "unknown" aborts
|
|
387
|
+
// because a silent listener is exactly the state where replacing files is dangerous.
|
|
388
|
+
const decision = decidePostStopUpdate({
|
|
389
|
+
status: stopRes.status,
|
|
390
|
+
hasRuntimeState: stillHasRuntimeState,
|
|
391
|
+
// Re-checked AFTER the stop: a quarantined receipt lets the stop itself succeed
|
|
392
|
+
// (there is nothing left to stop), so a pre-stop check alone let the retry install
|
|
393
|
+
// over a teardown that never ran.
|
|
394
|
+
teardownOutstanding: hasPendingTeardownIn(readdirSync, configDir()),
|
|
395
|
+
liveness: probeProxyLiveness(bakePort, bakeHostname),
|
|
396
|
+
});
|
|
397
|
+
const historyOnlyStop = decision.reason === "history-only";
|
|
398
|
+
if (!decision.proceed) {
|
|
348
399
|
if (trayBeforeUpdate.restoreOnFailure) runTrayLifecycle(launcher, "start");
|
|
349
|
-
|
|
400
|
+
if (decision.reason === "teardown-outstanding") {
|
|
401
|
+
console.error("opencodex: a shared teardown from an earlier stop is still outstanding and needs manual review; aborting the update.");
|
|
402
|
+
console.error("opencodex: confirm no proxy is running, run 'ocx restore', then remove the pending-teardown file in the opencodex home.");
|
|
403
|
+
} else console.error(decision.reason === "proxy-unknown"
|
|
404
|
+
? `opencodex: could not confirm the proxy on ${bakeHostname}:${bakePort} is stopped; aborting the update. Run 'ocx stop' and retry.`
|
|
405
|
+
: "opencodex: could not stop the running proxy; aborting the update. Run 'ocx stop' and retry.");
|
|
350
406
|
process.exit(1);
|
|
351
407
|
}
|
|
352
|
-
if (historyRestoreIncomplete()) {
|
|
408
|
+
if (historyOnlyStop || historyRestoreIncomplete()) {
|
|
353
409
|
console.warn(
|
|
354
410
|
"opencodex: WARNING — Codex resume-history metadata restore is incomplete (a backup manifest remains).\n" +
|
|
355
411
|
" The DB may be busy or the manifest/target may need review; untracked routed history is intentionally unchanged.\n" +
|
|
@@ -468,7 +524,7 @@ function fail(msg) {
|
|
|
468
524
|
process.exit(1);
|
|
469
525
|
}
|
|
470
526
|
|
|
471
|
-
function resolveBun() {
|
|
527
|
+
function resolveBun({ allowInstall = true } = {}) {
|
|
472
528
|
// Keep direct npm-launcher starts aligned with durable service/shim installs:
|
|
473
529
|
// a valid explicit runtime must win even when the bundled dependency exists.
|
|
474
530
|
const override = process.env[BUN_OVERRIDE_ENV]?.trim();
|
|
@@ -493,7 +549,7 @@ function resolveBun() {
|
|
|
493
549
|
// Lazy fallback: --ignore-scripts (or a failed postinstall) leaves the
|
|
494
550
|
// ~450-byte placeholder stub. Run the bun package's own installer once.
|
|
495
551
|
const installJs = join(bunDir, "install.js");
|
|
496
|
-
if (existsSync(installJs)) {
|
|
552
|
+
if (allowInstall && existsSync(installJs)) {
|
|
497
553
|
const r = spawnSync(process.execPath, [installJs], { stdio: "inherit" });
|
|
498
554
|
if (r.status === 0) bin = findBunBinary(bunDir);
|
|
499
555
|
}
|
|
@@ -512,6 +568,12 @@ if (updateHelpRequested) {
|
|
|
512
568
|
process.exit(0);
|
|
513
569
|
}
|
|
514
570
|
|
|
571
|
+
const codexCliUpdateInspection = isCodexCliUpdateInspectionArgv(process.argv);
|
|
572
|
+
if (codexCliUpdateInspection && typeof process.versions.bun === "string") {
|
|
573
|
+
console.error("opencodex: codex-cli-update inspection must use the published Node launcher.");
|
|
574
|
+
process.exit(1);
|
|
575
|
+
}
|
|
576
|
+
|
|
515
577
|
if (process.argv[2] === "update" && isNodeModulesInstall() && !isBunGlobalInstall()) {
|
|
516
578
|
runNpmSelfUpdate();
|
|
517
579
|
}
|
|
@@ -519,7 +581,7 @@ if (process.argv[2] === "update" && isNodeModulesInstall() && !isBunGlobalInstal
|
|
|
519
581
|
// #1849 boot probe: a prior update that lost power (or double-faulted) mid-swap leaves a
|
|
520
582
|
// backup sibling and a broken live tree. Restore before anything tries to run from the
|
|
521
583
|
// broken tree; reap stale backups once the live tree verifies healthy.
|
|
522
|
-
if (isNodeModulesInstall() && !isBunGlobalInstall()) {
|
|
584
|
+
if (!codexCliUpdateInspection && isNodeModulesInstall() && !isBunGlobalInstall()) {
|
|
523
585
|
try {
|
|
524
586
|
const probe = bootRestoreProbe(resolve(here, ".."));
|
|
525
587
|
if (probe.action === "restored") {
|
|
@@ -530,7 +592,7 @@ if (isNodeModulesInstall() && !isBunGlobalInstall()) {
|
|
|
530
592
|
} catch { /* the probe must never block launch */ }
|
|
531
593
|
}
|
|
532
594
|
|
|
533
|
-
const bunRuntime = resolveBun();
|
|
595
|
+
const bunRuntime = resolveBun({ allowInstall: !codexCliUpdateInspection });
|
|
534
596
|
const bun = bunRuntime.path;
|
|
535
597
|
|
|
536
598
|
// Run the Bun child asynchronously and FORWARD termination signals to it, then wait
|
|
@@ -554,12 +616,61 @@ const bun = bunRuntime.path;
|
|
|
554
616
|
// interpolation and provider settings legitimately read the project environment.
|
|
555
617
|
const preBunAnthropicSlots = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_BASE_URL"]
|
|
556
618
|
.filter(name => typeof process.env[name] === "string" && process.env[name] !== "");
|
|
619
|
+
// A configured CODEX_CLI_PATH may legitimately be cwd-relative (`./tools/codex`), which the
|
|
620
|
+
// ordinary runtime resolver accepts. Inspection only trusts absolute local paths, so capture
|
|
621
|
+
// the absolute form here, in the launcher, while the original cwd is still authoritative;
|
|
622
|
+
// resolving it later would silently reinterpret it against a different working directory.
|
|
623
|
+
//
|
|
624
|
+
// A bare command with no separator (`codex`) is NOT a relative path: the runtime resolver
|
|
625
|
+
// deliberately hands those to executable lookup along PATH. Rewriting it to `<cwd>/codex`
|
|
626
|
+
// would make the inspector treat it as an explicit path and stop searching PATH entirely.
|
|
627
|
+
const configuredCodexCliPath = typeof process.env.CODEX_CLI_PATH === "string" && process.env.CODEX_CLI_PATH !== ""
|
|
628
|
+
? process.env.CODEX_CLI_PATH
|
|
629
|
+
: null;
|
|
630
|
+
const preBunCodexCliPath = configuredCodexCliPath !== null
|
|
631
|
+
&& (configuredCodexCliPath.includes("/") || configuredCodexCliPath.includes("\\") || /^[A-Za-z]:/.test(configuredCodexCliPath))
|
|
632
|
+
? resolve(configuredCodexCliPath)
|
|
633
|
+
: configuredCodexCliPath;
|
|
634
|
+
const preBunPath = typeof process.env.PATH === "string" ? process.env.PATH : null;
|
|
635
|
+
const preBunPathExt = typeof process.env.PATHEXT === "string" ? process.env.PATHEXT : null;
|
|
636
|
+
const preBunCodexCliManagerRoots = Object.fromEntries(
|
|
637
|
+
CODEX_CLI_VERSION_MANAGER_ROOT_ENV_SLOTS.flatMap(name => {
|
|
638
|
+
const value = process.env[name];
|
|
639
|
+
return typeof value === "string" && value !== "" ? [[name, value]] : [];
|
|
640
|
+
}),
|
|
641
|
+
);
|
|
557
642
|
const launchProof = randomBytes(32).toString("base64url");
|
|
558
643
|
const launchContext = JSON.stringify({
|
|
559
644
|
version: 1,
|
|
560
645
|
proof: launchProof,
|
|
561
646
|
anthropicEnvSlots: preBunAnthropicSlots,
|
|
647
|
+
codexCliInspectionEnv: codexCliUpdateInspection ? {
|
|
648
|
+
codexCliPath: preBunCodexCliPath,
|
|
649
|
+
path: preBunPath,
|
|
650
|
+
pathExt: preBunPathExt,
|
|
651
|
+
managerRoots: preBunCodexCliManagerRoots,
|
|
652
|
+
configDir: configDir(),
|
|
653
|
+
} : null,
|
|
562
654
|
});
|
|
655
|
+
// The inspection snapshot above already carries PATH, PATHEXT, and the manager-root slots as
|
|
656
|
+
// proof-bound values, and `inspectCodexCliInstall` reads them from that snapshot rather than
|
|
657
|
+
// from the live environment. Inheriting them again would spend the 32,767-character Windows
|
|
658
|
+
// environment block twice, so a large-but-valid shell environment could stop the Bun child
|
|
659
|
+
// from spawning and fail the command before it reports anything. Drop the duplicates for the
|
|
660
|
+
// one-shot inspection launch only; every other launch inherits the environment unchanged.
|
|
661
|
+
// Windows environment names are case-insensitive, but this spread produces an ordinary
|
|
662
|
+
// case-sensitive object, and a real Windows environment commonly spells the variable `Path`.
|
|
663
|
+
// Deleting only the canonical upper-case spelling would silently leave that copy behind and
|
|
664
|
+
// reintroduce the duplication this block exists to prevent, so match on the lowercase form.
|
|
665
|
+
const inheritedEnv = { ...process.env };
|
|
666
|
+
if (codexCliUpdateInspection) {
|
|
667
|
+
const snapshotted = new Set(
|
|
668
|
+
["PATH", "PATHEXT", ...CODEX_CLI_VERSION_MANAGER_ROOT_ENV_SLOTS].map(name => name.toLowerCase()),
|
|
669
|
+
);
|
|
670
|
+
for (const name of Object.keys(inheritedEnv)) {
|
|
671
|
+
if (snapshotted.has(name.toLowerCase())) delete inheritedEnv[name];
|
|
672
|
+
}
|
|
673
|
+
}
|
|
563
674
|
const child = spawn(bun, [cliPath, `${NODE_LAUNCH_PROOF_PREFIX}${launchProof}`, ...process.argv.slice(2)], {
|
|
564
675
|
stdio: "inherit",
|
|
565
676
|
// A headless Windows parent (Task Scheduler, dashboard restart, shortcut) has no
|
|
@@ -567,7 +678,7 @@ const child = spawn(bun, [cliPath, `${NODE_LAUNCH_PROOF_PREFIX}${launchProof}`,
|
|
|
567
678
|
// the long-running Bun child, and closing that window kills the proxy (#1236).
|
|
568
679
|
windowsHide: true,
|
|
569
680
|
env: {
|
|
570
|
-
...
|
|
681
|
+
...inheritedEnv,
|
|
571
682
|
[NODE_LAUNCH_CONTEXT_ENV]: launchContext,
|
|
572
683
|
[BUN_RUNTIME_SOURCE_ENV]: bunRuntime.source,
|
|
573
684
|
[BUN_RUNTIME_PATH_ENV]: bunRuntime.path,
|