codexuse-cli 5.1.0 → 5.1.5

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
@@ -2022,7 +2022,7 @@ var require_toml = __commonJS({
2022
2022
  });
2023
2023
 
2024
2024
  // src/commands/accountPool.ts
2025
- var import_node_crypto4 = require("crypto");
2025
+ var import_node_crypto7 = require("crypto");
2026
2026
  var import_node_path7 = __toESM(require("path"));
2027
2027
 
2028
2028
  // ../../packages/contracts/src/settings/types.ts
@@ -2366,7 +2366,7 @@ async function withDatabase(dbPath, task) {
2366
2366
  function resolveAppStorageDbPath(userDataDir) {
2367
2367
  return import_node_path.default.join(userDataDir, APP_STORAGE_DB_DIR, APP_STORAGE_DB_NAME);
2368
2368
  }
2369
- async function readDocument(dbPath, namespace, normalize) {
2369
+ async function readDocument(dbPath, namespace, normalize2) {
2370
2370
  return withDatabase(dbPath, (db) => {
2371
2371
  const row = useStatement(
2372
2372
  db,
@@ -2377,10 +2377,10 @@ async function readDocument(dbPath, namespace, normalize) {
2377
2377
  if (parsed === null) {
2378
2378
  return null;
2379
2379
  }
2380
- return normalize(parsed);
2380
+ return normalize2(parsed);
2381
2381
  });
2382
2382
  }
2383
- async function readDocumentStrict(dbPath, namespace, normalize) {
2383
+ async function readDocumentStrict(dbPath, namespace, normalize2) {
2384
2384
  return withDatabase(dbPath, (db) => {
2385
2385
  const row = useStatement(
2386
2386
  db,
@@ -2401,7 +2401,7 @@ async function readDocumentStrict(dbPath, namespace, normalize) {
2401
2401
  );
2402
2402
  }
2403
2403
  try {
2404
- return normalize(parsed);
2404
+ return normalize2(parsed);
2405
2405
  } catch (error) {
2406
2406
  throw new AppStorageCorruptionError(
2407
2407
  `App storage document ${namespace} failed normalization.`,
@@ -2480,6 +2480,25 @@ async function updateDocument(input) {
2480
2480
  })
2481
2481
  );
2482
2482
  }
2483
+ async function deleteDocument(dbPath, namespace) {
2484
+ await withWriteQueue(
2485
+ dbPath,
2486
+ async () => withDatabase(dbPath, (db) => {
2487
+ beginImmediate(db);
2488
+ try {
2489
+ useStatement(
2490
+ db,
2491
+ `DELETE FROM ${APP_STORAGE_TABLE} WHERE namespace = ?`,
2492
+ (statement) => statement.run(namespace)
2493
+ );
2494
+ commit(db);
2495
+ } catch (error) {
2496
+ rollback(db);
2497
+ throw error;
2498
+ }
2499
+ })
2500
+ );
2501
+ }
2483
2502
 
2484
2503
  // ../../packages/runtime-app-state/src/app/state.ts
2485
2504
  var APP_STATE_DOCUMENT = "desktop.app-state";
@@ -2564,6 +2583,16 @@ function createDefaultAppState() {
2564
2583
  status: "inactive",
2565
2584
  signature: null
2566
2585
  },
2586
+ trial: {
2587
+ deviceId: null,
2588
+ startedAt: null,
2589
+ expiresAt: null,
2590
+ lastServerCheckAt: null,
2591
+ lastLocalSeenAt: null,
2592
+ offlineGraceUntil: null,
2593
+ serverExpired: false,
2594
+ signature: null
2595
+ },
2567
2596
  preferences: {
2568
2597
  excludeFolders: [],
2569
2598
  enableTaskCompleteBeep: true,
@@ -3011,6 +3040,25 @@ function normalizeAppState(raw) {
3011
3040
  if (!["inactive", "active", "grace", "error"].includes(merged.license.status)) {
3012
3041
  merged.license.status = "inactive";
3013
3042
  }
3043
+ if (!isRecord2(merged.trial)) {
3044
+ merged.trial = clone2(defaults.trial);
3045
+ }
3046
+ merged.trial.deviceId = asString(merged.trial.deviceId);
3047
+ merged.trial.startedAt = asString(merged.trial.startedAt);
3048
+ merged.trial.expiresAt = asString(merged.trial.expiresAt);
3049
+ merged.trial.lastServerCheckAt = asString(merged.trial.lastServerCheckAt);
3050
+ merged.trial.lastLocalSeenAt = asString(merged.trial.lastLocalSeenAt);
3051
+ merged.trial.offlineGraceUntil = asString(merged.trial.offlineGraceUntil);
3052
+ merged.trial.serverExpired = merged.trial.serverExpired === true;
3053
+ merged.trial.signature = asString(merged.trial.signature);
3054
+ {
3055
+ const allowedTrialKeys = new Set(Object.keys(defaults.trial));
3056
+ for (const key of Object.keys(merged.trial)) {
3057
+ if (!allowedTrialKeys.has(key)) {
3058
+ delete merged.trial[key];
3059
+ }
3060
+ }
3061
+ }
3014
3062
  if (!Array.isArray(merged.preferences.excludeFolders)) {
3015
3063
  merged.preferences.excludeFolders = [];
3016
3064
  }
@@ -3416,7 +3464,7 @@ async function writeAppSettings(settings, onUpdated) {
3416
3464
  }
3417
3465
 
3418
3466
  // ../../packages/runtime-profiles/src/license/service.ts
3419
- var import_node_crypto2 = __toESM(require("crypto"), 1);
3467
+ var import_node_crypto5 = __toESM(require("crypto"), 1);
3420
3468
 
3421
3469
  // ../../packages/runtime-codex/src/codex/settings.ts
3422
3470
  function asString2(value) {
@@ -3459,6 +3507,53 @@ function parseStoredLicense(raw) {
3459
3507
  );
3460
3508
  return hasValue ? license : null;
3461
3509
  }
3510
+ function parseStoredTrial(raw) {
3511
+ if (!isRecord3(raw)) {
3512
+ return null;
3513
+ }
3514
+ const trial = {
3515
+ deviceId: asString2(raw.deviceId ?? raw.device_id),
3516
+ startedAt: asString2(raw.startedAt ?? raw.started_at),
3517
+ expiresAt: asString2(raw.expiresAt ?? raw.expires_at),
3518
+ lastServerCheckAt: asString2(raw.lastServerCheckAt ?? raw.last_server_check_at),
3519
+ lastLocalSeenAt: asString2(raw.lastLocalSeenAt ?? raw.last_local_seen_at),
3520
+ offlineGraceUntil: asString2(raw.offlineGraceUntil ?? raw.offline_grace_until),
3521
+ serverExpired: raw.serverExpired === true || raw.server_expired === true,
3522
+ signature: asString2(raw.signature)
3523
+ };
3524
+ const hasValue = Boolean(
3525
+ trial.deviceId || trial.startedAt || trial.expiresAt || trial.lastServerCheckAt || trial.lastLocalSeenAt || trial.serverExpired || trial.signature
3526
+ );
3527
+ return hasValue ? trial : null;
3528
+ }
3529
+ async function getStoredTrial() {
3530
+ const state = await getAppState();
3531
+ return parseStoredTrial(state.trial);
3532
+ }
3533
+ async function persistTrial(trial) {
3534
+ const parsed = parseStoredTrial(trial);
3535
+ await patchAppState({
3536
+ trial: parsed ? {
3537
+ deviceId: parsed.deviceId ?? null,
3538
+ startedAt: parsed.startedAt ?? null,
3539
+ expiresAt: parsed.expiresAt ?? null,
3540
+ lastServerCheckAt: parsed.lastServerCheckAt ?? null,
3541
+ lastLocalSeenAt: parsed.lastLocalSeenAt ?? null,
3542
+ offlineGraceUntil: parsed.offlineGraceUntil ?? null,
3543
+ serverExpired: parsed.serverExpired === true,
3544
+ signature: parsed.signature ?? null
3545
+ } : {
3546
+ deviceId: null,
3547
+ startedAt: null,
3548
+ expiresAt: null,
3549
+ lastServerCheckAt: null,
3550
+ lastLocalSeenAt: null,
3551
+ offlineGraceUntil: null,
3552
+ serverExpired: false,
3553
+ signature: null
3554
+ }
3555
+ });
3556
+ }
3462
3557
  async function getStoredLicense() {
3463
3558
  const state = await getAppState();
3464
3559
  return parseStoredLicense(state.license);
@@ -3590,7 +3685,9 @@ function getActiveOffer() {
3590
3685
  isActive: true,
3591
3686
  campaign: "summer-2026",
3592
3687
  productPermalink: "codex-use",
3593
- checkoutBaseUrl: "https://hweihwang.gumroad.com/l/codex-use"
3688
+ checkoutBaseUrl: "https://hweihwang.gumroad.com/l/codex-use",
3689
+ trialEnabled: true,
3690
+ trialDays: 7
3594
3691
  };
3595
3692
  }
3596
3693
  function buildCheckoutUrl(offer2, options) {
@@ -3613,6 +3710,504 @@ function buildCheckoutUrl(offer2, options) {
3613
3710
  return url.toString();
3614
3711
  }
3615
3712
 
3713
+ // ../../packages/runtime-profiles/src/license/trial.ts
3714
+ var import_node_crypto4 = __toESM(require("crypto"), 1);
3715
+
3716
+ // ../../packages/runtime-profiles/src/license/device-id.ts
3717
+ var import_node_crypto2 = __toESM(require("crypto"), 1);
3718
+ var import_promises = require("fs/promises");
3719
+ var import_node_child_process = require("child_process");
3720
+ var import_node_util = require("util");
3721
+ var DEVICE_ID_DOCUMENT = "desktop.device-id";
3722
+ var SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/i;
3723
+ var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
3724
+ var memoizedDeviceId = null;
3725
+ function normalize(value) {
3726
+ return typeof value === "string" ? value.trim() : "";
3727
+ }
3728
+ async function readHardwareUuid() {
3729
+ if (process.platform !== "darwin") {
3730
+ return null;
3731
+ }
3732
+ try {
3733
+ const { stdout } = await execFileAsync(
3734
+ "ioreg",
3735
+ ["-rd1", "-c", "IOPlatformExpertDevice"],
3736
+ { timeout: 4e3 }
3737
+ );
3738
+ const match = stdout.match(/"IOPlatformUUID"\s*=\s*"([^"]+)"/);
3739
+ return normalize(match?.[1]) || null;
3740
+ } catch {
3741
+ return null;
3742
+ }
3743
+ }
3744
+ async function readLinuxMachineId() {
3745
+ if (process.platform !== "linux") {
3746
+ return null;
3747
+ }
3748
+ for (const file of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
3749
+ try {
3750
+ const value = normalize(await (0, import_promises.readFile)(file, "utf8"));
3751
+ if (value) {
3752
+ return value;
3753
+ }
3754
+ } catch {
3755
+ }
3756
+ }
3757
+ return null;
3758
+ }
3759
+ function hashDeviceComponent(value) {
3760
+ return import_node_crypto2.default.createHash("sha256").update(`codexuse-device:${value}`).digest("hex");
3761
+ }
3762
+ async function getDeviceId() {
3763
+ if (memoizedDeviceId) {
3764
+ return memoizedDeviceId;
3765
+ }
3766
+ const dbPath = resolveAppStorageDbPath(getUserDataDir());
3767
+ const cached = normalize(await readDocument(dbPath, DEVICE_ID_DOCUMENT, normalize));
3768
+ const stableDeviceSource = await readHardwareUuid() ?? await readLinuxMachineId();
3769
+ if (stableDeviceSource) {
3770
+ const deviceId2 = hashDeviceComponent(stableDeviceSource);
3771
+ if (cached !== deviceId2) {
3772
+ await writeDocument(dbPath, DEVICE_ID_DOCUMENT, deviceId2);
3773
+ }
3774
+ memoizedDeviceId = deviceId2;
3775
+ return deviceId2;
3776
+ }
3777
+ if (SHA256_HEX_PATTERN.test(cached)) {
3778
+ memoizedDeviceId = cached;
3779
+ return cached;
3780
+ }
3781
+ const seed = import_node_crypto2.default.randomBytes(32).toString("hex");
3782
+ const deviceId = hashDeviceComponent(seed);
3783
+ await writeDocument(dbPath, DEVICE_ID_DOCUMENT, deviceId);
3784
+ memoizedDeviceId = deviceId;
3785
+ return deviceId;
3786
+ }
3787
+ function hashEmail(email) {
3788
+ const normalized = typeof email === "string" ? email.trim().toLowerCase() : "";
3789
+ if (!normalized) {
3790
+ return null;
3791
+ }
3792
+ return import_node_crypto2.default.createHash("sha256").update(`codexuse-email:${normalized}`).digest("hex");
3793
+ }
3794
+
3795
+ // ../../packages/runtime-profiles/src/license/trial-client.ts
3796
+ var DEFAULT_API_BASE_URL = "https://api.codexuse.com";
3797
+ var TRIAL_REQUEST_TIMEOUT_MS = 1e4;
3798
+ function getApiBaseUrl() {
3799
+ return DEFAULT_API_BASE_URL;
3800
+ }
3801
+ function parseResponse(raw) {
3802
+ if (!raw || typeof raw !== "object") {
3803
+ return null;
3804
+ }
3805
+ const record = raw;
3806
+ const serverNow = typeof record.serverNow === "string" ? record.serverNow : null;
3807
+ if (!serverNow) {
3808
+ return null;
3809
+ }
3810
+ return {
3811
+ trialActive: record.trialActive === true,
3812
+ startedAt: typeof record.startedAt === "string" ? record.startedAt : null,
3813
+ expiresAt: typeof record.expiresAt === "string" ? record.expiresAt : null,
3814
+ trialToken: typeof record.trialToken === "string" ? record.trialToken : null,
3815
+ serverNow,
3816
+ offlineGraceMs: typeof record.offlineGraceMs === "number" && Number.isFinite(record.offlineGraceMs) ? record.offlineGraceMs : 0
3817
+ };
3818
+ }
3819
+ async function registerTrialWithServer(input) {
3820
+ const controller = new AbortController();
3821
+ const timeout = setTimeout(() => controller.abort(), TRIAL_REQUEST_TIMEOUT_MS);
3822
+ try {
3823
+ const response = await fetch(`${getApiBaseUrl()}/v1/trial/register`, {
3824
+ method: "POST",
3825
+ headers: { "Content-Type": "application/json" },
3826
+ body: JSON.stringify({
3827
+ deviceId: input.deviceId,
3828
+ emailHash: input.emailHash ?? null,
3829
+ trialToken: input.trialToken ?? null
3830
+ }),
3831
+ signal: controller.signal
3832
+ });
3833
+ if (!response.ok) {
3834
+ throw new Error(`Trial registration failed (${response.status}).`);
3835
+ }
3836
+ const parsed = parseResponse(await response.json());
3837
+ if (!parsed) {
3838
+ throw new Error("Trial registration response was incomplete.");
3839
+ }
3840
+ return parsed;
3841
+ } finally {
3842
+ clearTimeout(timeout);
3843
+ }
3844
+ }
3845
+
3846
+ // ../../packages/runtime-profiles/src/license/trial-token-store.ts
3847
+ var import_node_crypto3 = require("crypto");
3848
+ var import_node_child_process2 = require("child_process");
3849
+ var KEYCHAIN_SERVICE = "CODEXUSE_TRIAL_TOKEN";
3850
+ var KEYCHAIN_ACCOUNT_PREFIX = "device-sha256:";
3851
+ var FALLBACK_DOCUMENT_PREFIX = "desktop.trial-token.";
3852
+ function keychainAccountForDevice(deviceId) {
3853
+ const digest = (0, import_node_crypto3.createHash)("sha256").update(deviceId).digest("hex");
3854
+ return KEYCHAIN_ACCOUNT_PREFIX + digest;
3855
+ }
3856
+ function fallbackDocumentForDevice(deviceId) {
3857
+ const digest = (0, import_node_crypto3.createHash)("sha256").update(deviceId).digest("hex");
3858
+ return FALLBACK_DOCUMENT_PREFIX + digest;
3859
+ }
3860
+ function normalizeToken(value) {
3861
+ const trimmed = typeof value === "string" ? value.trim() : "";
3862
+ return trimmed.length > 0 ? trimmed : null;
3863
+ }
3864
+ function runSecurityCommand(args) {
3865
+ return new Promise((resolve, reject) => {
3866
+ const child = (0, import_node_child_process2.spawn)("security", args, { stdio: ["ignore", "pipe", "ignore"] });
3867
+ let stdout = "";
3868
+ child.stdout?.on("data", (chunk) => {
3869
+ stdout += String(chunk);
3870
+ });
3871
+ child.on("error", () => {
3872
+ reject(new Error("keychain-command-failed"));
3873
+ });
3874
+ child.on("close", (code) => {
3875
+ resolve({ code, stdout });
3876
+ });
3877
+ });
3878
+ }
3879
+ async function readStoredTrialToken(deviceId) {
3880
+ if (process.platform !== "darwin") {
3881
+ const dbPath = resolveAppStorageDbPath(getUserDataDir());
3882
+ return readDocument(
3883
+ dbPath,
3884
+ fallbackDocumentForDevice(deviceId),
3885
+ normalizeToken
3886
+ );
3887
+ }
3888
+ const result = await runSecurityCommand([
3889
+ "find-generic-password",
3890
+ "-a",
3891
+ keychainAccountForDevice(deviceId),
3892
+ "-s",
3893
+ KEYCHAIN_SERVICE,
3894
+ "-w"
3895
+ ]).catch(() => null);
3896
+ await deleteDocument(
3897
+ resolveAppStorageDbPath(getUserDataDir()),
3898
+ fallbackDocumentForDevice(deviceId)
3899
+ ).catch(() => void 0);
3900
+ if (!result || result.code !== 0) {
3901
+ return null;
3902
+ }
3903
+ return result.stdout.length > 0 ? result.stdout.replace(/\n$/, "") : null;
3904
+ }
3905
+ async function writeStoredTrialToken(deviceId, token) {
3906
+ const value = typeof token === "string" ? token.trim() : "";
3907
+ if (!value) {
3908
+ return;
3909
+ }
3910
+ if (process.platform !== "darwin") {
3911
+ const dbPath = resolveAppStorageDbPath(getUserDataDir());
3912
+ await writeDocument(
3913
+ dbPath,
3914
+ fallbackDocumentForDevice(deviceId),
3915
+ value
3916
+ );
3917
+ return;
3918
+ }
3919
+ const result = await runSecurityCommand([
3920
+ "add-generic-password",
3921
+ "-U",
3922
+ "-a",
3923
+ keychainAccountForDevice(deviceId),
3924
+ "-s",
3925
+ KEYCHAIN_SERVICE,
3926
+ "-w",
3927
+ value
3928
+ ]).catch(() => null);
3929
+ await deleteDocument(
3930
+ resolveAppStorageDbPath(getUserDataDir()),
3931
+ fallbackDocumentForDevice(deviceId)
3932
+ ).catch(() => void 0);
3933
+ if (!result || result.code !== 0) {
3934
+ throw new Error("trial-token-keychain-write-failed");
3935
+ }
3936
+ }
3937
+
3938
+ // ../../packages/runtime-profiles/src/license/trial.ts
3939
+ var DAY_MS = 24 * 60 * 60 * 1e3;
3940
+ var TRIAL_SERVER_REFRESH_MS = 15 * 60 * 1e3;
3941
+ var TRIAL_BACKGROUND_RETRY_MS = 60 * 1e3;
3942
+ var CLOCK_ROLLBACK_TOLERANCE_MS = 5 * 60 * 1e3;
3943
+ var verifiedTrialCache = null;
3944
+ var backgroundTrialSyncPromise = null;
3945
+ var nextBackgroundTrialSyncAtMs = 0;
3946
+ function isTrialEnforcementEnabled() {
3947
+ return true;
3948
+ }
3949
+ function trialSignaturePayload(trial) {
3950
+ return JSON.stringify({
3951
+ deviceId: trial.deviceId ?? null,
3952
+ startedAt: trial.startedAt ?? null,
3953
+ expiresAt: trial.expiresAt ?? null,
3954
+ lastServerCheckAt: trial.lastServerCheckAt ?? null,
3955
+ lastLocalSeenAt: trial.lastLocalSeenAt ?? null,
3956
+ offlineGraceUntil: trial.offlineGraceUntil ?? null,
3957
+ serverExpired: trial.serverExpired === true
3958
+ });
3959
+ }
3960
+ function signTrial(trial, secret) {
3961
+ return import_node_crypto4.default.createHmac("sha256", secret).update(trialSignaturePayload(trial)).digest("hex");
3962
+ }
3963
+ function withTrialSignature(trial, secret) {
3964
+ return { ...trial, signature: signTrial(trial, secret) };
3965
+ }
3966
+ function isSignatureValid(trial, secret) {
3967
+ return Boolean(trial.signature) && signTrial(trial, secret) === trial.signature;
3968
+ }
3969
+ function parseTs(value) {
3970
+ if (typeof value !== "string" || value.trim() === "") {
3971
+ return null;
3972
+ }
3973
+ const parsed = Date.parse(value);
3974
+ return Number.isNaN(parsed) ? null : parsed;
3975
+ }
3976
+ function buildTrialInfo(stored, now) {
3977
+ const expiresAtMs = parseTs(stored?.expiresAt);
3978
+ const expired = stored?.serverExpired === true || expiresAtMs === null || expiresAtMs <= now;
3979
+ const daysLeft = expired || expiresAtMs === null ? 0 : Math.max(0, Math.ceil((expiresAtMs - now) / DAY_MS));
3980
+ return {
3981
+ active: !expired,
3982
+ expired,
3983
+ expiresAt: stored?.expiresAt ?? null,
3984
+ daysLeft
3985
+ };
3986
+ }
3987
+ function buildLockedTrialInfo(stored) {
3988
+ return {
3989
+ active: false,
3990
+ expired: true,
3991
+ expiresAt: stored?.expiresAt ?? null,
3992
+ daysLeft: 0
3993
+ };
3994
+ }
3995
+ function hasTrustedServerRecord(stored, secret, deviceId) {
3996
+ return Boolean(
3997
+ stored && stored.deviceId === deviceId && stored.startedAt && stored.lastServerCheckAt && isSignatureValid(stored, secret)
3998
+ );
3999
+ }
4000
+ function shouldRefreshInBackground(stored, now) {
4001
+ const lastServerCheckMs = parseTs(stored.lastServerCheckAt);
4002
+ return lastServerCheckMs !== null && now - lastServerCheckMs >= TRIAL_SERVER_REFRESH_MS;
4003
+ }
4004
+ function hasLocalClockRollback(stored, now) {
4005
+ const lastTrustedMs = Math.max(
4006
+ parseTs(stored.lastLocalSeenAt) ?? 0,
4007
+ parseTs(stored.lastServerCheckAt) ?? 0
4008
+ );
4009
+ return lastTrustedMs > 0 && now + CLOCK_ROLLBACK_TOLERANCE_MS < lastTrustedMs;
4010
+ }
4011
+ function canUseOfflineTrial(stored, now) {
4012
+ if (stored.serverExpired === true || hasLocalClockRollback(stored, now)) {
4013
+ return false;
4014
+ }
4015
+ const expiresAtMs = parseTs(stored.expiresAt);
4016
+ const offlineGraceUntilMs = parseTs(stored.offlineGraceUntil);
4017
+ const effectiveNow = trustedTrialNow(stored, now);
4018
+ if (expiresAtMs === null || offlineGraceUntilMs === null) {
4019
+ return false;
4020
+ }
4021
+ return effectiveNow < expiresAtMs && effectiveNow <= offlineGraceUntilMs;
4022
+ }
4023
+ function trustedTrialNow(stored, now) {
4024
+ return Math.max(now, parseTs(stored.lastServerCheckAt) ?? now);
4025
+ }
4026
+ async function persistLocalSeenIfNeeded(stored, secret, now) {
4027
+ const lastLocalSeenMs = parseTs(stored.lastLocalSeenAt);
4028
+ if (lastLocalSeenMs !== null && now - lastLocalSeenMs < TRIAL_SERVER_REFRESH_MS) {
4029
+ return stored;
4030
+ }
4031
+ const next = withTrialSignature(
4032
+ {
4033
+ ...stored,
4034
+ lastLocalSeenAt: new Date(Math.max(now, lastLocalSeenMs ?? 0)).toISOString()
4035
+ },
4036
+ secret
4037
+ );
4038
+ await persistTrial(next);
4039
+ return next;
4040
+ }
4041
+ function startTrialSyncInBackground() {
4042
+ const now = Date.now();
4043
+ if (backgroundTrialSyncPromise || now < nextBackgroundTrialSyncAtMs) {
4044
+ return;
4045
+ }
4046
+ nextBackgroundTrialSyncAtMs = now + TRIAL_BACKGROUND_RETRY_MS;
4047
+ backgroundTrialSyncPromise = syncTrialWithServer({ force: true }).catch(() => false).finally(() => {
4048
+ backgroundTrialSyncPromise = null;
4049
+ });
4050
+ }
4051
+ async function resolveFirstProfileEmailHash() {
4052
+ try {
4053
+ const state = await getAppState();
4054
+ for (const record of Object.values(state.profilesByName ?? {})) {
4055
+ const hashed = hashEmail(record.email ?? null);
4056
+ if (hashed) {
4057
+ return hashed;
4058
+ }
4059
+ }
4060
+ } catch {
4061
+ }
4062
+ return null;
4063
+ }
4064
+ function signedServerTrial(input) {
4065
+ const serverNowMs = parseTs(input.response.serverNow) ?? input.now;
4066
+ return withTrialSignature(
4067
+ {
4068
+ deviceId: input.deviceId,
4069
+ startedAt: input.response.startedAt ?? input.stored?.startedAt ?? new Date(serverNowMs).toISOString(),
4070
+ expiresAt: input.response.expiresAt ?? input.stored?.expiresAt ?? null,
4071
+ lastServerCheckAt: input.response.serverNow,
4072
+ lastLocalSeenAt: new Date(input.now).toISOString(),
4073
+ offlineGraceUntil: new Date(serverNowMs + input.response.offlineGraceMs).toISOString(),
4074
+ serverExpired: input.response.trialActive === false
4075
+ },
4076
+ input.secret
4077
+ );
4078
+ }
4079
+ async function syncAndPersistTrial(input) {
4080
+ let deviceId;
4081
+ try {
4082
+ deviceId = await getDeviceId();
4083
+ } catch {
4084
+ return null;
4085
+ }
4086
+ const emailHash = input.emailHash ?? await resolveFirstProfileEmailHash();
4087
+ try {
4088
+ const trialToken = await readStoredTrialToken(deviceId).catch(() => null);
4089
+ const response = await registerTrialWithServer({ deviceId, emailHash, trialToken });
4090
+ if (response.trialToken) {
4091
+ try {
4092
+ await writeStoredTrialToken(deviceId, response.trialToken);
4093
+ } catch {
4094
+ if (!trialToken) {
4095
+ return null;
4096
+ }
4097
+ }
4098
+ }
4099
+ const next = signedServerTrial({
4100
+ response,
4101
+ secret: input.secret,
4102
+ stored: input.stored,
4103
+ now: input.now,
4104
+ deviceId
4105
+ });
4106
+ await persistTrial(next);
4107
+ rememberServerVerifiedTrial(next, input.now);
4108
+ return next;
4109
+ } catch {
4110
+ return null;
4111
+ }
4112
+ }
4113
+ function rememberServerVerifiedTrial(stored, now) {
4114
+ const refreshAtMs = now + TRIAL_SERVER_REFRESH_MS;
4115
+ const expiresAtMs = stored.serverExpired === true ? refreshAtMs : parseTs(stored.expiresAt) ?? now;
4116
+ verifiedTrialCache = {
4117
+ stored,
4118
+ usableUntilMs: Math.max(now, Math.min(expiresAtMs, refreshAtMs))
4119
+ };
4120
+ }
4121
+ function readServerVerifiedTrial(now) {
4122
+ if (!verifiedTrialCache || verifiedTrialCache.usableUntilMs <= now) {
4123
+ verifiedTrialCache = null;
4124
+ return null;
4125
+ }
4126
+ return verifiedTrialCache.stored;
4127
+ }
4128
+ async function resolveTrialState(now = Date.now(), options = {}) {
4129
+ if (!isTrialEnforcementEnabled()) {
4130
+ return { info: null, locked: false };
4131
+ }
4132
+ const allowNetwork = options.allowNetwork !== false;
4133
+ const secret = await getLicenseSecret();
4134
+ let stored = await getStoredTrial();
4135
+ const hadStoredTrial = stored !== null;
4136
+ const currentDeviceId = await getDeviceId().catch(() => null);
4137
+ const cached = readServerVerifiedTrial(now);
4138
+ if (cached) {
4139
+ if (!currentDeviceId || !hasTrustedServerRecord(cached, secret, currentDeviceId)) {
4140
+ verifiedTrialCache = null;
4141
+ } else {
4142
+ if (hasLocalClockRollback(cached, now)) {
4143
+ const refreshed2 = allowNetwork ? await syncAndPersistTrial({ stored: cached, secret, now }) : null;
4144
+ if (!refreshed2) {
4145
+ return { info: buildLockedTrialInfo(cached), locked: true };
4146
+ }
4147
+ const info3 = buildTrialInfo(refreshed2, trustedTrialNow(refreshed2, now));
4148
+ return { info: info3, locked: info3.expired };
4149
+ }
4150
+ if (shouldRefreshInBackground(cached, now)) {
4151
+ void syncTrialWithServer({ force: true }).catch(() => void 0);
4152
+ }
4153
+ const info2 = buildTrialInfo(cached, trustedTrialNow(cached, now));
4154
+ return { info: info2, locked: info2.expired };
4155
+ }
4156
+ }
4157
+ if (stored && (!currentDeviceId || !hasTrustedServerRecord(stored, secret, currentDeviceId))) {
4158
+ stored = null;
4159
+ }
4160
+ if (!allowNetwork) {
4161
+ if (stored && canUseOfflineTrial(stored, now)) {
4162
+ const next = await persistLocalSeenIfNeeded(stored, secret, now).catch(() => stored);
4163
+ rememberServerVerifiedTrial(next, now);
4164
+ if (options.refreshInBackground === true && shouldRefreshInBackground(next, now)) {
4165
+ startTrialSyncInBackground();
4166
+ }
4167
+ const info2 = buildTrialInfo(next, trustedTrialNow(next, now));
4168
+ return { info: info2, locked: info2.expired };
4169
+ }
4170
+ if (options.refreshInBackground === true) {
4171
+ startTrialSyncInBackground();
4172
+ }
4173
+ if (!hadStoredTrial && options.refreshInBackground === true) {
4174
+ return { info: null, locked: false };
4175
+ }
4176
+ return { info: buildLockedTrialInfo(stored), locked: true };
4177
+ }
4178
+ const refreshed = await syncAndPersistTrial({ stored, secret, now });
4179
+ if (!refreshed) {
4180
+ if (stored && canUseOfflineTrial(stored, now)) {
4181
+ const next = await persistLocalSeenIfNeeded(stored, secret, now).catch(() => stored);
4182
+ rememberServerVerifiedTrial(next, now);
4183
+ const info2 = buildTrialInfo(next, trustedTrialNow(next, now));
4184
+ return { info: info2, locked: info2.expired };
4185
+ }
4186
+ return { info: buildLockedTrialInfo(stored), locked: true };
4187
+ }
4188
+ const info = buildTrialInfo(refreshed, trustedTrialNow(refreshed, now));
4189
+ return { info, locked: info.expired };
4190
+ }
4191
+ async function syncTrialWithServer(opts = {}) {
4192
+ if (!isTrialEnforcementEnabled()) {
4193
+ return true;
4194
+ }
4195
+ const now = Date.now();
4196
+ const secret = await getLicenseSecret();
4197
+ const stored = await getStoredTrial();
4198
+ const explicitEmailHash = opts.emailHash ?? null;
4199
+ if (!opts.force && !explicitEmailHash && readServerVerifiedTrial(now)) {
4200
+ return true;
4201
+ }
4202
+ const next = await syncAndPersistTrial({
4203
+ stored,
4204
+ secret,
4205
+ now,
4206
+ emailHash: explicitEmailHash
4207
+ });
4208
+ return next !== null;
4209
+ }
4210
+
3616
4211
  // ../../packages/runtime-profiles/src/license/service.ts
3617
4212
  var offer = getActiveOffer();
3618
4213
  var PRODUCT_PERMALINK = offer.productPermalink;
@@ -3677,7 +4272,7 @@ function licenseSignaturePayload(license) {
3677
4272
  return JSON.stringify(payload);
3678
4273
  }
3679
4274
  function signLicense(license, secret) {
3680
- return import_node_crypto2.default.createHmac("sha256", secret).update(licenseSignaturePayload(license)).digest("hex");
4275
+ return import_node_crypto5.default.createHmac("sha256", secret).update(licenseSignaturePayload(license)).digest("hex");
3681
4276
  }
3682
4277
  function withSignature(license, secret) {
3683
4278
  return {
@@ -3685,7 +4280,7 @@ function withSignature(license, secret) {
3685
4280
  signature: signLicense(license, secret)
3686
4281
  };
3687
4282
  }
3688
- function isSignatureValid(license, secret) {
4283
+ function isSignatureValid2(license, secret) {
3689
4284
  if (!license.signature) {
3690
4285
  return false;
3691
4286
  }
@@ -3732,9 +4327,19 @@ async function requestGumroadVerify(licenseKey, mode) {
3732
4327
  clearTimeout(timeout);
3733
4328
  }
3734
4329
  }
3735
- 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) {
3736
4338
  if (!response.success) {
3737
4339
  const message = response.message ?? "License key is invalid.";
4340
+ if (mode === "refresh" && !isExplicitRevocationMessage(message)) {
4341
+ throw new LicenseError(message, "network");
4342
+ }
3738
4343
  throw new LicenseError(message, "invalid");
3739
4344
  }
3740
4345
  if (!response.purchase) {
@@ -3763,6 +4368,47 @@ function ensureWithinUseLimit(response) {
3763
4368
  );
3764
4369
  }
3765
4370
  }
4371
+ function computeCapabilities(opts) {
4372
+ return {
4373
+ unlimitedProfiles: opts.entitled,
4374
+ accountPool: opts.entitled,
4375
+ telegram: opts.entitled,
4376
+ autoRoll: opts.entitled,
4377
+ cloudSync: opts.licensed || opts.entitled
4378
+ };
4379
+ }
4380
+ function applyTrial(base, trial) {
4381
+ if (base.isPro) {
4382
+ return { ...base, trial: null };
4383
+ }
4384
+ const { info, locked } = trial;
4385
+ if (!info) {
4386
+ return base;
4387
+ }
4388
+ if (info.active) {
4389
+ return {
4390
+ ...base,
4391
+ tier: "trial",
4392
+ state: "trial",
4393
+ capabilities: computeCapabilities({ licensed: false, entitled: true }),
4394
+ profileLimit: null,
4395
+ profilesRemaining: null,
4396
+ trial: info
4397
+ };
4398
+ }
4399
+ if (locked) {
4400
+ return {
4401
+ ...base,
4402
+ tier: "free",
4403
+ state: "locked",
4404
+ capabilities: computeCapabilities({ licensed: false, entitled: false }),
4405
+ profileLimit: 0,
4406
+ profilesRemaining: 0,
4407
+ trial: info
4408
+ };
4409
+ }
4410
+ return { ...base, trial: info };
4411
+ }
3766
4412
  function toLicenseStatus(stored, overrides = {}) {
3767
4413
  const tier = determineTierFromStored(stored);
3768
4414
  const isPro = tier === "pro";
@@ -3771,6 +4417,8 @@ function toLicenseStatus(stored, overrides = {}) {
3771
4417
  tier,
3772
4418
  state,
3773
4419
  isPro,
4420
+ capabilities: computeCapabilities({ licensed: isPro, entitled: isPro }),
4421
+ trial: null,
3774
4422
  profileLimit: isPro ? null : FREE_PROFILE_LIMIT,
3775
4423
  profilesRemaining: null,
3776
4424
  purchaseEmail: stored?.purchaseEmail ?? null,
@@ -3812,15 +4460,27 @@ var LicenseService = class {
3812
4460
  const refreshInBackground = Boolean(options.refreshInBackground);
3813
4461
  const secret = await getLicenseSecret();
3814
4462
  const stored = await getStoredLicense();
4463
+ const finalize = async (status) => {
4464
+ if (status.isPro) {
4465
+ return { ...status, trial: null };
4466
+ }
4467
+ return applyTrial(
4468
+ status,
4469
+ await resolveTrialState(Date.now(), {
4470
+ allowNetwork: !allowStale || forceRefresh,
4471
+ refreshInBackground
4472
+ })
4473
+ );
4474
+ };
3815
4475
  if (!stored?.licenseKey) {
3816
- return toLicenseStatus(null);
4476
+ return finalize(toLicenseStatus(null));
3817
4477
  }
3818
4478
  const now = Date.now();
3819
4479
  const nextCheckTs = parseTimestamp(stored.nextCheckAt);
3820
4480
  const lastVerifiedTs = parseTimestamp(stored.lastVerifiedAt);
3821
4481
  const graceStale = (stored.status === "grace" || stored.status === "error") && (lastVerifiedTs === null || lastVerifiedTs + GRACE_MAX_AGE_MS < now);
3822
4482
  let workingStored = { ...stored };
3823
- const signatureValid = isSignatureValid(workingStored, secret);
4483
+ const signatureValid = isSignatureValid2(workingStored, secret);
3824
4484
  let cappedNextCheckTs = nextCheckTs;
3825
4485
  if (nextCheckTs !== null && nextCheckTs > now + MAX_NEXT_CHECK_MS) {
3826
4486
  cappedNextCheckTs = now;
@@ -3843,7 +4503,7 @@ var LicenseService = class {
3843
4503
  if (allowStale && shouldRefresh && refreshInBackground) {
3844
4504
  this.refreshStatusInBackground({ force: forceRefresh });
3845
4505
  }
3846
- return cached;
4506
+ return finalize(cached);
3847
4507
  }
3848
4508
  if (this.verificationPromise && !forceRefresh) {
3849
4509
  return this.verificationPromise;
@@ -3852,7 +4512,7 @@ var LicenseService = class {
3852
4512
  try {
3853
4513
  const result = await requestGumroadVerify(workingStored.licenseKey, "refresh");
3854
4514
  ensureWithinUseLimit(result);
3855
- const normalized = normalizeVerificationResult(result);
4515
+ const normalized = normalizeVerificationResult(result, "refresh");
3856
4516
  const updated = {
3857
4517
  licenseKey: workingStored.licenseKey,
3858
4518
  purchaseEmail: normalized.email,
@@ -3863,7 +4523,7 @@ var LicenseService = class {
3863
4523
  };
3864
4524
  const signed = withSignature(updated, secret);
3865
4525
  await persistLicense(signed);
3866
- return toLicenseStatus(signed);
4526
+ return finalize(toLicenseStatus(signed));
3867
4527
  } catch (error) {
3868
4528
  const message = error instanceof Error ? error.message : "License verification failed.";
3869
4529
  if (error instanceof LicenseError && error.code === "network") {
@@ -3881,7 +4541,7 @@ var LicenseService = class {
3881
4541
  state: fallbackStored2.status ?? "grace",
3882
4542
  error: message
3883
4543
  });
3884
- return fallback;
4544
+ return finalize(fallback);
3885
4545
  }
3886
4546
  const fallbackStored = withSignature({
3887
4547
  licenseKey: workingStored.licenseKey,
@@ -3892,7 +4552,7 @@ var LicenseService = class {
3892
4552
  lastVerificationError: message
3893
4553
  }, secret);
3894
4554
  await persistLicense(fallbackStored);
3895
- return toLicenseStatus(fallbackStored, { error: message });
4555
+ return finalize(toLicenseStatus(fallbackStored, { error: message }));
3896
4556
  }
3897
4557
  };
3898
4558
  this.verificationPromise = verify();
@@ -3908,10 +4568,10 @@ var LicenseService = class {
3908
4568
  throw new Error("License key is required.");
3909
4569
  }
3910
4570
  const secret = await getLicenseSecret();
3911
- const digest = import_node_crypto2.default.createHash("sha256").update(trimmed).digest("hex");
4571
+ const digest = import_node_crypto5.default.createHash("sha256").update(trimmed).digest("hex");
3912
4572
  const result = await requestGumroadVerify(trimmed, "activation");
3913
4573
  ensureWithinUseLimit(result);
3914
- const normalized = normalizeVerificationResult(result);
4574
+ const normalized = normalizeVerificationResult(result, "activation");
3915
4575
  const stored = {
3916
4576
  licenseKey: trimmed,
3917
4577
  purchaseEmail: normalized.email,
@@ -3950,9 +4610,28 @@ var LicenseService = class {
3950
4610
  }
3951
4611
  };
3952
4612
  var licenseService = new LicenseService();
4613
+ function isExplicitInvalidation(message) {
4614
+ if (!message) {
4615
+ return false;
4616
+ }
4617
+ const normalized = message.toLowerCase();
4618
+ return normalized.includes("revoked") || normalized.includes("refunded") || normalized.includes("invalid") || normalized.includes("no longer active");
4619
+ }
4620
+ function shouldEnforceProfileLimit(status) {
4621
+ if (status.capabilities.unlimitedProfiles) {
4622
+ return false;
4623
+ }
4624
+ if (status.state === "grace" || status.state === "verifying" || status.state === "error") {
4625
+ return false;
4626
+ }
4627
+ if (isExplicitInvalidation(status.error)) {
4628
+ return true;
4629
+ }
4630
+ return status.state === "inactive" || status.state === "locked";
4631
+ }
3953
4632
 
3954
4633
  // ../../packages/runtime-profiles/src/profiles/profile-manager.ts
3955
- var import_node_crypto3 = require("crypto");
4634
+ var import_node_crypto6 = require("crypto");
3956
4635
  var import_fs = require("fs");
3957
4636
  var import_path = __toESM(require("path"), 1);
3958
4637
  var import_path2 = require("path");
@@ -4001,11 +4680,15 @@ function resolveProfileIdentityKey(profile) {
4001
4680
  return profileName ? `profile:${profileName}` : null;
4002
4681
  }
4003
4682
  function resolveProfileIdentityKeyFromProfile(profile) {
4683
+ const rateLimitKey = normalizeValue(profile.rateLimitKey);
4684
+ if (rateLimitKey) {
4685
+ return rateLimitKey;
4686
+ }
4004
4687
  return resolveProfileIdentityKey(profile) ?? `profile:${profile.name}`;
4005
4688
  }
4006
4689
 
4007
4690
  // ../../packages/runtime-codex/src/codex/rpc.ts
4008
- var import_node_child_process2 = require("child_process");
4691
+ var import_node_child_process4 = require("child_process");
4009
4692
  var import_node_readline = __toESM(require("readline"), 1);
4010
4693
  var import_node_fs3 = require("fs");
4011
4694
  var import_node_os2 = __toESM(require("os"), 1);
@@ -4137,7 +4820,7 @@ async function requireCodexCli() {
4137
4820
  }
4138
4821
 
4139
4822
  // ../../packages/runtime-codex/src/codex/command.ts
4140
- var import_node_child_process = require("child_process");
4823
+ var import_node_child_process3 = require("child_process");
4141
4824
  var import_node_path4 = __toESM(require("path"), 1);
4142
4825
  var cachedNodeRuntime = null;
4143
4826
  function isJavaScriptEntrypoint(binaryPath) {
@@ -4180,7 +4863,7 @@ function resolveNodeRuntime(env) {
4180
4863
  )
4181
4864
  );
4182
4865
  for (const candidate of candidates) {
4183
- const probe = (0, import_node_child_process.spawnSync)(candidate, ["-v"], { env: runtimeEnv, stdio: "ignore" });
4866
+ const probe = (0, import_node_child_process3.spawnSync)(candidate, ["-v"], { env: runtimeEnv, stdio: "ignore" });
4184
4867
  if (!probe.error && probe.status === 0) {
4185
4868
  cachedNodeRuntime = candidate;
4186
4869
  return candidate;
@@ -4204,6 +4887,17 @@ function buildCodexCommand(binaryPath, args, env) {
4204
4887
  };
4205
4888
  }
4206
4889
 
4890
+ // ../../packages/runtime-codex/src/cli/env.ts
4891
+ function buildCodexChildEnv(overrides = {}) {
4892
+ const env = { ...process.env };
4893
+ for (const key of Object.keys(env)) {
4894
+ if (key.startsWith("OPENAI_")) {
4895
+ delete env[key];
4896
+ }
4897
+ }
4898
+ return { ...env, ...overrides };
4899
+ }
4900
+
4207
4901
  // ../../packages/shared/src/core/logger.ts
4208
4902
  var isTestEnv = process.env.NODE_ENV === "test" || process.env.VITEST === "true" || process.env.VITEST === "1";
4209
4903
  function isMocked(fn) {
@@ -5046,20 +5740,19 @@ async function fetchRateLimitsViaRpc(envOverride, options = {}) {
5046
5740
  });
5047
5741
  return null;
5048
5742
  }
5049
- const childEnv = {
5050
- ...process.env,
5743
+ const childEnv = buildCodexChildEnv({
5051
5744
  ...envOverride ?? {},
5052
5745
  HOME: tempHome,
5053
5746
  CODEX_HOME: tempHome,
5054
5747
  CODEX_TELEMETRY_LABEL: "codex-rpc",
5055
5748
  ELECTRON_RUN_AS_NODE: "1"
5056
- };
5749
+ });
5057
5750
  const command = buildCodexCommand(
5058
5751
  binaryPath,
5059
5752
  ["-s", "read-only", "-a", "untrusted", "app-server"],
5060
5753
  childEnv
5061
5754
  );
5062
- const child = (0, import_node_child_process2.spawn)(command.command, command.args, {
5755
+ const child = (0, import_node_child_process4.spawn)(command.command, command.args, {
5063
5756
  stdio: ["pipe", "pipe", "pipe"],
5064
5757
  env: childEnv,
5065
5758
  shell: command.shell
@@ -5156,20 +5849,19 @@ async function activateResetWindowViaRpc(envOverride, options = {}) {
5156
5849
  });
5157
5850
  return { status: "skipped", reason: "auth-missing" };
5158
5851
  }
5159
- const childEnv = {
5160
- ...process.env,
5852
+ const childEnv = buildCodexChildEnv({
5161
5853
  ...envOverride ?? {},
5162
5854
  HOME: tempHome,
5163
5855
  CODEX_HOME: tempHome,
5164
5856
  CODEX_TELEMETRY_LABEL: "codex-reset-activation",
5165
5857
  ELECTRON_RUN_AS_NODE: "1"
5166
- };
5858
+ });
5167
5859
  const command = buildCodexCommand(
5168
5860
  binaryPath,
5169
5861
  ["-s", "read-only", "-a", "untrusted", "app-server"],
5170
5862
  childEnv
5171
5863
  );
5172
- const child = (0, import_node_child_process2.spawn)(command.command, command.args, {
5864
+ const child = (0, import_node_child_process4.spawn)(command.command, command.args, {
5173
5865
  stdio: ["pipe", "pipe", "pipe"],
5174
5866
  env: childEnv,
5175
5867
  shell: command.shell
@@ -5486,6 +6178,7 @@ var ProfileManager = class {
5486
6178
  displayName: record.displayName ?? null,
5487
6179
  data: record.data,
5488
6180
  metadata: record.metadata,
6181
+ rateLimitKey: record.rateLimitKey ?? null,
5489
6182
  accountId: record.accountId ?? null,
5490
6183
  workspaceId: record.workspaceId ?? null,
5491
6184
  workspaceName: record.workspaceName ?? null,
@@ -5503,11 +6196,14 @@ var ProfileManager = class {
5503
6196
  if (!dataRaw || typeof dataRaw !== "object") {
5504
6197
  return null;
5505
6198
  }
5506
- return {
6199
+ const data = cloneJson(dataRaw);
6200
+ const metadata = raw.metadata ? cloneJson(raw.metadata) : void 0;
6201
+ const fallbackRecord = {
5507
6202
  name: profileName,
5508
6203
  displayName: typeof raw.displayName === "string" ? raw.displayName : null,
5509
- data: cloneJson(dataRaw),
5510
- metadata: raw.metadata ? cloneJson(raw.metadata) : void 0,
6204
+ data,
6205
+ metadata,
6206
+ rateLimitKey: typeof raw.rateLimitKey === "string" ? raw.rateLimitKey : null,
5511
6207
  accountId: typeof raw.accountId === "string" ? raw.accountId : null,
5512
6208
  workspaceId: typeof raw.workspaceId === "string" ? raw.workspaceId : null,
5513
6209
  workspaceName: typeof raw.workspaceName === "string" ? raw.workspaceName : null,
@@ -5516,6 +6212,10 @@ var ProfileManager = class {
5516
6212
  createdAt: typeof raw.createdAt === "string" ? raw.createdAt : null,
5517
6213
  updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : null
5518
6214
  };
6215
+ return {
6216
+ ...fallbackRecord,
6217
+ rateLimitKey: fallbackRecord.rateLimitKey ?? this.resolveProfileIdentityFromRecord(fallbackRecord)
6218
+ };
5519
6219
  }
5520
6220
  async readProfilesStateSource() {
5521
6221
  const state = await getAppState();
@@ -5565,10 +6265,11 @@ var ProfileManager = class {
5565
6265
  }
5566
6266
  rateLimitSnapshotKeysForRecord(record) {
5567
6267
  return Array.from(
5568
- /* @__PURE__ */ new Set([
6268
+ new Set([
5569
6269
  this.resolveProfileIdentityFromRecord(record),
6270
+ record.rateLimitKey,
5570
6271
  resolveFallbackAccountKey(record.name)
5571
- ])
6272
+ ].filter((key) => Boolean(key)))
5572
6273
  );
5573
6274
  }
5574
6275
  rateLimitSnapshotKeysForStateMap(map) {
@@ -5633,7 +6334,7 @@ var ProfileManager = class {
5633
6334
  if (!trimmed) {
5634
6335
  return this.emptyAuthSnapshot();
5635
6336
  }
5636
- const fingerprint = (0, import_node_crypto3.createHash)("sha256").update(trimmed).digest("hex");
6337
+ const fingerprint = (0, import_node_crypto6.createHash)("sha256").update(trimmed).digest("hex");
5637
6338
  try {
5638
6339
  const parsed = JSON.parse(trimmed);
5639
6340
  const normalized = this.normalizeProfileData(parsed);
@@ -6281,6 +6982,7 @@ var ProfileManager = class {
6281
6982
  displayName,
6282
6983
  data,
6283
6984
  metadata: resolvedMetadata,
6985
+ rateLimitKey: existingRecord?.rateLimitKey ?? this.resolveProfileIdentityFromData(resolvedName, data, resolvedMetadata),
6284
6986
  accountId,
6285
6987
  workspaceId: data.workspace_id ?? workspaceId,
6286
6988
  workspaceName: data.workspace_name ?? workspaceName,
@@ -6299,6 +7001,7 @@ var ProfileManager = class {
6299
7001
  createdAt: row.createdAt ?? void 0,
6300
7002
  authMethod: row.authMethod ?? void 0,
6301
7003
  accountId: row.accountId ?? void 0,
7004
+ rateLimitKey: row.rateLimitKey ?? void 0,
6302
7005
  workspaceId: row.workspaceId ?? void 0,
6303
7006
  workspaceName: row.workspaceName ?? void 0,
6304
7007
  metadata: row.metadata
@@ -6335,6 +7038,7 @@ var ProfileManager = class {
6335
7038
  name,
6336
7039
  displayName: fallback?.displayName ?? name,
6337
7040
  isValid: Boolean(data && Object.keys(data).length > 0),
7041
+ rateLimitKey: fallback?.rateLimitKey,
6338
7042
  accountId,
6339
7043
  workspaceId,
6340
7044
  workspaceName,
@@ -6726,11 +7430,10 @@ var ProfileManager = class {
6726
7430
  const codexFormat = this.convertToCodexFormat(profileData);
6727
7431
  const profileHome = await this.prepareProfileHome(profileName, codexFormat);
6728
7432
  const authPath = import_path.default.join(profileHome, "auth.json");
6729
- const envOverrides = {
6730
- ...process.env,
7433
+ const envOverrides = buildCodexChildEnv({
6731
7434
  HOME: profileHome,
6732
7435
  CODEX_HOME: profileHome
6733
- };
7436
+ });
6734
7437
  try {
6735
7438
  return await action(envOverrides);
6736
7439
  } finally {
@@ -6780,11 +7483,10 @@ var ProfileManager = class {
6780
7483
  const profileHome = await this.prepareProfileHome(profileName, codexFormat);
6781
7484
  return {
6782
7485
  profileHome,
6783
- env: {
6784
- ...process.env,
7486
+ env: buildCodexChildEnv({
6785
7487
  HOME: profileHome,
6786
7488
  CODEX_HOME: profileHome
6787
- }
7489
+ })
6788
7490
  };
6789
7491
  })
6790
7492
  );
@@ -7029,13 +7731,13 @@ var ProfileManager = class {
7029
7731
  profileName,
7030
7732
  async (env) => {
7031
7733
  try {
7032
- const oauthSnapshot = await fetchRateLimitsViaOAuth(env);
7033
- if (oauthSnapshot) {
7034
- return oauthSnapshot;
7734
+ const rpcSnapshot = await fetchRateLimitsViaRpc(env, { codexPath: options.codexPath });
7735
+ if (rpcSnapshot) {
7736
+ return rpcSnapshot;
7035
7737
  }
7036
7738
  } catch {
7037
7739
  }
7038
- return fetchRateLimitsViaRpc(env, { codexPath: options.codexPath });
7740
+ return fetchRateLimitsViaOAuth(env);
7039
7741
  },
7040
7742
  { syncFromActiveAuthBeforeAction: false }
7041
7743
  )
@@ -7285,7 +7987,7 @@ var ProfileManager = class {
7285
7987
  }
7286
7988
  if (options.canAutoImport === false) {
7287
7989
  return this.buildActiveCodexAuthStatus("unmanaged", description, {
7288
- importBlockedReason: options.importBlockedReason ?? "Profile limit reached. Upgrade to CodexUse Pro or remove a profile before importing this Codex login."
7990
+ importBlockedReason: options.importBlockedReason ?? "Your CodexUse trial has ended. Upgrade to Pro before importing this Codex login."
7289
7991
  });
7290
7992
  }
7291
7993
  const records = await this.listProfileRecords();
@@ -7380,6 +8082,7 @@ var ProfileManager = class {
7380
8082
  displayName: typeof candidate.displayName === "string" ? candidate.displayName : null,
7381
8083
  data,
7382
8084
  metadata,
8085
+ rateLimitKey: this.resolveProfileIdentityFromData(name, data, metadata),
7383
8086
  accountId: typeof candidate.accountId === "string" ? candidate.accountId : null,
7384
8087
  workspaceId: typeof candidate.workspaceId === "string" ? candidate.workspaceId : null,
7385
8088
  workspaceName: typeof candidate.workspaceName === "string" ? candidate.workspaceName : null,
@@ -7473,7 +8176,7 @@ Flags:
7473
8176
  --runtime=NAME Accounts Pool runtime store: desktop
7474
8177
  --state-dir=PATH Override the runtime state dir for Accounts Pool inspection
7475
8178
  --passphrase-stdin Read Cloud Sync passphrase from stdin
7476
- Note: profile autoroll requires Pro.
8179
+ Note: profile autoroll requires Pro or an active trial.
7477
8180
  Cloud Sync: set CODEXUSE_SYNC_PASSPHRASE or use --passphrase-stdin unless the passphrase is saved in Keychain.
7478
8181
  `);
7479
8182
  }
@@ -7525,7 +8228,7 @@ function parseStringFlag(flags, name) {
7525
8228
 
7526
8229
  // src/commands/accountPool.ts
7527
8230
  var ACCOUNT_POOL_DOCUMENT = "desktop.account-pool.v2";
7528
- var ACCOUNT_POOL_PRO_REQUIRED_MESSAGE = "Accounts Pool requires a Pro license.";
8231
+ var ACCOUNT_POOL_PRO_REQUIRED_MESSAGE = "Accounts Pool requires a Pro license or an active trial.";
7529
8232
  var DESKTOP_RPC_STATE_DIR = "desktop-rpc";
7530
8233
  var ACCOUNT_POOL_STORE_VERSION = 3;
7531
8234
  var MAX_RESPONSE_IDS_PER_SESSION = 64;
@@ -7913,13 +8616,13 @@ async function listApiKeys(stateDir) {
7913
8616
  return Object.values(store.apiKeysById).filter((key) => key.revokedAt === null).sort((left, right) => right.createdAt.localeCompare(left.createdAt)).map(accountPoolApiKeyView);
7914
8617
  }
7915
8618
  function hashToken(token) {
7916
- return (0, import_node_crypto4.createHash)("sha256").update(token).digest("hex");
8619
+ return (0, import_node_crypto7.createHash)("sha256").update(token).digest("hex");
7917
8620
  }
7918
8621
  async function createApiKey(stateDir) {
7919
- const plaintextToken = `cux_pool_${(0, import_node_crypto4.randomBytes)(24).toString("hex")}`;
8622
+ const plaintextToken = `cux_pool_${(0, import_node_crypto7.randomBytes)(24).toString("hex")}`;
7920
8623
  const now = (/* @__PURE__ */ new Date()).toISOString();
7921
8624
  const keyRecord = {
7922
- id: (0, import_node_crypto4.randomUUID)(),
8625
+ id: (0, import_node_crypto7.randomUUID)(),
7923
8626
  tokenHash: hashToken(plaintextToken),
7924
8627
  tokenPreview: `${plaintextToken.slice(0, 8)}...${plaintextToken.slice(-6)}`,
7925
8628
  createdAt: now,
@@ -8013,7 +8716,7 @@ async function readAccountPoolRuntimeSummary(input = {}) {
8013
8716
  stateDir,
8014
8717
  baseUrl: resolveBaseUrlFromPort(runtime, input.port ?? null),
8015
8718
  enabled: normalized.accountPoolEnabled,
8016
- hasProLicense: license?.isPro === true,
8719
+ hasAccountPoolAccess: license?.capabilities.accountPool === true,
8017
8720
  routingStrategy: normalized.accountPoolRoutingStrategy,
8018
8721
  activeApiKeyCount: apiKeys.length,
8019
8722
  activeSessionCount: sessions.length
@@ -8030,7 +8733,7 @@ async function updateSettings(transform) {
8030
8733
  const { raw, normalized } = await readSettingsSnapshot();
8031
8734
  const nextSettings = transform(normalized);
8032
8735
  const license = await licenseService.getStatus().catch(() => null);
8033
- const forcedDisabledByLicense = !license?.isPro && nextSettings.accountPoolEnabled === true;
8736
+ const forcedDisabledByLicense = license?.capabilities.accountPool !== true && nextSettings.accountPoolEnabled === true;
8034
8737
  const sanitizedSettings = {
8035
8738
  ...nextSettings,
8036
8739
  accountPoolEnabled: forcedDisabledByLicense ? false : nextSettings.accountPoolEnabled,
@@ -8057,7 +8760,7 @@ async function updateSettings(transform) {
8057
8760
  }
8058
8761
  async function requireProAccess() {
8059
8762
  const license = await licenseService.getStatus();
8060
- if (!license.isPro) {
8763
+ if (!license.capabilities.accountPool) {
8061
8764
  throw new Error(ACCOUNT_POOL_PRO_REQUIRED_MESSAGE);
8062
8765
  }
8063
8766
  }
@@ -8119,7 +8822,7 @@ async function handleStatus(flags) {
8119
8822
  console.log(`Runtime: ${runtime}`);
8120
8823
  console.log(`State dir: ${stateDir}`);
8121
8824
  console.log(`Routing: ${formatRoutingStrategy(normalized.accountPoolRoutingStrategy)}`);
8122
- console.log(`Public API ready: ${normalized.accountPoolEnabled && license?.isPro === true && apiKeys.length > 0 ? "yes" : "no"}`);
8825
+ console.log(`Public API ready: ${normalized.accountPoolEnabled && license?.capabilities.accountPool === true && apiKeys.length > 0 ? "yes" : "no"}`);
8123
8826
  console.log(`API keys: ${apiKeys.length}`);
8124
8827
  console.log(`Sessions: ${sessions.length}`);
8125
8828
  console.log(`Selection mode: ${explicitSelection.length > 0 ? "explicit" : "all saved profiles"}`);
@@ -8135,7 +8838,7 @@ async function handleStatus(flags) {
8135
8838
  printStringList("Published models", normalized.accountPoolExposedModels);
8136
8839
  printStringList("Reasoning aliases", normalized.accountPoolExposedReasoningEfforts);
8137
8840
  printStringList("Fast-mode aliases", normalized.accountPoolExposedFastModeReasoningEfforts);
8138
- if (normalized.accountPoolEnabled && license?.isPro !== true) {
8841
+ if (normalized.accountPoolEnabled && license?.capabilities.accountPool !== true) {
8139
8842
  console.log(ACCOUNT_POOL_PRO_REQUIRED_MESSAGE);
8140
8843
  }
8141
8844
  }
@@ -8340,7 +9043,7 @@ async function handleQuickstart(flags) {
8340
9043
  console.log("Accounts Pool quickstart");
8341
9044
  console.log(`Runtime: ${summary.runtime}`);
8342
9045
  console.log(`Enabled: ${summary.enabled ? "yes" : "no"}`);
8343
- console.log(`Pro: ${summary.hasProLicense ? "yes" : "no"}`);
9046
+ console.log(`Access: ${summary.hasAccountPoolAccess ? "yes" : "no"}`);
8344
9047
  console.log(`API keys: ${summary.activeApiKeyCount}`);
8345
9048
  console.log(`Base URL: ${baseUrl}`);
8346
9049
  console.log("");
@@ -8424,7 +9127,7 @@ async function handleAccountPoolCommand(args, version) {
8424
9127
  }
8425
9128
 
8426
9129
  // src/commands/codex.ts
8427
- var import_node_child_process4 = require("child_process");
9130
+ var import_node_child_process6 = require("child_process");
8428
9131
 
8429
9132
  // ../../packages/runtime-profiles/src/profiles/rate-limit-notifier.ts
8430
9133
  function maxUsedPercent(snapshot) {
@@ -8441,8 +9144,108 @@ function maxUsedPercent(snapshot) {
8441
9144
  return Math.max(...candidates);
8442
9145
  }
8443
9146
 
9147
+ // ../../packages/runtime-profiles/src/profiles/profile-visibility.ts
9148
+ function resolveLicenseVisibleProfiles(args) {
9149
+ const { profiles, license, currentProfile } = args;
9150
+ const licenseWithCounts = licenseService.applyProfileCount(license, profiles.length);
9151
+ const enforceProfileLimit = shouldEnforceProfileLimit(licenseWithCounts);
9152
+ const visibleProfiles = enforceProfileLimit ? resolveVisibleProfiles(profiles, licenseWithCounts, currentProfile) : profiles;
9153
+ return {
9154
+ allProfiles: profiles,
9155
+ profiles: licenseWithCounts.capabilities.unlimitedProfiles ? profiles : visibleProfiles,
9156
+ license,
9157
+ licenseWithCounts,
9158
+ enforceProfileLimit
9159
+ };
9160
+ }
9161
+ async function loadLicenseVisibleProfiles(profileManager, options = {}) {
9162
+ await profileManager.initialize();
9163
+ const license = options.freshLicense ? await licenseService.getStatus() : await licenseService.getCachedStatus();
9164
+ const profiles = await profileManager.listProfiles();
9165
+ const currentProfile = options.currentProfile !== void 0 ? options.currentProfile : (await profileManager.getCurrentProfile()).name;
9166
+ return resolveLicenseVisibleProfiles({
9167
+ profiles,
9168
+ license,
9169
+ currentProfile
9170
+ });
9171
+ }
9172
+ function resolveVisibleProfiles(profiles, license, currentProfile) {
9173
+ if (license.capabilities.unlimitedProfiles) {
9174
+ return profiles;
9175
+ }
9176
+ const limit = typeof license.profileLimit === "number" && license.profileLimit >= 0 ? license.profileLimit : FREE_PROFILE_LIMIT;
9177
+ if (profiles.length <= limit) {
9178
+ return profiles;
9179
+ }
9180
+ const normalizedCurrent = currentProfile ?? null;
9181
+ const sorted = profiles.slice().sort((a, b) => compareProfilesForLimit(a, b, normalizedCurrent));
9182
+ return sorted.slice(0, limit);
9183
+ }
9184
+ function compareProfilesForLimit(a, b, currentProfile) {
9185
+ if (currentProfile) {
9186
+ if (a.name === currentProfile && b.name !== currentProfile) {
9187
+ return -1;
9188
+ }
9189
+ if (b.name === currentProfile && a.name !== currentProfile) {
9190
+ return 1;
9191
+ }
9192
+ }
9193
+ if (Boolean(a.isValid) !== Boolean(b.isValid)) {
9194
+ return a.isValid ? -1 : 1;
9195
+ }
9196
+ const aTimestamp = parseTimestamp3(a.createdAt ?? null);
9197
+ const bTimestamp = parseTimestamp3(b.createdAt ?? null);
9198
+ if (aTimestamp !== null && bTimestamp !== null) {
9199
+ if (aTimestamp === bTimestamp) {
9200
+ return a.name.localeCompare(b.name);
9201
+ }
9202
+ return bTimestamp - aTimestamp;
9203
+ }
9204
+ if (aTimestamp !== null) {
9205
+ return -1;
9206
+ }
9207
+ if (bTimestamp !== null) {
9208
+ return 1;
9209
+ }
9210
+ return a.name.localeCompare(b.name);
9211
+ }
9212
+ function parseTimestamp3(value) {
9213
+ if (typeof value !== "string" || value.trim() === "") {
9214
+ return null;
9215
+ }
9216
+ const parsed = Date.parse(value);
9217
+ return Number.isNaN(parsed) ? null : parsed;
9218
+ }
9219
+
9220
+ // ../../packages/runtime-profiles/src/license/guard.ts
9221
+ var PROFILE_ACCESS_DENIED_MESSAGE = "Your CodexUse trial has ended. Upgrade to Pro to use saved profiles.";
9222
+ async function assertProfileCreationAllowed(profileManager) {
9223
+ const manager = profileManager ?? new ProfileManager();
9224
+ await manager.initialize();
9225
+ const license = await licenseService.getStatus();
9226
+ const profiles = await manager.listProfiles();
9227
+ const licenseWithCounts = licenseService.applyProfileCount(license, profiles.length);
9228
+ if (typeof licenseWithCounts.profileLimit === "number" && licenseWithCounts.profilesRemaining !== null && licenseWithCounts.profilesRemaining <= 0) {
9229
+ throw new Error("Your CodexUse trial has ended. Upgrade to Pro for unlimited profiles.");
9230
+ }
9231
+ }
9232
+ async function assertProfileAccessAllowed(profileManager, profileName) {
9233
+ const name = profileName.trim();
9234
+ if (!name) {
9235
+ throw new Error("Profile name is required.");
9236
+ }
9237
+ const visible = await loadLicenseVisibleProfiles(profileManager, {
9238
+ freshLicense: true
9239
+ });
9240
+ const exists = visible.allProfiles.some((profile) => profile.name === name);
9241
+ const allowed = visible.profiles.some((profile) => profile.name === name);
9242
+ if (exists && !allowed) {
9243
+ throw new Error(PROFILE_ACCESS_DENIED_MESSAGE);
9244
+ }
9245
+ }
9246
+
8444
9247
  // src/platform/codexCli.ts
8445
- var import_node_child_process3 = require("child_process");
9248
+ var import_node_child_process5 = require("child_process");
8446
9249
  var import_node_fs5 = require("fs");
8447
9250
  var import_node_path8 = __toESM(require("path"));
8448
9251
  var ENV_HINTS2 = ["CODEX_BINARY", "CODEX_CLI_PATH", "CODEX_PATH"];
@@ -8514,7 +9317,7 @@ async function runCodexLogin(mode) {
8514
9317
  const resolvedMode = resolveLoginMode(mode ?? null);
8515
9318
  const loginArgs = resolvedMode === "device" ? ["login", "--device-auth"] : ["login"];
8516
9319
  const { command, args, shell } = buildCodexCommand2(codexPath, loginArgs);
8517
- const child = (0, import_node_child_process3.spawn)(command, args, {
9320
+ const child = (0, import_node_child_process5.spawn)(command, args, {
8518
9321
  stdio: "inherit",
8519
9322
  env: process.env,
8520
9323
  shell
@@ -8586,7 +9389,7 @@ function compareCandidates(left, right) {
8586
9389
  async function runCommand(codexPath, args, timeoutMs) {
8587
9390
  const command = buildCodexCommand2(codexPath, args);
8588
9391
  return new Promise((resolve) => {
8589
- const child = (0, import_node_child_process4.spawn)(command.command, command.args, {
9392
+ const child = (0, import_node_child_process6.spawn)(command.command, command.args, {
8590
9393
  env: process.env,
8591
9394
  shell: command.shell,
8592
9395
  stdio: ["ignore", "pipe", "pipe"]
@@ -8647,12 +9450,13 @@ async function runCodexWithProfile(manager, profileName, codexArgs) {
8647
9450
  if (!codexPath) {
8648
9451
  throw new Error("Codex CLI not found. Install Codex CLI or set CODEX_BINARY.");
8649
9452
  }
9453
+ await assertProfileAccessAllowed(manager, profileName);
8650
9454
  const runtime = await manager.prepareProfileRuntime(profileName, {
8651
9455
  syncFromActiveAuthBeforeAction: false
8652
9456
  });
8653
9457
  const command = buildCodexCommand2(codexPath, codexArgs);
8654
9458
  try {
8655
- const child = (0, import_node_child_process4.spawn)(command.command, command.args, {
9459
+ const child = (0, import_node_child_process6.spawn)(command.command, command.args, {
8656
9460
  env: runtime.env,
8657
9461
  shell: command.shell,
8658
9462
  stdio: "inherit"
@@ -8753,7 +9557,7 @@ async function handleBestCommand(args) {
8753
9557
  console.log(`Usage:
8754
9558
  codexuse best -- <codex args>
8755
9559
 
8756
- Picks the healthiest saved profile, then runs Codex. Auto-run requires Pro.`);
9560
+ Picks the healthiest saved profile, then runs Codex. Auto-run requires Pro or an active trial.`);
8757
9561
  return;
8758
9562
  }
8759
9563
  const codexPath = resolveCodexBinary();
@@ -8761,20 +9565,17 @@ Picks the healthiest saved profile, then runs Codex. Auto-run requires Pro.`);
8761
9565
  throw new Error("Codex CLI not found. Install Codex CLI or set CODEX_BINARY.");
8762
9566
  }
8763
9567
  const manager = new ProfileManager();
8764
- const profiles = await manager.listProfiles();
9568
+ const visible = await loadLicenseVisibleProfiles(manager, { freshLicense: true });
9569
+ if (!visible.licenseWithCounts.capabilities.autoRoll) {
9570
+ throw new Error("Auto-run requires Pro or an active trial.");
9571
+ }
9572
+ const profiles = visible.profiles;
8765
9573
  const best = await selectBestProfile(manager, profiles, codexPath);
8766
9574
  if (!best) {
8767
9575
  throw new Error("No valid saved profiles found. Add one with `codexuse profile add <name>`.");
8768
9576
  }
8769
9577
  const dryRun = hasFlag(flags, "--dry-run");
8770
- const license = await licenseService.getStatus();
8771
9578
  const summary = `${best.profile.name} (${formatUsagePercent(best.usedPercent)} used)`;
8772
- if (!license.isPro) {
8773
- console.log(`Best profile: ${summary}`);
8774
- console.log("Auto-run is Pro. Free path:");
8775
- console.log(` codexuse run --profile ${best.profile.name} -- ${codexArgs.join(" ")}`.trimEnd());
8776
- return;
8777
- }
8778
9579
  if (dryRun) {
8779
9580
  console.log(`Would run with profile: ${summary}`);
8780
9581
  return;
@@ -8832,21 +9633,9 @@ async function handleLicense(args, version) {
8832
9633
  }
8833
9634
  }
8834
9635
 
8835
- // ../../packages/runtime-profiles/src/license/guard.ts
8836
- async function assertProfileCreationAllowed(profileManager) {
8837
- const manager = profileManager ?? new ProfileManager();
8838
- await manager.initialize();
8839
- const license = await licenseService.getStatus();
8840
- const profiles = await manager.listProfiles();
8841
- const licenseWithCounts = licenseService.applyProfileCount(license, profiles.length);
8842
- if (typeof licenseWithCounts.profileLimit === "number" && licenseWithCounts.profilesRemaining !== null && licenseWithCounts.profilesRemaining <= 0) {
8843
- throw new Error("CodexUse Free supports up to 2 profiles. Upgrade to CodexUse Pro for unlimited profiles.");
8844
- }
8845
- }
8846
-
8847
9636
  // ../../packages/runtime-codex/src/codex/officialAppRestart.ts
8848
- var import_node_child_process5 = require("child_process");
8849
- var import_node_crypto5 = require("crypto");
9637
+ var import_node_child_process7 = require("child_process");
9638
+ var import_node_crypto8 = require("crypto");
8850
9639
  var import_node_fs7 = require("fs");
8851
9640
  var import_node_os3 = require("os");
8852
9641
  var import_node_net = __toESM(require("net"), 1);
@@ -8856,6 +9645,7 @@ var import_node_path10 = __toESM(require("path"), 1);
8856
9645
  var import_node_fs6 = require("fs");
8857
9646
  var import_node_path9 = __toESM(require("path"), 1);
8858
9647
  var ROLLOUT_DIRS = ["sessions", "archived_sessions"];
9648
+ var SQLITE_EXTENSIONS = /* @__PURE__ */ new Set([".db", ".sqlite", ".sqlite3"]);
8859
9649
  function isRecord5(value) {
8860
9650
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8861
9651
  }
@@ -8974,8 +9764,91 @@ function resolveRolloutPath(profileHome, rolloutPath) {
8974
9764
  }
8975
9765
  return import_node_path9.default.isAbsolute(rolloutPath) ? rolloutPath : import_node_path9.default.join(profileHome, rolloutPath);
8976
9766
  }
8977
- async function readThreadRecordFromStateDb(profileHome, threadId) {
8978
- const dbPath = import_node_path9.default.join(profileHome, "state_5.sqlite");
9767
+ async function collectSessionDatabasePaths(profileHome) {
9768
+ const paths = [];
9769
+ const sqliteDir = import_node_path9.default.join(profileHome, "sqlite");
9770
+ try {
9771
+ const entries = await import_node_fs6.promises.readdir(sqliteDir, {
9772
+ withFileTypes: true,
9773
+ encoding: "utf8"
9774
+ });
9775
+ for (const entry of entries) {
9776
+ if (!entry.isFile()) {
9777
+ continue;
9778
+ }
9779
+ const entryName = String(entry.name);
9780
+ if (SQLITE_EXTENSIONS.has(import_node_path9.default.extname(entryName))) {
9781
+ paths.push(import_node_path9.default.join(sqliteDir, entryName));
9782
+ }
9783
+ }
9784
+ } catch {
9785
+ }
9786
+ paths.sort((left, right) => {
9787
+ const leftName = import_node_path9.default.basename(left);
9788
+ const rightName = import_node_path9.default.basename(right);
9789
+ if (leftName === "codex-dev.db" && rightName !== "codex-dev.db") return -1;
9790
+ if (rightName === "codex-dev.db" && leftName !== "codex-dev.db") return 1;
9791
+ return leftName.localeCompare(rightName);
9792
+ });
9793
+ const legacy = import_node_path9.default.join(profileHome, "state_5.sqlite");
9794
+ if (!paths.includes(legacy)) {
9795
+ paths.push(legacy);
9796
+ }
9797
+ return paths;
9798
+ }
9799
+ function tableColumns(db, table) {
9800
+ try {
9801
+ return new Set(
9802
+ db.prepare(`PRAGMA table_info(${table})`).all().map((row) => isRecord5(row) ? recordString(row.name) : null).filter((name) => Boolean(name))
9803
+ );
9804
+ } catch {
9805
+ return /* @__PURE__ */ new Set();
9806
+ }
9807
+ }
9808
+ function firstColumn(columns, names) {
9809
+ return names.find((name) => columns.has(name)) ?? null;
9810
+ }
9811
+ function sqlColumnOrNull(column, alias) {
9812
+ return column ? `${column} AS ${alias}` : `NULL AS ${alias}`;
9813
+ }
9814
+ function queryThreadRecordFromTable(db, profileHome, threadId, config) {
9815
+ const columns = tableColumns(db, config.table);
9816
+ const idColumn = firstColumn(columns, config.id);
9817
+ if (!idColumn) {
9818
+ return null;
9819
+ }
9820
+ const variants = threadIdVariants(threadId);
9821
+ const placeholders = variants.map(() => "?").join(", ");
9822
+ const orderByColumn = firstColumn(columns, [
9823
+ "updated_at_ms",
9824
+ "updated_at",
9825
+ "created_at_ms",
9826
+ "created_at"
9827
+ ]);
9828
+ const select = [
9829
+ sqlColumnOrNull(firstColumn(columns, config.rolloutPath), "rollout_path"),
9830
+ sqlColumnOrNull(firstColumn(columns, config.title), "title"),
9831
+ sqlColumnOrNull(firstColumn(columns, config.cwd), "cwd"),
9832
+ sqlColumnOrNull(firstColumn(columns, ["updated_at"]), "updated_at"),
9833
+ sqlColumnOrNull(firstColumn(columns, ["updated_at_ms"]), "updated_at_ms"),
9834
+ sqlColumnOrNull(firstColumn(columns, ["created_at_ms", "created_at"]), "created_at_ms")
9835
+ ].join(", ");
9836
+ const orderBy = orderByColumn ? ` ORDER BY ${orderByColumn} DESC, ${idColumn} DESC` : ` ORDER BY ${idColumn} DESC`;
9837
+ const row = db.prepare(
9838
+ `SELECT ${select} FROM ${config.table} WHERE ${idColumn} IN (${placeholders})${orderBy} LIMIT 1`
9839
+ ).all(...variants).find(isRecord5);
9840
+ if (!row) {
9841
+ return null;
9842
+ }
9843
+ return {
9844
+ rolloutPath: resolveRolloutPath(profileHome, recordString(row.rollout_path)),
9845
+ title: recordString(row.title),
9846
+ cwd: recordString(row.cwd),
9847
+ updatedAt: recordString(row.updated_at),
9848
+ updatedAtMs: normalizeTimestampMs(row.updated_at_ms) ?? normalizeTimestampMs(row.updated_at) ?? normalizeTimestampMs(row.created_at_ms)
9849
+ };
9850
+ }
9851
+ async function readThreadRecordFromDb(profileHome, dbPath, threadId) {
8979
9852
  try {
8980
9853
  await import_node_fs6.promises.access(dbPath);
8981
9854
  } catch {
@@ -8984,42 +9857,28 @@ async function readThreadRecordFromStateDb(profileHome, threadId) {
8984
9857
  let db = null;
8985
9858
  try {
8986
9859
  db = await openReadonlyDatabase(dbPath);
8987
- const columns = new Set(
8988
- db.prepare("PRAGMA table_info(threads)").all().map((row2) => isRecord5(row2) ? recordString(row2.name) : null).filter((name) => Boolean(name))
8989
- );
8990
- const idColumn = columns.has("id") ? "id" : columns.has("thread_id") ? "thread_id" : null;
8991
- if (!idColumn) {
8992
- return null;
8993
- }
8994
- const variants = threadIdVariants(threadId);
8995
- const placeholders = variants.map(() => "?").join(", ");
8996
- const select = [
8997
- columns.has("rollout_path") ? "rollout_path AS rollout_path" : "NULL AS rollout_path",
8998
- columns.has("title") ? "title AS title" : "NULL AS title",
8999
- columns.has("cwd") ? "cwd AS cwd" : "NULL AS cwd",
9000
- columns.has("updated_at") ? "updated_at AS updated_at" : "NULL AS updated_at",
9001
- columns.has("updated_at_ms") ? "updated_at_ms AS updated_at_ms" : "NULL AS updated_at_ms",
9002
- columns.has("created_at_ms") ? "created_at_ms AS created_at_ms" : "NULL AS created_at_ms"
9003
- ].join(", ");
9004
- 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;
9005
- const orderBy = orderByColumn ? ` ORDER BY ${orderByColumn} DESC, ${idColumn} DESC` : ` ORDER BY ${idColumn} DESC`;
9006
- const rows = db.prepare(
9007
- `SELECT ${select} FROM threads WHERE ${idColumn} IN (${placeholders})${orderBy} LIMIT 1`
9008
- ).all(...variants);
9009
- const row = rows.find(isRecord5);
9010
- if (!row) {
9011
- return null;
9860
+ for (const config of [
9861
+ {
9862
+ table: "threads",
9863
+ id: ["id", "thread_id"],
9864
+ title: ["title", "thread_title"],
9865
+ cwd: ["cwd", "source_cwd"],
9866
+ rolloutPath: ["rollout_path"]
9867
+ },
9868
+ {
9869
+ table: "automation_runs",
9870
+ id: ["thread_id", "id"],
9871
+ title: ["thread_title", "title", "inbox_title"],
9872
+ cwd: ["source_cwd", "cwd"],
9873
+ rolloutPath: []
9874
+ }
9875
+ ]) {
9876
+ const record = queryThreadRecordFromTable(db, profileHome, threadId, config);
9877
+ if (record) {
9878
+ return record;
9879
+ }
9012
9880
  }
9013
- return {
9014
- rolloutPath: resolveRolloutPath(
9015
- profileHome,
9016
- recordString(row.rollout_path)
9017
- ),
9018
- title: recordString(row.title),
9019
- cwd: recordString(row.cwd),
9020
- updatedAt: recordString(row.updated_at),
9021
- updatedAtMs: normalizeTimestampMs(row.updated_at_ms) ?? normalizeTimestampMs(row.updated_at) ?? normalizeTimestampMs(row.created_at_ms)
9022
- };
9881
+ return null;
9023
9882
  } catch {
9024
9883
  return null;
9025
9884
  } finally {
@@ -9027,9 +9886,16 @@ async function readThreadRecordFromStateDb(profileHome, threadId) {
9027
9886
  }
9028
9887
  }
9029
9888
  async function findOfficialCodexThreadRecord(profileHome, threadId) {
9030
- const stateRecord = await readThreadRecordFromStateDb(profileHome, threadId);
9031
- if (stateRecord) {
9032
- return stateRecord;
9889
+ const records = [];
9890
+ for (const dbPath of await collectSessionDatabasePaths(profileHome)) {
9891
+ const stateRecord = await readThreadRecordFromDb(profileHome, dbPath, threadId);
9892
+ if (stateRecord) {
9893
+ records.push(stateRecord);
9894
+ }
9895
+ }
9896
+ if (records.length > 0) {
9897
+ records.sort((left, right) => (right.updatedAtMs ?? 0) - (left.updatedAtMs ?? 0));
9898
+ return records[0] ?? null;
9033
9899
  }
9034
9900
  const rolloutMatch = await findRolloutFileByScan(profileHome, threadId);
9035
9901
  if (!rolloutMatch) {
@@ -9121,7 +9987,7 @@ function hashProfileKey(profileKey) {
9121
9987
  if (!profileKey) {
9122
9988
  return null;
9123
9989
  }
9124
- return (0, import_node_crypto5.createHash)("sha256").update(profileKey).digest("hex").slice(0, 12);
9990
+ return (0, import_node_crypto8.createHash)("sha256").update(profileKey).digest("hex").slice(0, 12);
9125
9991
  }
9126
9992
  function sanitizeOfficialCodexOverlayActionTargetsForRenderer(targets) {
9127
9993
  const sanitized = [];
@@ -9395,13 +10261,14 @@ async function readCdpTargets(port) {
9395
10261
  }
9396
10262
  throw lastError instanceof Error ? lastError : new Error("cdp-list-failed");
9397
10263
  }
9398
- function pickCodexCdpTarget(targets) {
10264
+ function pickCodexCdpTarget(targets, options = {}) {
9399
10265
  const pages = targets.filter(
9400
10266
  (target) => target.webSocketDebuggerUrl && (target.type === "page" || target.type === "webview" || !target.type)
9401
10267
  );
9402
- return pages.find(
10268
+ const codexPage = pages.find(
9403
10269
  (target) => `${target.title ?? ""} ${target.url ?? ""}`.toLowerCase().includes("codex")
9404
- ) ?? pages[0] ?? null;
10270
+ ) ?? null;
10271
+ return codexPage ?? (options.allowAnyPage === true ? pages[0] ?? null : null);
9405
10272
  }
9406
10273
  function buildCdpDevToolsUrl(port, target) {
9407
10274
  const frontendUrl = target.devtoolsFrontendUrl?.trim();
@@ -9744,6 +10611,9 @@ function buildInCodexStatusOverlayCssRules() {
9744
10611
  `${chip} .codexuse-handoff-main{display:inline-flex;align-items:center;padding:5px 8px 5px 10px;border-radius:999px;cursor:pointer;}`,
9745
10612
  `${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;}`,
9746
10613
  `${chip} .codexuse-handoff-hide:hover{background:var(--cu-border);color:var(--cu-fg,#ececf1);}`,
10614
+ `body>[data-radix-popper-content-wrapper],body>[data-floating-ui-portal]{z-index:2147483004!important;}`,
10615
+ // Official Codex marks its titlebar draggable; injected controls must opt out.
10616
+ `${id},${id} *,${chip},${chip} *,${picker},${picker} *{-webkit-app-region:no-drag;}`,
9747
10617
  // Hand-off account picker is a standalone body child (not inside the pill),
9748
10618
  // so the pill-scoped popover rules don't reach it — give it its own palette
9749
10619
  // + popover styling, mirroring the chip.
@@ -10125,6 +10995,7 @@ function createBridgeApplyQolExpression(settings) {
10125
10995
  const overlayPosKey = "codexuse:overlay:pos";
10126
10996
  const handoffHiddenKey = "codexuse:handoff:hidden";
10127
10997
  const handoffPosKey = "codexuse:handoff:pos:v2";
10998
+ const defaultPosKey = "codexuse:overlay:top-default:v1";
10128
10999
  const readOverlayStore = (key) => {
10129
11000
  try {
10130
11001
  return window.localStorage.getItem(key);
@@ -10219,8 +11090,8 @@ function createBridgeApplyQolExpression(settings) {
10219
11090
  };
10220
11091
  const placeInitialOverlayPosition = (pill) => {
10221
11092
  const rect = pill.getBoundingClientRect();
10222
- const x = Math.round((window.innerWidth - rect.width) / 2);
10223
- const y = Math.max(72, Math.min(140, Math.round(window.innerHeight * 0.16)));
11093
+ const x = Math.max(8, window.innerWidth - rect.width - 32);
11094
+ const y = Math.max(96, Math.min(132, Math.round(window.innerHeight * 0.12)));
10224
11095
  placeOverlay(pill, x, y);
10225
11096
  };
10226
11097
  const rectsOverlap = (a, b, gap = 0) =>
@@ -10234,30 +11105,17 @@ function createBridgeApplyQolExpression(settings) {
10234
11105
  right: pos.x + rect.width,
10235
11106
  bottom: pos.y + rect.height
10236
11107
  });
10237
- const placeInitialHandoffPosition = (chip, anchorRect = null) => {
11108
+ const placeInitialHandoffPosition = (chip) => {
10238
11109
  const rect = chip.getBoundingClientRect();
10239
- if (anchorRect && rect.width > 0 && rect.height > 0) {
10240
- const gap = 8;
10241
- const middleY = Math.round(anchorRect.top + (anchorRect.height - rect.height) / 2);
10242
- const candidates = [
10243
- { x: anchorRect.right + gap, y: middleY },
10244
- { x: anchorRect.left - rect.width - gap, y: middleY },
10245
- { x: anchorRect.right - rect.width, y: anchorRect.top - rect.height - gap },
10246
- { x: anchorRect.left, y: anchorRect.top - rect.height - gap },
10247
- { x: anchorRect.right - rect.width, y: anchorRect.bottom + gap }
10248
- ];
10249
- for (const candidate of candidates) {
10250
- const next = clampOverlayXY(chip, candidate.x, candidate.y);
10251
- if (!rectsOverlap(positionedRect(rect, next), anchorRect, 6)) {
10252
- placeOverlay(chip, next.x, next.y);
10253
- return;
10254
- }
10255
- }
10256
- }
10257
- const x = Math.max(8, window.innerWidth - rect.width - 16);
10258
- const y = Math.max(64, Math.min(128, Math.round(window.innerHeight * 0.14)));
11110
+ const x = Math.round((window.innerWidth - rect.width) / 2);
11111
+ const y = 14;
10259
11112
  placeOverlay(chip, x, y);
10260
11113
  };
11114
+ if (readOverlayStore(defaultPosKey) !== "1") {
11115
+ writeOverlayStore(overlayPosKey, null);
11116
+ writeOverlayStore(handoffPosKey, null);
11117
+ writeOverlayStore(defaultPosKey, "1");
11118
+ }
10261
11119
  const setOverlayMessage = (value) => {
10262
11120
  const node = document.querySelector("#" + statusId + " [data-codexuse-action-status]");
10263
11121
  if (node) node.textContent = value || "";
@@ -10387,7 +11245,8 @@ function createBridgeApplyQolExpression(settings) {
10387
11245
  renderHandoff();
10388
11246
  }, true);
10389
11247
  document.body.appendChild(pill);
10390
- applyStoredOverlayPosition(pill);
11248
+ if (hasStoredPosition) applyStoredOverlayPosition(pill);
11249
+ else placeInitialOverlayPosition(pill);
10391
11250
  return true;
10392
11251
  }
10393
11252
  pill.dataset.open = currentAutoRollDecision || wasOpen || shouldShowIntro ? "true" : "false";
@@ -10692,6 +11551,8 @@ function createBridgeApplyQolExpression(settings) {
10692
11551
  if (shouldShowIntro) {
10693
11552
  placeInitialOverlayPosition(pill);
10694
11553
  writeOverlayStore(overlayIntroKey, "1");
11554
+ } else if (!hasStoredPosition) {
11555
+ placeInitialOverlayPosition(pill);
10695
11556
  } else {
10696
11557
  applyStoredOverlayPosition(pill);
10697
11558
  }
@@ -10936,18 +11797,18 @@ function createBridgeApplyQolExpression(settings) {
10936
11797
  const next = clampOverlayXY(chip, pos.x, pos.y);
10937
11798
  const chipRect = chip.getBoundingClientRect();
10938
11799
  if (rectsOverlap(positionedRect(chipRect, next), rect, 6)) {
10939
- placeInitialHandoffPosition(chip, rect);
11800
+ placeInitialHandoffPosition(chip);
10940
11801
  } else {
10941
11802
  placeOverlay(chip, next.x, next.y);
10942
11803
  }
10943
11804
  } else {
10944
- placeInitialHandoffPosition(chip, rect);
11805
+ placeInitialHandoffPosition(chip);
10945
11806
  }
10946
11807
  } catch {
10947
- placeInitialHandoffPosition(chip, rect);
11808
+ placeInitialHandoffPosition(chip);
10948
11809
  }
10949
11810
  } else {
10950
- placeInitialHandoffPosition(chip, rect);
11811
+ placeInitialHandoffPosition(chip);
10951
11812
  }
10952
11813
  if (wasOpen) openPicker();
10953
11814
  reportHandoff("rendered");
@@ -11299,11 +12160,23 @@ function createBridgeApplyPowerExpression(settings, settingsExpression) {
11299
12160
  || typeof item.name === "string"
11300
12161
  )
11301
12162
  );
11302
- const patchModelArray = (items, allowEmpty = false) => {
12163
+ const modelLabelLooksKnown = (value) =>
12164
+ typeof value === "string" && /(?:gpt|codex|chatgpt|claude|gemini|llama|mistral|qwen|deepseek|grok|davinci|\\bo[1-9]\\b)/i.test(value);
12165
+ const objectArrayLooksModelLike = (items) =>
12166
+ objectArrayLooksPatchable(items)
12167
+ && items.some((item) =>
12168
+ modelLabelLooksKnown(item.model)
12169
+ || modelLabelLooksKnown(item.id)
12170
+ || modelLabelLooksKnown(item.slug)
12171
+ || modelLabelLooksKnown(item.name)
12172
+ || modelLabelLooksKnown(item.displayName)
12173
+ || modelLabelLooksKnown(item.title)
12174
+ );
12175
+ const patchModelArray = (items, allowEmpty = false, requireModelLike = false) => {
11303
12176
  if (!Array.isArray(items)) return false;
11304
12177
  let localChanged = false;
11305
- unhideArray(items);
11306
12178
  if (stringArrayLooksPatchable(items)) {
12179
+ if (requireModelLike && !items.some(modelLabelLooksKnown)) return false;
11307
12180
  for (const model of modelWhitelistModels) {
11308
12181
  if (!items.includes(model)) {
11309
12182
  items.push(model);
@@ -11312,7 +12185,8 @@ function createBridgeApplyPowerExpression(settings, settingsExpression) {
11312
12185
  }
11313
12186
  return localChanged;
11314
12187
  }
11315
- if (objectArrayLooksPatchable(items, allowEmpty)) {
12188
+ if (objectArrayLooksPatchable(items, allowEmpty) && (!requireModelLike || allowEmpty || objectArrayLooksModelLike(items))) {
12189
+ unhideArray(items);
11316
12190
  const existing = new Set();
11317
12191
  for (const item of items) {
11318
12192
  existing.add(String(item.model || item.id || item.slug || item.name || ""));
@@ -11327,8 +12201,8 @@ function createBridgeApplyPowerExpression(settings, settingsExpression) {
11327
12201
  return localChanged;
11328
12202
  };
11329
12203
  if (patchModelArray(value.models, "defaultModel" in value || "availableModels" in value)) changed = true;
11330
- if (patchModelArray(value.data)) changed = true;
11331
- if (patchModelArray(value.result)) changed = true;
12204
+ if (patchModelArray(value.data, false, true)) changed = true;
12205
+ if (patchModelArray(value.result, false, true)) changed = true;
11332
12206
  if (patchModelArray(value.availableModels, true)) changed = true;
11333
12207
  if (patchModelArray(value.available_models, true)) changed = true;
11334
12208
  if (value.available_models instanceof Set) {
@@ -11445,11 +12319,23 @@ function createBridgeApplyPowerExpression(settings, settingsExpression) {
11445
12319
  return changed;
11446
12320
  };
11447
12321
  const reactFiberKeys = (element) => Object.keys(element || {}).filter((key) => key.startsWith("__reactFiber") || key.startsWith("__reactInternalInstance") || key.startsWith("__reactProps"));
12322
+ const reactModelStatePatchSelector = "[role='menu'],[role='dialog'],[role='listbox'],[data-radix-popper-content-wrapper],[data-floating-ui-portal]";
12323
+ const isWorkspaceChromeNode = (node) => {
12324
+ if (!node || node.nodeType !== 1) return false;
12325
+ 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]")) {
12326
+ return true;
12327
+ }
12328
+ return Boolean(node.closest?.("main aside"));
12329
+ };
12330
+ const reactModelStatePatchNodes = () => {
12331
+ return Array.from(document.querySelectorAll(reactModelStatePatchSelector))
12332
+ .filter((node) => node && !isWorkspaceChromeNode(node));
12333
+ };
11448
12334
  const patchReactModelState = () => {
11449
12335
  if (!enabled.modelWhitelistUnlock) return false;
11450
12336
  try {
11451
12337
  const visited = new WeakSet();
11452
- const nodes = [document.body, ...Array.from(document.querySelectorAll("button,[role='menu'],[role='dialog'],[data-radix-popper-content-wrapper]"))].filter(Boolean);
12338
+ const nodes = reactModelStatePatchNodes();
11453
12339
  let changed = false;
11454
12340
  for (const node of nodes.slice(0, 220)) {
11455
12341
  for (const key of reactFiberKeys(node)) {
@@ -11464,6 +12350,39 @@ function createBridgeApplyPowerExpression(settings, settingsExpression) {
11464
12350
  return false;
11465
12351
  }
11466
12352
  };
12353
+ const installModelReactStateObserver = () => {
12354
+ if (typeof state.cleanupModelReactStateObserver === "function") {
12355
+ state.cleanupModelReactStateObserver();
12356
+ state.cleanupModelReactStateObserver = null;
12357
+ }
12358
+ if (!enabled.modelWhitelistUnlock) return false;
12359
+ let frame = 0;
12360
+ const schedulePatch = () => {
12361
+ if (frame) return;
12362
+ frame = requestAnimationFrame(() => {
12363
+ frame = 0;
12364
+ patchReactModelState();
12365
+ });
12366
+ };
12367
+ const isPatchableMutationNode = (node) => {
12368
+ const element = node?.nodeType === 1 ? node : node?.parentElement;
12369
+ return Boolean(
12370
+ element?.matches?.(reactModelStatePatchSelector)
12371
+ || element?.querySelector?.(reactModelStatePatchSelector)
12372
+ );
12373
+ };
12374
+ const observer = new MutationObserver((mutations) => {
12375
+ if (mutations.some((mutation) => Array.from(mutation.addedNodes).some(isPatchableMutationNode))) {
12376
+ schedulePatch();
12377
+ }
12378
+ });
12379
+ observer.observe(document.body, { childList: true, subtree: true });
12380
+ state.cleanupModelReactStateObserver = () => {
12381
+ observer.disconnect();
12382
+ if (frame) cancelAnimationFrame(frame);
12383
+ };
12384
+ return true;
12385
+ };
11467
12386
  const patchPluginContainer = (value, visited = new WeakSet(), depth = 0, inheritedMarketplaceName = null) => {
11468
12387
  if (!enabled.pluginMarketplaceUnlock || !value || typeof value !== "object" || visited.has(value) || depth > 4) return false;
11469
12388
  visited.add(value);
@@ -12007,6 +12926,7 @@ function createBridgeApplyPowerExpression(settings, settingsExpression) {
12007
12926
  const modelStatsigPatchApplied = enabled.modelWhitelistUnlock
12008
12927
  ? patchStatsigModelWhitelist()
12009
12928
  : false;
12929
+ installModelReactStateObserver();
12010
12930
  const modelReactStatePatched = enabled.modelWhitelistUnlock
12011
12931
  ? patchReactModelState()
12012
12932
  : false;
@@ -12673,7 +13593,7 @@ async function runCdpCommandSequence(debuggerUrl, commands, timeoutMs = CODEX_CD
12673
13593
  });
12674
13594
  }
12675
13595
  async function verifyCdpBindingRoundTrip(debuggerUrl) {
12676
- const nonce = (0, import_node_crypto5.randomUUID)();
13596
+ const nonce = (0, import_node_crypto8.randomUUID)();
12677
13597
  const expression = `(() => {
12678
13598
  const binding = window[${JSON.stringify(CODEXUSE_BRIDGE_BINDING_NAME)}];
12679
13599
  if (typeof binding !== "function") return false;
@@ -13183,14 +14103,16 @@ async function reloadOfficialCodexBridgePage(debuggerUrl) {
13183
14103
  return false;
13184
14104
  }
13185
14105
  }
13186
- async function probeOfficialCodexBridge(instance, forceInstall = false) {
14106
+ async function probeOfficialCodexBridge(instance, forceInstall = false, allowAnyPageTarget = false) {
13187
14107
  const checkedAt = Date.now();
13188
14108
  if (!instance.cdpPort) {
13189
14109
  return bridgeStateUnavailable();
13190
14110
  }
13191
14111
  try {
13192
14112
  const targets = await readCdpTargets(instance.cdpPort);
13193
- const target = pickCodexCdpTarget(targets);
14113
+ const target = pickCodexCdpTarget(targets, {
14114
+ allowAnyPage: allowAnyPageTarget
14115
+ });
13194
14116
  if (!target?.webSocketDebuggerUrl) {
13195
14117
  return bridgeStateUnhealthy(
13196
14118
  instance.cdpPort,
@@ -13260,14 +14182,16 @@ async function probeOfficialCodexBridge(instance, forceInstall = false) {
13260
14182
  );
13261
14183
  }
13262
14184
  }
13263
- async function reapplyDesiredBridgeSettings(instance, bridge) {
14185
+ async function reapplyDesiredBridgeSettings(instance, bridge, allowAnyPageTarget = false) {
13264
14186
  const shouldClearPowerRuntime = !instance.desiredPowerSettings && hasEnabledBridgePowerRuntime(bridge.bridgePower);
13265
14187
  if (bridge.bridgeStatus !== "healthy" || !instance.cdpPort || !instance.desiredQolSettings && !instance.desiredPowerSettings && !shouldClearPowerRuntime) {
13266
14188
  return bridge;
13267
14189
  }
13268
14190
  try {
13269
14191
  const targets = await readCdpTargets(instance.cdpPort);
13270
- const target = pickCodexCdpTarget(targets);
14192
+ const target = pickCodexCdpTarget(targets, {
14193
+ allowAnyPage: allowAnyPageTarget
14194
+ });
13271
14195
  if (!target?.webSocketDebuggerUrl) {
13272
14196
  return bridge;
13273
14197
  }
@@ -13353,7 +14277,7 @@ async function reapplyDesiredBridgeSettings(instance, bridge) {
13353
14277
  };
13354
14278
  }
13355
14279
  }
13356
- async function refreshBridgeStateIfNeeded(instance, running, force = false, reapplyDesired = false) {
14280
+ async function refreshBridgeStateIfNeeded(instance, running, force = false, reapplyDesired = false, allowAnyPageTarget = false) {
13357
14281
  if (!running || !instance.cdpPort) {
13358
14282
  return bridgeStateUnavailable();
13359
14283
  }
@@ -13361,12 +14285,16 @@ async function refreshBridgeStateIfNeeded(instance, running, force = false, reap
13361
14285
  if (!force && checkedAt && Date.now() - checkedAt < CODEX_BRIDGE_PROBE_TTL_MS) {
13362
14286
  return bridgeStateForStoredInstance(instance, true);
13363
14287
  }
13364
- const bridge = await probeOfficialCodexBridge(instance, force);
13365
- return reapplyDesired ? await reapplyDesiredBridgeSettings(instance, bridge) : bridge;
14288
+ const bridge = await probeOfficialCodexBridge(
14289
+ instance,
14290
+ force,
14291
+ allowAnyPageTarget
14292
+ );
14293
+ return reapplyDesired ? await reapplyDesiredBridgeSettings(instance, bridge, allowAnyPageTarget) : bridge;
13366
14294
  }
13367
14295
  async function waitForBridgeStateAfterLaunch(instance) {
13368
14296
  const deadline = Date.now() + CODEX_BRIDGE_LAUNCH_WAIT_MS;
13369
- let latest = await refreshBridgeStateIfNeeded(instance, true, true, true);
14297
+ let latest = await refreshBridgeStateIfNeeded(instance, true, true, true, true);
13370
14298
  while (latest.bridgeStatus !== "healthy" && Date.now() < deadline) {
13371
14299
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
13372
14300
  latest = await refreshBridgeStateIfNeeded(
@@ -13376,6 +14304,7 @@ async function waitForBridgeStateAfterLaunch(instance) {
13376
14304
  },
13377
14305
  true,
13378
14306
  true,
14307
+ true,
13379
14308
  true
13380
14309
  );
13381
14310
  }
@@ -13384,7 +14313,7 @@ async function waitForBridgeStateAfterLaunch(instance) {
13384
14313
  async function waitForBridgeStateAfterReload(instance) {
13385
14314
  const deadline = Date.now() + CODEX_BRIDGE_LAUNCH_WAIT_MS;
13386
14315
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
13387
- let latest = await refreshBridgeStateIfNeeded(instance, true, true, true);
14316
+ let latest = await refreshBridgeStateIfNeeded(instance, true, true, true, true);
13388
14317
  while (latest.bridgeStatus !== "healthy" && Date.now() < deadline) {
13389
14318
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
13390
14319
  latest = await refreshBridgeStateIfNeeded(
@@ -13394,6 +14323,7 @@ async function waitForBridgeStateAfterReload(instance) {
13394
14323
  },
13395
14324
  true,
13396
14325
  true,
14326
+ true,
13397
14327
  true
13398
14328
  );
13399
14329
  }
@@ -13446,7 +14376,7 @@ async function recordOfficialCodexActivity(input) {
13446
14376
  }
13447
14377
  function runCommand2(command, args, timeoutMs = COMMAND_TIMEOUT_MS) {
13448
14378
  return new Promise((resolve) => {
13449
- const child = (0, import_node_child_process5.spawn)(command, args, {
14379
+ const child = (0, import_node_child_process7.spawn)(command, args, {
13450
14380
  stdio: ["ignore", "pipe", "pipe"]
13451
14381
  });
13452
14382
  let stdout = "";
@@ -13745,7 +14675,7 @@ async function openCodexWithProfileHome(candidate, profileHome, profileName, cdp
13745
14675
  if (appUserDataDir) {
13746
14676
  (0, import_node_fs7.mkdirSync)(appUserDataDir, { recursive: true });
13747
14677
  }
13748
- child = (0, import_node_child_process5.spawn)(
14678
+ child = (0, import_node_child_process7.spawn)(
13749
14679
  "/usr/bin/open",
13750
14680
  [
13751
14681
  "-n",
@@ -13763,7 +14693,7 @@ async function openCodexWithProfileHome(candidate, profileHome, profileName, cdp
13763
14693
  ],
13764
14694
  {
13765
14695
  detached: true,
13766
- env: process.env,
14696
+ env: buildCodexChildEnv(),
13767
14697
  stdio: "ignore"
13768
14698
  }
13769
14699
  );
@@ -14524,6 +15454,13 @@ function formatProfileLabel(name, displayName) {
14524
15454
  }
14525
15455
  return name;
14526
15456
  }
15457
+ var AUTO_ROLL_ACCESS_REQUIRED_MESSAGE = "Auto-roll requires a Pro license or an active trial.";
15458
+ async function assertAutoRollAccess() {
15459
+ const license = await licenseService.getStatus();
15460
+ if (!license.capabilities.autoRoll) {
15461
+ throw new Error(AUTO_ROLL_ACCESS_REQUIRED_MESSAGE);
15462
+ }
15463
+ }
14527
15464
  function profileRateLimitKey(profile) {
14528
15465
  return resolveProfileIdentityKeyFromProfile(profile);
14529
15466
  }
@@ -15180,6 +16117,7 @@ async function collectUsageMap(manager, profiles, codexPath) {
15180
16117
  return usageMap;
15181
16118
  }
15182
16119
  async function runAutoRollPass(manager, options) {
16120
+ await assertAutoRollAccess();
15183
16121
  const profiles = await manager.listProfiles();
15184
16122
  if (!profiles.length) {
15185
16123
  return { switched: false, message: "No profiles found.", source: null, target: null };
@@ -15304,9 +16242,13 @@ async function handleProfileCommand(args, version) {
15304
16242
  const manager = new ProfileManager();
15305
16243
  switch (sub) {
15306
16244
  case "list": {
15307
- const profiles = await manager.listProfiles();
16245
+ const visible = await loadLicenseVisibleProfiles(manager, { freshLicense: true });
16246
+ const profiles = visible.profiles;
15308
16247
  const current = await manager.getCurrentProfile();
15309
16248
  if (!profiles.length) {
16249
+ if (visible.allProfiles.length) {
16250
+ throw new Error(PROFILE_ACCESS_DENIED_MESSAGE);
16251
+ }
15310
16252
  console.log("No profiles found.");
15311
16253
  return;
15312
16254
  }
@@ -15348,6 +16290,7 @@ async function handleProfileCommand(args, version) {
15348
16290
  console.log("No active profile.");
15349
16291
  return;
15350
16292
  }
16293
+ await assertProfileAccessAllowed(manager, current.name);
15351
16294
  console.log(current.name);
15352
16295
  return;
15353
16296
  }
@@ -15371,6 +16314,7 @@ async function handleProfileCommand(args, version) {
15371
16314
  if (!name) {
15372
16315
  throw new Error("Profile name is required.");
15373
16316
  }
16317
+ await assertProfileAccessAllowed(manager, name);
15374
16318
  if (!hasFlag(flags, "--skip-login")) {
15375
16319
  const loginMode = resolveLoginMode(parseLoginMode(flags));
15376
16320
  await runCodexLogin(loginMode);
@@ -15385,6 +16329,7 @@ async function handleProfileCommand(args, version) {
15385
16329
  if (!name) {
15386
16330
  throw new Error("Profile name is required.");
15387
16331
  }
16332
+ await assertProfileAccessAllowed(manager, name);
15388
16333
  const activateOfficialCodex = resolveActivateCodexFlag(flags, false);
15389
16334
  const profiles = await manager.listProfiles();
15390
16335
  const targetProfileKey = findProfileKey(profiles, name);
@@ -15404,10 +16349,7 @@ async function handleProfileCommand(args, version) {
15404
16349
  }
15405
16350
  case "autoroll":
15406
16351
  case "auto-roll": {
15407
- const license = await licenseService.getStatus();
15408
- if (!license.isPro) {
15409
- throw new Error("Auto-roll requires a Pro license.");
15410
- }
16352
+ await assertAutoRollAccess();
15411
16353
  const watch = hasFlag(flags, "--watch");
15412
16354
  const dryRun = hasFlag(flags, "--dry-run");
15413
16355
  const settings = await getStoredAutoRollSettings().catch(() => null);
@@ -15487,6 +16429,7 @@ async function handleProfileCommand(args, version) {
15487
16429
  if (!from || !to) {
15488
16430
  throw new Error("Old and new profile names are required.");
15489
16431
  }
16432
+ await assertProfileAccessAllowed(manager, from);
15490
16433
  await manager.renameProfile(from, to);
15491
16434
  console.log(`Profile renamed: ${from} -> ${to}`);
15492
16435
  return;
@@ -15615,7 +16558,7 @@ function normalizeSnapshot(value) {
15615
16558
  settingsJson
15616
16559
  };
15617
16560
  }
15618
- async function requestJson(method, pathname, licenseKey, body, rawBody) {
16561
+ async function requestJson(method, pathname, access, body, rawBody) {
15619
16562
  const controller = new AbortController();
15620
16563
  const timeout = setTimeout(() => controller.abort(), CLOUD_SYNC_TIMEOUT_MS);
15621
16564
  try {
@@ -15623,7 +16566,10 @@ async function requestJson(method, pathname, licenseKey, body, rawBody) {
15623
16566
  method,
15624
16567
  headers: {
15625
16568
  "Content-Type": "application/json",
15626
- "x-codexuse-license-key": licenseKey
16569
+ "x-codexuse-license-key": access.syncKey,
16570
+ ...access.trialDeviceId ? { "x-codexuse-trial-device-id": access.trialDeviceId } : {},
16571
+ ...access.trialToken ? { "x-codexuse-trial-token": access.trialToken } : {},
16572
+ ...access.trialMigration ? { "x-codexuse-sync-migrate-trial": "1" } : {}
15627
16573
  },
15628
16574
  body: typeof rawBody === "string" ? rawBody : body === void 0 ? void 0 : JSON.stringify(body),
15629
16575
  signal: controller.signal
@@ -15650,15 +16596,15 @@ async function requestJson(method, pathname, licenseKey, body, rawBody) {
15650
16596
  clearTimeout(timeout);
15651
16597
  }
15652
16598
  }
15653
- async function fetchRemoteSnapshot(licenseKey) {
15654
- const response = await requestJson("GET", "/v1/sync/snapshot", licenseKey);
16599
+ async function fetchRemoteSnapshot(access) {
16600
+ const response = await requestJson("GET", "/v1/sync/snapshot", access);
15655
16601
  return normalizeSnapshot(response.snapshot);
15656
16602
  }
15657
- async function fetchRemoteSnapshotMeta(licenseKey) {
16603
+ async function fetchRemoteSnapshotMeta(access) {
15658
16604
  const response = await requestJson(
15659
16605
  "GET",
15660
16606
  "/v1/sync/snapshot/meta",
15661
- licenseKey
16607
+ access
15662
16608
  );
15663
16609
  const updatedAt = toIsoOrNull(response.updatedAt);
15664
16610
  const snapshotKind = normalizeSnapshotKind(response.snapshotKind);
@@ -15667,12 +16613,12 @@ async function fetchRemoteSnapshotMeta(licenseKey) {
15667
16613
  snapshotKind: updatedAt && response.snapshotKind === void 0 ? "legacy-plaintext" : snapshotKind
15668
16614
  };
15669
16615
  }
15670
- async function pushRemoteSnapshot(licenseKey, snapshot, options) {
16616
+ async function pushRemoteSnapshot(access, snapshot, options) {
15671
16617
  const serializedSnapshot = typeof options?.serializedSnapshot === "string" ? options.serializedSnapshot : JSON.stringify(snapshot);
15672
16618
  const response = await requestJson(
15673
16619
  "PUT",
15674
16620
  "/v1/sync/snapshot",
15675
- licenseKey,
16621
+ access,
15676
16622
  void 0,
15677
16623
  `{"snapshot":${serializedSnapshot}}`
15678
16624
  );
@@ -15691,8 +16637,8 @@ async function pushRemoteSnapshot(licenseKey, snapshot, options) {
15691
16637
  var import_toml3 = __toESM(require_toml(), 1);
15692
16638
 
15693
16639
  // ../../packages/runtime-codex/src/codex/config-metadata.ts
15694
- var import_node_child_process6 = require("child_process");
15695
- var import_promises = require("fs/promises");
16640
+ var import_node_child_process8 = require("child_process");
16641
+ var import_promises2 = require("fs/promises");
15696
16642
  var import_node_path11 = __toESM(require("path"), 1);
15697
16643
  var CONFIG_SCHEMA_URL = "https://raw.githubusercontent.com/openai/codex/main/codex-rs/core/config.schema.json";
15698
16644
  var METADATA_CACHE_TTL_MS = 6e4;
@@ -15803,9 +16749,9 @@ function uniqueSorted(values) {
15803
16749
  }
15804
16750
  async function runCommand3(command, args, timeoutMs = 3e3) {
15805
16751
  return new Promise((resolve, reject) => {
15806
- const child = (0, import_node_child_process6.spawn)(command, args, {
16752
+ const child = (0, import_node_child_process8.spawn)(command, args, {
15807
16753
  stdio: ["ignore", "pipe", "pipe"],
15808
- env: process.env
16754
+ env: buildCodexChildEnv()
15809
16755
  });
15810
16756
  let stdout = "";
15811
16757
  let stderr = "";
@@ -15884,7 +16830,7 @@ async function readSchemaFromLocal() {
15884
16830
  ].filter((candidate) => Boolean(candidate));
15885
16831
  for (const candidate of candidates) {
15886
16832
  try {
15887
- return await (0, import_promises.readFile)(candidate, "utf8");
16833
+ return await (0, import_promises2.readFile)(candidate, "utf8");
15888
16834
  } catch {
15889
16835
  }
15890
16836
  }
@@ -15984,7 +16930,7 @@ async function getCodexConfigMetadata(forceRefresh = false) {
15984
16930
  }
15985
16931
 
15986
16932
  // ../../packages/runtime-codex/src/codex/config-io.ts
15987
- var import_promises2 = require("fs/promises");
16933
+ var import_promises3 = require("fs/promises");
15988
16934
  var import_node_path13 = __toESM(require("path"), 1);
15989
16935
 
15990
16936
  // ../../packages/runtime-codex/src/codex/home.ts
@@ -16094,7 +17040,7 @@ function getConfigPath(options) {
16094
17040
  }
16095
17041
  async function ensureConfigDirExists(filePath) {
16096
17042
  const dir = import_node_path13.default.dirname(filePath);
16097
- await (0, import_promises2.mkdir)(dir, { recursive: true });
17043
+ await (0, import_promises3.mkdir)(dir, { recursive: true });
16098
17044
  }
16099
17045
  function normalizeLineEndings(content) {
16100
17046
  return content.replace(/\r\n/g, "\n");
@@ -16106,7 +17052,7 @@ function ensureTrailingNewline(content) {
16106
17052
  async function readConfigContent(options) {
16107
17053
  const configPath = getConfigPath(options);
16108
17054
  try {
16109
- const content = await (0, import_promises2.readFile)(configPath, "utf8");
17055
+ const content = await (0, import_promises3.readFile)(configPath, "utf8");
16110
17056
  return {
16111
17057
  exists: true,
16112
17058
  content: normalizeLineEndings(content)
@@ -16126,14 +17072,14 @@ async function writeConfigContent(content, options) {
16126
17072
  const configPath = getConfigPath(options);
16127
17073
  await ensureConfigDirExists(configPath);
16128
17074
  const normalized = ensureTrailingNewline(normalizeLineEndings(content));
16129
- await (0, import_promises2.writeFile)(configPath, normalized, "utf8");
17075
+ await (0, import_promises3.writeFile)(configPath, normalized, "utf8");
16130
17076
  }
16131
17077
  async function getUpdatedAt(configPath, exists) {
16132
17078
  if (!exists) {
16133
17079
  return null;
16134
17080
  }
16135
17081
  try {
16136
- const stats = await (0, import_promises2.stat)(configPath);
17082
+ const stats = await (0, import_promises3.stat)(configPath);
16137
17083
  return stats.mtimeMs;
16138
17084
  } catch (error) {
16139
17085
  const nodeError = error;
@@ -16647,10 +17593,10 @@ async function saveCodexConfigContent(content, options) {
16647
17593
  }
16648
17594
 
16649
17595
  // ../../packages/runtime-profiles/src/cloud-sync/encryption.ts
16650
- var import_node_child_process7 = require("child_process");
16651
- var import_node_crypto6 = require("crypto");
16652
- var KEYCHAIN_SERVICE = "CODEXUSE_CLOUD_SYNC_PASSPHRASE";
16653
- var KEYCHAIN_ACCOUNT_PREFIX = "license-sha256:";
17596
+ var import_node_child_process9 = require("child_process");
17597
+ var import_node_crypto9 = require("crypto");
17598
+ var KEYCHAIN_SERVICE2 = "CODEXUSE_CLOUD_SYNC_PASSPHRASE";
17599
+ var KEYCHAIN_ACCOUNT_PREFIX2 = "license-sha256:";
16654
17600
  var ENCRYPTION_AAD = Buffer.from("codexuse-cloud-sync-v2", "utf8");
16655
17601
  var SCRYPT_PARAMS = {
16656
17602
  N: 32768,
@@ -16673,7 +17619,7 @@ function requireCloudSyncPassphrase(value) {
16673
17619
  }
16674
17620
  async function deriveKey(passphrase, salt, params = SCRYPT_PARAMS) {
16675
17621
  return new Promise((resolve, reject) => {
16676
- (0, import_node_crypto6.scrypt)(passphrase, salt, params.keyLength, {
17622
+ (0, import_node_crypto9.scrypt)(passphrase, salt, params.keyLength, {
16677
17623
  N: params.N,
16678
17624
  r: params.r,
16679
17625
  p: params.p,
@@ -16710,10 +17656,10 @@ function normalizeDecryptedSnapshot(value) {
16710
17656
  };
16711
17657
  }
16712
17658
  async function encryptCloudSyncSnapshot(snapshot, passphrase) {
16713
- const salt = (0, import_node_crypto6.randomBytes)(16);
16714
- const iv = (0, import_node_crypto6.randomBytes)(12);
17659
+ const salt = (0, import_node_crypto9.randomBytes)(16);
17660
+ const iv = (0, import_node_crypto9.randomBytes)(12);
16715
17661
  const key = await deriveKey(requireCloudSyncPassphrase(passphrase), salt);
16716
- const cipher = (0, import_node_crypto6.createCipheriv)("aes-256-gcm", key, iv);
17662
+ const cipher = (0, import_node_crypto9.createCipheriv)("aes-256-gcm", key, iv);
16717
17663
  cipher.setAAD(ENCRYPTION_AAD);
16718
17664
  const plaintext = Buffer.from(JSON.stringify(snapshot), "utf8");
16719
17665
  const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
@@ -16740,7 +17686,7 @@ async function decryptCloudSyncSnapshot(snapshot, passphrase) {
16740
17686
  const tag = fromBase64(snapshot.encryption.tag);
16741
17687
  const ciphertext = fromBase64(snapshot.encryption.ciphertext);
16742
17688
  const key = await deriveKey(requireCloudSyncPassphrase(passphrase), salt, snapshot.encryption.kdfParams);
16743
- const decipher = (0, import_node_crypto6.createDecipheriv)("aes-256-gcm", key, iv);
17689
+ const decipher = (0, import_node_crypto9.createDecipheriv)("aes-256-gcm", key, iv);
16744
17690
  decipher.setAAD(ENCRYPTION_AAD);
16745
17691
  decipher.setAuthTag(tag);
16746
17692
  const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
@@ -16755,12 +17701,12 @@ async function decryptCloudSyncSnapshot(snapshot, passphrase) {
16755
17701
  }
16756
17702
  }
16757
17703
  function keychainAccountForLicense(licenseKey) {
16758
- const digest = (0, import_node_crypto6.createHash)("sha256").update(licenseKey).digest("hex");
16759
- return KEYCHAIN_ACCOUNT_PREFIX + digest;
17704
+ const digest = (0, import_node_crypto9.createHash)("sha256").update(licenseKey).digest("hex");
17705
+ return KEYCHAIN_ACCOUNT_PREFIX2 + digest;
16760
17706
  }
16761
- function runSecurityCommand(args) {
17707
+ function runSecurityCommand2(args) {
16762
17708
  return new Promise((resolve, reject) => {
16763
- const child = (0, import_node_child_process7.spawn)("security", args, { stdio: ["ignore", "pipe", "ignore"] });
17709
+ const child = (0, import_node_child_process9.spawn)("security", args, { stdio: ["ignore", "pipe", "ignore"] });
16764
17710
  let stdout = "";
16765
17711
  child.stdout?.on("data", (chunk) => {
16766
17712
  stdout += String(chunk);
@@ -16777,12 +17723,12 @@ async function readRememberedCloudSyncPassphrase(licenseKey) {
16777
17723
  if (process.platform !== "darwin") {
16778
17724
  return null;
16779
17725
  }
16780
- const result = await runSecurityCommand([
17726
+ const result = await runSecurityCommand2([
16781
17727
  "find-generic-password",
16782
17728
  "-a",
16783
17729
  keychainAccountForLicense(licenseKey),
16784
17730
  "-s",
16785
- KEYCHAIN_SERVICE,
17731
+ KEYCHAIN_SERVICE2,
16786
17732
  "-w"
16787
17733
  ]);
16788
17734
  if (result.code !== 0) {
@@ -16795,13 +17741,13 @@ async function writeRememberedCloudSyncPassphrase(licenseKey, passphrase) {
16795
17741
  throw new Error("keychain-unsupported");
16796
17742
  }
16797
17743
  const value = requireCloudSyncPassphrase(passphrase);
16798
- const result = await runSecurityCommand([
17744
+ const result = await runSecurityCommand2([
16799
17745
  "add-generic-password",
16800
17746
  "-U",
16801
17747
  "-a",
16802
17748
  keychainAccountForLicense(licenseKey),
16803
17749
  "-s",
16804
- KEYCHAIN_SERVICE,
17750
+ KEYCHAIN_SERVICE2,
16805
17751
  "-w",
16806
17752
  value
16807
17753
  ]);
@@ -16880,31 +17826,144 @@ async function writeState(patch) {
16880
17826
  async function resolveEligibility() {
16881
17827
  const stored = await getStoredLicense();
16882
17828
  const licenseKey = typeof stored?.licenseKey === "string" ? stored.licenseKey.trim() : "";
16883
- if (!licenseKey) {
17829
+ const status = await licenseService.getStatus();
17830
+ if (licenseKey && status.isPro) {
17831
+ const active = status.state === "active" || status.state === "grace";
17832
+ if (active) {
17833
+ await migrateTrialCloudSyncToPaidLicenseSafe(licenseKey);
17834
+ }
16884
17835
  return {
16885
- canSync: false,
16886
- reason: "License key is required for cloud sync.",
16887
- licenseKey: null,
16888
- licenseState: null
17836
+ canSync: active,
17837
+ canDelete: active,
17838
+ reason: active ? null : "Cloud sync requires an active Pro license.",
17839
+ access: active ? { syncKey: licenseKey } : null,
17840
+ hasPaidLicenseKey: true,
17841
+ licenseState: status.state
16889
17842
  };
16890
17843
  }
16891
- const status = await licenseService.getStatus();
16892
- const active = status.state === "active" || status.state === "grace";
16893
- if (!active) {
17844
+ if (status.trial?.active && status.capabilities.cloudSync) {
17845
+ const trialAccess = await resolveTrialCloudSyncAccess();
17846
+ if (trialAccess) {
17847
+ return {
17848
+ canSync: true,
17849
+ canDelete: true,
17850
+ reason: null,
17851
+ access: trialAccess,
17852
+ hasPaidLicenseKey: false,
17853
+ licenseState: status.state
17854
+ };
17855
+ }
16894
17856
  return {
16895
17857
  canSync: false,
16896
- reason: "Cloud sync requires an active Pro license.",
16897
- licenseKey,
17858
+ canDelete: false,
17859
+ reason: "Cloud sync trial identity is unavailable.",
17860
+ access: null,
17861
+ hasPaidLicenseKey: false,
16898
17862
  licenseState: status.state
16899
17863
  };
16900
17864
  }
17865
+ if (status.trial?.expired) {
17866
+ const trialAccess = await resolveTrialCloudSyncAccess();
17867
+ if (trialAccess) {
17868
+ return {
17869
+ canSync: false,
17870
+ canDelete: true,
17871
+ reason: "Cloud sync requires an active trial or Pro license.",
17872
+ access: trialAccess,
17873
+ hasPaidLicenseKey: false,
17874
+ licenseState: status.state
17875
+ };
17876
+ }
17877
+ }
16901
17878
  return {
16902
- canSync: true,
16903
- reason: null,
16904
- licenseKey,
17879
+ canSync: false,
17880
+ canDelete: false,
17881
+ reason: "Cloud sync requires an active trial or Pro license.",
17882
+ access: null,
17883
+ hasPaidLicenseKey: false,
16905
17884
  licenseState: status.state
16906
17885
  };
16907
17886
  }
17887
+ async function hasRemoteSnapshot(access) {
17888
+ const meta = await fetchRemoteSnapshotMeta(access);
17889
+ return meta.snapshotKind !== "none" || Boolean(meta.updatedAt);
17890
+ }
17891
+ async function readRemoteSnapshotOrNull(access) {
17892
+ try {
17893
+ return await fetchRemoteSnapshot(access);
17894
+ } catch (error) {
17895
+ if (error instanceof CloudSyncClientError && (error.status === 403 || error.status === 404)) {
17896
+ return null;
17897
+ }
17898
+ throw error;
17899
+ }
17900
+ }
17901
+ async function migrateTrialPassphraseToPaidLicense(trialKey, licenseKey) {
17902
+ const paidPassphrase = await readRememberedCloudSyncPassphrase(licenseKey).catch(() => null);
17903
+ if (paidPassphrase) {
17904
+ return;
17905
+ }
17906
+ const trialPassphrase = await readRememberedCloudSyncPassphrase(trialKey).catch(() => null);
17907
+ if (!trialPassphrase) {
17908
+ return;
17909
+ }
17910
+ await writeRememberedCloudSyncPassphrase(licenseKey, trialPassphrase);
17911
+ }
17912
+ async function migrateTrialCloudSyncToPaidLicense(licenseKey) {
17913
+ const paidLicenseKey = licenseKey.trim();
17914
+ if (!paidLicenseKey) {
17915
+ return;
17916
+ }
17917
+ const trialAccess = await resolveTrialCloudSyncAccess();
17918
+ if (!trialAccess || trialAccess.syncKey === paidLicenseKey) {
17919
+ return;
17920
+ }
17921
+ if (await hasRemoteSnapshot({ syncKey: paidLicenseKey })) {
17922
+ await migrateTrialPassphraseToPaidLicense(trialAccess.syncKey, paidLicenseKey).catch((error) => {
17923
+ logWarn("[cloud-sync] failed to migrate remembered trial passphrase", {
17924
+ error: error instanceof Error ? error.message : String(error)
17925
+ });
17926
+ });
17927
+ return;
17928
+ }
17929
+ const trialSnapshot = await readRemoteSnapshotOrNull({
17930
+ ...trialAccess,
17931
+ syncKey: paidLicenseKey,
17932
+ trialMigration: true
17933
+ });
17934
+ if (trialSnapshot) {
17935
+ await pushRemoteSnapshot({ syncKey: paidLicenseKey }, trialSnapshot, {
17936
+ serializedSnapshot: JSON.stringify(trialSnapshot)
17937
+ });
17938
+ }
17939
+ await migrateTrialPassphraseToPaidLicense(trialAccess.syncKey, paidLicenseKey);
17940
+ }
17941
+ async function migrateTrialCloudSyncToPaidLicenseSafe(licenseKey) {
17942
+ try {
17943
+ await migrateTrialCloudSyncToPaidLicense(licenseKey);
17944
+ } catch (error) {
17945
+ logWarn("[cloud-sync] trial snapshot migration to paid license failed", {
17946
+ error: error instanceof Error ? error.message : String(error)
17947
+ });
17948
+ }
17949
+ }
17950
+ async function resolveTrialCloudSyncAccess() {
17951
+ let deviceId;
17952
+ try {
17953
+ deviceId = await getDeviceId();
17954
+ } catch {
17955
+ return null;
17956
+ }
17957
+ const trialToken = await readStoredTrialToken(deviceId).catch(() => null);
17958
+ if (!trialToken) {
17959
+ return null;
17960
+ }
17961
+ return {
17962
+ syncKey: `trial:${deviceId}`,
17963
+ trialDeviceId: deviceId,
17964
+ trialToken
17965
+ };
17966
+ }
16908
17967
  function formatMegabytes(bytes) {
16909
17968
  return (bytes / MB_DIVISOR).toFixed(2);
16910
17969
  }
@@ -16997,19 +18056,19 @@ async function getCloudSyncStatus() {
16997
18056
  let remoteUpdatedAt = state.remoteUpdatedAt ?? null;
16998
18057
  let remoteKind = state.remoteKind ?? "none";
16999
18058
  let hasRememberedPassphrase = false;
17000
- if (eligibility.canSync && eligibility.licenseKey) {
18059
+ if (eligibility.canSync && eligibility.access) {
17001
18060
  hasRememberedPassphrase = Boolean(
17002
- await readRememberedCloudSyncPassphrase(eligibility.licenseKey).catch(() => null)
18061
+ await readRememberedCloudSyncPassphrase(eligibility.access.syncKey).catch(() => null)
17003
18062
  );
17004
18063
  try {
17005
- const remoteMeta = await fetchRemoteSnapshotMeta(eligibility.licenseKey);
18064
+ const remoteMeta = await fetchRemoteSnapshotMeta(eligibility.access);
17006
18065
  remoteUpdatedAt = remoteMeta.updatedAt;
17007
18066
  remoteKind = remoteMeta.snapshotKind;
17008
18067
  await writeState({ remoteUpdatedAt, remoteKind });
17009
18068
  } catch (error) {
17010
18069
  if (error instanceof CloudSyncClientError && error.status === 404) {
17011
18070
  try {
17012
- const remote = await fetchRemoteSnapshot(eligibility.licenseKey);
18071
+ const remote = await fetchRemoteSnapshot(eligibility.access);
17013
18072
  remoteUpdatedAt = remote?.updatedAt ?? null;
17014
18073
  remoteKind = getSnapshotKind(remote);
17015
18074
  } catch {
@@ -17019,9 +18078,10 @@ async function getCloudSyncStatus() {
17019
18078
  }
17020
18079
  return {
17021
18080
  canSync: eligibility.canSync,
18081
+ canDelete: eligibility.canDelete,
17022
18082
  reason: eligibility.reason,
17023
18083
  licenseState: eligibility.licenseState,
17024
- hasLicenseKey: Boolean(eligibility.licenseKey),
18084
+ hasLicenseKey: eligibility.hasPaidLicenseKey,
17025
18085
  hasRememberedPassphrase,
17026
18086
  lastPushAt: state.lastPushAt ?? null,
17027
18087
  lastPullAt: state.lastPullAt ?? null,
@@ -17032,7 +18092,7 @@ async function getCloudSyncStatus() {
17032
18092
  }
17033
18093
  async function pushCloudSync(options = {}) {
17034
18094
  const eligibility = await resolveEligibility();
17035
- if (!eligibility.canSync || !eligibility.licenseKey) {
18095
+ if (!eligibility.canSync || !eligibility.access) {
17036
18096
  return {
17037
18097
  mode: "push",
17038
18098
  status: "skipped",
@@ -17045,7 +18105,7 @@ async function pushCloudSync(options = {}) {
17045
18105
  try {
17046
18106
  await profileManager.initialize();
17047
18107
  const localSnapshot = await buildLocalSnapshot(profileManager, { enforcePushGuards: true });
17048
- const passphrase = await resolvePassphrase(eligibility.licenseKey, options);
18108
+ const passphrase = await resolvePassphrase(eligibility.access.syncKey, options);
17049
18109
  const encryptedSnapshot = await encryptCloudSyncSnapshot(localSnapshot, passphrase.value);
17050
18110
  const serializedSnapshot = JSON.stringify(encryptedSnapshot);
17051
18111
  const snapshotBytes = Buffer.byteLength(serializedSnapshot, "utf8");
@@ -17063,7 +18123,7 @@ async function pushCloudSync(options = {}) {
17063
18123
  if (process.env.NODE_ENV !== "production") {
17064
18124
  logInfo("[cloud-sync] push snapshot summary", summarizeSnapshot(localSnapshot));
17065
18125
  }
17066
- const remote = await pushRemoteSnapshot(eligibility.licenseKey, encryptedSnapshot, {
18126
+ const remote = await pushRemoteSnapshot(eligibility.access, encryptedSnapshot, {
17067
18127
  serializedSnapshot
17068
18128
  });
17069
18129
  const remoteKind = getSnapshotKind(remote.snapshot);
@@ -17082,7 +18142,7 @@ async function pushCloudSync(options = {}) {
17082
18142
  remoteUpdatedAt: remote.snapshot.updatedAt
17083
18143
  };
17084
18144
  }
17085
- await rememberPassphraseIfRequested(eligibility.licenseKey, options, passphrase);
18145
+ await rememberPassphraseIfRequested(eligibility.access.syncKey, options, passphrase);
17086
18146
  return {
17087
18147
  mode: "push",
17088
18148
  status: "applied",
@@ -17099,7 +18159,7 @@ async function pushCloudSync(options = {}) {
17099
18159
  }
17100
18160
  async function pullCloudSync(options = {}) {
17101
18161
  const eligibility = await resolveEligibility();
17102
- if (!eligibility.canSync || !eligibility.licenseKey) {
18162
+ if (!eligibility.canSync || !eligibility.access) {
17103
18163
  return {
17104
18164
  mode: "pull",
17105
18165
  status: "skipped",
@@ -17111,7 +18171,7 @@ async function pullCloudSync(options = {}) {
17111
18171
  const profileManager = new ProfileManager();
17112
18172
  try {
17113
18173
  await profileManager.initialize();
17114
- const remote = await fetchRemoteSnapshot(eligibility.licenseKey);
18174
+ const remote = await fetchRemoteSnapshot(eligibility.access);
17115
18175
  if (!remote) {
17116
18176
  await writeState({ remoteUpdatedAt: null, remoteKind: "none" });
17117
18177
  return {
@@ -17126,7 +18186,7 @@ async function pullCloudSync(options = {}) {
17126
18186
  let passphrase = null;
17127
18187
  let plainSnapshot;
17128
18188
  if (remote.schemaVersion === CLOUD_SYNC_ENCRYPTED_SCHEMA_VERSION) {
17129
- passphrase = await resolvePassphrase(eligibility.licenseKey, options);
18189
+ passphrase = await resolvePassphrase(eligibility.access.syncKey, options);
17130
18190
  plainSnapshot = await decryptCloudSyncSnapshot(remote, passphrase.value);
17131
18191
  } else {
17132
18192
  plainSnapshot = remote;
@@ -17139,7 +18199,7 @@ async function pullCloudSync(options = {}) {
17139
18199
  lastError: void 0
17140
18200
  });
17141
18201
  if (passphrase) {
17142
- await rememberPassphraseIfRequested(eligibility.licenseKey, options, passphrase);
18202
+ await rememberPassphraseIfRequested(eligibility.access.syncKey, options, passphrase);
17143
18203
  }
17144
18204
  return {
17145
18205
  mode: "pull",
@@ -17252,7 +18312,7 @@ async function ensureCliStorageReady() {
17252
18312
  }
17253
18313
 
17254
18314
  // src/app/main.ts
17255
- var VERSION = true ? "5.1.0" : "0.0.0";
18315
+ var VERSION = true ? "5.1.5" : "0.0.0";
17256
18316
  async function runCli() {
17257
18317
  const args = process.argv.slice(2);
17258
18318
  if (args.length === 0) {