codexuse-cli 5.1.0 → 5.1.1

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
  }
@@ -3763,6 +4358,47 @@ function ensureWithinUseLimit(response) {
3763
4358
  );
3764
4359
  }
3765
4360
  }
4361
+ function computeCapabilities(opts) {
4362
+ return {
4363
+ unlimitedProfiles: opts.entitled,
4364
+ accountPool: opts.entitled,
4365
+ telegram: opts.entitled,
4366
+ autoRoll: opts.entitled,
4367
+ cloudSync: opts.licensed || opts.entitled
4368
+ };
4369
+ }
4370
+ function applyTrial(base, trial) {
4371
+ if (base.isPro) {
4372
+ return { ...base, trial: null };
4373
+ }
4374
+ const { info, locked } = trial;
4375
+ if (!info) {
4376
+ return base;
4377
+ }
4378
+ if (info.active) {
4379
+ return {
4380
+ ...base,
4381
+ tier: "trial",
4382
+ state: "trial",
4383
+ capabilities: computeCapabilities({ licensed: false, entitled: true }),
4384
+ profileLimit: null,
4385
+ profilesRemaining: null,
4386
+ trial: info
4387
+ };
4388
+ }
4389
+ if (locked) {
4390
+ return {
4391
+ ...base,
4392
+ tier: "free",
4393
+ state: "locked",
4394
+ capabilities: computeCapabilities({ licensed: false, entitled: false }),
4395
+ profileLimit: 0,
4396
+ profilesRemaining: 0,
4397
+ trial: info
4398
+ };
4399
+ }
4400
+ return { ...base, trial: info };
4401
+ }
3766
4402
  function toLicenseStatus(stored, overrides = {}) {
3767
4403
  const tier = determineTierFromStored(stored);
3768
4404
  const isPro = tier === "pro";
@@ -3771,6 +4407,8 @@ function toLicenseStatus(stored, overrides = {}) {
3771
4407
  tier,
3772
4408
  state,
3773
4409
  isPro,
4410
+ capabilities: computeCapabilities({ licensed: isPro, entitled: isPro }),
4411
+ trial: null,
3774
4412
  profileLimit: isPro ? null : FREE_PROFILE_LIMIT,
3775
4413
  profilesRemaining: null,
3776
4414
  purchaseEmail: stored?.purchaseEmail ?? null,
@@ -3812,15 +4450,27 @@ var LicenseService = class {
3812
4450
  const refreshInBackground = Boolean(options.refreshInBackground);
3813
4451
  const secret = await getLicenseSecret();
3814
4452
  const stored = await getStoredLicense();
4453
+ const finalize = async (status) => {
4454
+ if (status.isPro) {
4455
+ return { ...status, trial: null };
4456
+ }
4457
+ return applyTrial(
4458
+ status,
4459
+ await resolveTrialState(Date.now(), {
4460
+ allowNetwork: !allowStale || forceRefresh,
4461
+ refreshInBackground
4462
+ })
4463
+ );
4464
+ };
3815
4465
  if (!stored?.licenseKey) {
3816
- return toLicenseStatus(null);
4466
+ return finalize(toLicenseStatus(null));
3817
4467
  }
3818
4468
  const now = Date.now();
3819
4469
  const nextCheckTs = parseTimestamp(stored.nextCheckAt);
3820
4470
  const lastVerifiedTs = parseTimestamp(stored.lastVerifiedAt);
3821
4471
  const graceStale = (stored.status === "grace" || stored.status === "error") && (lastVerifiedTs === null || lastVerifiedTs + GRACE_MAX_AGE_MS < now);
3822
4472
  let workingStored = { ...stored };
3823
- const signatureValid = isSignatureValid(workingStored, secret);
4473
+ const signatureValid = isSignatureValid2(workingStored, secret);
3824
4474
  let cappedNextCheckTs = nextCheckTs;
3825
4475
  if (nextCheckTs !== null && nextCheckTs > now + MAX_NEXT_CHECK_MS) {
3826
4476
  cappedNextCheckTs = now;
@@ -3843,7 +4493,7 @@ var LicenseService = class {
3843
4493
  if (allowStale && shouldRefresh && refreshInBackground) {
3844
4494
  this.refreshStatusInBackground({ force: forceRefresh });
3845
4495
  }
3846
- return cached;
4496
+ return finalize(cached);
3847
4497
  }
3848
4498
  if (this.verificationPromise && !forceRefresh) {
3849
4499
  return this.verificationPromise;
@@ -3863,7 +4513,7 @@ var LicenseService = class {
3863
4513
  };
3864
4514
  const signed = withSignature(updated, secret);
3865
4515
  await persistLicense(signed);
3866
- return toLicenseStatus(signed);
4516
+ return finalize(toLicenseStatus(signed));
3867
4517
  } catch (error) {
3868
4518
  const message = error instanceof Error ? error.message : "License verification failed.";
3869
4519
  if (error instanceof LicenseError && error.code === "network") {
@@ -3881,7 +4531,7 @@ var LicenseService = class {
3881
4531
  state: fallbackStored2.status ?? "grace",
3882
4532
  error: message
3883
4533
  });
3884
- return fallback;
4534
+ return finalize(fallback);
3885
4535
  }
3886
4536
  const fallbackStored = withSignature({
3887
4537
  licenseKey: workingStored.licenseKey,
@@ -3892,7 +4542,7 @@ var LicenseService = class {
3892
4542
  lastVerificationError: message
3893
4543
  }, secret);
3894
4544
  await persistLicense(fallbackStored);
3895
- return toLicenseStatus(fallbackStored, { error: message });
4545
+ return finalize(toLicenseStatus(fallbackStored, { error: message }));
3896
4546
  }
3897
4547
  };
3898
4548
  this.verificationPromise = verify();
@@ -3908,7 +4558,7 @@ var LicenseService = class {
3908
4558
  throw new Error("License key is required.");
3909
4559
  }
3910
4560
  const secret = await getLicenseSecret();
3911
- const digest = import_node_crypto2.default.createHash("sha256").update(trimmed).digest("hex");
4561
+ const digest = import_node_crypto5.default.createHash("sha256").update(trimmed).digest("hex");
3912
4562
  const result = await requestGumroadVerify(trimmed, "activation");
3913
4563
  ensureWithinUseLimit(result);
3914
4564
  const normalized = normalizeVerificationResult(result);
@@ -3950,9 +4600,28 @@ var LicenseService = class {
3950
4600
  }
3951
4601
  };
3952
4602
  var licenseService = new LicenseService();
4603
+ function isExplicitInvalidation(message) {
4604
+ if (!message) {
4605
+ return false;
4606
+ }
4607
+ const normalized = message.toLowerCase();
4608
+ return normalized.includes("revoked") || normalized.includes("refunded") || normalized.includes("invalid") || normalized.includes("no longer active");
4609
+ }
4610
+ function shouldEnforceProfileLimit(status) {
4611
+ if (status.capabilities.unlimitedProfiles) {
4612
+ return false;
4613
+ }
4614
+ if (status.state === "grace" || status.state === "verifying" || status.state === "error") {
4615
+ return false;
4616
+ }
4617
+ if (isExplicitInvalidation(status.error)) {
4618
+ return true;
4619
+ }
4620
+ return status.state === "inactive" || status.state === "locked";
4621
+ }
3953
4622
 
3954
4623
  // ../../packages/runtime-profiles/src/profiles/profile-manager.ts
3955
- var import_node_crypto3 = require("crypto");
4624
+ var import_node_crypto6 = require("crypto");
3956
4625
  var import_fs = require("fs");
3957
4626
  var import_path = __toESM(require("path"), 1);
3958
4627
  var import_path2 = require("path");
@@ -4005,7 +4674,7 @@ function resolveProfileIdentityKeyFromProfile(profile) {
4005
4674
  }
4006
4675
 
4007
4676
  // ../../packages/runtime-codex/src/codex/rpc.ts
4008
- var import_node_child_process2 = require("child_process");
4677
+ var import_node_child_process4 = require("child_process");
4009
4678
  var import_node_readline = __toESM(require("readline"), 1);
4010
4679
  var import_node_fs3 = require("fs");
4011
4680
  var import_node_os2 = __toESM(require("os"), 1);
@@ -4137,7 +4806,7 @@ async function requireCodexCli() {
4137
4806
  }
4138
4807
 
4139
4808
  // ../../packages/runtime-codex/src/codex/command.ts
4140
- var import_node_child_process = require("child_process");
4809
+ var import_node_child_process3 = require("child_process");
4141
4810
  var import_node_path4 = __toESM(require("path"), 1);
4142
4811
  var cachedNodeRuntime = null;
4143
4812
  function isJavaScriptEntrypoint(binaryPath) {
@@ -4180,7 +4849,7 @@ function resolveNodeRuntime(env) {
4180
4849
  )
4181
4850
  );
4182
4851
  for (const candidate of candidates) {
4183
- const probe = (0, import_node_child_process.spawnSync)(candidate, ["-v"], { env: runtimeEnv, stdio: "ignore" });
4852
+ const probe = (0, import_node_child_process3.spawnSync)(candidate, ["-v"], { env: runtimeEnv, stdio: "ignore" });
4184
4853
  if (!probe.error && probe.status === 0) {
4185
4854
  cachedNodeRuntime = candidate;
4186
4855
  return candidate;
@@ -5059,7 +5728,7 @@ async function fetchRateLimitsViaRpc(envOverride, options = {}) {
5059
5728
  ["-s", "read-only", "-a", "untrusted", "app-server"],
5060
5729
  childEnv
5061
5730
  );
5062
- const child = (0, import_node_child_process2.spawn)(command.command, command.args, {
5731
+ const child = (0, import_node_child_process4.spawn)(command.command, command.args, {
5063
5732
  stdio: ["pipe", "pipe", "pipe"],
5064
5733
  env: childEnv,
5065
5734
  shell: command.shell
@@ -5169,7 +5838,7 @@ async function activateResetWindowViaRpc(envOverride, options = {}) {
5169
5838
  ["-s", "read-only", "-a", "untrusted", "app-server"],
5170
5839
  childEnv
5171
5840
  );
5172
- const child = (0, import_node_child_process2.spawn)(command.command, command.args, {
5841
+ const child = (0, import_node_child_process4.spawn)(command.command, command.args, {
5173
5842
  stdio: ["pipe", "pipe", "pipe"],
5174
5843
  env: childEnv,
5175
5844
  shell: command.shell
@@ -5633,7 +6302,7 @@ var ProfileManager = class {
5633
6302
  if (!trimmed) {
5634
6303
  return this.emptyAuthSnapshot();
5635
6304
  }
5636
- const fingerprint = (0, import_node_crypto3.createHash)("sha256").update(trimmed).digest("hex");
6305
+ const fingerprint = (0, import_node_crypto6.createHash)("sha256").update(trimmed).digest("hex");
5637
6306
  try {
5638
6307
  const parsed = JSON.parse(trimmed);
5639
6308
  const normalized = this.normalizeProfileData(parsed);
@@ -7285,7 +7954,7 @@ var ProfileManager = class {
7285
7954
  }
7286
7955
  if (options.canAutoImport === false) {
7287
7956
  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."
7957
+ importBlockedReason: options.importBlockedReason ?? "Your CodexUse trial has ended. Upgrade to Pro before importing this Codex login."
7289
7958
  });
7290
7959
  }
7291
7960
  const records = await this.listProfileRecords();
@@ -7473,7 +8142,7 @@ Flags:
7473
8142
  --runtime=NAME Accounts Pool runtime store: desktop
7474
8143
  --state-dir=PATH Override the runtime state dir for Accounts Pool inspection
7475
8144
  --passphrase-stdin Read Cloud Sync passphrase from stdin
7476
- Note: profile autoroll requires Pro.
8145
+ Note: profile autoroll requires Pro or an active trial.
7477
8146
  Cloud Sync: set CODEXUSE_SYNC_PASSPHRASE or use --passphrase-stdin unless the passphrase is saved in Keychain.
7478
8147
  `);
7479
8148
  }
@@ -7525,7 +8194,7 @@ function parseStringFlag(flags, name) {
7525
8194
 
7526
8195
  // src/commands/accountPool.ts
7527
8196
  var ACCOUNT_POOL_DOCUMENT = "desktop.account-pool.v2";
7528
- var ACCOUNT_POOL_PRO_REQUIRED_MESSAGE = "Accounts Pool requires a Pro license.";
8197
+ var ACCOUNT_POOL_PRO_REQUIRED_MESSAGE = "Accounts Pool requires a Pro license or an active trial.";
7529
8198
  var DESKTOP_RPC_STATE_DIR = "desktop-rpc";
7530
8199
  var ACCOUNT_POOL_STORE_VERSION = 3;
7531
8200
  var MAX_RESPONSE_IDS_PER_SESSION = 64;
@@ -7913,13 +8582,13 @@ async function listApiKeys(stateDir) {
7913
8582
  return Object.values(store.apiKeysById).filter((key) => key.revokedAt === null).sort((left, right) => right.createdAt.localeCompare(left.createdAt)).map(accountPoolApiKeyView);
7914
8583
  }
7915
8584
  function hashToken(token) {
7916
- return (0, import_node_crypto4.createHash)("sha256").update(token).digest("hex");
8585
+ return (0, import_node_crypto7.createHash)("sha256").update(token).digest("hex");
7917
8586
  }
7918
8587
  async function createApiKey(stateDir) {
7919
- const plaintextToken = `cux_pool_${(0, import_node_crypto4.randomBytes)(24).toString("hex")}`;
8588
+ const plaintextToken = `cux_pool_${(0, import_node_crypto7.randomBytes)(24).toString("hex")}`;
7920
8589
  const now = (/* @__PURE__ */ new Date()).toISOString();
7921
8590
  const keyRecord = {
7922
- id: (0, import_node_crypto4.randomUUID)(),
8591
+ id: (0, import_node_crypto7.randomUUID)(),
7923
8592
  tokenHash: hashToken(plaintextToken),
7924
8593
  tokenPreview: `${plaintextToken.slice(0, 8)}...${plaintextToken.slice(-6)}`,
7925
8594
  createdAt: now,
@@ -8013,7 +8682,7 @@ async function readAccountPoolRuntimeSummary(input = {}) {
8013
8682
  stateDir,
8014
8683
  baseUrl: resolveBaseUrlFromPort(runtime, input.port ?? null),
8015
8684
  enabled: normalized.accountPoolEnabled,
8016
- hasProLicense: license?.isPro === true,
8685
+ hasAccountPoolAccess: license?.capabilities.accountPool === true,
8017
8686
  routingStrategy: normalized.accountPoolRoutingStrategy,
8018
8687
  activeApiKeyCount: apiKeys.length,
8019
8688
  activeSessionCount: sessions.length
@@ -8030,7 +8699,7 @@ async function updateSettings(transform) {
8030
8699
  const { raw, normalized } = await readSettingsSnapshot();
8031
8700
  const nextSettings = transform(normalized);
8032
8701
  const license = await licenseService.getStatus().catch(() => null);
8033
- const forcedDisabledByLicense = !license?.isPro && nextSettings.accountPoolEnabled === true;
8702
+ const forcedDisabledByLicense = license?.capabilities.accountPool !== true && nextSettings.accountPoolEnabled === true;
8034
8703
  const sanitizedSettings = {
8035
8704
  ...nextSettings,
8036
8705
  accountPoolEnabled: forcedDisabledByLicense ? false : nextSettings.accountPoolEnabled,
@@ -8057,7 +8726,7 @@ async function updateSettings(transform) {
8057
8726
  }
8058
8727
  async function requireProAccess() {
8059
8728
  const license = await licenseService.getStatus();
8060
- if (!license.isPro) {
8729
+ if (!license.capabilities.accountPool) {
8061
8730
  throw new Error(ACCOUNT_POOL_PRO_REQUIRED_MESSAGE);
8062
8731
  }
8063
8732
  }
@@ -8119,7 +8788,7 @@ async function handleStatus(flags) {
8119
8788
  console.log(`Runtime: ${runtime}`);
8120
8789
  console.log(`State dir: ${stateDir}`);
8121
8790
  console.log(`Routing: ${formatRoutingStrategy(normalized.accountPoolRoutingStrategy)}`);
8122
- console.log(`Public API ready: ${normalized.accountPoolEnabled && license?.isPro === true && apiKeys.length > 0 ? "yes" : "no"}`);
8791
+ console.log(`Public API ready: ${normalized.accountPoolEnabled && license?.capabilities.accountPool === true && apiKeys.length > 0 ? "yes" : "no"}`);
8123
8792
  console.log(`API keys: ${apiKeys.length}`);
8124
8793
  console.log(`Sessions: ${sessions.length}`);
8125
8794
  console.log(`Selection mode: ${explicitSelection.length > 0 ? "explicit" : "all saved profiles"}`);
@@ -8135,7 +8804,7 @@ async function handleStatus(flags) {
8135
8804
  printStringList("Published models", normalized.accountPoolExposedModels);
8136
8805
  printStringList("Reasoning aliases", normalized.accountPoolExposedReasoningEfforts);
8137
8806
  printStringList("Fast-mode aliases", normalized.accountPoolExposedFastModeReasoningEfforts);
8138
- if (normalized.accountPoolEnabled && license?.isPro !== true) {
8807
+ if (normalized.accountPoolEnabled && license?.capabilities.accountPool !== true) {
8139
8808
  console.log(ACCOUNT_POOL_PRO_REQUIRED_MESSAGE);
8140
8809
  }
8141
8810
  }
@@ -8340,7 +9009,7 @@ async function handleQuickstart(flags) {
8340
9009
  console.log("Accounts Pool quickstart");
8341
9010
  console.log(`Runtime: ${summary.runtime}`);
8342
9011
  console.log(`Enabled: ${summary.enabled ? "yes" : "no"}`);
8343
- console.log(`Pro: ${summary.hasProLicense ? "yes" : "no"}`);
9012
+ console.log(`Access: ${summary.hasAccountPoolAccess ? "yes" : "no"}`);
8344
9013
  console.log(`API keys: ${summary.activeApiKeyCount}`);
8345
9014
  console.log(`Base URL: ${baseUrl}`);
8346
9015
  console.log("");
@@ -8424,7 +9093,7 @@ async function handleAccountPoolCommand(args, version) {
8424
9093
  }
8425
9094
 
8426
9095
  // src/commands/codex.ts
8427
- var import_node_child_process4 = require("child_process");
9096
+ var import_node_child_process6 = require("child_process");
8428
9097
 
8429
9098
  // ../../packages/runtime-profiles/src/profiles/rate-limit-notifier.ts
8430
9099
  function maxUsedPercent(snapshot) {
@@ -8441,8 +9110,108 @@ function maxUsedPercent(snapshot) {
8441
9110
  return Math.max(...candidates);
8442
9111
  }
8443
9112
 
9113
+ // ../../packages/runtime-profiles/src/profiles/profile-visibility.ts
9114
+ function resolveLicenseVisibleProfiles(args) {
9115
+ const { profiles, license, currentProfile } = args;
9116
+ const licenseWithCounts = licenseService.applyProfileCount(license, profiles.length);
9117
+ const enforceProfileLimit = shouldEnforceProfileLimit(licenseWithCounts);
9118
+ const visibleProfiles = enforceProfileLimit ? resolveVisibleProfiles(profiles, licenseWithCounts, currentProfile) : profiles;
9119
+ return {
9120
+ allProfiles: profiles,
9121
+ profiles: licenseWithCounts.capabilities.unlimitedProfiles ? profiles : visibleProfiles,
9122
+ license,
9123
+ licenseWithCounts,
9124
+ enforceProfileLimit
9125
+ };
9126
+ }
9127
+ async function loadLicenseVisibleProfiles(profileManager, options = {}) {
9128
+ await profileManager.initialize();
9129
+ const license = options.freshLicense ? await licenseService.getStatus() : await licenseService.getCachedStatus();
9130
+ const profiles = await profileManager.listProfiles();
9131
+ const currentProfile = options.currentProfile !== void 0 ? options.currentProfile : (await profileManager.getCurrentProfile()).name;
9132
+ return resolveLicenseVisibleProfiles({
9133
+ profiles,
9134
+ license,
9135
+ currentProfile
9136
+ });
9137
+ }
9138
+ function resolveVisibleProfiles(profiles, license, currentProfile) {
9139
+ if (license.capabilities.unlimitedProfiles) {
9140
+ return profiles;
9141
+ }
9142
+ const limit = typeof license.profileLimit === "number" && license.profileLimit >= 0 ? license.profileLimit : FREE_PROFILE_LIMIT;
9143
+ if (profiles.length <= limit) {
9144
+ return profiles;
9145
+ }
9146
+ const normalizedCurrent = currentProfile ?? null;
9147
+ const sorted = profiles.slice().sort((a, b) => compareProfilesForLimit(a, b, normalizedCurrent));
9148
+ return sorted.slice(0, limit);
9149
+ }
9150
+ function compareProfilesForLimit(a, b, currentProfile) {
9151
+ if (currentProfile) {
9152
+ if (a.name === currentProfile && b.name !== currentProfile) {
9153
+ return -1;
9154
+ }
9155
+ if (b.name === currentProfile && a.name !== currentProfile) {
9156
+ return 1;
9157
+ }
9158
+ }
9159
+ if (Boolean(a.isValid) !== Boolean(b.isValid)) {
9160
+ return a.isValid ? -1 : 1;
9161
+ }
9162
+ const aTimestamp = parseTimestamp3(a.createdAt ?? null);
9163
+ const bTimestamp = parseTimestamp3(b.createdAt ?? null);
9164
+ if (aTimestamp !== null && bTimestamp !== null) {
9165
+ if (aTimestamp === bTimestamp) {
9166
+ return a.name.localeCompare(b.name);
9167
+ }
9168
+ return bTimestamp - aTimestamp;
9169
+ }
9170
+ if (aTimestamp !== null) {
9171
+ return -1;
9172
+ }
9173
+ if (bTimestamp !== null) {
9174
+ return 1;
9175
+ }
9176
+ return a.name.localeCompare(b.name);
9177
+ }
9178
+ function parseTimestamp3(value) {
9179
+ if (typeof value !== "string" || value.trim() === "") {
9180
+ return null;
9181
+ }
9182
+ const parsed = Date.parse(value);
9183
+ return Number.isNaN(parsed) ? null : parsed;
9184
+ }
9185
+
9186
+ // ../../packages/runtime-profiles/src/license/guard.ts
9187
+ var PROFILE_ACCESS_DENIED_MESSAGE = "Your CodexUse trial has ended. Upgrade to Pro to use saved profiles.";
9188
+ async function assertProfileCreationAllowed(profileManager) {
9189
+ const manager = profileManager ?? new ProfileManager();
9190
+ await manager.initialize();
9191
+ const license = await licenseService.getStatus();
9192
+ const profiles = await manager.listProfiles();
9193
+ const licenseWithCounts = licenseService.applyProfileCount(license, profiles.length);
9194
+ if (typeof licenseWithCounts.profileLimit === "number" && licenseWithCounts.profilesRemaining !== null && licenseWithCounts.profilesRemaining <= 0) {
9195
+ throw new Error("Your CodexUse trial has ended. Upgrade to Pro for unlimited profiles.");
9196
+ }
9197
+ }
9198
+ async function assertProfileAccessAllowed(profileManager, profileName) {
9199
+ const name = profileName.trim();
9200
+ if (!name) {
9201
+ throw new Error("Profile name is required.");
9202
+ }
9203
+ const visible = await loadLicenseVisibleProfiles(profileManager, {
9204
+ freshLicense: true
9205
+ });
9206
+ const exists = visible.allProfiles.some((profile) => profile.name === name);
9207
+ const allowed = visible.profiles.some((profile) => profile.name === name);
9208
+ if (exists && !allowed) {
9209
+ throw new Error(PROFILE_ACCESS_DENIED_MESSAGE);
9210
+ }
9211
+ }
9212
+
8444
9213
  // src/platform/codexCli.ts
8445
- var import_node_child_process3 = require("child_process");
9214
+ var import_node_child_process5 = require("child_process");
8446
9215
  var import_node_fs5 = require("fs");
8447
9216
  var import_node_path8 = __toESM(require("path"));
8448
9217
  var ENV_HINTS2 = ["CODEX_BINARY", "CODEX_CLI_PATH", "CODEX_PATH"];
@@ -8514,7 +9283,7 @@ async function runCodexLogin(mode) {
8514
9283
  const resolvedMode = resolveLoginMode(mode ?? null);
8515
9284
  const loginArgs = resolvedMode === "device" ? ["login", "--device-auth"] : ["login"];
8516
9285
  const { command, args, shell } = buildCodexCommand2(codexPath, loginArgs);
8517
- const child = (0, import_node_child_process3.spawn)(command, args, {
9286
+ const child = (0, import_node_child_process5.spawn)(command, args, {
8518
9287
  stdio: "inherit",
8519
9288
  env: process.env,
8520
9289
  shell
@@ -8586,7 +9355,7 @@ function compareCandidates(left, right) {
8586
9355
  async function runCommand(codexPath, args, timeoutMs) {
8587
9356
  const command = buildCodexCommand2(codexPath, args);
8588
9357
  return new Promise((resolve) => {
8589
- const child = (0, import_node_child_process4.spawn)(command.command, command.args, {
9358
+ const child = (0, import_node_child_process6.spawn)(command.command, command.args, {
8590
9359
  env: process.env,
8591
9360
  shell: command.shell,
8592
9361
  stdio: ["ignore", "pipe", "pipe"]
@@ -8647,12 +9416,13 @@ async function runCodexWithProfile(manager, profileName, codexArgs) {
8647
9416
  if (!codexPath) {
8648
9417
  throw new Error("Codex CLI not found. Install Codex CLI or set CODEX_BINARY.");
8649
9418
  }
9419
+ await assertProfileAccessAllowed(manager, profileName);
8650
9420
  const runtime = await manager.prepareProfileRuntime(profileName, {
8651
9421
  syncFromActiveAuthBeforeAction: false
8652
9422
  });
8653
9423
  const command = buildCodexCommand2(codexPath, codexArgs);
8654
9424
  try {
8655
- const child = (0, import_node_child_process4.spawn)(command.command, command.args, {
9425
+ const child = (0, import_node_child_process6.spawn)(command.command, command.args, {
8656
9426
  env: runtime.env,
8657
9427
  shell: command.shell,
8658
9428
  stdio: "inherit"
@@ -8753,7 +9523,7 @@ async function handleBestCommand(args) {
8753
9523
  console.log(`Usage:
8754
9524
  codexuse best -- <codex args>
8755
9525
 
8756
- Picks the healthiest saved profile, then runs Codex. Auto-run requires Pro.`);
9526
+ Picks the healthiest saved profile, then runs Codex. Auto-run requires Pro or an active trial.`);
8757
9527
  return;
8758
9528
  }
8759
9529
  const codexPath = resolveCodexBinary();
@@ -8761,20 +9531,17 @@ Picks the healthiest saved profile, then runs Codex. Auto-run requires Pro.`);
8761
9531
  throw new Error("Codex CLI not found. Install Codex CLI or set CODEX_BINARY.");
8762
9532
  }
8763
9533
  const manager = new ProfileManager();
8764
- const profiles = await manager.listProfiles();
9534
+ const visible = await loadLicenseVisibleProfiles(manager, { freshLicense: true });
9535
+ if (!visible.licenseWithCounts.capabilities.autoRoll) {
9536
+ throw new Error("Auto-run requires Pro or an active trial.");
9537
+ }
9538
+ const profiles = visible.profiles;
8765
9539
  const best = await selectBestProfile(manager, profiles, codexPath);
8766
9540
  if (!best) {
8767
9541
  throw new Error("No valid saved profiles found. Add one with `codexuse profile add <name>`.");
8768
9542
  }
8769
9543
  const dryRun = hasFlag(flags, "--dry-run");
8770
- const license = await licenseService.getStatus();
8771
9544
  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
9545
  if (dryRun) {
8779
9546
  console.log(`Would run with profile: ${summary}`);
8780
9547
  return;
@@ -8832,21 +9599,9 @@ async function handleLicense(args, version) {
8832
9599
  }
8833
9600
  }
8834
9601
 
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
9602
  // ../../packages/runtime-codex/src/codex/officialAppRestart.ts
8848
- var import_node_child_process5 = require("child_process");
8849
- var import_node_crypto5 = require("crypto");
9603
+ var import_node_child_process7 = require("child_process");
9604
+ var import_node_crypto8 = require("crypto");
8850
9605
  var import_node_fs7 = require("fs");
8851
9606
  var import_node_os3 = require("os");
8852
9607
  var import_node_net = __toESM(require("net"), 1);
@@ -9121,7 +9876,7 @@ function hashProfileKey(profileKey) {
9121
9876
  if (!profileKey) {
9122
9877
  return null;
9123
9878
  }
9124
- return (0, import_node_crypto5.createHash)("sha256").update(profileKey).digest("hex").slice(0, 12);
9879
+ return (0, import_node_crypto8.createHash)("sha256").update(profileKey).digest("hex").slice(0, 12);
9125
9880
  }
9126
9881
  function sanitizeOfficialCodexOverlayActionTargetsForRenderer(targets) {
9127
9882
  const sanitized = [];
@@ -9744,6 +10499,7 @@ function buildInCodexStatusOverlayCssRules() {
9744
10499
  `${chip} .codexuse-handoff-main{display:inline-flex;align-items:center;padding:5px 8px 5px 10px;border-radius:999px;cursor:pointer;}`,
9745
10500
  `${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
10501
  `${chip} .codexuse-handoff-hide:hover{background:var(--cu-border);color:var(--cu-fg,#ececf1);}`,
10502
+ `body>[data-radix-popper-content-wrapper],body>[data-floating-ui-portal]{z-index:2147483004!important;}`,
9747
10503
  // Hand-off account picker is a standalone body child (not inside the pill),
9748
10504
  // so the pill-scoped popover rules don't reach it — give it its own palette
9749
10505
  // + popover styling, mirroring the chip.
@@ -12673,7 +13429,7 @@ async function runCdpCommandSequence(debuggerUrl, commands, timeoutMs = CODEX_CD
12673
13429
  });
12674
13430
  }
12675
13431
  async function verifyCdpBindingRoundTrip(debuggerUrl) {
12676
- const nonce = (0, import_node_crypto5.randomUUID)();
13432
+ const nonce = (0, import_node_crypto8.randomUUID)();
12677
13433
  const expression = `(() => {
12678
13434
  const binding = window[${JSON.stringify(CODEXUSE_BRIDGE_BINDING_NAME)}];
12679
13435
  if (typeof binding !== "function") return false;
@@ -13446,7 +14202,7 @@ async function recordOfficialCodexActivity(input) {
13446
14202
  }
13447
14203
  function runCommand2(command, args, timeoutMs = COMMAND_TIMEOUT_MS) {
13448
14204
  return new Promise((resolve) => {
13449
- const child = (0, import_node_child_process5.spawn)(command, args, {
14205
+ const child = (0, import_node_child_process7.spawn)(command, args, {
13450
14206
  stdio: ["ignore", "pipe", "pipe"]
13451
14207
  });
13452
14208
  let stdout = "";
@@ -13745,7 +14501,7 @@ async function openCodexWithProfileHome(candidate, profileHome, profileName, cdp
13745
14501
  if (appUserDataDir) {
13746
14502
  (0, import_node_fs7.mkdirSync)(appUserDataDir, { recursive: true });
13747
14503
  }
13748
- child = (0, import_node_child_process5.spawn)(
14504
+ child = (0, import_node_child_process7.spawn)(
13749
14505
  "/usr/bin/open",
13750
14506
  [
13751
14507
  "-n",
@@ -14524,6 +15280,13 @@ function formatProfileLabel(name, displayName) {
14524
15280
  }
14525
15281
  return name;
14526
15282
  }
15283
+ var AUTO_ROLL_ACCESS_REQUIRED_MESSAGE = "Auto-roll requires a Pro license or an active trial.";
15284
+ async function assertAutoRollAccess() {
15285
+ const license = await licenseService.getStatus();
15286
+ if (!license.capabilities.autoRoll) {
15287
+ throw new Error(AUTO_ROLL_ACCESS_REQUIRED_MESSAGE);
15288
+ }
15289
+ }
14527
15290
  function profileRateLimitKey(profile) {
14528
15291
  return resolveProfileIdentityKeyFromProfile(profile);
14529
15292
  }
@@ -15180,6 +15943,7 @@ async function collectUsageMap(manager, profiles, codexPath) {
15180
15943
  return usageMap;
15181
15944
  }
15182
15945
  async function runAutoRollPass(manager, options) {
15946
+ await assertAutoRollAccess();
15183
15947
  const profiles = await manager.listProfiles();
15184
15948
  if (!profiles.length) {
15185
15949
  return { switched: false, message: "No profiles found.", source: null, target: null };
@@ -15304,9 +16068,13 @@ async function handleProfileCommand(args, version) {
15304
16068
  const manager = new ProfileManager();
15305
16069
  switch (sub) {
15306
16070
  case "list": {
15307
- const profiles = await manager.listProfiles();
16071
+ const visible = await loadLicenseVisibleProfiles(manager, { freshLicense: true });
16072
+ const profiles = visible.profiles;
15308
16073
  const current = await manager.getCurrentProfile();
15309
16074
  if (!profiles.length) {
16075
+ if (visible.allProfiles.length) {
16076
+ throw new Error(PROFILE_ACCESS_DENIED_MESSAGE);
16077
+ }
15310
16078
  console.log("No profiles found.");
15311
16079
  return;
15312
16080
  }
@@ -15348,6 +16116,7 @@ async function handleProfileCommand(args, version) {
15348
16116
  console.log("No active profile.");
15349
16117
  return;
15350
16118
  }
16119
+ await assertProfileAccessAllowed(manager, current.name);
15351
16120
  console.log(current.name);
15352
16121
  return;
15353
16122
  }
@@ -15371,6 +16140,7 @@ async function handleProfileCommand(args, version) {
15371
16140
  if (!name) {
15372
16141
  throw new Error("Profile name is required.");
15373
16142
  }
16143
+ await assertProfileAccessAllowed(manager, name);
15374
16144
  if (!hasFlag(flags, "--skip-login")) {
15375
16145
  const loginMode = resolveLoginMode(parseLoginMode(flags));
15376
16146
  await runCodexLogin(loginMode);
@@ -15385,6 +16155,7 @@ async function handleProfileCommand(args, version) {
15385
16155
  if (!name) {
15386
16156
  throw new Error("Profile name is required.");
15387
16157
  }
16158
+ await assertProfileAccessAllowed(manager, name);
15388
16159
  const activateOfficialCodex = resolveActivateCodexFlag(flags, false);
15389
16160
  const profiles = await manager.listProfiles();
15390
16161
  const targetProfileKey = findProfileKey(profiles, name);
@@ -15404,10 +16175,7 @@ async function handleProfileCommand(args, version) {
15404
16175
  }
15405
16176
  case "autoroll":
15406
16177
  case "auto-roll": {
15407
- const license = await licenseService.getStatus();
15408
- if (!license.isPro) {
15409
- throw new Error("Auto-roll requires a Pro license.");
15410
- }
16178
+ await assertAutoRollAccess();
15411
16179
  const watch = hasFlag(flags, "--watch");
15412
16180
  const dryRun = hasFlag(flags, "--dry-run");
15413
16181
  const settings = await getStoredAutoRollSettings().catch(() => null);
@@ -15487,6 +16255,7 @@ async function handleProfileCommand(args, version) {
15487
16255
  if (!from || !to) {
15488
16256
  throw new Error("Old and new profile names are required.");
15489
16257
  }
16258
+ await assertProfileAccessAllowed(manager, from);
15490
16259
  await manager.renameProfile(from, to);
15491
16260
  console.log(`Profile renamed: ${from} -> ${to}`);
15492
16261
  return;
@@ -15615,7 +16384,7 @@ function normalizeSnapshot(value) {
15615
16384
  settingsJson
15616
16385
  };
15617
16386
  }
15618
- async function requestJson(method, pathname, licenseKey, body, rawBody) {
16387
+ async function requestJson(method, pathname, access, body, rawBody) {
15619
16388
  const controller = new AbortController();
15620
16389
  const timeout = setTimeout(() => controller.abort(), CLOUD_SYNC_TIMEOUT_MS);
15621
16390
  try {
@@ -15623,7 +16392,10 @@ async function requestJson(method, pathname, licenseKey, body, rawBody) {
15623
16392
  method,
15624
16393
  headers: {
15625
16394
  "Content-Type": "application/json",
15626
- "x-codexuse-license-key": licenseKey
16395
+ "x-codexuse-license-key": access.syncKey,
16396
+ ...access.trialDeviceId ? { "x-codexuse-trial-device-id": access.trialDeviceId } : {},
16397
+ ...access.trialToken ? { "x-codexuse-trial-token": access.trialToken } : {},
16398
+ ...access.trialMigration ? { "x-codexuse-sync-migrate-trial": "1" } : {}
15627
16399
  },
15628
16400
  body: typeof rawBody === "string" ? rawBody : body === void 0 ? void 0 : JSON.stringify(body),
15629
16401
  signal: controller.signal
@@ -15650,15 +16422,15 @@ async function requestJson(method, pathname, licenseKey, body, rawBody) {
15650
16422
  clearTimeout(timeout);
15651
16423
  }
15652
16424
  }
15653
- async function fetchRemoteSnapshot(licenseKey) {
15654
- const response = await requestJson("GET", "/v1/sync/snapshot", licenseKey);
16425
+ async function fetchRemoteSnapshot(access) {
16426
+ const response = await requestJson("GET", "/v1/sync/snapshot", access);
15655
16427
  return normalizeSnapshot(response.snapshot);
15656
16428
  }
15657
- async function fetchRemoteSnapshotMeta(licenseKey) {
16429
+ async function fetchRemoteSnapshotMeta(access) {
15658
16430
  const response = await requestJson(
15659
16431
  "GET",
15660
16432
  "/v1/sync/snapshot/meta",
15661
- licenseKey
16433
+ access
15662
16434
  );
15663
16435
  const updatedAt = toIsoOrNull(response.updatedAt);
15664
16436
  const snapshotKind = normalizeSnapshotKind(response.snapshotKind);
@@ -15667,12 +16439,12 @@ async function fetchRemoteSnapshotMeta(licenseKey) {
15667
16439
  snapshotKind: updatedAt && response.snapshotKind === void 0 ? "legacy-plaintext" : snapshotKind
15668
16440
  };
15669
16441
  }
15670
- async function pushRemoteSnapshot(licenseKey, snapshot, options) {
16442
+ async function pushRemoteSnapshot(access, snapshot, options) {
15671
16443
  const serializedSnapshot = typeof options?.serializedSnapshot === "string" ? options.serializedSnapshot : JSON.stringify(snapshot);
15672
16444
  const response = await requestJson(
15673
16445
  "PUT",
15674
16446
  "/v1/sync/snapshot",
15675
- licenseKey,
16447
+ access,
15676
16448
  void 0,
15677
16449
  `{"snapshot":${serializedSnapshot}}`
15678
16450
  );
@@ -15691,8 +16463,8 @@ async function pushRemoteSnapshot(licenseKey, snapshot, options) {
15691
16463
  var import_toml3 = __toESM(require_toml(), 1);
15692
16464
 
15693
16465
  // ../../packages/runtime-codex/src/codex/config-metadata.ts
15694
- var import_node_child_process6 = require("child_process");
15695
- var import_promises = require("fs/promises");
16466
+ var import_node_child_process8 = require("child_process");
16467
+ var import_promises2 = require("fs/promises");
15696
16468
  var import_node_path11 = __toESM(require("path"), 1);
15697
16469
  var CONFIG_SCHEMA_URL = "https://raw.githubusercontent.com/openai/codex/main/codex-rs/core/config.schema.json";
15698
16470
  var METADATA_CACHE_TTL_MS = 6e4;
@@ -15803,7 +16575,7 @@ function uniqueSorted(values) {
15803
16575
  }
15804
16576
  async function runCommand3(command, args, timeoutMs = 3e3) {
15805
16577
  return new Promise((resolve, reject) => {
15806
- const child = (0, import_node_child_process6.spawn)(command, args, {
16578
+ const child = (0, import_node_child_process8.spawn)(command, args, {
15807
16579
  stdio: ["ignore", "pipe", "pipe"],
15808
16580
  env: process.env
15809
16581
  });
@@ -15884,7 +16656,7 @@ async function readSchemaFromLocal() {
15884
16656
  ].filter((candidate) => Boolean(candidate));
15885
16657
  for (const candidate of candidates) {
15886
16658
  try {
15887
- return await (0, import_promises.readFile)(candidate, "utf8");
16659
+ return await (0, import_promises2.readFile)(candidate, "utf8");
15888
16660
  } catch {
15889
16661
  }
15890
16662
  }
@@ -15984,7 +16756,7 @@ async function getCodexConfigMetadata(forceRefresh = false) {
15984
16756
  }
15985
16757
 
15986
16758
  // ../../packages/runtime-codex/src/codex/config-io.ts
15987
- var import_promises2 = require("fs/promises");
16759
+ var import_promises3 = require("fs/promises");
15988
16760
  var import_node_path13 = __toESM(require("path"), 1);
15989
16761
 
15990
16762
  // ../../packages/runtime-codex/src/codex/home.ts
@@ -16094,7 +16866,7 @@ function getConfigPath(options) {
16094
16866
  }
16095
16867
  async function ensureConfigDirExists(filePath) {
16096
16868
  const dir = import_node_path13.default.dirname(filePath);
16097
- await (0, import_promises2.mkdir)(dir, { recursive: true });
16869
+ await (0, import_promises3.mkdir)(dir, { recursive: true });
16098
16870
  }
16099
16871
  function normalizeLineEndings(content) {
16100
16872
  return content.replace(/\r\n/g, "\n");
@@ -16106,7 +16878,7 @@ function ensureTrailingNewline(content) {
16106
16878
  async function readConfigContent(options) {
16107
16879
  const configPath = getConfigPath(options);
16108
16880
  try {
16109
- const content = await (0, import_promises2.readFile)(configPath, "utf8");
16881
+ const content = await (0, import_promises3.readFile)(configPath, "utf8");
16110
16882
  return {
16111
16883
  exists: true,
16112
16884
  content: normalizeLineEndings(content)
@@ -16126,14 +16898,14 @@ async function writeConfigContent(content, options) {
16126
16898
  const configPath = getConfigPath(options);
16127
16899
  await ensureConfigDirExists(configPath);
16128
16900
  const normalized = ensureTrailingNewline(normalizeLineEndings(content));
16129
- await (0, import_promises2.writeFile)(configPath, normalized, "utf8");
16901
+ await (0, import_promises3.writeFile)(configPath, normalized, "utf8");
16130
16902
  }
16131
16903
  async function getUpdatedAt(configPath, exists) {
16132
16904
  if (!exists) {
16133
16905
  return null;
16134
16906
  }
16135
16907
  try {
16136
- const stats = await (0, import_promises2.stat)(configPath);
16908
+ const stats = await (0, import_promises3.stat)(configPath);
16137
16909
  return stats.mtimeMs;
16138
16910
  } catch (error) {
16139
16911
  const nodeError = error;
@@ -16647,10 +17419,10 @@ async function saveCodexConfigContent(content, options) {
16647
17419
  }
16648
17420
 
16649
17421
  // ../../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:";
17422
+ var import_node_child_process9 = require("child_process");
17423
+ var import_node_crypto9 = require("crypto");
17424
+ var KEYCHAIN_SERVICE2 = "CODEXUSE_CLOUD_SYNC_PASSPHRASE";
17425
+ var KEYCHAIN_ACCOUNT_PREFIX2 = "license-sha256:";
16654
17426
  var ENCRYPTION_AAD = Buffer.from("codexuse-cloud-sync-v2", "utf8");
16655
17427
  var SCRYPT_PARAMS = {
16656
17428
  N: 32768,
@@ -16673,7 +17445,7 @@ function requireCloudSyncPassphrase(value) {
16673
17445
  }
16674
17446
  async function deriveKey(passphrase, salt, params = SCRYPT_PARAMS) {
16675
17447
  return new Promise((resolve, reject) => {
16676
- (0, import_node_crypto6.scrypt)(passphrase, salt, params.keyLength, {
17448
+ (0, import_node_crypto9.scrypt)(passphrase, salt, params.keyLength, {
16677
17449
  N: params.N,
16678
17450
  r: params.r,
16679
17451
  p: params.p,
@@ -16710,10 +17482,10 @@ function normalizeDecryptedSnapshot(value) {
16710
17482
  };
16711
17483
  }
16712
17484
  async function encryptCloudSyncSnapshot(snapshot, passphrase) {
16713
- const salt = (0, import_node_crypto6.randomBytes)(16);
16714
- const iv = (0, import_node_crypto6.randomBytes)(12);
17485
+ const salt = (0, import_node_crypto9.randomBytes)(16);
17486
+ const iv = (0, import_node_crypto9.randomBytes)(12);
16715
17487
  const key = await deriveKey(requireCloudSyncPassphrase(passphrase), salt);
16716
- const cipher = (0, import_node_crypto6.createCipheriv)("aes-256-gcm", key, iv);
17488
+ const cipher = (0, import_node_crypto9.createCipheriv)("aes-256-gcm", key, iv);
16717
17489
  cipher.setAAD(ENCRYPTION_AAD);
16718
17490
  const plaintext = Buffer.from(JSON.stringify(snapshot), "utf8");
16719
17491
  const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
@@ -16740,7 +17512,7 @@ async function decryptCloudSyncSnapshot(snapshot, passphrase) {
16740
17512
  const tag = fromBase64(snapshot.encryption.tag);
16741
17513
  const ciphertext = fromBase64(snapshot.encryption.ciphertext);
16742
17514
  const key = await deriveKey(requireCloudSyncPassphrase(passphrase), salt, snapshot.encryption.kdfParams);
16743
- const decipher = (0, import_node_crypto6.createDecipheriv)("aes-256-gcm", key, iv);
17515
+ const decipher = (0, import_node_crypto9.createDecipheriv)("aes-256-gcm", key, iv);
16744
17516
  decipher.setAAD(ENCRYPTION_AAD);
16745
17517
  decipher.setAuthTag(tag);
16746
17518
  const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
@@ -16755,12 +17527,12 @@ async function decryptCloudSyncSnapshot(snapshot, passphrase) {
16755
17527
  }
16756
17528
  }
16757
17529
  function keychainAccountForLicense(licenseKey) {
16758
- const digest = (0, import_node_crypto6.createHash)("sha256").update(licenseKey).digest("hex");
16759
- return KEYCHAIN_ACCOUNT_PREFIX + digest;
17530
+ const digest = (0, import_node_crypto9.createHash)("sha256").update(licenseKey).digest("hex");
17531
+ return KEYCHAIN_ACCOUNT_PREFIX2 + digest;
16760
17532
  }
16761
- function runSecurityCommand(args) {
17533
+ function runSecurityCommand2(args) {
16762
17534
  return new Promise((resolve, reject) => {
16763
- const child = (0, import_node_child_process7.spawn)("security", args, { stdio: ["ignore", "pipe", "ignore"] });
17535
+ const child = (0, import_node_child_process9.spawn)("security", args, { stdio: ["ignore", "pipe", "ignore"] });
16764
17536
  let stdout = "";
16765
17537
  child.stdout?.on("data", (chunk) => {
16766
17538
  stdout += String(chunk);
@@ -16777,12 +17549,12 @@ async function readRememberedCloudSyncPassphrase(licenseKey) {
16777
17549
  if (process.platform !== "darwin") {
16778
17550
  return null;
16779
17551
  }
16780
- const result = await runSecurityCommand([
17552
+ const result = await runSecurityCommand2([
16781
17553
  "find-generic-password",
16782
17554
  "-a",
16783
17555
  keychainAccountForLicense(licenseKey),
16784
17556
  "-s",
16785
- KEYCHAIN_SERVICE,
17557
+ KEYCHAIN_SERVICE2,
16786
17558
  "-w"
16787
17559
  ]);
16788
17560
  if (result.code !== 0) {
@@ -16795,13 +17567,13 @@ async function writeRememberedCloudSyncPassphrase(licenseKey, passphrase) {
16795
17567
  throw new Error("keychain-unsupported");
16796
17568
  }
16797
17569
  const value = requireCloudSyncPassphrase(passphrase);
16798
- const result = await runSecurityCommand([
17570
+ const result = await runSecurityCommand2([
16799
17571
  "add-generic-password",
16800
17572
  "-U",
16801
17573
  "-a",
16802
17574
  keychainAccountForLicense(licenseKey),
16803
17575
  "-s",
16804
- KEYCHAIN_SERVICE,
17576
+ KEYCHAIN_SERVICE2,
16805
17577
  "-w",
16806
17578
  value
16807
17579
  ]);
@@ -16880,31 +17652,144 @@ async function writeState(patch) {
16880
17652
  async function resolveEligibility() {
16881
17653
  const stored = await getStoredLicense();
16882
17654
  const licenseKey = typeof stored?.licenseKey === "string" ? stored.licenseKey.trim() : "";
16883
- if (!licenseKey) {
17655
+ const status = await licenseService.getStatus();
17656
+ if (licenseKey && status.isPro) {
17657
+ const active = status.state === "active" || status.state === "grace";
17658
+ if (active) {
17659
+ await migrateTrialCloudSyncToPaidLicenseSafe(licenseKey);
17660
+ }
16884
17661
  return {
16885
- canSync: false,
16886
- reason: "License key is required for cloud sync.",
16887
- licenseKey: null,
16888
- licenseState: null
17662
+ canSync: active,
17663
+ canDelete: active,
17664
+ reason: active ? null : "Cloud sync requires an active Pro license.",
17665
+ access: active ? { syncKey: licenseKey } : null,
17666
+ hasPaidLicenseKey: true,
17667
+ licenseState: status.state
16889
17668
  };
16890
17669
  }
16891
- const status = await licenseService.getStatus();
16892
- const active = status.state === "active" || status.state === "grace";
16893
- if (!active) {
17670
+ if (status.trial?.active && status.capabilities.cloudSync) {
17671
+ const trialAccess = await resolveTrialCloudSyncAccess();
17672
+ if (trialAccess) {
17673
+ return {
17674
+ canSync: true,
17675
+ canDelete: true,
17676
+ reason: null,
17677
+ access: trialAccess,
17678
+ hasPaidLicenseKey: false,
17679
+ licenseState: status.state
17680
+ };
17681
+ }
16894
17682
  return {
16895
17683
  canSync: false,
16896
- reason: "Cloud sync requires an active Pro license.",
16897
- licenseKey,
17684
+ canDelete: false,
17685
+ reason: "Cloud sync trial identity is unavailable.",
17686
+ access: null,
17687
+ hasPaidLicenseKey: false,
16898
17688
  licenseState: status.state
16899
17689
  };
16900
17690
  }
17691
+ if (status.trial?.expired) {
17692
+ const trialAccess = await resolveTrialCloudSyncAccess();
17693
+ if (trialAccess) {
17694
+ return {
17695
+ canSync: false,
17696
+ canDelete: true,
17697
+ reason: "Cloud sync requires an active trial or Pro license.",
17698
+ access: trialAccess,
17699
+ hasPaidLicenseKey: false,
17700
+ licenseState: status.state
17701
+ };
17702
+ }
17703
+ }
16901
17704
  return {
16902
- canSync: true,
16903
- reason: null,
16904
- licenseKey,
17705
+ canSync: false,
17706
+ canDelete: false,
17707
+ reason: "Cloud sync requires an active trial or Pro license.",
17708
+ access: null,
17709
+ hasPaidLicenseKey: false,
16905
17710
  licenseState: status.state
16906
17711
  };
16907
17712
  }
17713
+ async function hasRemoteSnapshot(access) {
17714
+ const meta = await fetchRemoteSnapshotMeta(access);
17715
+ return meta.snapshotKind !== "none" || Boolean(meta.updatedAt);
17716
+ }
17717
+ async function readRemoteSnapshotOrNull(access) {
17718
+ try {
17719
+ return await fetchRemoteSnapshot(access);
17720
+ } catch (error) {
17721
+ if (error instanceof CloudSyncClientError && (error.status === 403 || error.status === 404)) {
17722
+ return null;
17723
+ }
17724
+ throw error;
17725
+ }
17726
+ }
17727
+ async function migrateTrialPassphraseToPaidLicense(trialKey, licenseKey) {
17728
+ const paidPassphrase = await readRememberedCloudSyncPassphrase(licenseKey).catch(() => null);
17729
+ if (paidPassphrase) {
17730
+ return;
17731
+ }
17732
+ const trialPassphrase = await readRememberedCloudSyncPassphrase(trialKey).catch(() => null);
17733
+ if (!trialPassphrase) {
17734
+ return;
17735
+ }
17736
+ await writeRememberedCloudSyncPassphrase(licenseKey, trialPassphrase);
17737
+ }
17738
+ async function migrateTrialCloudSyncToPaidLicense(licenseKey) {
17739
+ const paidLicenseKey = licenseKey.trim();
17740
+ if (!paidLicenseKey) {
17741
+ return;
17742
+ }
17743
+ const trialAccess = await resolveTrialCloudSyncAccess();
17744
+ if (!trialAccess || trialAccess.syncKey === paidLicenseKey) {
17745
+ return;
17746
+ }
17747
+ if (await hasRemoteSnapshot({ syncKey: paidLicenseKey })) {
17748
+ await migrateTrialPassphraseToPaidLicense(trialAccess.syncKey, paidLicenseKey).catch((error) => {
17749
+ logWarn("[cloud-sync] failed to migrate remembered trial passphrase", {
17750
+ error: error instanceof Error ? error.message : String(error)
17751
+ });
17752
+ });
17753
+ return;
17754
+ }
17755
+ const trialSnapshot = await readRemoteSnapshotOrNull({
17756
+ ...trialAccess,
17757
+ syncKey: paidLicenseKey,
17758
+ trialMigration: true
17759
+ });
17760
+ if (trialSnapshot) {
17761
+ await pushRemoteSnapshot({ syncKey: paidLicenseKey }, trialSnapshot, {
17762
+ serializedSnapshot: JSON.stringify(trialSnapshot)
17763
+ });
17764
+ }
17765
+ await migrateTrialPassphraseToPaidLicense(trialAccess.syncKey, paidLicenseKey);
17766
+ }
17767
+ async function migrateTrialCloudSyncToPaidLicenseSafe(licenseKey) {
17768
+ try {
17769
+ await migrateTrialCloudSyncToPaidLicense(licenseKey);
17770
+ } catch (error) {
17771
+ logWarn("[cloud-sync] trial snapshot migration to paid license failed", {
17772
+ error: error instanceof Error ? error.message : String(error)
17773
+ });
17774
+ }
17775
+ }
17776
+ async function resolveTrialCloudSyncAccess() {
17777
+ let deviceId;
17778
+ try {
17779
+ deviceId = await getDeviceId();
17780
+ } catch {
17781
+ return null;
17782
+ }
17783
+ const trialToken = await readStoredTrialToken(deviceId).catch(() => null);
17784
+ if (!trialToken) {
17785
+ return null;
17786
+ }
17787
+ return {
17788
+ syncKey: `trial:${deviceId}`,
17789
+ trialDeviceId: deviceId,
17790
+ trialToken
17791
+ };
17792
+ }
16908
17793
  function formatMegabytes(bytes) {
16909
17794
  return (bytes / MB_DIVISOR).toFixed(2);
16910
17795
  }
@@ -16997,19 +17882,19 @@ async function getCloudSyncStatus() {
16997
17882
  let remoteUpdatedAt = state.remoteUpdatedAt ?? null;
16998
17883
  let remoteKind = state.remoteKind ?? "none";
16999
17884
  let hasRememberedPassphrase = false;
17000
- if (eligibility.canSync && eligibility.licenseKey) {
17885
+ if (eligibility.canSync && eligibility.access) {
17001
17886
  hasRememberedPassphrase = Boolean(
17002
- await readRememberedCloudSyncPassphrase(eligibility.licenseKey).catch(() => null)
17887
+ await readRememberedCloudSyncPassphrase(eligibility.access.syncKey).catch(() => null)
17003
17888
  );
17004
17889
  try {
17005
- const remoteMeta = await fetchRemoteSnapshotMeta(eligibility.licenseKey);
17890
+ const remoteMeta = await fetchRemoteSnapshotMeta(eligibility.access);
17006
17891
  remoteUpdatedAt = remoteMeta.updatedAt;
17007
17892
  remoteKind = remoteMeta.snapshotKind;
17008
17893
  await writeState({ remoteUpdatedAt, remoteKind });
17009
17894
  } catch (error) {
17010
17895
  if (error instanceof CloudSyncClientError && error.status === 404) {
17011
17896
  try {
17012
- const remote = await fetchRemoteSnapshot(eligibility.licenseKey);
17897
+ const remote = await fetchRemoteSnapshot(eligibility.access);
17013
17898
  remoteUpdatedAt = remote?.updatedAt ?? null;
17014
17899
  remoteKind = getSnapshotKind(remote);
17015
17900
  } catch {
@@ -17019,9 +17904,10 @@ async function getCloudSyncStatus() {
17019
17904
  }
17020
17905
  return {
17021
17906
  canSync: eligibility.canSync,
17907
+ canDelete: eligibility.canDelete,
17022
17908
  reason: eligibility.reason,
17023
17909
  licenseState: eligibility.licenseState,
17024
- hasLicenseKey: Boolean(eligibility.licenseKey),
17910
+ hasLicenseKey: eligibility.hasPaidLicenseKey,
17025
17911
  hasRememberedPassphrase,
17026
17912
  lastPushAt: state.lastPushAt ?? null,
17027
17913
  lastPullAt: state.lastPullAt ?? null,
@@ -17032,7 +17918,7 @@ async function getCloudSyncStatus() {
17032
17918
  }
17033
17919
  async function pushCloudSync(options = {}) {
17034
17920
  const eligibility = await resolveEligibility();
17035
- if (!eligibility.canSync || !eligibility.licenseKey) {
17921
+ if (!eligibility.canSync || !eligibility.access) {
17036
17922
  return {
17037
17923
  mode: "push",
17038
17924
  status: "skipped",
@@ -17045,7 +17931,7 @@ async function pushCloudSync(options = {}) {
17045
17931
  try {
17046
17932
  await profileManager.initialize();
17047
17933
  const localSnapshot = await buildLocalSnapshot(profileManager, { enforcePushGuards: true });
17048
- const passphrase = await resolvePassphrase(eligibility.licenseKey, options);
17934
+ const passphrase = await resolvePassphrase(eligibility.access.syncKey, options);
17049
17935
  const encryptedSnapshot = await encryptCloudSyncSnapshot(localSnapshot, passphrase.value);
17050
17936
  const serializedSnapshot = JSON.stringify(encryptedSnapshot);
17051
17937
  const snapshotBytes = Buffer.byteLength(serializedSnapshot, "utf8");
@@ -17063,7 +17949,7 @@ async function pushCloudSync(options = {}) {
17063
17949
  if (process.env.NODE_ENV !== "production") {
17064
17950
  logInfo("[cloud-sync] push snapshot summary", summarizeSnapshot(localSnapshot));
17065
17951
  }
17066
- const remote = await pushRemoteSnapshot(eligibility.licenseKey, encryptedSnapshot, {
17952
+ const remote = await pushRemoteSnapshot(eligibility.access, encryptedSnapshot, {
17067
17953
  serializedSnapshot
17068
17954
  });
17069
17955
  const remoteKind = getSnapshotKind(remote.snapshot);
@@ -17082,7 +17968,7 @@ async function pushCloudSync(options = {}) {
17082
17968
  remoteUpdatedAt: remote.snapshot.updatedAt
17083
17969
  };
17084
17970
  }
17085
- await rememberPassphraseIfRequested(eligibility.licenseKey, options, passphrase);
17971
+ await rememberPassphraseIfRequested(eligibility.access.syncKey, options, passphrase);
17086
17972
  return {
17087
17973
  mode: "push",
17088
17974
  status: "applied",
@@ -17099,7 +17985,7 @@ async function pushCloudSync(options = {}) {
17099
17985
  }
17100
17986
  async function pullCloudSync(options = {}) {
17101
17987
  const eligibility = await resolveEligibility();
17102
- if (!eligibility.canSync || !eligibility.licenseKey) {
17988
+ if (!eligibility.canSync || !eligibility.access) {
17103
17989
  return {
17104
17990
  mode: "pull",
17105
17991
  status: "skipped",
@@ -17111,7 +17997,7 @@ async function pullCloudSync(options = {}) {
17111
17997
  const profileManager = new ProfileManager();
17112
17998
  try {
17113
17999
  await profileManager.initialize();
17114
- const remote = await fetchRemoteSnapshot(eligibility.licenseKey);
18000
+ const remote = await fetchRemoteSnapshot(eligibility.access);
17115
18001
  if (!remote) {
17116
18002
  await writeState({ remoteUpdatedAt: null, remoteKind: "none" });
17117
18003
  return {
@@ -17126,7 +18012,7 @@ async function pullCloudSync(options = {}) {
17126
18012
  let passphrase = null;
17127
18013
  let plainSnapshot;
17128
18014
  if (remote.schemaVersion === CLOUD_SYNC_ENCRYPTED_SCHEMA_VERSION) {
17129
- passphrase = await resolvePassphrase(eligibility.licenseKey, options);
18015
+ passphrase = await resolvePassphrase(eligibility.access.syncKey, options);
17130
18016
  plainSnapshot = await decryptCloudSyncSnapshot(remote, passphrase.value);
17131
18017
  } else {
17132
18018
  plainSnapshot = remote;
@@ -17139,7 +18025,7 @@ async function pullCloudSync(options = {}) {
17139
18025
  lastError: void 0
17140
18026
  });
17141
18027
  if (passphrase) {
17142
- await rememberPassphraseIfRequested(eligibility.licenseKey, options, passphrase);
18028
+ await rememberPassphraseIfRequested(eligibility.access.syncKey, options, passphrase);
17143
18029
  }
17144
18030
  return {
17145
18031
  mode: "pull",
@@ -17252,7 +18138,7 @@ async function ensureCliStorageReady() {
17252
18138
  }
17253
18139
 
17254
18140
  // src/app/main.ts
17255
- var VERSION = true ? "5.1.0" : "0.0.0";
18141
+ var VERSION = true ? "5.1.1" : "0.0.0";
17256
18142
  async function runCli() {
17257
18143
  const args = process.argv.slice(2);
17258
18144
  if (args.length === 0) {