codexuse-cli 5.1.1 → 5.1.6

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/dist/index.js CHANGED
@@ -4327,9 +4327,19 @@ async function requestGumroadVerify(licenseKey, mode) {
4327
4327
  clearTimeout(timeout);
4328
4328
  }
4329
4329
  }
4330
- function normalizeVerificationResult(response) {
4330
+ function isExplicitRevocationMessage(message) {
4331
+ if (!message) {
4332
+ return false;
4333
+ }
4334
+ const normalized = message.toLowerCase();
4335
+ return normalized.includes("revoked") || normalized.includes("refunded") || normalized.includes("chargeback") || normalized.includes("disabled") || normalized.includes("subscription") || normalized.includes("no longer active");
4336
+ }
4337
+ function normalizeVerificationResult(response, mode) {
4331
4338
  if (!response.success) {
4332
4339
  const message = response.message ?? "License key is invalid.";
4340
+ if (mode === "refresh" && !isExplicitRevocationMessage(message)) {
4341
+ throw new LicenseError(message, "network");
4342
+ }
4333
4343
  throw new LicenseError(message, "invalid");
4334
4344
  }
4335
4345
  if (!response.purchase) {
@@ -4502,7 +4512,7 @@ var LicenseService = class {
4502
4512
  try {
4503
4513
  const result = await requestGumroadVerify(workingStored.licenseKey, "refresh");
4504
4514
  ensureWithinUseLimit(result);
4505
- const normalized = normalizeVerificationResult(result);
4515
+ const normalized = normalizeVerificationResult(result, "refresh");
4506
4516
  const updated = {
4507
4517
  licenseKey: workingStored.licenseKey,
4508
4518
  purchaseEmail: normalized.email,
@@ -4561,7 +4571,7 @@ var LicenseService = class {
4561
4571
  const digest = import_node_crypto5.default.createHash("sha256").update(trimmed).digest("hex");
4562
4572
  const result = await requestGumroadVerify(trimmed, "activation");
4563
4573
  ensureWithinUseLimit(result);
4564
- const normalized = normalizeVerificationResult(result);
4574
+ const normalized = normalizeVerificationResult(result, "activation");
4565
4575
  const stored = {
4566
4576
  licenseKey: trimmed,
4567
4577
  purchaseEmail: normalized.email,
@@ -4625,7 +4635,7 @@ var import_node_crypto6 = require("crypto");
4625
4635
  var import_fs = require("fs");
4626
4636
  var import_path = __toESM(require("path"), 1);
4627
4637
  var import_path2 = require("path");
4628
- var import_toml2 = __toESM(require_toml(), 1);
4638
+ var import_toml = __toESM(require_toml(), 1);
4629
4639
 
4630
4640
  // ../../packages/contracts/src/profiles/identity.ts
4631
4641
  function normalizeValue(value) {
@@ -4670,6 +4680,10 @@ function resolveProfileIdentityKey(profile) {
4670
4680
  return profileName ? `profile:${profileName}` : null;
4671
4681
  }
4672
4682
  function resolveProfileIdentityKeyFromProfile(profile) {
4683
+ const rateLimitKey = normalizeValue(profile.rateLimitKey);
4684
+ if (rateLimitKey) {
4685
+ return rateLimitKey;
4686
+ }
4673
4687
  return resolveProfileIdentityKey(profile) ?? `profile:${profile.name}`;
4674
4688
  }
4675
4689
 
@@ -4679,7 +4693,6 @@ var import_node_readline = __toESM(require("readline"), 1);
4679
4693
  var import_node_fs3 = require("fs");
4680
4694
  var import_node_os2 = __toESM(require("os"), 1);
4681
4695
  var import_node_path5 = __toESM(require("path"), 1);
4682
- var import_toml = __toESM(require_toml(), 1);
4683
4696
 
4684
4697
  // ../../packages/runtime-codex/src/codex/cli.ts
4685
4698
  var import_node_fs2 = require("fs");
@@ -4873,6 +4886,17 @@ function buildCodexCommand(binaryPath, args, env) {
4873
4886
  };
4874
4887
  }
4875
4888
 
4889
+ // ../../packages/runtime-codex/src/cli/env.ts
4890
+ function buildCodexChildEnv(overrides = {}) {
4891
+ const env = { ...process.env };
4892
+ for (const key of Object.keys(env)) {
4893
+ if (key.startsWith("OPENAI_")) {
4894
+ delete env[key];
4895
+ }
4896
+ }
4897
+ return { ...env, ...overrides };
4898
+ }
4899
+
4876
4900
  // ../../packages/shared/src/core/logger.ts
4877
4901
  var isTestEnv = process.env.NODE_ENV === "test" || process.env.VITEST === "true" || process.env.VITEST === "1";
4878
4902
  function isMocked(fn) {
@@ -4905,12 +4929,6 @@ var ACTIVATION_MODEL = "gpt-5.1-codex-mini";
4905
4929
  var MAX_STDERR_CAPTURE_CHARS = 32768;
4906
4930
  var REFRESH_TOKEN_REDEEMED_SNIPPET = "refresh token was already used";
4907
4931
  var authFileCache = /* @__PURE__ */ new Map();
4908
- var CODEX_OAUTH_REFRESH_URL = "https://auth.openai.com/oauth/token";
4909
- var CODEX_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
4910
- var CODEX_OAUTH_REFRESH_MAX_AGE_MS = 8 * 24 * 60 * 60 * 1e3;
4911
- var CODEX_OAUTH_ACCESS_TOKEN_REFRESH_SKEW_MS = 2 * 60 * 1e3;
4912
- var CODEX_USAGE_DEFAULT_BASE_URL = "https://chatgpt.com/backend-api";
4913
- var CODEX_USAGE_TIMEOUT_MS = 3e4;
4914
4932
  function isRecord4(value) {
4915
4933
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
4916
4934
  }
@@ -5134,17 +5152,6 @@ function extractJwtIssuedAtMs(token) {
5134
5152
  }
5135
5153
  return issuedAt * 1e3;
5136
5154
  }
5137
- function extractJwtExpiresAtMs(token) {
5138
- const payload = decodeJwtPayload(token);
5139
- if (!payload) {
5140
- return null;
5141
- }
5142
- const expiresAt = payload["exp"];
5143
- if (typeof expiresAt !== "number" || !Number.isFinite(expiresAt)) {
5144
- return null;
5145
- }
5146
- return expiresAt * 1e3;
5147
- }
5148
5155
  function parseAuthRecord(content) {
5149
5156
  try {
5150
5157
  const parsed = JSON.parse(content);
@@ -5233,353 +5240,6 @@ async function writeAuthFileCached(filePath, content) {
5233
5240
  authFileCache.delete(filePath);
5234
5241
  }
5235
5242
  }
5236
- function nonEmptyString(value) {
5237
- return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
5238
- }
5239
- function resolveCodexAuthPathForEnv(envOverride) {
5240
- return envOverride?.CODEX_HOME ? import_node_path5.default.join(envOverride.CODEX_HOME, "auth.json") : import_node_path5.default.join(
5241
- envOverride?.HOME ?? process.env.HOME ?? import_node_os2.default.homedir(),
5242
- ".codex",
5243
- "auth.json"
5244
- );
5245
- }
5246
- function parseCodexOAuthCredentials(content) {
5247
- const parsed = parseAuthRecord(content);
5248
- if (!parsed) {
5249
- return null;
5250
- }
5251
- const tokens = isRecord4(parsed.tokens) ? parsed.tokens : {};
5252
- const accessToken = nonEmptyString(tokens.access_token) ?? nonEmptyString(parsed.access_token);
5253
- const refreshToken = nonEmptyString(tokens.refresh_token) ?? nonEmptyString(parsed.refresh_token);
5254
- if (!accessToken && !refreshToken) {
5255
- return null;
5256
- }
5257
- return {
5258
- accessToken: accessToken ?? "",
5259
- refreshToken: refreshToken ?? "",
5260
- idToken: nonEmptyString(tokens.id_token) ?? nonEmptyString(parsed.id_token),
5261
- accountId: nonEmptyString(tokens.account_id) ?? nonEmptyString(parsed.account_id),
5262
- lastRefreshMs: parseTimestamp2(tokens.last_refresh) ?? parseTimestamp2(parsed.last_refresh)
5263
- };
5264
- }
5265
- function shouldRefreshCodexOAuthToken(credentials) {
5266
- if (!credentials.refreshToken) {
5267
- return false;
5268
- }
5269
- const accessExpiresAt = extractJwtExpiresAtMs(credentials.accessToken);
5270
- if (accessExpiresAt !== null && accessExpiresAt - Date.now() <= CODEX_OAUTH_ACCESS_TOKEN_REFRESH_SKEW_MS) {
5271
- return true;
5272
- }
5273
- if (credentials.lastRefreshMs === null) {
5274
- return true;
5275
- }
5276
- return Date.now() - credentials.lastRefreshMs > CODEX_OAUTH_REFRESH_MAX_AGE_MS;
5277
- }
5278
- async function writeCodexOAuthCredentials(authPath, content, credentials) {
5279
- let json = {};
5280
- try {
5281
- const parsed = JSON.parse(content);
5282
- if (isRecord4(parsed)) {
5283
- json = { ...parsed };
5284
- }
5285
- } catch {
5286
- json = {};
5287
- }
5288
- const existingTokens = isRecord4(json.tokens) ? json.tokens : {};
5289
- json.tokens = {
5290
- ...existingTokens,
5291
- access_token: credentials.accessToken,
5292
- refresh_token: credentials.refreshToken,
5293
- ...credentials.idToken ? { id_token: credentials.idToken } : {},
5294
- ...credentials.accountId ? { account_id: credentials.accountId } : {},
5295
- last_refresh: (/* @__PURE__ */ new Date()).toISOString()
5296
- };
5297
- json.last_refresh = (/* @__PURE__ */ new Date()).toISOString();
5298
- await writeAuthFileCached(authPath, `${JSON.stringify(json, null, 2)}
5299
- `);
5300
- }
5301
- async function refreshCodexOAuthCredentials(credentials) {
5302
- if (!credentials.refreshToken) {
5303
- return credentials;
5304
- }
5305
- const response = await fetch(CODEX_OAUTH_REFRESH_URL, {
5306
- method: "POST",
5307
- headers: { "Content-Type": "application/json" },
5308
- signal: AbortSignal.timeout(CODEX_USAGE_TIMEOUT_MS),
5309
- body: JSON.stringify({
5310
- client_id: CODEX_OAUTH_CLIENT_ID,
5311
- grant_type: "refresh_token",
5312
- refresh_token: credentials.refreshToken,
5313
- scope: "openid profile email"
5314
- })
5315
- });
5316
- const body = await response.text();
5317
- if (!response.ok) {
5318
- let code = "";
5319
- try {
5320
- const parsed2 = JSON.parse(body);
5321
- if (isRecord4(parsed2)) {
5322
- const error = isRecord4(parsed2.error) ? parsed2.error : {};
5323
- code = nonEmptyString(error.code) ?? nonEmptyString(parsed2.error) ?? nonEmptyString(parsed2.code) ?? "";
5324
- }
5325
- } catch {
5326
- code = "";
5327
- }
5328
- if (code === "refresh_token_reused") {
5329
- throw new Error("refresh token was already used");
5330
- }
5331
- if (code === "refresh_token_expired") {
5332
- throw new Error("refresh token expired");
5333
- }
5334
- if (code === "invalid_grant" || code === "refresh_token_invalidated") {
5335
- throw new Error("refresh token was revoked");
5336
- }
5337
- throw new Error(`Codex OAuth refresh failed HTTP ${response.status}`);
5338
- }
5339
- let parsed;
5340
- try {
5341
- parsed = JSON.parse(body);
5342
- } catch {
5343
- throw new Error("Codex OAuth refresh returned invalid JSON");
5344
- }
5345
- if (!isRecord4(parsed)) {
5346
- throw new Error("Codex OAuth refresh returned invalid data");
5347
- }
5348
- return {
5349
- accessToken: nonEmptyString(parsed.access_token) ?? credentials.accessToken,
5350
- refreshToken: nonEmptyString(parsed.refresh_token) ?? credentials.refreshToken,
5351
- idToken: nonEmptyString(parsed.id_token) ?? credentials.idToken,
5352
- accountId: credentials.accountId,
5353
- lastRefreshMs: Date.now()
5354
- };
5355
- }
5356
- async function loadCodexConfigContents(envOverride) {
5357
- const codexHome = envOverride?.CODEX_HOME?.trim();
5358
- const root = codexHome || import_node_path5.default.join(envOverride?.HOME ?? process.env.HOME ?? import_node_os2.default.homedir(), ".codex");
5359
- try {
5360
- return await import_node_fs3.promises.readFile(import_node_path5.default.join(root, "config.toml"), "utf8");
5361
- } catch {
5362
- return null;
5363
- }
5364
- }
5365
- function parseChatGPTBaseUrl(contents) {
5366
- if (!contents) {
5367
- return CODEX_USAGE_DEFAULT_BASE_URL;
5368
- }
5369
- try {
5370
- const parsed = (0, import_toml.parse)(contents);
5371
- if (isRecord4(parsed)) {
5372
- return nonEmptyString(parsed.chatgpt_base_url) ?? CODEX_USAGE_DEFAULT_BASE_URL;
5373
- }
5374
- } catch {
5375
- return CODEX_USAGE_DEFAULT_BASE_URL;
5376
- }
5377
- return CODEX_USAGE_DEFAULT_BASE_URL;
5378
- }
5379
- async function resolveCodexUsageUrl(envOverride) {
5380
- let base = parseChatGPTBaseUrl(await loadCodexConfigContents(envOverride));
5381
- while (base.endsWith("/")) {
5382
- base = base.slice(0, -1);
5383
- }
5384
- if ((base.startsWith("https://chatgpt.com") || base.startsWith("https://chat.openai.com")) && !base.includes("/backend-api")) {
5385
- base += "/backend-api";
5386
- }
5387
- return `${base}${base.includes("/backend-api") ? "/wham/usage" : "/api/codex/usage"}`;
5388
- }
5389
- function numberFromUnknown(value) {
5390
- if (typeof value === "number" && Number.isFinite(value)) {
5391
- return value;
5392
- }
5393
- if (typeof value === "string" && value.trim()) {
5394
- const parsed = Number(value.trim());
5395
- return Number.isFinite(parsed) ? parsed : null;
5396
- }
5397
- return null;
5398
- }
5399
- function toOAuthWindow(window) {
5400
- if (!window) {
5401
- return void 0;
5402
- }
5403
- const usedPercent = numberFromUnknown(window.used_percent);
5404
- const resetAt = numberFromUnknown(window.reset_at);
5405
- const limitWindowSeconds = numberFromUnknown(window.limit_window_seconds);
5406
- if (usedPercent === null && resetAt === null && limitWindowSeconds === null) {
5407
- return void 0;
5408
- }
5409
- const result = {};
5410
- if (usedPercent !== null) {
5411
- result.usedPercent = Math.max(0, Math.min(100, usedPercent));
5412
- }
5413
- if (limitWindowSeconds !== null) {
5414
- result.windowMinutes = Math.round(limitWindowSeconds / 60);
5415
- }
5416
- if (resetAt !== null) {
5417
- const resetMs = resetAt > 1e10 ? resetAt : resetAt * 1e3;
5418
- result.resetsAt = new Date(resetMs).toISOString();
5419
- result.resetsInSeconds = Math.max(0, Math.round((resetMs - Date.now()) / 1e3));
5420
- }
5421
- return result;
5422
- }
5423
- function firstNonEmptyString(...values) {
5424
- for (const value of values) {
5425
- const text = nonEmptyString(value);
5426
- if (text) {
5427
- return text;
5428
- }
5429
- }
5430
- return null;
5431
- }
5432
- function slugForRateLimitId(value) {
5433
- return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
5434
- }
5435
- function isSparkRateLimit(limitName, meteredFeature) {
5436
- return [limitName, meteredFeature].filter((value) => Boolean(value)).some((value) => value.toLowerCase().includes("spark"));
5437
- }
5438
- function sparkWindowIdentity(window, fallback) {
5439
- const limitWindowSeconds = numberFromUnknown(window.limit_window_seconds);
5440
- const windowMinutes = limitWindowSeconds !== null ? Math.round(limitWindowSeconds / 60) : null;
5441
- const kind = windowMinutes !== null && windowMinutes > 0 && windowMinutes <= 6 * 60 ? "five-hour" : windowMinutes !== null && windowMinutes >= 6 * 24 * 60 ? "weekly" : fallback;
5442
- return kind === "weekly" ? { id: "codex-spark-weekly", label: "Codex Spark Weekly" } : { id: "codex-spark", label: "Codex Spark 5-hour" };
5443
- }
5444
- function toExtraRateLimitWindow(args) {
5445
- const window = toOAuthWindow(args.window);
5446
- if (!window) {
5447
- return null;
5448
- }
5449
- return {
5450
- id: args.id,
5451
- label: args.label,
5452
- ...args.meteredFeature ? { meteredFeature: args.meteredFeature } : {},
5453
- ...window
5454
- };
5455
- }
5456
- function parseExtraRateLimitWindows(additionalRateLimits) {
5457
- if (!Array.isArray(additionalRateLimits)) {
5458
- return [];
5459
- }
5460
- const usedIds = /* @__PURE__ */ new Set();
5461
- const extraWindows = [];
5462
- for (const entry of additionalRateLimits) {
5463
- if (!isRecord4(entry)) {
5464
- continue;
5465
- }
5466
- const limitName = firstNonEmptyString(entry.limit_name);
5467
- const meteredFeature = firstNonEmptyString(entry.metered_feature);
5468
- const rateLimit = isRecord4(entry.rate_limit) ? entry.rate_limit : null;
5469
- if (!rateLimit) {
5470
- continue;
5471
- }
5472
- const primary = isRecord4(rateLimit.primary_window) ? rateLimit.primary_window : null;
5473
- const secondary = isRecord4(rateLimit.secondary_window) ? rateLimit.secondary_window : null;
5474
- if (isSparkRateLimit(limitName, meteredFeature)) {
5475
- const candidates = [
5476
- { window: primary, fallback: "five-hour" },
5477
- { window: secondary, fallback: "weekly" }
5478
- ];
5479
- for (const candidate of candidates) {
5480
- if (!candidate.window) {
5481
- continue;
5482
- }
5483
- const identity = sparkWindowIdentity(candidate.window, candidate.fallback);
5484
- if (usedIds.has(identity.id)) {
5485
- continue;
5486
- }
5487
- const extraWindow2 = toExtraRateLimitWindow({
5488
- ...identity,
5489
- meteredFeature,
5490
- window: candidate.window
5491
- });
5492
- if (extraWindow2) {
5493
- usedIds.add(identity.id);
5494
- extraWindows.push(extraWindow2);
5495
- }
5496
- }
5497
- continue;
5498
- }
5499
- const idSource = firstNonEmptyString(meteredFeature, limitName);
5500
- const slug = idSource ? slugForRateLimitId(idSource) : "";
5501
- if (!slug) {
5502
- continue;
5503
- }
5504
- const id = `codex-${slug}`;
5505
- if (usedIds.has(id)) {
5506
- continue;
5507
- }
5508
- const extraWindow = toExtraRateLimitWindow({
5509
- id,
5510
- label: firstNonEmptyString(limitName, meteredFeature) ?? "Codex extra limit",
5511
- meteredFeature,
5512
- window: primary ?? secondary
5513
- });
5514
- if (extraWindow) {
5515
- usedIds.add(id);
5516
- extraWindows.push(extraWindow);
5517
- }
5518
- }
5519
- return extraWindows;
5520
- }
5521
- function parseRateLimitSnapshotFromOAuthUsage(value) {
5522
- if (!isRecord4(value)) {
5523
- throw new Error("Codex usage API returned invalid data");
5524
- }
5525
- const usage = value;
5526
- const primary = toOAuthWindow(usage.rate_limit?.primary_window ?? null);
5527
- const secondary = toOAuthWindow(usage.rate_limit?.secondary_window ?? null);
5528
- const extraWindows = parseExtraRateLimitWindows(usage.additional_rate_limits);
5529
- if (!primary && !secondary && extraWindows.length === 0) {
5530
- return null;
5531
- }
5532
- return {
5533
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
5534
- source: "codex-oauth-estimate",
5535
- ...primary ? { primary } : {},
5536
- ...secondary ? { secondary } : {},
5537
- ...extraWindows.length > 0 ? { extraWindows } : {}
5538
- };
5539
- }
5540
- async function fetchRateLimitsViaOAuth(envOverride) {
5541
- const authPath = resolveCodexAuthPathForEnv(envOverride);
5542
- const authContent = await readAuthFileCached(authPath);
5543
- if (!authContent) {
5544
- return null;
5545
- }
5546
- let credentials = parseCodexOAuthCredentials(authContent);
5547
- if (!credentials) {
5548
- return null;
5549
- }
5550
- if (shouldRefreshCodexOAuthToken(credentials)) {
5551
- credentials = await refreshCodexOAuthCredentials(credentials);
5552
- await writeCodexOAuthCredentials(authPath, authContent, credentials);
5553
- }
5554
- if (!credentials.accessToken) {
5555
- return null;
5556
- }
5557
- const usageUrl = await resolveCodexUsageUrl(envOverride);
5558
- const response = await fetch(usageUrl, {
5559
- method: "GET",
5560
- headers: {
5561
- Authorization: `Bearer ${credentials.accessToken}`,
5562
- Accept: "application/json",
5563
- "User-Agent": "CodexUse",
5564
- ...credentials.accountId ? { "ChatGPT-Account-Id": credentials.accountId } : {}
5565
- },
5566
- signal: AbortSignal.timeout(CODEX_USAGE_TIMEOUT_MS)
5567
- });
5568
- const body = await response.text();
5569
- if (response.status === 401 || response.status === 403) {
5570
- throw new Error(`Codex OAuth usage failed HTTP ${response.status} (${usageUrl})`);
5571
- }
5572
- if (!response.ok) {
5573
- throw new Error(`Codex usage API failed HTTP ${response.status} (${usageUrl}): ${body.slice(0, 500)}`);
5574
- }
5575
- let parsed;
5576
- try {
5577
- parsed = JSON.parse(body);
5578
- } catch {
5579
- throw new Error("Codex usage API returned invalid JSON");
5580
- }
5581
- return parseRateLimitSnapshotFromOAuthUsage(parsed);
5582
- }
5583
5243
  function inferRefreshFailureHint(stderrOutput) {
5584
5244
  if (!stderrOutput) {
5585
5245
  return null;
@@ -5715,14 +5375,13 @@ async function fetchRateLimitsViaRpc(envOverride, options = {}) {
5715
5375
  });
5716
5376
  return null;
5717
5377
  }
5718
- const childEnv = {
5719
- ...process.env,
5378
+ const childEnv = buildCodexChildEnv({
5720
5379
  ...envOverride ?? {},
5721
5380
  HOME: tempHome,
5722
5381
  CODEX_HOME: tempHome,
5723
5382
  CODEX_TELEMETRY_LABEL: "codex-rpc",
5724
5383
  ELECTRON_RUN_AS_NODE: "1"
5725
- };
5384
+ });
5726
5385
  const command = buildCodexCommand(
5727
5386
  binaryPath,
5728
5387
  ["-s", "read-only", "-a", "untrusted", "app-server"],
@@ -5825,14 +5484,13 @@ async function activateResetWindowViaRpc(envOverride, options = {}) {
5825
5484
  });
5826
5485
  return { status: "skipped", reason: "auth-missing" };
5827
5486
  }
5828
- const childEnv = {
5829
- ...process.env,
5487
+ const childEnv = buildCodexChildEnv({
5830
5488
  ...envOverride ?? {},
5831
5489
  HOME: tempHome,
5832
5490
  CODEX_HOME: tempHome,
5833
5491
  CODEX_TELEMETRY_LABEL: "codex-reset-activation",
5834
5492
  ELECTRON_RUN_AS_NODE: "1"
5835
- };
5493
+ });
5836
5494
  const command = buildCodexCommand(
5837
5495
  binaryPath,
5838
5496
  ["-s", "read-only", "-a", "untrusted", "app-server"],
@@ -6155,6 +5813,7 @@ var ProfileManager = class {
6155
5813
  displayName: record.displayName ?? null,
6156
5814
  data: record.data,
6157
5815
  metadata: record.metadata,
5816
+ rateLimitKey: record.rateLimitKey ?? null,
6158
5817
  accountId: record.accountId ?? null,
6159
5818
  workspaceId: record.workspaceId ?? null,
6160
5819
  workspaceName: record.workspaceName ?? null,
@@ -6172,11 +5831,14 @@ var ProfileManager = class {
6172
5831
  if (!dataRaw || typeof dataRaw !== "object") {
6173
5832
  return null;
6174
5833
  }
6175
- return {
5834
+ const data = cloneJson(dataRaw);
5835
+ const metadata = raw.metadata ? cloneJson(raw.metadata) : void 0;
5836
+ const fallbackRecord = {
6176
5837
  name: profileName,
6177
5838
  displayName: typeof raw.displayName === "string" ? raw.displayName : null,
6178
- data: cloneJson(dataRaw),
6179
- metadata: raw.metadata ? cloneJson(raw.metadata) : void 0,
5839
+ data,
5840
+ metadata,
5841
+ rateLimitKey: typeof raw.rateLimitKey === "string" ? raw.rateLimitKey : null,
6180
5842
  accountId: typeof raw.accountId === "string" ? raw.accountId : null,
6181
5843
  workspaceId: typeof raw.workspaceId === "string" ? raw.workspaceId : null,
6182
5844
  workspaceName: typeof raw.workspaceName === "string" ? raw.workspaceName : null,
@@ -6185,6 +5847,10 @@ var ProfileManager = class {
6185
5847
  createdAt: typeof raw.createdAt === "string" ? raw.createdAt : null,
6186
5848
  updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : null
6187
5849
  };
5850
+ return {
5851
+ ...fallbackRecord,
5852
+ rateLimitKey: fallbackRecord.rateLimitKey ?? this.resolveProfileIdentityFromRecord(fallbackRecord)
5853
+ };
6188
5854
  }
6189
5855
  async readProfilesStateSource() {
6190
5856
  const state = await getAppState();
@@ -6234,10 +5900,11 @@ var ProfileManager = class {
6234
5900
  }
6235
5901
  rateLimitSnapshotKeysForRecord(record) {
6236
5902
  return Array.from(
6237
- /* @__PURE__ */ new Set([
5903
+ new Set([
6238
5904
  this.resolveProfileIdentityFromRecord(record),
5905
+ record.rateLimitKey,
6239
5906
  resolveFallbackAccountKey(record.name)
6240
- ])
5907
+ ].filter((key) => Boolean(key)))
6241
5908
  );
6242
5909
  }
6243
5910
  rateLimitSnapshotKeysForStateMap(map) {
@@ -6950,6 +6617,7 @@ var ProfileManager = class {
6950
6617
  displayName,
6951
6618
  data,
6952
6619
  metadata: resolvedMetadata,
6620
+ rateLimitKey: existingRecord?.rateLimitKey ?? this.resolveProfileIdentityFromData(resolvedName, data, resolvedMetadata),
6953
6621
  accountId,
6954
6622
  workspaceId: data.workspace_id ?? workspaceId,
6955
6623
  workspaceName: data.workspace_name ?? workspaceName,
@@ -6968,6 +6636,7 @@ var ProfileManager = class {
6968
6636
  createdAt: row.createdAt ?? void 0,
6969
6637
  authMethod: row.authMethod ?? void 0,
6970
6638
  accountId: row.accountId ?? void 0,
6639
+ rateLimitKey: row.rateLimitKey ?? void 0,
6971
6640
  workspaceId: row.workspaceId ?? void 0,
6972
6641
  workspaceName: row.workspaceName ?? void 0,
6973
6642
  metadata: row.metadata
@@ -7004,6 +6673,7 @@ var ProfileManager = class {
7004
6673
  name,
7005
6674
  displayName: fallback?.displayName ?? name,
7006
6675
  isValid: Boolean(data && Object.keys(data).length > 0),
6676
+ rateLimitKey: fallback?.rateLimitKey,
7007
6677
  accountId,
7008
6678
  workspaceId,
7009
6679
  workspaceName,
@@ -7322,7 +6992,7 @@ var ProfileManager = class {
7322
6992
  }
7323
6993
  let parsed;
7324
6994
  try {
7325
- parsed = (0, import_toml2.parse)(raw);
6995
+ parsed = (0, import_toml.parse)(raw);
7326
6996
  } catch (error) {
7327
6997
  logWarn(`Failed to parse config.toml for profile home '${profileHome}':`, error);
7328
6998
  return;
@@ -7332,7 +7002,7 @@ var ProfileManager = class {
7332
7002
  }
7333
7003
  delete parsed["model_reasoning_effort"];
7334
7004
  const sanitized = this.ensureTrailingNewline(
7335
- (0, import_toml2.stringify)(parsed)
7005
+ (0, import_toml.stringify)(parsed)
7336
7006
  );
7337
7007
  try {
7338
7008
  await import_fs.promises.writeFile(configPath, sanitized, "utf8");
@@ -7395,11 +7065,10 @@ var ProfileManager = class {
7395
7065
  const codexFormat = this.convertToCodexFormat(profileData);
7396
7066
  const profileHome = await this.prepareProfileHome(profileName, codexFormat);
7397
7067
  const authPath = import_path.default.join(profileHome, "auth.json");
7398
- const envOverrides = {
7399
- ...process.env,
7068
+ const envOverrides = buildCodexChildEnv({
7400
7069
  HOME: profileHome,
7401
7070
  CODEX_HOME: profileHome
7402
- };
7071
+ });
7403
7072
  try {
7404
7073
  return await action(envOverrides);
7405
7074
  } finally {
@@ -7449,11 +7118,10 @@ var ProfileManager = class {
7449
7118
  const profileHome = await this.prepareProfileHome(profileName, codexFormat);
7450
7119
  return {
7451
7120
  profileHome,
7452
- env: {
7453
- ...process.env,
7121
+ env: buildCodexChildEnv({
7454
7122
  HOME: profileHome,
7455
7123
  CODEX_HOME: profileHome
7456
- }
7124
+ })
7457
7125
  };
7458
7126
  })
7459
7127
  );
@@ -7696,16 +7364,7 @@ var ProfileManager = class {
7696
7364
  profileName,
7697
7365
  () => this.runWithPreparedProfileHome(
7698
7366
  profileName,
7699
- async (env) => {
7700
- try {
7701
- const oauthSnapshot = await fetchRateLimitsViaOAuth(env);
7702
- if (oauthSnapshot) {
7703
- return oauthSnapshot;
7704
- }
7705
- } catch {
7706
- }
7707
- return fetchRateLimitsViaRpc(env, { codexPath: options.codexPath });
7708
- },
7367
+ (env) => fetchRateLimitsViaRpc(env, { codexPath: options.codexPath }),
7709
7368
  { syncFromActiveAuthBeforeAction: false }
7710
7369
  )
7711
7370
  );
@@ -8049,6 +7708,7 @@ var ProfileManager = class {
8049
7708
  displayName: typeof candidate.displayName === "string" ? candidate.displayName : null,
8050
7709
  data,
8051
7710
  metadata,
7711
+ rateLimitKey: this.resolveProfileIdentityFromData(name, data, metadata),
8052
7712
  accountId: typeof candidate.accountId === "string" ? candidate.accountId : null,
8053
7713
  workspaceId: typeof candidate.workspaceId === "string" ? candidate.workspaceId : null,
8054
7714
  workspaceName: typeof candidate.workspaceName === "string" ? candidate.workspaceName : null,
@@ -9335,10 +8995,6 @@ function snapshotResetSeconds(snapshot) {
9335
8995
  ].filter((value) => typeof value === "number" && Number.isFinite(value));
9336
8996
  return values.length > 0 ? Math.min(...values) : null;
9337
8997
  }
9338
- function fallbackUsedPercent(profile) {
9339
- const cached = maxUsedPercent(profile.rateLimit ?? null);
9340
- return typeof cached === "number" && Number.isFinite(cached) ? cached : null;
9341
- }
9342
8998
  function compareCandidates(left, right) {
9343
8999
  const leftUsage = left.usedPercent ?? Number.POSITIVE_INFINITY;
9344
9000
  const rightUsage = right.usedPercent ?? Number.POSITIVE_INFINITY;
@@ -9396,16 +9052,17 @@ async function selectBestProfile(manager, profiles, codexPath) {
9396
9052
  }
9397
9053
  try {
9398
9054
  const snapshot = await manager.readLiveRateLimits(profile.name, { codexPath });
9055
+ const usedPercent = maxUsedPercent(snapshot);
9399
9056
  candidates.push({
9400
9057
  profile,
9401
- usedPercent: typeof maxUsedPercent(snapshot) === "number" ? maxUsedPercent(snapshot) : fallbackUsedPercent(profile),
9058
+ usedPercent: typeof usedPercent === "number" ? usedPercent : null,
9402
9059
  resetSeconds: snapshotResetSeconds(snapshot)
9403
9060
  });
9404
9061
  } catch {
9405
9062
  candidates.push({
9406
9063
  profile,
9407
- usedPercent: fallbackUsedPercent(profile),
9408
- resetSeconds: snapshotResetSeconds(profile.rateLimit ?? null)
9064
+ usedPercent: null,
9065
+ resetSeconds: null
9409
9066
  });
9410
9067
  }
9411
9068
  }
@@ -9540,6 +9197,9 @@ Picks the healthiest saved profile, then runs Codex. Auto-run requires Pro or an
9540
9197
  if (!best) {
9541
9198
  throw new Error("No valid saved profiles found. Add one with `codexuse profile add <name>`.");
9542
9199
  }
9200
+ if (best.usedPercent === null) {
9201
+ throw new Error("No live rate-limit usage found. Skipping best profile run.");
9202
+ }
9543
9203
  const dryRun = hasFlag(flags, "--dry-run");
9544
9204
  const summary = `${best.profile.name} (${formatUsagePercent(best.usedPercent)} used)`;
9545
9205
  if (dryRun) {
@@ -9611,6 +9271,7 @@ var import_node_path10 = __toESM(require("path"), 1);
9611
9271
  var import_node_fs6 = require("fs");
9612
9272
  var import_node_path9 = __toESM(require("path"), 1);
9613
9273
  var ROLLOUT_DIRS = ["sessions", "archived_sessions"];
9274
+ var SQLITE_EXTENSIONS = /* @__PURE__ */ new Set([".db", ".sqlite", ".sqlite3"]);
9614
9275
  function isRecord5(value) {
9615
9276
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9616
9277
  }
@@ -9729,8 +9390,91 @@ function resolveRolloutPath(profileHome, rolloutPath) {
9729
9390
  }
9730
9391
  return import_node_path9.default.isAbsolute(rolloutPath) ? rolloutPath : import_node_path9.default.join(profileHome, rolloutPath);
9731
9392
  }
9732
- async function readThreadRecordFromStateDb(profileHome, threadId) {
9733
- const dbPath = import_node_path9.default.join(profileHome, "state_5.sqlite");
9393
+ async function collectSessionDatabasePaths(profileHome) {
9394
+ const paths = [];
9395
+ const sqliteDir = import_node_path9.default.join(profileHome, "sqlite");
9396
+ try {
9397
+ const entries = await import_node_fs6.promises.readdir(sqliteDir, {
9398
+ withFileTypes: true,
9399
+ encoding: "utf8"
9400
+ });
9401
+ for (const entry of entries) {
9402
+ if (!entry.isFile()) {
9403
+ continue;
9404
+ }
9405
+ const entryName = String(entry.name);
9406
+ if (SQLITE_EXTENSIONS.has(import_node_path9.default.extname(entryName))) {
9407
+ paths.push(import_node_path9.default.join(sqliteDir, entryName));
9408
+ }
9409
+ }
9410
+ } catch {
9411
+ }
9412
+ paths.sort((left, right) => {
9413
+ const leftName = import_node_path9.default.basename(left);
9414
+ const rightName = import_node_path9.default.basename(right);
9415
+ if (leftName === "codex-dev.db" && rightName !== "codex-dev.db") return -1;
9416
+ if (rightName === "codex-dev.db" && leftName !== "codex-dev.db") return 1;
9417
+ return leftName.localeCompare(rightName);
9418
+ });
9419
+ const legacy = import_node_path9.default.join(profileHome, "state_5.sqlite");
9420
+ if (!paths.includes(legacy)) {
9421
+ paths.push(legacy);
9422
+ }
9423
+ return paths;
9424
+ }
9425
+ function tableColumns(db, table) {
9426
+ try {
9427
+ return new Set(
9428
+ db.prepare(`PRAGMA table_info(${table})`).all().map((row) => isRecord5(row) ? recordString(row.name) : null).filter((name) => Boolean(name))
9429
+ );
9430
+ } catch {
9431
+ return /* @__PURE__ */ new Set();
9432
+ }
9433
+ }
9434
+ function firstColumn(columns, names) {
9435
+ return names.find((name) => columns.has(name)) ?? null;
9436
+ }
9437
+ function sqlColumnOrNull(column, alias) {
9438
+ return column ? `${column} AS ${alias}` : `NULL AS ${alias}`;
9439
+ }
9440
+ function queryThreadRecordFromTable(db, profileHome, threadId, config) {
9441
+ const columns = tableColumns(db, config.table);
9442
+ const idColumn = firstColumn(columns, config.id);
9443
+ if (!idColumn) {
9444
+ return null;
9445
+ }
9446
+ const variants = threadIdVariants(threadId);
9447
+ const placeholders = variants.map(() => "?").join(", ");
9448
+ const orderByColumn = firstColumn(columns, [
9449
+ "updated_at_ms",
9450
+ "updated_at",
9451
+ "created_at_ms",
9452
+ "created_at"
9453
+ ]);
9454
+ const select = [
9455
+ sqlColumnOrNull(firstColumn(columns, config.rolloutPath), "rollout_path"),
9456
+ sqlColumnOrNull(firstColumn(columns, config.title), "title"),
9457
+ sqlColumnOrNull(firstColumn(columns, config.cwd), "cwd"),
9458
+ sqlColumnOrNull(firstColumn(columns, ["updated_at"]), "updated_at"),
9459
+ sqlColumnOrNull(firstColumn(columns, ["updated_at_ms"]), "updated_at_ms"),
9460
+ sqlColumnOrNull(firstColumn(columns, ["created_at_ms", "created_at"]), "created_at_ms")
9461
+ ].join(", ");
9462
+ const orderBy = orderByColumn ? ` ORDER BY ${orderByColumn} DESC, ${idColumn} DESC` : ` ORDER BY ${idColumn} DESC`;
9463
+ const row = db.prepare(
9464
+ `SELECT ${select} FROM ${config.table} WHERE ${idColumn} IN (${placeholders})${orderBy} LIMIT 1`
9465
+ ).all(...variants).find(isRecord5);
9466
+ if (!row) {
9467
+ return null;
9468
+ }
9469
+ return {
9470
+ rolloutPath: resolveRolloutPath(profileHome, recordString(row.rollout_path)),
9471
+ title: recordString(row.title),
9472
+ cwd: recordString(row.cwd),
9473
+ updatedAt: recordString(row.updated_at),
9474
+ updatedAtMs: normalizeTimestampMs(row.updated_at_ms) ?? normalizeTimestampMs(row.updated_at) ?? normalizeTimestampMs(row.created_at_ms)
9475
+ };
9476
+ }
9477
+ async function readThreadRecordFromDb(profileHome, dbPath, threadId) {
9734
9478
  try {
9735
9479
  await import_node_fs6.promises.access(dbPath);
9736
9480
  } catch {
@@ -9739,42 +9483,28 @@ async function readThreadRecordFromStateDb(profileHome, threadId) {
9739
9483
  let db = null;
9740
9484
  try {
9741
9485
  db = await openReadonlyDatabase(dbPath);
9742
- const columns = new Set(
9743
- db.prepare("PRAGMA table_info(threads)").all().map((row2) => isRecord5(row2) ? recordString(row2.name) : null).filter((name) => Boolean(name))
9744
- );
9745
- const idColumn = columns.has("id") ? "id" : columns.has("thread_id") ? "thread_id" : null;
9746
- if (!idColumn) {
9747
- return null;
9748
- }
9749
- const variants = threadIdVariants(threadId);
9750
- const placeholders = variants.map(() => "?").join(", ");
9751
- const select = [
9752
- columns.has("rollout_path") ? "rollout_path AS rollout_path" : "NULL AS rollout_path",
9753
- columns.has("title") ? "title AS title" : "NULL AS title",
9754
- columns.has("cwd") ? "cwd AS cwd" : "NULL AS cwd",
9755
- columns.has("updated_at") ? "updated_at AS updated_at" : "NULL AS updated_at",
9756
- columns.has("updated_at_ms") ? "updated_at_ms AS updated_at_ms" : "NULL AS updated_at_ms",
9757
- columns.has("created_at_ms") ? "created_at_ms AS created_at_ms" : "NULL AS created_at_ms"
9758
- ].join(", ");
9759
- const orderByColumn = columns.has("updated_at_ms") ? "updated_at_ms" : columns.has("updated_at") ? "updated_at" : columns.has("created_at_ms") ? "created_at_ms" : null;
9760
- const orderBy = orderByColumn ? ` ORDER BY ${orderByColumn} DESC, ${idColumn} DESC` : ` ORDER BY ${idColumn} DESC`;
9761
- const rows = db.prepare(
9762
- `SELECT ${select} FROM threads WHERE ${idColumn} IN (${placeholders})${orderBy} LIMIT 1`
9763
- ).all(...variants);
9764
- const row = rows.find(isRecord5);
9765
- if (!row) {
9766
- return null;
9486
+ for (const config of [
9487
+ {
9488
+ table: "threads",
9489
+ id: ["id", "thread_id"],
9490
+ title: ["title", "thread_title"],
9491
+ cwd: ["cwd", "source_cwd"],
9492
+ rolloutPath: ["rollout_path"]
9493
+ },
9494
+ {
9495
+ table: "automation_runs",
9496
+ id: ["thread_id", "id"],
9497
+ title: ["thread_title", "title", "inbox_title"],
9498
+ cwd: ["source_cwd", "cwd"],
9499
+ rolloutPath: []
9500
+ }
9501
+ ]) {
9502
+ const record = queryThreadRecordFromTable(db, profileHome, threadId, config);
9503
+ if (record) {
9504
+ return record;
9505
+ }
9767
9506
  }
9768
- return {
9769
- rolloutPath: resolveRolloutPath(
9770
- profileHome,
9771
- recordString(row.rollout_path)
9772
- ),
9773
- title: recordString(row.title),
9774
- cwd: recordString(row.cwd),
9775
- updatedAt: recordString(row.updated_at),
9776
- updatedAtMs: normalizeTimestampMs(row.updated_at_ms) ?? normalizeTimestampMs(row.updated_at) ?? normalizeTimestampMs(row.created_at_ms)
9777
- };
9507
+ return null;
9778
9508
  } catch {
9779
9509
  return null;
9780
9510
  } finally {
@@ -9782,9 +9512,16 @@ async function readThreadRecordFromStateDb(profileHome, threadId) {
9782
9512
  }
9783
9513
  }
9784
9514
  async function findOfficialCodexThreadRecord(profileHome, threadId) {
9785
- const stateRecord = await readThreadRecordFromStateDb(profileHome, threadId);
9786
- if (stateRecord) {
9787
- return stateRecord;
9515
+ const records = [];
9516
+ for (const dbPath of await collectSessionDatabasePaths(profileHome)) {
9517
+ const stateRecord = await readThreadRecordFromDb(profileHome, dbPath, threadId);
9518
+ if (stateRecord) {
9519
+ records.push(stateRecord);
9520
+ }
9521
+ }
9522
+ if (records.length > 0) {
9523
+ records.sort((left, right) => (right.updatedAtMs ?? 0) - (left.updatedAtMs ?? 0));
9524
+ return records[0] ?? null;
9788
9525
  }
9789
9526
  const rolloutMatch = await findRolloutFileByScan(profileHome, threadId);
9790
9527
  if (!rolloutMatch) {
@@ -10150,13 +9887,14 @@ async function readCdpTargets(port) {
10150
9887
  }
10151
9888
  throw lastError instanceof Error ? lastError : new Error("cdp-list-failed");
10152
9889
  }
10153
- function pickCodexCdpTarget(targets) {
9890
+ function pickCodexCdpTarget(targets, options = {}) {
10154
9891
  const pages = targets.filter(
10155
9892
  (target) => target.webSocketDebuggerUrl && (target.type === "page" || target.type === "webview" || !target.type)
10156
9893
  );
10157
- return pages.find(
9894
+ const codexPage = pages.find(
10158
9895
  (target) => `${target.title ?? ""} ${target.url ?? ""}`.toLowerCase().includes("codex")
10159
- ) ?? pages[0] ?? null;
9896
+ ) ?? null;
9897
+ return codexPage ?? (options.allowAnyPage === true ? pages[0] ?? null : null);
10160
9898
  }
10161
9899
  function buildCdpDevToolsUrl(port, target) {
10162
9900
  const frontendUrl = target.devtoolsFrontendUrl?.trim();
@@ -10500,6 +10238,8 @@ function buildInCodexStatusOverlayCssRules() {
10500
10238
  `${chip} .codexuse-handoff-hide{display:inline-flex;width:20px;height:20px;align-items:center;justify-content:center;margin-right:3px;border-radius:50%;color:var(--cu-muted);cursor:pointer;font-size:12px;line-height:1;}`,
10501
10239
  `${chip} .codexuse-handoff-hide:hover{background:var(--cu-border);color:var(--cu-fg,#ececf1);}`,
10502
10240
  `body>[data-radix-popper-content-wrapper],body>[data-floating-ui-portal]{z-index:2147483004!important;}`,
10241
+ // Official Codex marks its titlebar draggable; injected controls must opt out.
10242
+ `${id},${id} *,${chip},${chip} *,${picker},${picker} *{-webkit-app-region:no-drag;}`,
10503
10243
  // Hand-off account picker is a standalone body child (not inside the pill),
10504
10244
  // so the pill-scoped popover rules don't reach it — give it its own palette
10505
10245
  // + popover styling, mirroring the chip.
@@ -10881,6 +10621,7 @@ function createBridgeApplyQolExpression(settings) {
10881
10621
  const overlayPosKey = "codexuse:overlay:pos";
10882
10622
  const handoffHiddenKey = "codexuse:handoff:hidden";
10883
10623
  const handoffPosKey = "codexuse:handoff:pos:v2";
10624
+ const defaultPosKey = "codexuse:overlay:top-default:v1";
10884
10625
  const readOverlayStore = (key) => {
10885
10626
  try {
10886
10627
  return window.localStorage.getItem(key);
@@ -10975,8 +10716,8 @@ function createBridgeApplyQolExpression(settings) {
10975
10716
  };
10976
10717
  const placeInitialOverlayPosition = (pill) => {
10977
10718
  const rect = pill.getBoundingClientRect();
10978
- const x = Math.round((window.innerWidth - rect.width) / 2);
10979
- const y = Math.max(72, Math.min(140, Math.round(window.innerHeight * 0.16)));
10719
+ const x = Math.max(8, window.innerWidth - rect.width - 32);
10720
+ const y = Math.max(96, Math.min(132, Math.round(window.innerHeight * 0.12)));
10980
10721
  placeOverlay(pill, x, y);
10981
10722
  };
10982
10723
  const rectsOverlap = (a, b, gap = 0) =>
@@ -10990,30 +10731,17 @@ function createBridgeApplyQolExpression(settings) {
10990
10731
  right: pos.x + rect.width,
10991
10732
  bottom: pos.y + rect.height
10992
10733
  });
10993
- const placeInitialHandoffPosition = (chip, anchorRect = null) => {
10734
+ const placeInitialHandoffPosition = (chip) => {
10994
10735
  const rect = chip.getBoundingClientRect();
10995
- if (anchorRect && rect.width > 0 && rect.height > 0) {
10996
- const gap = 8;
10997
- const middleY = Math.round(anchorRect.top + (anchorRect.height - rect.height) / 2);
10998
- const candidates = [
10999
- { x: anchorRect.right + gap, y: middleY },
11000
- { x: anchorRect.left - rect.width - gap, y: middleY },
11001
- { x: anchorRect.right - rect.width, y: anchorRect.top - rect.height - gap },
11002
- { x: anchorRect.left, y: anchorRect.top - rect.height - gap },
11003
- { x: anchorRect.right - rect.width, y: anchorRect.bottom + gap }
11004
- ];
11005
- for (const candidate of candidates) {
11006
- const next = clampOverlayXY(chip, candidate.x, candidate.y);
11007
- if (!rectsOverlap(positionedRect(rect, next), anchorRect, 6)) {
11008
- placeOverlay(chip, next.x, next.y);
11009
- return;
11010
- }
11011
- }
11012
- }
11013
- const x = Math.max(8, window.innerWidth - rect.width - 16);
11014
- const y = Math.max(64, Math.min(128, Math.round(window.innerHeight * 0.14)));
10736
+ const x = Math.round((window.innerWidth - rect.width) / 2);
10737
+ const y = 14;
11015
10738
  placeOverlay(chip, x, y);
11016
10739
  };
10740
+ if (readOverlayStore(defaultPosKey) !== "1") {
10741
+ writeOverlayStore(overlayPosKey, null);
10742
+ writeOverlayStore(handoffPosKey, null);
10743
+ writeOverlayStore(defaultPosKey, "1");
10744
+ }
11017
10745
  const setOverlayMessage = (value) => {
11018
10746
  const node = document.querySelector("#" + statusId + " [data-codexuse-action-status]");
11019
10747
  if (node) node.textContent = value || "";
@@ -11143,7 +10871,8 @@ function createBridgeApplyQolExpression(settings) {
11143
10871
  renderHandoff();
11144
10872
  }, true);
11145
10873
  document.body.appendChild(pill);
11146
- applyStoredOverlayPosition(pill);
10874
+ if (hasStoredPosition) applyStoredOverlayPosition(pill);
10875
+ else placeInitialOverlayPosition(pill);
11147
10876
  return true;
11148
10877
  }
11149
10878
  pill.dataset.open = currentAutoRollDecision || wasOpen || shouldShowIntro ? "true" : "false";
@@ -11448,6 +11177,8 @@ function createBridgeApplyQolExpression(settings) {
11448
11177
  if (shouldShowIntro) {
11449
11178
  placeInitialOverlayPosition(pill);
11450
11179
  writeOverlayStore(overlayIntroKey, "1");
11180
+ } else if (!hasStoredPosition) {
11181
+ placeInitialOverlayPosition(pill);
11451
11182
  } else {
11452
11183
  applyStoredOverlayPosition(pill);
11453
11184
  }
@@ -11692,18 +11423,18 @@ function createBridgeApplyQolExpression(settings) {
11692
11423
  const next = clampOverlayXY(chip, pos.x, pos.y);
11693
11424
  const chipRect = chip.getBoundingClientRect();
11694
11425
  if (rectsOverlap(positionedRect(chipRect, next), rect, 6)) {
11695
- placeInitialHandoffPosition(chip, rect);
11426
+ placeInitialHandoffPosition(chip);
11696
11427
  } else {
11697
11428
  placeOverlay(chip, next.x, next.y);
11698
11429
  }
11699
11430
  } else {
11700
- placeInitialHandoffPosition(chip, rect);
11431
+ placeInitialHandoffPosition(chip);
11701
11432
  }
11702
11433
  } catch {
11703
- placeInitialHandoffPosition(chip, rect);
11434
+ placeInitialHandoffPosition(chip);
11704
11435
  }
11705
11436
  } else {
11706
- placeInitialHandoffPosition(chip, rect);
11437
+ placeInitialHandoffPosition(chip);
11707
11438
  }
11708
11439
  if (wasOpen) openPicker();
11709
11440
  reportHandoff("rendered");
@@ -12055,11 +11786,23 @@ function createBridgeApplyPowerExpression(settings, settingsExpression) {
12055
11786
  || typeof item.name === "string"
12056
11787
  )
12057
11788
  );
12058
- const patchModelArray = (items, allowEmpty = false) => {
11789
+ const modelLabelLooksKnown = (value) =>
11790
+ typeof value === "string" && /(?:gpt|codex|chatgpt|claude|gemini|llama|mistral|qwen|deepseek|grok|davinci|\\bo[1-9]\\b)/i.test(value);
11791
+ const objectArrayLooksModelLike = (items) =>
11792
+ objectArrayLooksPatchable(items)
11793
+ && items.some((item) =>
11794
+ modelLabelLooksKnown(item.model)
11795
+ || modelLabelLooksKnown(item.id)
11796
+ || modelLabelLooksKnown(item.slug)
11797
+ || modelLabelLooksKnown(item.name)
11798
+ || modelLabelLooksKnown(item.displayName)
11799
+ || modelLabelLooksKnown(item.title)
11800
+ );
11801
+ const patchModelArray = (items, allowEmpty = false, requireModelLike = false) => {
12059
11802
  if (!Array.isArray(items)) return false;
12060
11803
  let localChanged = false;
12061
- unhideArray(items);
12062
11804
  if (stringArrayLooksPatchable(items)) {
11805
+ if (requireModelLike && !items.some(modelLabelLooksKnown)) return false;
12063
11806
  for (const model of modelWhitelistModels) {
12064
11807
  if (!items.includes(model)) {
12065
11808
  items.push(model);
@@ -12068,7 +11811,8 @@ function createBridgeApplyPowerExpression(settings, settingsExpression) {
12068
11811
  }
12069
11812
  return localChanged;
12070
11813
  }
12071
- if (objectArrayLooksPatchable(items, allowEmpty)) {
11814
+ if (objectArrayLooksPatchable(items, allowEmpty) && (!requireModelLike || allowEmpty || objectArrayLooksModelLike(items))) {
11815
+ unhideArray(items);
12072
11816
  const existing = new Set();
12073
11817
  for (const item of items) {
12074
11818
  existing.add(String(item.model || item.id || item.slug || item.name || ""));
@@ -12083,8 +11827,8 @@ function createBridgeApplyPowerExpression(settings, settingsExpression) {
12083
11827
  return localChanged;
12084
11828
  };
12085
11829
  if (patchModelArray(value.models, "defaultModel" in value || "availableModels" in value)) changed = true;
12086
- if (patchModelArray(value.data)) changed = true;
12087
- if (patchModelArray(value.result)) changed = true;
11830
+ if (patchModelArray(value.data, false, true)) changed = true;
11831
+ if (patchModelArray(value.result, false, true)) changed = true;
12088
11832
  if (patchModelArray(value.availableModels, true)) changed = true;
12089
11833
  if (patchModelArray(value.available_models, true)) changed = true;
12090
11834
  if (value.available_models instanceof Set) {
@@ -12201,11 +11945,23 @@ function createBridgeApplyPowerExpression(settings, settingsExpression) {
12201
11945
  return changed;
12202
11946
  };
12203
11947
  const reactFiberKeys = (element) => Object.keys(element || {}).filter((key) => key.startsWith("__reactFiber") || key.startsWith("__reactInternalInstance") || key.startsWith("__reactProps"));
11948
+ const reactModelStatePatchSelector = "[role='menu'],[role='dialog'],[role='listbox'],[data-radix-popper-content-wrapper],[data-floating-ui-portal]";
11949
+ const isWorkspaceChromeNode = (node) => {
11950
+ if (!node || node.nodeType !== 1) return false;
11951
+ if (node.closest?.("[data-app-action-sidebar-section-heading='Chats'],[data-app-action-sidebar-section-heading='Projects'],[data-app-action-sidebar-thread-id],[data-app-action-sidebar-project-row],[data-app-action-sidebar-project-id]")) {
11952
+ return true;
11953
+ }
11954
+ return Boolean(node.closest?.("main aside"));
11955
+ };
11956
+ const reactModelStatePatchNodes = () => {
11957
+ return Array.from(document.querySelectorAll(reactModelStatePatchSelector))
11958
+ .filter((node) => node && !isWorkspaceChromeNode(node));
11959
+ };
12204
11960
  const patchReactModelState = () => {
12205
11961
  if (!enabled.modelWhitelistUnlock) return false;
12206
11962
  try {
12207
11963
  const visited = new WeakSet();
12208
- const nodes = [document.body, ...Array.from(document.querySelectorAll("button,[role='menu'],[role='dialog'],[data-radix-popper-content-wrapper]"))].filter(Boolean);
11964
+ const nodes = reactModelStatePatchNodes();
12209
11965
  let changed = false;
12210
11966
  for (const node of nodes.slice(0, 220)) {
12211
11967
  for (const key of reactFiberKeys(node)) {
@@ -12220,6 +11976,39 @@ function createBridgeApplyPowerExpression(settings, settingsExpression) {
12220
11976
  return false;
12221
11977
  }
12222
11978
  };
11979
+ const installModelReactStateObserver = () => {
11980
+ if (typeof state.cleanupModelReactStateObserver === "function") {
11981
+ state.cleanupModelReactStateObserver();
11982
+ state.cleanupModelReactStateObserver = null;
11983
+ }
11984
+ if (!enabled.modelWhitelistUnlock) return false;
11985
+ let frame = 0;
11986
+ const schedulePatch = () => {
11987
+ if (frame) return;
11988
+ frame = requestAnimationFrame(() => {
11989
+ frame = 0;
11990
+ patchReactModelState();
11991
+ });
11992
+ };
11993
+ const isPatchableMutationNode = (node) => {
11994
+ const element = node?.nodeType === 1 ? node : node?.parentElement;
11995
+ return Boolean(
11996
+ element?.matches?.(reactModelStatePatchSelector)
11997
+ || element?.querySelector?.(reactModelStatePatchSelector)
11998
+ );
11999
+ };
12000
+ const observer = new MutationObserver((mutations) => {
12001
+ if (mutations.some((mutation) => Array.from(mutation.addedNodes).some(isPatchableMutationNode))) {
12002
+ schedulePatch();
12003
+ }
12004
+ });
12005
+ observer.observe(document.body, { childList: true, subtree: true });
12006
+ state.cleanupModelReactStateObserver = () => {
12007
+ observer.disconnect();
12008
+ if (frame) cancelAnimationFrame(frame);
12009
+ };
12010
+ return true;
12011
+ };
12223
12012
  const patchPluginContainer = (value, visited = new WeakSet(), depth = 0, inheritedMarketplaceName = null) => {
12224
12013
  if (!enabled.pluginMarketplaceUnlock || !value || typeof value !== "object" || visited.has(value) || depth > 4) return false;
12225
12014
  visited.add(value);
@@ -12763,6 +12552,7 @@ function createBridgeApplyPowerExpression(settings, settingsExpression) {
12763
12552
  const modelStatsigPatchApplied = enabled.modelWhitelistUnlock
12764
12553
  ? patchStatsigModelWhitelist()
12765
12554
  : false;
12555
+ installModelReactStateObserver();
12766
12556
  const modelReactStatePatched = enabled.modelWhitelistUnlock
12767
12557
  ? patchReactModelState()
12768
12558
  : false;
@@ -13939,14 +13729,16 @@ async function reloadOfficialCodexBridgePage(debuggerUrl) {
13939
13729
  return false;
13940
13730
  }
13941
13731
  }
13942
- async function probeOfficialCodexBridge(instance, forceInstall = false) {
13732
+ async function probeOfficialCodexBridge(instance, forceInstall = false, allowAnyPageTarget = false) {
13943
13733
  const checkedAt = Date.now();
13944
13734
  if (!instance.cdpPort) {
13945
13735
  return bridgeStateUnavailable();
13946
13736
  }
13947
13737
  try {
13948
13738
  const targets = await readCdpTargets(instance.cdpPort);
13949
- const target = pickCodexCdpTarget(targets);
13739
+ const target = pickCodexCdpTarget(targets, {
13740
+ allowAnyPage: allowAnyPageTarget
13741
+ });
13950
13742
  if (!target?.webSocketDebuggerUrl) {
13951
13743
  return bridgeStateUnhealthy(
13952
13744
  instance.cdpPort,
@@ -14016,14 +13808,16 @@ async function probeOfficialCodexBridge(instance, forceInstall = false) {
14016
13808
  );
14017
13809
  }
14018
13810
  }
14019
- async function reapplyDesiredBridgeSettings(instance, bridge) {
13811
+ async function reapplyDesiredBridgeSettings(instance, bridge, allowAnyPageTarget = false) {
14020
13812
  const shouldClearPowerRuntime = !instance.desiredPowerSettings && hasEnabledBridgePowerRuntime(bridge.bridgePower);
14021
13813
  if (bridge.bridgeStatus !== "healthy" || !instance.cdpPort || !instance.desiredQolSettings && !instance.desiredPowerSettings && !shouldClearPowerRuntime) {
14022
13814
  return bridge;
14023
13815
  }
14024
13816
  try {
14025
13817
  const targets = await readCdpTargets(instance.cdpPort);
14026
- const target = pickCodexCdpTarget(targets);
13818
+ const target = pickCodexCdpTarget(targets, {
13819
+ allowAnyPage: allowAnyPageTarget
13820
+ });
14027
13821
  if (!target?.webSocketDebuggerUrl) {
14028
13822
  return bridge;
14029
13823
  }
@@ -14109,7 +13903,7 @@ async function reapplyDesiredBridgeSettings(instance, bridge) {
14109
13903
  };
14110
13904
  }
14111
13905
  }
14112
- async function refreshBridgeStateIfNeeded(instance, running, force = false, reapplyDesired = false) {
13906
+ async function refreshBridgeStateIfNeeded(instance, running, force = false, reapplyDesired = false, allowAnyPageTarget = false) {
14113
13907
  if (!running || !instance.cdpPort) {
14114
13908
  return bridgeStateUnavailable();
14115
13909
  }
@@ -14117,12 +13911,16 @@ async function refreshBridgeStateIfNeeded(instance, running, force = false, reap
14117
13911
  if (!force && checkedAt && Date.now() - checkedAt < CODEX_BRIDGE_PROBE_TTL_MS) {
14118
13912
  return bridgeStateForStoredInstance(instance, true);
14119
13913
  }
14120
- const bridge = await probeOfficialCodexBridge(instance, force);
14121
- return reapplyDesired ? await reapplyDesiredBridgeSettings(instance, bridge) : bridge;
13914
+ const bridge = await probeOfficialCodexBridge(
13915
+ instance,
13916
+ force,
13917
+ allowAnyPageTarget
13918
+ );
13919
+ return reapplyDesired ? await reapplyDesiredBridgeSettings(instance, bridge, allowAnyPageTarget) : bridge;
14122
13920
  }
14123
13921
  async function waitForBridgeStateAfterLaunch(instance) {
14124
13922
  const deadline = Date.now() + CODEX_BRIDGE_LAUNCH_WAIT_MS;
14125
- let latest = await refreshBridgeStateIfNeeded(instance, true, true, true);
13923
+ let latest = await refreshBridgeStateIfNeeded(instance, true, true, true, true);
14126
13924
  while (latest.bridgeStatus !== "healthy" && Date.now() < deadline) {
14127
13925
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
14128
13926
  latest = await refreshBridgeStateIfNeeded(
@@ -14132,6 +13930,7 @@ async function waitForBridgeStateAfterLaunch(instance) {
14132
13930
  },
14133
13931
  true,
14134
13932
  true,
13933
+ true,
14135
13934
  true
14136
13935
  );
14137
13936
  }
@@ -14140,7 +13939,7 @@ async function waitForBridgeStateAfterLaunch(instance) {
14140
13939
  async function waitForBridgeStateAfterReload(instance) {
14141
13940
  const deadline = Date.now() + CODEX_BRIDGE_LAUNCH_WAIT_MS;
14142
13941
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
14143
- let latest = await refreshBridgeStateIfNeeded(instance, true, true, true);
13942
+ let latest = await refreshBridgeStateIfNeeded(instance, true, true, true, true);
14144
13943
  while (latest.bridgeStatus !== "healthy" && Date.now() < deadline) {
14145
13944
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
14146
13945
  latest = await refreshBridgeStateIfNeeded(
@@ -14150,6 +13949,7 @@ async function waitForBridgeStateAfterReload(instance) {
14150
13949
  },
14151
13950
  true,
14152
13951
  true,
13952
+ true,
14153
13953
  true
14154
13954
  );
14155
13955
  }
@@ -14519,7 +14319,7 @@ async function openCodexWithProfileHome(candidate, profileHome, profileName, cdp
14519
14319
  ],
14520
14320
  {
14521
14321
  detached: true,
14522
- env: process.env,
14322
+ env: buildCodexChildEnv(),
14523
14323
  stdio: "ignore"
14524
14324
  }
14525
14325
  );
@@ -15487,7 +15287,7 @@ function summarizeRateLimitSnapshot(snapshot) {
15487
15287
  return summary;
15488
15288
  }
15489
15289
  function fallbackUsage(profile) {
15490
- const usageSummary = summarizeRateLimitSnapshot(profile.rateLimit ?? null);
15290
+ const usageSummary = summarizeRateLimitSnapshot(null);
15491
15291
  if (!profile.isValid) {
15492
15292
  return { summary: "invalid", rows: null, usageSummary };
15493
15293
  }
@@ -15503,8 +15303,7 @@ async function resolveProfileUsage(manager, profile, codexPath) {
15503
15303
  try {
15504
15304
  const snapshot = await manager.readLiveRateLimits(profile.name, { codexPath });
15505
15305
  if (!snapshot) {
15506
- const usageSummary = summarizeRateLimitSnapshot(profile.rateLimit ?? null);
15507
- return { summary: "n/a", rows: null, usageSummary };
15306
+ return fallbackUsage(profile);
15508
15307
  }
15509
15308
  const rows = [];
15510
15309
  if (snapshot.primary) {
@@ -15556,7 +15355,7 @@ function computeAutoRollCandidate(profiles, usageMap, currentProfileName, curren
15556
15355
  (profile) => profile.name !== currentProfileName && !blockedProfileNames.has(profile.name) && profile.isValid && !profile.tokenStatus?.requiresUserAction
15557
15356
  ).map((profile) => ({
15558
15357
  profile,
15559
- usageSummary: usageMap.get(profile.name)?.usageSummary ?? summarizeRateLimitSnapshot(profile.rateLimit ?? null)
15358
+ usageSummary: usageMap.get(profile.name)?.usageSummary ?? summarizeRateLimitSnapshot(null)
15560
15359
  }));
15561
15360
  if (candidates.length === 0) {
15562
15361
  return null;
@@ -15971,7 +15770,7 @@ async function runAutoRollPass(manager, options) {
15971
15770
  target: null
15972
15771
  };
15973
15772
  }
15974
- const currentUsage = usageMap.get(current.name)?.usageSummary ?? summarizeRateLimitSnapshot(currentProfile.rateLimit ?? null);
15773
+ const currentUsage = usageMap.get(current.name)?.usageSummary ?? summarizeRateLimitSnapshot(null);
15975
15774
  if (!currentUsage.hasUsage) {
15976
15775
  return {
15977
15776
  switched: false,
@@ -16089,7 +15888,7 @@ async function handleProfileCommand(args, version) {
16089
15888
  usageMap.set(profile.name, {
16090
15889
  summary: "codex cli missing",
16091
15890
  rows: null,
16092
- usageSummary: summarizeRateLimitSnapshot(profile.rateLimit ?? null)
15891
+ usageSummary: summarizeRateLimitSnapshot(null)
16093
15892
  });
16094
15893
  }
16095
15894
  } else {
@@ -16460,7 +16259,7 @@ async function pushRemoteSnapshot(access, snapshot, options) {
16460
16259
  }
16461
16260
 
16462
16261
  // ../../packages/runtime-codex/src/codex/config.ts
16463
- var import_toml3 = __toESM(require_toml(), 1);
16262
+ var import_toml2 = __toESM(require_toml(), 1);
16464
16263
 
16465
16264
  // ../../packages/runtime-codex/src/codex/config-metadata.ts
16466
16265
  var import_node_child_process8 = require("child_process");
@@ -16577,7 +16376,7 @@ async function runCommand3(command, args, timeoutMs = 3e3) {
16577
16376
  return new Promise((resolve, reject) => {
16578
16377
  const child = (0, import_node_child_process8.spawn)(command, args, {
16579
16378
  stdio: ["ignore", "pipe", "pipe"],
16580
- env: process.env
16379
+ env: buildCodexChildEnv()
16581
16380
  });
16582
16381
  let stdout = "";
16583
16382
  let stderr = "";
@@ -17099,7 +16898,7 @@ function formatUserFacingError(error, options = {}) {
17099
16898
  // ../../packages/runtime-codex/src/codex/config.ts
17100
16899
  function tryParseToml(content) {
17101
16900
  try {
17102
- const parsed = (0, import_toml3.parse)(content);
16901
+ const parsed = (0, import_toml2.parse)(content);
17103
16902
  return { data: parsed ?? {}, error: null };
17104
16903
  } catch (error) {
17105
16904
  const maybe = error;
@@ -18138,7 +17937,7 @@ async function ensureCliStorageReady() {
18138
17937
  }
18139
17938
 
18140
17939
  // src/app/main.ts
18141
- var VERSION = true ? "5.1.1" : "0.0.0";
17940
+ var VERSION = true ? "5.1.6" : "0.0.0";
18142
17941
  async function runCli() {
18143
17942
  const args = process.argv.slice(2);
18144
17943
  if (args.length === 0) {