codexuse-cli 5.1.7 → 5.2.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.
package/README.md CHANGED
@@ -8,13 +8,10 @@ npm install -g codexuse-cli
8
8
  Commands:
9
9
  ```bash
10
10
  codexuse account-pool status [--runtime=desktop] [--state-dir=/abs/path]
11
- codexuse account-pool enable
12
- codexuse account-pool disable
13
11
  codexuse account-pool routing <least-used|round-robin>
14
12
  codexuse account-pool profiles <list|set|add|remove|reset> [names...]
15
13
  codexuse account-pool models <list|add|remove|reset> [model-ids...]
16
14
  codexuse account-pool reasoning <list|add|remove|reset> [values...]
17
- codexuse account-pool fast-mode <list|add|remove|reset> [values...]
18
15
  codexuse account-pool keys <list|create|revoke> [id]
19
16
  codexuse account-pool sessions list [--runtime=desktop] [--state-dir=/abs/path]
20
17
 
package/dist/index.js CHANGED
@@ -2027,6 +2027,11 @@ var import_node_path7 = __toESM(require("path"));
2027
2027
 
2028
2028
  // ../../packages/contracts/src/settings/types.ts
2029
2029
  var DEFAULT_ACCOUNT_POOL_EXPOSED_MODELS = [
2030
+ "gpt-5.5",
2031
+ "gpt-5.3-codex-spark",
2032
+ "gpt-5.4-mini"
2033
+ ];
2034
+ var LEGACY_ACCOUNT_POOL_EXPOSED_MODELS_DEFAULT = [
2030
2035
  "gpt-5.5",
2031
2036
  "gpt-5.4",
2032
2037
  "gpt-5.4-mini",
@@ -2034,15 +2039,27 @@ var DEFAULT_ACCOUNT_POOL_EXPOSED_MODELS = [
2034
2039
  ];
2035
2040
  var DEFAULT_ACCOUNT_POOL_EXPOSED_REASONING_EFFORTS = [
2036
2041
  "none",
2037
- "minimal",
2038
2042
  "low",
2039
2043
  "medium",
2040
2044
  "high",
2041
2045
  "xhigh"
2042
2046
  ];
2043
- var DEFAULT_ACCOUNT_POOL_EXPOSED_FAST_MODE_REASONING_EFFORTS = [
2047
+ var LEGACY_ACCOUNT_POOL_EXPOSED_REASONING_EFFORTS_DEFAULT = [
2048
+ "none",
2049
+ "minimal",
2050
+ "low",
2051
+ "medium",
2052
+ "high",
2044
2053
  "xhigh"
2045
2054
  ];
2055
+ function migrateLegacyAccountPoolExposedModelDefaults(models) {
2056
+ return models.length === LEGACY_ACCOUNT_POOL_EXPOSED_MODELS_DEFAULT.length && models.every((model, index) => model === LEGACY_ACCOUNT_POOL_EXPOSED_MODELS_DEFAULT[index]) ? [...DEFAULT_ACCOUNT_POOL_EXPOSED_MODELS] : [...models];
2057
+ }
2058
+ function migrateLegacyAccountPoolExposedReasoningDefaults(efforts) {
2059
+ return efforts.length === LEGACY_ACCOUNT_POOL_EXPOSED_REASONING_EFFORTS_DEFAULT.length && efforts.every(
2060
+ (effort, index) => effort === LEGACY_ACCOUNT_POOL_EXPOSED_REASONING_EFFORTS_DEFAULT[index]
2061
+ ) ? [...DEFAULT_ACCOUNT_POOL_EXPOSED_REASONING_EFFORTS] : [...efforts];
2062
+ }
2046
2063
 
2047
2064
  // ../../packages/runtime-app-state/src/app/state.ts
2048
2065
  var import_node_async_hooks = require("async_hooks");
@@ -3526,6 +3543,53 @@ function parseStoredTrial(raw) {
3526
3543
  );
3527
3544
  return hasValue ? trial : null;
3528
3545
  }
3546
+ var CLOUD_SYNC_RUNTIME_SETTING_KEYS = /* @__PURE__ */ new Set([
3547
+ "keepAppRunningAfterWindowClose",
3548
+ "rateLimitPercentMode",
3549
+ "officialCodexWideViewEnabled",
3550
+ "officialCodexWideViewMaxWidth",
3551
+ "officialCodexScrollRestoreEnabled",
3552
+ "officialCodexConversationTimelineEnabled",
3553
+ "officialCodexInCodexStatusEnabled",
3554
+ "officialCodexHandoffChipEnabled",
3555
+ "officialCodexAutoControlEnabled",
3556
+ "officialCodexRelayMode",
3557
+ "officialCodexRelayProfileId",
3558
+ "officialCodexModelWhitelistUnlockEnabled",
3559
+ "officialCodexPluginMarketplaceUnlockEnabled",
3560
+ "officialCodexForcePluginInstallEnabled",
3561
+ "accountPoolEnabled",
3562
+ "accountPoolRoutingStrategy",
3563
+ "accountPoolProfilePool",
3564
+ "accountPoolExposedModels",
3565
+ "accountPoolExposedReasoningEfforts"
3566
+ ]);
3567
+ function cloneJsonValue(value) {
3568
+ if (value === void 0) {
3569
+ return void 0;
3570
+ }
3571
+ try {
3572
+ return JSON.parse(JSON.stringify(value));
3573
+ } catch {
3574
+ return void 0;
3575
+ }
3576
+ }
3577
+ function pickCloudSyncRuntimeSettings(raw) {
3578
+ if (!isRecord3(raw)) {
3579
+ return void 0;
3580
+ }
3581
+ const picked = {};
3582
+ for (const key of CLOUD_SYNC_RUNTIME_SETTING_KEYS) {
3583
+ if (!(key in raw)) {
3584
+ continue;
3585
+ }
3586
+ const value = cloneJsonValue(raw[key]);
3587
+ if (value !== void 0) {
3588
+ picked[key] = value;
3589
+ }
3590
+ }
3591
+ return Object.keys(picked).length > 0 ? picked : void 0;
3592
+ }
3529
3593
  async function getStoredTrial() {
3530
3594
  const state = await getAppState();
3531
3595
  return parseStoredTrial(state.trial);
@@ -3599,7 +3663,7 @@ async function readCodexSettingsJsonRaw() {
3599
3663
  subagentSystemNotificationsEnabled: state.preferences.subagentSystemNotificationsEnabled,
3600
3664
  folderHistory: state.preferences.folderHistory,
3601
3665
  pinnedPaths: state.preferences.pinnedPaths,
3602
- sync: state.sync
3666
+ runtimeSettings: pickCloudSyncRuntimeSettings(state.runtimeSettings) ?? {}
3603
3667
  };
3604
3668
  }
3605
3669
  async function writeCodexSettingsJsonRaw(payload) {
@@ -3608,6 +3672,7 @@ async function writeCodexSettingsJsonRaw(payload) {
3608
3672
  }
3609
3673
  const autoRoll = parseAutoRoll(payload.autoRoll ?? payload.auto_roll);
3610
3674
  const license = parseStoredLicense(payload.license);
3675
+ const runtimeSettings = pickCloudSyncRuntimeSettings(payload.runtimeSettings);
3611
3676
  await patchAppState({
3612
3677
  app: {
3613
3678
  lastProfileName: asString2(payload.lastProfileName ?? payload.last_profile_name),
@@ -3642,7 +3707,7 @@ async function writeCodexSettingsJsonRaw(payload) {
3642
3707
  folderHistory: Array.isArray(payload.folderHistory) ? payload.folderHistory : void 0,
3643
3708
  pinnedPaths: Array.isArray(payload.pinnedPaths) ? payload.pinnedPaths : void 0
3644
3709
  },
3645
- sync: isRecord3(payload.sync) ? payload.sync : void 0
3710
+ runtimeSettings
3646
3711
  });
3647
3712
  }
3648
3713
 
@@ -7759,8 +7824,6 @@ Usage:
7759
7824
 
7760
7825
  codexuse account-pool status [--runtime=desktop] [--state-dir=/abs/path]
7761
7826
  codexuse account-pool quickstart
7762
- codexuse account-pool enable
7763
- codexuse account-pool disable
7764
7827
  codexuse account-pool routing <least-used|round-robin>
7765
7828
  codexuse account-pool profiles list
7766
7829
  codexuse account-pool profiles set <name> [more...]
@@ -7945,7 +8008,7 @@ function normalizeAccountPoolExposedModels(value, fallbackToDefault) {
7945
8008
  result.push(normalized);
7946
8009
  }
7947
8010
  if (result.length > 0) {
7948
- return result;
8011
+ return migrateLegacyAccountPoolExposedModelDefaults(result);
7949
8012
  }
7950
8013
  return fallbackToDefault ? [...DEFAULT_ACCOUNT_POOL_EXPOSED_MODELS] : [];
7951
8014
  }
@@ -7962,7 +8025,7 @@ function normalizeAccountPoolReasoningEfforts(value, fallback) {
7962
8025
  result.push(normalized);
7963
8026
  }
7964
8027
  if (result.length > 0 || Array.isArray(value)) {
7965
- return result;
8028
+ return migrateLegacyAccountPoolExposedReasoningDefaults(result);
7966
8029
  }
7967
8030
  return fallback ? [...fallback] : [];
7968
8031
  }
@@ -7979,10 +8042,7 @@ function normalizeAccountPoolSettings(settings) {
7979
8042
  settings.accountPoolExposedReasoningEfforts,
7980
8043
  DEFAULT_ACCOUNT_POOL_EXPOSED_REASONING_EFFORTS
7981
8044
  ),
7982
- accountPoolExposedFastModeReasoningEfforts: normalizeAccountPoolReasoningEfforts(
7983
- settings.accountPoolExposedFastModeReasoningEfforts,
7984
- DEFAULT_ACCOUNT_POOL_EXPOSED_FAST_MODE_REASONING_EFFORTS
7985
- )
8045
+ accountPoolExposedFastModeReasoningEfforts: []
7986
8046
  };
7987
8047
  }
7988
8048
  function applyAccountPoolSettings(settings, nextAccountPoolSettings) {
@@ -8003,8 +8063,6 @@ function printAccountPoolHelp(version) {
8003
8063
  Usage:
8004
8064
  codexuse account-pool status [--runtime=desktop] [--state-dir=/abs/path]
8005
8065
  codexuse account-pool quickstart [--runtime=desktop] [--state-dir=/abs/path]
8006
- codexuse account-pool enable
8007
- codexuse account-pool disable
8008
8066
  codexuse account-pool routing <least-used|round-robin>
8009
8067
 
8010
8068
  codexuse account-pool profiles list
@@ -8023,11 +8081,6 @@ Usage:
8023
8081
  codexuse account-pool reasoning remove <effort> [more...]
8024
8082
  codexuse account-pool reasoning reset
8025
8083
 
8026
- codexuse account-pool fast-mode list
8027
- codexuse account-pool fast-mode add <effort> [more...]
8028
- codexuse account-pool fast-mode remove <effort> [more...]
8029
- codexuse account-pool fast-mode reset
8030
-
8031
8084
  codexuse account-pool keys list [--runtime=desktop] [--state-dir=/abs/path]
8032
8085
  codexuse account-pool keys create [--runtime=desktop] [--state-dir=/abs/path]
8033
8086
  codexuse account-pool keys revoke <id> [--runtime=desktop] [--state-dir=/abs/path]
@@ -8056,6 +8109,7 @@ function normalizeApiKeyRecord(id, value) {
8056
8109
  id,
8057
8110
  tokenHash,
8058
8111
  tokenPreview,
8112
+ plaintextToken: asString4(record.plaintextToken),
8059
8113
  createdAt,
8060
8114
  lastUsedAt: normalizeIsoString(record.lastUsedAt),
8061
8115
  revokedAt: normalizeIsoString(record.revokedAt)
@@ -8232,6 +8286,7 @@ function accountPoolApiKeyView(record) {
8232
8286
  return {
8233
8287
  id: record.id,
8234
8288
  tokenPreview: record.tokenPreview,
8289
+ plaintextToken: record.plaintextToken,
8235
8290
  createdAt: record.createdAt,
8236
8291
  lastUsedAt: record.lastUsedAt,
8237
8292
  revokedAt: record.revokedAt
@@ -8251,6 +8306,7 @@ async function createApiKey(stateDir) {
8251
8306
  id: (0, import_node_crypto7.randomUUID)(),
8252
8307
  tokenHash: hashToken(plaintextToken),
8253
8308
  tokenPreview: `${plaintextToken.slice(0, 8)}...${plaintextToken.slice(-6)}`,
8309
+ plaintextToken,
8254
8310
  createdAt: now,
8255
8311
  lastUsedAt: null,
8256
8312
  revokedAt: null
@@ -8341,7 +8397,7 @@ async function readAccountPoolRuntimeSummary(input = {}) {
8341
8397
  runtime,
8342
8398
  stateDir,
8343
8399
  baseUrl: resolveBaseUrlFromPort(runtime, input.port ?? null),
8344
- enabled: normalized.accountPoolEnabled,
8400
+ enabled: true,
8345
8401
  hasAccountPoolAccess: license?.capabilities.accountPool === true,
8346
8402
  routingStrategy: normalized.accountPoolRoutingStrategy,
8347
8403
  activeApiKeyCount: apiKeys.length,
@@ -8373,10 +8429,7 @@ async function updateSettings(transform) {
8373
8429
  nextSettings.accountPoolExposedReasoningEfforts,
8374
8430
  null
8375
8431
  ),
8376
- accountPoolExposedFastModeReasoningEfforts: normalizeAccountPoolReasoningEfforts(
8377
- nextSettings.accountPoolExposedFastModeReasoningEfforts,
8378
- null
8379
- )
8432
+ accountPoolExposedFastModeReasoningEfforts: []
8380
8433
  };
8381
8434
  await writeAppSettings(applyAccountPoolSettings(raw, sanitizedSettings));
8382
8435
  return {
@@ -8444,11 +8497,11 @@ async function handleStatus(flags) {
8444
8497
  (profileName) => !profiles.some((profile) => profile.name === profileName)
8445
8498
  );
8446
8499
  console.log(`License: ${license ? `${license.tier} (${license.state})` : "unknown"}`);
8447
- console.log(`Enabled: ${normalized.accountPoolEnabled ? "yes" : "no"}`);
8500
+ console.log("Enabled: yes");
8448
8501
  console.log(`Runtime: ${runtime}`);
8449
8502
  console.log(`State dir: ${stateDir}`);
8450
8503
  console.log(`Routing: ${formatRoutingStrategy(normalized.accountPoolRoutingStrategy)}`);
8451
- console.log(`Public API ready: ${normalized.accountPoolEnabled && license?.capabilities.accountPool === true && apiKeys.length > 0 ? "yes" : "no"}`);
8504
+ console.log(`Public API ready: ${license?.capabilities.accountPool === true && apiKeys.length > 0 ? "yes" : "no"}`);
8452
8505
  console.log(`API keys: ${apiKeys.length}`);
8453
8506
  console.log(`Sessions: ${sessions.length}`);
8454
8507
  console.log(`Selection mode: ${explicitSelection.length > 0 ? "explicit" : "all saved profiles"}`);
@@ -8463,25 +8516,16 @@ async function handleStatus(flags) {
8463
8516
  }
8464
8517
  printStringList("Published models", normalized.accountPoolExposedModels);
8465
8518
  printStringList("Reasoning aliases", normalized.accountPoolExposedReasoningEfforts);
8466
- printStringList("Fast-mode aliases", normalized.accountPoolExposedFastModeReasoningEfforts);
8467
- if (normalized.accountPoolEnabled && license?.capabilities.accountPool !== true) {
8519
+ if (license?.capabilities.accountPool !== true) {
8468
8520
  console.log(ACCOUNT_POOL_PRO_REQUIRED_MESSAGE);
8469
8521
  }
8470
8522
  }
8471
8523
  async function handleEnable() {
8472
8524
  await requireProAccess();
8473
- const result = await updateSettings((current) => ({
8474
- ...current,
8475
- accountPoolEnabled: true
8476
- }));
8477
- console.log(result.settings.accountPoolEnabled ? "Accounts Pool enabled." : "Accounts Pool is disabled.");
8525
+ console.log("Accounts Pool is always on while CodexUse is running.");
8478
8526
  }
8479
8527
  async function handleDisable() {
8480
- const result = await updateSettings((current) => ({
8481
- ...current,
8482
- accountPoolEnabled: false
8483
- }));
8484
- console.log(result.settings.accountPoolEnabled ? "Accounts Pool is enabled." : "Accounts Pool disabled.");
8528
+ console.log("Accounts Pool is always on while CodexUse is running.");
8485
8529
  }
8486
8530
  async function handleRouting(params) {
8487
8531
  const value = parseRoutingStrategy(params[1]);
@@ -8673,15 +8717,14 @@ async function handleQuickstart(flags) {
8673
8717
  console.log(`API keys: ${summary.activeApiKeyCount}`);
8674
8718
  console.log(`Base URL: ${baseUrl}`);
8675
8719
  console.log("");
8676
- console.log("1. Enable pool:");
8677
- console.log(" codexuse account-pool enable");
8678
- console.log("2. Create key:");
8720
+ console.log("1. Create key:");
8679
8721
  console.log(` codexuse account-pool keys create --runtime=${summary.runtime}`);
8680
- console.log("3. Use OpenAI-compatible settings:");
8722
+ console.log("2. Use OpenAI-compatible settings:");
8681
8723
  console.log(` Base URL: ${baseUrl}/v1`);
8682
8724
  console.log(" API key: cux_pool_...");
8683
- console.log("4. Verify:");
8725
+ console.log("3. Verify:");
8684
8726
  console.log(` curl ${baseUrl}/v1/models -H 'Authorization: Bearer cux_pool_...'`);
8727
+ console.log(` curl ${baseUrl}/v1/chat/completions -H 'Authorization: Bearer cux_pool_...'`);
8685
8728
  }
8686
8729
  async function handleAccountPoolCommand(args, version) {
8687
8730
  const flags = args.filter((arg) => arg.startsWith("-"));
@@ -8730,16 +8773,6 @@ async function handleAccountPoolCommand(args, version) {
8730
8773
  normalizeValue: (value) => normalizeReasoningEffort(value)
8731
8774
  });
8732
8775
  return;
8733
- case "fast-mode":
8734
- await handleArraySetting({
8735
- label: "Fast-mode aliases",
8736
- actionName: "fast-mode",
8737
- params,
8738
- key: "accountPoolExposedFastModeReasoningEfforts",
8739
- defaultValues: DEFAULT_ACCOUNT_POOL_EXPOSED_FAST_MODE_REASONING_EFFORTS,
8740
- normalizeValue: (value) => normalizeReasoningEffort(value)
8741
- });
8742
- return;
8743
8776
  case "keys":
8744
8777
  await handleKeys(params, flags);
8745
8778
  return;
@@ -9539,8 +9572,10 @@ async function findOfficialCodexThreadRecord(profileHome, threadId) {
9539
9572
 
9540
9573
  // ../../packages/runtime-codex/src/codex/officialAppRestart.ts
9541
9574
  var COMMAND_TIMEOUT_MS = 3e3;
9575
+ var EXIT_WAIT_MS = 1e4;
9542
9576
  var LAUNCH_WAIT_MS = 15e3;
9543
9577
  var POLL_INTERVAL_MS = 250;
9578
+ var PROCESS_EXIT_GRACE_MS = 15e3;
9544
9579
  var APP_DISCOVERY_CACHE_TTL_MS = 6e4;
9545
9580
  var APP_DISCOVERY_MISS_CACHE_TTL_MS = 5e3;
9546
9581
  var OFFICIAL_CODEX_ACTIVITY_LIMIT = 50;
@@ -9551,6 +9586,8 @@ var CODEX_BRIDGE_LAUNCH_WAIT_MS = 3e4;
9551
9586
  var CODEXUSE_BRIDGE_BINDING_NAME = "__codexuseBridgeBinding";
9552
9587
  var CODEXUSE_BRIDGE_INSTALL_TTL_MS = 5e3;
9553
9588
  var CODEXUSE_BRIDGE_VERSION = "0.2.0";
9589
+ var CODEXUSE_STALE_LAUNCH_GRACE_MS = 45e3;
9590
+ var CODEXUSE_STALE_BRIDGE_MISS_TTL_MS = 2 * 6e4;
9554
9591
  var officialCodexBridgeActionHandler = null;
9555
9592
  var bridgeActionListeners = /* @__PURE__ */ new Map();
9556
9593
  var handledBridgeActionIds = [];
@@ -9609,6 +9646,7 @@ function sanitizeBridgeActionRoute(value) {
9609
9646
  var profileActionLock = Promise.resolve();
9610
9647
  var appDiscoveryCache = null;
9611
9648
  var bridgeInstallCache = /* @__PURE__ */ new Map();
9649
+ var staleOfficialCodexBridgeMissesByPid = /* @__PURE__ */ new Map();
9612
9650
  function hashProfileKey(profileKey) {
9613
9651
  if (!profileKey) {
9614
9652
  return null;
@@ -14159,6 +14197,26 @@ async function describeUnmanagedProfileHint(appServerPid) {
14159
14197
  }
14160
14198
  return {};
14161
14199
  }
14200
+ function getDescendantPids(rootPid, rows) {
14201
+ const descendants = [];
14202
+ const queue = [rootPid];
14203
+ const seen = /* @__PURE__ */ new Set();
14204
+ while (queue.length > 0) {
14205
+ const current = queue.shift();
14206
+ if (seen.has(current)) {
14207
+ continue;
14208
+ }
14209
+ seen.add(current);
14210
+ for (const row of rows) {
14211
+ if (row.ppid !== current || seen.has(row.pid)) {
14212
+ continue;
14213
+ }
14214
+ descendants.push(row.pid);
14215
+ queue.push(row.pid);
14216
+ }
14217
+ }
14218
+ return descendants;
14219
+ }
14162
14220
  async function waitForNewMainPid(candidate, previousPids) {
14163
14221
  const deadline = Date.now() + LAUNCH_WAIT_MS;
14164
14222
  while (Date.now() < deadline) {
@@ -14186,6 +14244,110 @@ async function waitForAppServerPid(mainPid, profileHome) {
14186
14244
  }
14187
14245
  return null;
14188
14246
  }
14247
+ async function waitForPidsExit(pids, timeoutMs) {
14248
+ const remaining = new Set(pids);
14249
+ if (remaining.size === 0) {
14250
+ return [];
14251
+ }
14252
+ const deadline = Date.now() + timeoutMs;
14253
+ while (Date.now() < deadline) {
14254
+ const rows = await readProcessRows();
14255
+ for (const pid of Array.from(remaining)) {
14256
+ if (!rows.some((row) => row.pid === pid)) {
14257
+ remaining.delete(pid);
14258
+ }
14259
+ }
14260
+ if (remaining.size === 0) {
14261
+ return [];
14262
+ }
14263
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
14264
+ }
14265
+ return Array.from(remaining);
14266
+ }
14267
+ async function stopProcessTree(rootPid, rows) {
14268
+ const tree = [rootPid, ...getDescendantPids(rootPid, rows)].filter((pid, index, all) => all.indexOf(pid) === index).sort((a, b) => b - a);
14269
+ await signalPids(tree, "SIGTERM");
14270
+ let remaining = await waitForPidsExit(tree, PROCESS_EXIT_GRACE_MS);
14271
+ if (remaining.length > 0) {
14272
+ await signalPids(remaining.sort((a, b) => b - a), "SIGKILL");
14273
+ remaining = await waitForPidsExit(remaining, EXIT_WAIT_MS);
14274
+ }
14275
+ return remaining;
14276
+ }
14277
+ async function stopUnverifiedLaunch(rootPid) {
14278
+ try {
14279
+ await stopProcessTree(rootPid, await readProcessRows());
14280
+ } catch {
14281
+ }
14282
+ }
14283
+ async function isCodexUseLaunchedProcess(pid) {
14284
+ const result = await runCommand2(
14285
+ "/bin/ps",
14286
+ ["eww", "-p", String(pid), "-o", "command="],
14287
+ 2e3
14288
+ );
14289
+ return result.code === 0 && result.stdout.includes("CODEX_TELEMETRY_LABEL=codexuse-profile-");
14290
+ }
14291
+ async function hasRecoverableOfficialCodexBridge(cdpPort) {
14292
+ try {
14293
+ const target = pickCodexCdpTarget(await readCdpTargets(cdpPort), {
14294
+ allowAnyPage: true
14295
+ });
14296
+ if (!target?.webSocketDebuggerUrl) {
14297
+ return false;
14298
+ }
14299
+ await ensureOfficialCodexBridgeInstalled(target.webSocketDebuggerUrl, false);
14300
+ const health = normalizeBridgeHealth(
14301
+ await evaluateCdpExpression(
14302
+ target.webSocketDebuggerUrl,
14303
+ createBridgeHealthExpression()
14304
+ )
14305
+ );
14306
+ return health.ok;
14307
+ } catch {
14308
+ return false;
14309
+ }
14310
+ }
14311
+ async function reapStaleOfficialCodexManagedLaunchRows(candidate, rows) {
14312
+ const now = Date.now();
14313
+ const reaped = [];
14314
+ let currentRows = rows;
14315
+ const livePids = new Set(rows.map((row) => row.pid));
14316
+ for (const pid of staleOfficialCodexBridgeMissesByPid.keys()) {
14317
+ if (!livePids.has(pid)) {
14318
+ staleOfficialCodexBridgeMissesByPid.delete(pid);
14319
+ }
14320
+ }
14321
+ for (const row of rows) {
14322
+ const cdpPort = parseRemoteDebuggingPort(row.args);
14323
+ if (!isMainProcessRow(row, candidate) || cdpPort === null || row.startedAt === null || now - row.startedAt < CODEXUSE_STALE_LAUNCH_GRACE_MS || !await isCodexUseLaunchedProcess(row.pid)) {
14324
+ continue;
14325
+ }
14326
+ const appServerPid = findAppServerPid(currentRows, row.pid);
14327
+ if (appServerPid !== null) {
14328
+ if (await hasRecoverableOfficialCodexBridge(cdpPort)) {
14329
+ staleOfficialCodexBridgeMissesByPid.delete(row.pid);
14330
+ continue;
14331
+ }
14332
+ const previousMissAt = staleOfficialCodexBridgeMissesByPid.get(row.pid);
14333
+ staleOfficialCodexBridgeMissesByPid.set(row.pid, now);
14334
+ if (previousMissAt === void 0 || now - previousMissAt > CODEXUSE_STALE_BRIDGE_MISS_TTL_MS) {
14335
+ continue;
14336
+ }
14337
+ }
14338
+ await stopProcessTree(row.pid, currentRows);
14339
+ currentRows = await readProcessRows();
14340
+ if (!currentRows.some((entry) => entry.pid === row.pid)) {
14341
+ staleOfficialCodexBridgeMissesByPid.delete(row.pid);
14342
+ reaped.push(row.pid);
14343
+ if (sharedHomeCdpWindow?.pid === row.pid) {
14344
+ sharedHomeCdpWindow = null;
14345
+ }
14346
+ }
14347
+ break;
14348
+ }
14349
+ return reaped;
14350
+ }
14189
14351
  async function focusOfficialCodexApp(candidate) {
14190
14352
  const result = await runCommand2("/usr/bin/open", [candidate.appPath], 5e3);
14191
14353
  return result.code === 0;
@@ -14488,7 +14650,19 @@ async function resolveCodexAppTarget() {
14488
14650
  const mainPids = getRunningCodexMainPidsFromRows(fallback, rows);
14489
14651
  return { candidate: fallback, runningPids, mainPids };
14490
14652
  }
14653
+ async function signalPids(pids, signal) {
14654
+ const signaled = [];
14655
+ for (const pid of pids) {
14656
+ try {
14657
+ process.kill(pid, signal);
14658
+ signaled.push(pid);
14659
+ } catch {
14660
+ }
14661
+ }
14662
+ return signaled;
14663
+ }
14491
14664
  var SHARED_CODEX_HOME = import_node_path10.default.join((0, import_node_os3.homedir)(), ".codex");
14665
+ var sharedHomeCdpWindow = null;
14492
14666
  function toIso(value) {
14493
14667
  return typeof value === "number" && Number.isFinite(value) ? new Date(value).toISOString() : null;
14494
14668
  }
@@ -14560,7 +14734,13 @@ async function getOfficialCodexProfileInstances(options = {}) {
14560
14734
  unmanaged: []
14561
14735
  };
14562
14736
  }
14563
- const [state, rows] = await Promise.all([getAppState(), readProcessRows()]);
14737
+ const [state, initialRows] = await Promise.all([getAppState(), readProcessRows()]);
14738
+ let rows = initialRows;
14739
+ let visibleMainPids = mainPids;
14740
+ if ((await reapStaleOfficialCodexManagedLaunchRows(candidate, rows)).length > 0) {
14741
+ rows = await readProcessRows();
14742
+ visibleMainPids = rows.filter((row) => isMainProcessRow(row, candidate)).map((row) => row.pid);
14743
+ }
14564
14744
  const allowedProfileNames = options.profileNames ? new Set(options.profileNames.map((name) => name.trim()).filter(Boolean)) : null;
14565
14745
  const managed = [];
14566
14746
  const managedPids = /* @__PURE__ */ new Set();
@@ -14622,7 +14802,7 @@ async function getOfficialCodexProfileInstances(options = {}) {
14622
14802
  }
14623
14803
  managed.sort((a, b) => a.profileName.localeCompare(b.profileName));
14624
14804
  const unmanaged = [];
14625
- const unmanagedPids = mainPids.filter((entry) => !managedPids.has(entry));
14805
+ const unmanagedPids = visibleMainPids.filter((entry) => !managedPids.has(entry));
14626
14806
  const allowedFallbackProfileName = allowedProfileNames?.size === 1 ? Array.from(allowedProfileNames)[0] : null;
14627
14807
  for (const pid of unmanagedPids) {
14628
14808
  const mainRow = rows.find((row) => row.pid === pid) ?? null;
@@ -14711,6 +14891,14 @@ async function launchOfficialCodexProfileInstanceOnce(options) {
14711
14891
  reason: "official-codex-app-not-found"
14712
14892
  };
14713
14893
  }
14894
+ let launchBaselineMainPids = mainPids;
14895
+ const staleLaunchPids = await reapStaleOfficialCodexManagedLaunchRows(
14896
+ candidate,
14897
+ await readProcessRows()
14898
+ );
14899
+ if (staleLaunchPids.length > 0) {
14900
+ launchBaselineMainPids = (await readProcessRows()).filter((row) => isMainProcessRow(row, candidate)).map((row) => row.pid);
14901
+ }
14714
14902
  const existing = await readManagedInstance(options.profileName);
14715
14903
  const desiredQolSettings = resolveDesiredQolSettings({
14716
14904
  requested: options.desiredQolSettings,
@@ -14795,7 +14983,7 @@ async function launchOfficialCodexProfileInstanceOnce(options) {
14795
14983
  options.profileHome,
14796
14984
  options.profileName,
14797
14985
  cdpPort,
14798
- new Set(mainPids)
14986
+ new Set(launchBaselineMainPids)
14799
14987
  );
14800
14988
  if (!launch.opened) {
14801
14989
  const reason = launch.reason ?? "open-failed";
@@ -14854,6 +15042,7 @@ async function launchOfficialCodexProfileInstanceOnce(options) {
14854
15042
  options.profileHome
14855
15043
  );
14856
15044
  if (appServerPid === null) {
15045
+ await stopUnverifiedLaunch(launchedPid);
14857
15046
  const failed = {
14858
15047
  profileName: options.profileName,
14859
15048
  profileKey: options.profileKey,
@@ -16107,6 +16296,24 @@ function buildSyncUrl(pathname) {
16107
16296
  const normalizedPath = pathname.startsWith("/") ? pathname : `/${pathname}`;
16108
16297
  return `${baseUrl}${normalizedPath}`;
16109
16298
  }
16299
+ function formatErrorResponse(raw, status) {
16300
+ const trimmed = raw.trim();
16301
+ if (trimmed) {
16302
+ try {
16303
+ const parsed = JSON.parse(trimmed);
16304
+ if (isRecord6(parsed)) {
16305
+ const message = parsed.error ?? parsed.message;
16306
+ if (typeof message === "string" && message.trim().length > 0) {
16307
+ return message.trim();
16308
+ }
16309
+ }
16310
+ } catch {
16311
+ return trimmed;
16312
+ }
16313
+ return trimmed;
16314
+ }
16315
+ return `Cloud sync request failed (${status}).`;
16316
+ }
16110
16317
  function normalizeSnapshotKind(value) {
16111
16318
  if (value === "encrypted" || value === "legacy-plaintext") {
16112
16319
  return value;
@@ -16202,7 +16409,7 @@ async function requestJson(method, pathname, access, body, rawBody) {
16202
16409
  if (!response.ok) {
16203
16410
  const message = await response.text().catch(() => "");
16204
16411
  throw new CloudSyncClientError(
16205
- message || `Cloud sync request failed (${response.status}).`,
16412
+ formatErrorResponse(message, response.status),
16206
16413
  response.status
16207
16414
  );
16208
16415
  }
@@ -17752,13 +17959,12 @@ async function pushCloudSync(options = {}) {
17752
17959
  serializedSnapshot
17753
17960
  });
17754
17961
  const remoteKind = getSnapshotKind(remote.snapshot);
17755
- await writeState({
17756
- lastPushAt: (/* @__PURE__ */ new Date()).toISOString(),
17757
- remoteUpdatedAt: remote.snapshot.updatedAt,
17758
- remoteKind,
17759
- lastError: void 0
17760
- });
17761
17962
  if (remote.status === "stale") {
17963
+ await writeState({
17964
+ remoteUpdatedAt: remote.snapshot.updatedAt,
17965
+ remoteKind,
17966
+ lastError: void 0
17967
+ });
17762
17968
  return {
17763
17969
  mode: "push",
17764
17970
  status: "stale",
@@ -17768,6 +17974,12 @@ async function pushCloudSync(options = {}) {
17768
17974
  };
17769
17975
  }
17770
17976
  await rememberPassphraseIfRequested(eligibility.access.syncKey, options, passphrase);
17977
+ await writeState({
17978
+ lastPushAt: (/* @__PURE__ */ new Date()).toISOString(),
17979
+ remoteUpdatedAt: remote.snapshot.updatedAt,
17980
+ remoteKind,
17981
+ lastError: void 0
17982
+ });
17771
17983
  return {
17772
17984
  mode: "push",
17773
17985
  status: "applied",
@@ -17937,7 +18149,7 @@ async function ensureCliStorageReady() {
17937
18149
  }
17938
18150
 
17939
18151
  // src/app/main.ts
17940
- var VERSION = true ? "5.1.7" : "0.0.0";
18152
+ var VERSION = true ? "5.2.0" : "0.0.0";
17941
18153
  async function runCli() {
17942
18154
  const args = process.argv.slice(2);
17943
18155
  if (args.length === 0) {