codexuse-cli 2.4.2 → 2.4.4

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
@@ -34,15 +34,45 @@ var DEFAULT_AUTO_ROLL_ENABLED = false;
34
34
  var DEFAULT_AUTO_ROLL_WARNING_THRESHOLD = 85;
35
35
  var DEFAULT_AUTO_ROLL_SWITCH_THRESHOLD = 95;
36
36
  var AUTO_ROLL_WARNING_MIN = 50;
37
+ var AUTO_ROLL_WARNING_MAX = 99;
38
+ var AUTO_ROLL_SWITCH_MAX = 100;
37
39
  function clampNumber(value, min, max) {
38
40
  return Math.min(max, Math.max(min, value));
39
41
  }
42
+ function resolveFiniteNumber(value, fallback) {
43
+ return Number.isFinite(value) ? value : fallback;
44
+ }
45
+ function sanitizeAutoRollWarningThreshold(value) {
46
+ const numeric = resolveFiniteNumber(value, DEFAULT_AUTO_ROLL_WARNING_THRESHOLD);
47
+ return clampNumber(numeric, AUTO_ROLL_WARNING_MIN, AUTO_ROLL_WARNING_MAX);
48
+ }
49
+ function sanitizeAutoRollSwitchThreshold(value, warningThreshold) {
50
+ const sanitizedWarning = sanitizeAutoRollWarningThreshold(warningThreshold);
51
+ const numeric = resolveFiniteNumber(value, DEFAULT_AUTO_ROLL_SWITCH_THRESHOLD);
52
+ return clampNumber(numeric, sanitizedWarning + 1, AUTO_ROLL_SWITCH_MAX);
53
+ }
54
+ function sanitizeAutoRollThresholds(warningThreshold, switchThreshold) {
55
+ const sanitizedWarning = sanitizeAutoRollWarningThreshold(warningThreshold);
56
+ const sanitizedSwitch = sanitizeAutoRollSwitchThreshold(switchThreshold, sanitizedWarning);
57
+ return {
58
+ warningThreshold: sanitizedWarning,
59
+ switchThreshold: sanitizedSwitch
60
+ };
61
+ }
40
62
  function normalizeAutoRollSettings(raw) {
41
63
  const enabled = typeof raw?.enabled === "boolean" ? raw.enabled : DEFAULT_AUTO_ROLL_ENABLED;
42
- const rawWarning = typeof raw?.warningThreshold === "number" && Number.isFinite(raw.warningThreshold) ? raw.warningThreshold : DEFAULT_AUTO_ROLL_WARNING_THRESHOLD;
43
- const rawSwitch = typeof raw?.switchThreshold === "number" && Number.isFinite(raw.switchThreshold) ? raw.switchThreshold : DEFAULT_AUTO_ROLL_SWITCH_THRESHOLD;
44
- const normalizedWarning = clampNumber(rawWarning, AUTO_ROLL_WARNING_MIN, 99);
45
- const normalizedSwitch = clampNumber(rawSwitch, normalizedWarning + 1, 100);
64
+ const rawWarning = resolveFiniteNumber(
65
+ typeof raw?.warningThreshold === "number" ? raw.warningThreshold : NaN,
66
+ DEFAULT_AUTO_ROLL_WARNING_THRESHOLD
67
+ );
68
+ const rawSwitch = resolveFiniteNumber(
69
+ typeof raw?.switchThreshold === "number" ? raw.switchThreshold : NaN,
70
+ DEFAULT_AUTO_ROLL_SWITCH_THRESHOLD
71
+ );
72
+ const { warningThreshold: normalizedWarning, switchThreshold: normalizedSwitch } = sanitizeAutoRollThresholds(
73
+ rawWarning,
74
+ rawSwitch
75
+ );
46
76
  return {
47
77
  enabled,
48
78
  warningThreshold: normalizedWarning,
@@ -375,6 +405,11 @@ async function withWriteLock(task) {
375
405
  release?.();
376
406
  }
377
407
  }
408
+ async function initializeAppState(userDataDir) {
409
+ configuredUserDataDir = userDataDir;
410
+ const state = await ensureInitialized();
411
+ return clone(state);
412
+ }
378
413
  async function getAppState() {
379
414
  const state = await ensureInitialized();
380
415
  return clone(state);
@@ -3659,7 +3694,6 @@ async function getCloudSyncStatus() {
3659
3694
  }
3660
3695
  }
3661
3696
  return {
3662
- endpoint: getCloudSyncApiBaseUrl(),
3663
3697
  canSync: eligibility.canSync,
3664
3698
  reason: eligibility.reason,
3665
3699
  licenseState: eligibility.licenseState,
@@ -4071,8 +4105,790 @@ function maxUsedPercent(snapshot) {
4071
4105
  return Math.max(...candidates);
4072
4106
  }
4073
4107
 
4108
+ // ../../lib/storage-migration-v1.ts
4109
+ var import_node_fs7 = require("fs");
4110
+ var import_node_path9 = __toESM(require("path"));
4111
+ var import_node_os3 = __toESM(require("os"));
4112
+
4113
+ // ../../lib/legacy-localstorage-keys.ts
4114
+ var LEGACY_LOCALSTORAGE_KEYS = [
4115
+ "settings-storage",
4116
+ "provider",
4117
+ "sandbox-storage",
4118
+ "project-settings-storage",
4119
+ "folder-storage",
4120
+ "conversation-categories-storage",
4121
+ "codex:auto-roll-settings"
4122
+ ];
4123
+
4124
+ // ../../lib/storage-migration-v1.ts
4125
+ var SQLITE_STORAGE_DIR = ".f86eb5e712267207";
4126
+ var LEGACY_SETTINGS_FILE = "settings.json";
4127
+ var LEGACY_SETTINGS_BACKUP_FILE = "settings.json.bak";
4128
+ var LEGACY_SYNC_STATE_FILE = "sync-state.json";
4129
+ var LEGACY_PROFILE_HOMES_DIR = "profile-homes";
4130
+ var LEGACY_SKILLS_DIR = "skills";
4131
+ var LEGACY_SKILL_CACHE_DIR = "skill-cache";
4132
+ var LEGACY_SKILLS_REPOS_FILE = "repos.json";
4133
+ var LEGACY_SKILL_MANIFEST = ".codexuse-skill.json";
4134
+ var LEGACY_LICENSE_SECRET_FILE = "license.secret";
4135
+ function isRecord5(value) {
4136
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4137
+ }
4138
+ function asString3(value) {
4139
+ if (typeof value !== "string") {
4140
+ return null;
4141
+ }
4142
+ const trimmed = value.trim();
4143
+ return trimmed.length > 0 ? trimmed : null;
4144
+ }
4145
+ function resolveHomeDir2() {
4146
+ const home = process.env.HOME || process.env.USERPROFILE || import_node_os3.default.homedir();
4147
+ if (!home) {
4148
+ throw new Error("HOME is not set.");
4149
+ }
4150
+ return home;
4151
+ }
4152
+ function resolveCodexDir() {
4153
+ return import_node_path9.default.join(resolveHomeDir2(), ".codex");
4154
+ }
4155
+ function resolveLegacyPath(...segments) {
4156
+ return import_node_path9.default.join(resolveCodexDir(), ...segments);
4157
+ }
4158
+ async function readJsonFile(filePath) {
4159
+ const raw = await import_node_fs7.promises.readFile(filePath, "utf8");
4160
+ return JSON.parse(raw);
4161
+ }
4162
+ async function readJsonFileIfExists(filePath) {
4163
+ try {
4164
+ return await readJsonFile(filePath);
4165
+ } catch (error) {
4166
+ const code = error.code;
4167
+ if (code === "ENOENT") {
4168
+ return null;
4169
+ }
4170
+ throw error;
4171
+ }
4172
+ }
4173
+ async function copyDirectoryManual(source, destination) {
4174
+ await import_node_fs7.promises.mkdir(destination, { recursive: true });
4175
+ const entries = await import_node_fs7.promises.readdir(source, { withFileTypes: true });
4176
+ for (const entry of entries) {
4177
+ const srcPath = import_node_path9.default.join(source, entry.name);
4178
+ const destPath = import_node_path9.default.join(destination, entry.name);
4179
+ if (entry.isSymbolicLink()) {
4180
+ const linkTarget = await import_node_fs7.promises.readlink(srcPath);
4181
+ await import_node_fs7.promises.symlink(linkTarget, destPath).catch((error) => {
4182
+ if (error.code !== "EEXIST") {
4183
+ throw error;
4184
+ }
4185
+ });
4186
+ continue;
4187
+ }
4188
+ if (entry.isDirectory()) {
4189
+ await copyDirectoryManual(srcPath, destPath);
4190
+ continue;
4191
+ }
4192
+ if (entry.isFile()) {
4193
+ await import_node_fs7.promises.copyFile(srcPath, destPath);
4194
+ }
4195
+ }
4196
+ }
4197
+ async function copyDirIfExists(source, destination) {
4198
+ let stats = null;
4199
+ try {
4200
+ stats = await import_node_fs7.promises.stat(source);
4201
+ } catch (error) {
4202
+ if (error.code === "ENOENT") {
4203
+ return;
4204
+ }
4205
+ throw error;
4206
+ }
4207
+ if (!stats.isDirectory()) {
4208
+ return;
4209
+ }
4210
+ await import_node_fs7.promises.rm(destination, { recursive: true, force: true });
4211
+ await import_node_fs7.promises.mkdir(import_node_path9.default.dirname(destination), { recursive: true });
4212
+ try {
4213
+ await import_node_fs7.promises.cp(source, destination, {
4214
+ recursive: true,
4215
+ errorOnExist: false,
4216
+ force: true,
4217
+ dereference: false,
4218
+ verbatimSymlinks: true
4219
+ });
4220
+ } catch (error) {
4221
+ if (error.code === "ERR_FS_CP_EINVAL") {
4222
+ await copyDirectoryManual(source, destination);
4223
+ return;
4224
+ }
4225
+ throw error;
4226
+ }
4227
+ }
4228
+ async function copyFileIfExists(source, destination, options) {
4229
+ try {
4230
+ const sourceStat = await import_node_fs7.promises.stat(source);
4231
+ if (!sourceStat.isFile()) {
4232
+ return;
4233
+ }
4234
+ } catch (error) {
4235
+ if (error.code === "ENOENT") {
4236
+ return;
4237
+ }
4238
+ throw error;
4239
+ }
4240
+ try {
4241
+ const destinationStat = await import_node_fs7.promises.stat(destination);
4242
+ if (destinationStat.isFile()) {
4243
+ return;
4244
+ }
4245
+ } catch (error) {
4246
+ if (error.code !== "ENOENT") {
4247
+ throw error;
4248
+ }
4249
+ }
4250
+ await import_node_fs7.promises.mkdir(import_node_path9.default.dirname(destination), { recursive: true });
4251
+ await import_node_fs7.promises.copyFile(source, destination);
4252
+ if (typeof options?.mode === "number") {
4253
+ await import_node_fs7.promises.chmod(destination, options.mode).catch(() => void 0);
4254
+ }
4255
+ }
4256
+ async function cleanupCopiedSkillsMetadata(skillsDir) {
4257
+ await removeIfExists(import_node_path9.default.join(skillsDir, LEGACY_SKILLS_REPOS_FILE));
4258
+ let entries = [];
4259
+ try {
4260
+ entries = await import_node_fs7.promises.readdir(skillsDir, { withFileTypes: true });
4261
+ } catch {
4262
+ return;
4263
+ }
4264
+ for (const entry of entries) {
4265
+ if (!entry.isDirectory() || entry.name.startsWith(".")) {
4266
+ continue;
4267
+ }
4268
+ await removeIfExists(import_node_path9.default.join(skillsDir, entry.name, LEGACY_SKILL_MANIFEST));
4269
+ }
4270
+ }
4271
+ async function migrateLegacyDirectoriesToUserData() {
4272
+ const userDataDir = getUserDataDir();
4273
+ const legacyCodexDir = resolveCodexDir();
4274
+ await copyDirIfExists(
4275
+ import_node_path9.default.join(legacyCodexDir, LEGACY_PROFILE_HOMES_DIR),
4276
+ import_node_path9.default.join(userDataDir, LEGACY_PROFILE_HOMES_DIR)
4277
+ );
4278
+ await copyDirIfExists(
4279
+ import_node_path9.default.join(legacyCodexDir, LEGACY_SKILLS_DIR),
4280
+ import_node_path9.default.join(userDataDir, LEGACY_SKILLS_DIR)
4281
+ );
4282
+ await copyDirIfExists(
4283
+ import_node_path9.default.join(legacyCodexDir, LEGACY_SKILL_CACHE_DIR),
4284
+ import_node_path9.default.join(userDataDir, LEGACY_SKILL_CACHE_DIR)
4285
+ );
4286
+ await copyFileIfExists(
4287
+ import_node_path9.default.join(legacyCodexDir, LEGACY_LICENSE_SECRET_FILE),
4288
+ import_node_path9.default.join(userDataDir, LEGACY_LICENSE_SECRET_FILE),
4289
+ { mode: 384 }
4290
+ );
4291
+ await cleanupCopiedSkillsMetadata(import_node_path9.default.join(userDataDir, LEGACY_SKILLS_DIR));
4292
+ }
4293
+ function pickAutoRoll(raw) {
4294
+ if (!raw) {
4295
+ return null;
4296
+ }
4297
+ try {
4298
+ return normalizeAutoRollSettings(raw);
4299
+ } catch {
4300
+ return null;
4301
+ }
4302
+ }
4303
+ function parseLegacyLicense(raw) {
4304
+ if (!isRecord5(raw)) {
4305
+ return {
4306
+ licenseKey: null,
4307
+ purchaseEmail: null,
4308
+ lastVerifiedAt: null,
4309
+ nextCheckAt: null,
4310
+ lastVerificationError: null,
4311
+ status: "inactive",
4312
+ signature: null
4313
+ };
4314
+ }
4315
+ const statusCandidate = asString3(raw.status);
4316
+ const status = ["inactive", "active", "grace", "error"].includes(statusCandidate ?? "") ? statusCandidate : "inactive";
4317
+ return {
4318
+ licenseKey: asString3(raw.licenseKey ?? raw.license_key),
4319
+ purchaseEmail: asString3(raw.purchaseEmail ?? raw.purchase_email),
4320
+ lastVerifiedAt: asString3(raw.lastVerifiedAt ?? raw.last_verified_at),
4321
+ nextCheckAt: asString3(raw.nextCheckAt ?? raw.next_check_at),
4322
+ lastVerificationError: asString3(raw.lastVerificationError ?? raw.last_verification_error),
4323
+ status,
4324
+ signature: asString3(raw.signature)
4325
+ };
4326
+ }
4327
+ function parseLegacyProfileRecord(name, raw) {
4328
+ if (!isRecord5(raw)) {
4329
+ return null;
4330
+ }
4331
+ const dataRaw = raw.data;
4332
+ let data = null;
4333
+ if (isRecord5(dataRaw)) {
4334
+ data = dataRaw;
4335
+ } else if (typeof dataRaw === "string") {
4336
+ try {
4337
+ data = JSON.parse(dataRaw);
4338
+ } catch {
4339
+ data = null;
4340
+ }
4341
+ }
4342
+ if (!data) {
4343
+ return null;
4344
+ }
4345
+ return {
4346
+ name,
4347
+ displayName: asString3(raw.displayName ?? raw.display_name) ?? name,
4348
+ data,
4349
+ metadata: isRecord5(raw.metadata) ? raw.metadata : void 0,
4350
+ accountId: asString3(raw.accountId ?? raw.account_id),
4351
+ workspaceId: asString3(raw.workspaceId ?? raw.workspace_id),
4352
+ workspaceName: asString3(raw.workspaceName ?? raw.workspace_name),
4353
+ email: asString3(raw.email),
4354
+ authMethod: asString3(raw.authMethod ?? raw.auth_method),
4355
+ createdAt: asString3(raw.createdAt ?? raw.created_at),
4356
+ updatedAt: asString3(raw.updatedAt ?? raw.updated_at)
4357
+ };
4358
+ }
4359
+ async function loadLegacySettingsPatch() {
4360
+ const filePath = resolveLegacyPath(LEGACY_SETTINGS_FILE);
4361
+ const raw = await readJsonFileIfExists(filePath);
4362
+ if (!isRecord5(raw)) {
4363
+ return {};
4364
+ }
4365
+ const cliChannel = parseCodexCliChannel(raw.cliChannel ?? raw.cli_channel);
4366
+ const autoRoll = pickAutoRoll(raw.autoRoll ?? raw.auto_roll);
4367
+ const license = parseLegacyLicense(raw.license ?? raw.license_data ?? raw.license_state);
4368
+ return {
4369
+ app: {
4370
+ lastAppVersion: asString3(raw.lastAppVersion ?? raw.last_app_version),
4371
+ pendingUpdateVersion: asString3(raw.pendingUpdateVersion ?? raw.pending_update_version),
4372
+ cliChannel: cliChannel ?? void 0,
4373
+ lastProfileName: asString3(raw.lastProfileName ?? raw.last_profile_name)
4374
+ },
4375
+ license,
4376
+ autoRoll: autoRoll ? {
4377
+ enabled: autoRoll.enabled,
4378
+ warningThreshold: autoRoll.warningThreshold,
4379
+ switchThreshold: autoRoll.switchThreshold
4380
+ } : void 0
4381
+ };
4382
+ }
4383
+ async function loadLegacySyncPatch() {
4384
+ const filePath = resolveLegacyPath(LEGACY_SYNC_STATE_FILE);
4385
+ const raw = await readJsonFileIfExists(filePath);
4386
+ if (!isRecord5(raw)) {
4387
+ return {};
4388
+ }
4389
+ return {
4390
+ sync: {
4391
+ lastPushAt: asString3(raw.lastPushAt),
4392
+ lastPullAt: asString3(raw.lastPullAt),
4393
+ lastError: asString3(raw.lastError),
4394
+ remoteUpdatedAt: asString3(raw.remoteUpdatedAt)
4395
+ }
4396
+ };
4397
+ }
4398
+ async function loadLegacyProfilesPatch() {
4399
+ const root = resolveLegacyPath(LEGACY_PROFILE_HOMES_DIR);
4400
+ let entries = [];
4401
+ try {
4402
+ entries = await import_node_fs7.promises.readdir(root, { withFileTypes: true });
4403
+ } catch (error) {
4404
+ if (error.code === "ENOENT") {
4405
+ return {};
4406
+ }
4407
+ throw error;
4408
+ }
4409
+ const profilesByName = {};
4410
+ for (const entry of entries) {
4411
+ if (!entry.isDirectory() || entry.name.startsWith(".")) {
4412
+ continue;
4413
+ }
4414
+ const profileFile = import_node_path9.default.join(root, entry.name, "profile.json");
4415
+ const raw = await readJsonFileIfExists(profileFile);
4416
+ if (!raw) {
4417
+ continue;
4418
+ }
4419
+ const parsed = parseLegacyProfileRecord(entry.name, raw);
4420
+ if (!parsed) {
4421
+ continue;
4422
+ }
4423
+ profilesByName[entry.name] = parsed;
4424
+ }
4425
+ if (Object.keys(profilesByName).length === 0) {
4426
+ return {};
4427
+ }
4428
+ return { profilesByName };
4429
+ }
4430
+ function parseSkillInstallMetadata(raw) {
4431
+ if (!isRecord5(raw)) {
4432
+ return null;
4433
+ }
4434
+ const id = asString3(raw.id);
4435
+ if (!id) {
4436
+ return null;
4437
+ }
4438
+ return {
4439
+ id,
4440
+ repo: asString3(raw.repo),
4441
+ repoPath: asString3(raw.repoPath),
4442
+ sourceLabel: asString3(raw.sourceLabel),
4443
+ sourceType: raw.sourceType === "official" || raw.sourceType === "community" || raw.sourceType === "local" ? raw.sourceType : void 0,
4444
+ viewUrl: asString3(raw.viewUrl),
4445
+ createdAt: asString3(raw.createdAt)
4446
+ };
4447
+ }
4448
+ async function loadLegacySkillsPatch() {
4449
+ const skillsRoot = resolveLegacyPath(LEGACY_SKILLS_DIR);
4450
+ const reposPath = import_node_path9.default.join(skillsRoot, LEGACY_SKILLS_REPOS_FILE);
4451
+ const reposRaw = await readJsonFileIfExists(reposPath);
4452
+ const installsBySlug = {};
4453
+ let dirEntries = [];
4454
+ try {
4455
+ dirEntries = await import_node_fs7.promises.readdir(skillsRoot, { withFileTypes: true });
4456
+ } catch (error) {
4457
+ if (error.code !== "ENOENT") {
4458
+ throw error;
4459
+ }
4460
+ }
4461
+ for (const entry of dirEntries) {
4462
+ if (!entry.isDirectory()) {
4463
+ continue;
4464
+ }
4465
+ if (entry.name.startsWith(".")) {
4466
+ continue;
4467
+ }
4468
+ const manifestPath = import_node_path9.default.join(skillsRoot, entry.name, LEGACY_SKILL_MANIFEST);
4469
+ const manifestRaw = await readJsonFileIfExists(manifestPath);
4470
+ const parsed = parseSkillInstallMetadata(manifestRaw);
4471
+ if (!parsed) {
4472
+ continue;
4473
+ }
4474
+ installsBySlug[entry.name] = parsed;
4475
+ }
4476
+ const sources = isRecord5(reposRaw) && Array.isArray(reposRaw.sources) ? reposRaw.sources : [];
4477
+ if (sources.length === 0 && Object.keys(installsBySlug).length === 0) {
4478
+ return {};
4479
+ }
4480
+ return {
4481
+ skills: {
4482
+ sources,
4483
+ installsBySlug
4484
+ }
4485
+ };
4486
+ }
4487
+ function mergeLegacyLocalStoragePatch(payload) {
4488
+ const patch = {};
4489
+ const consumedKeys = /* @__PURE__ */ new Set();
4490
+ const skippedKeys = /* @__PURE__ */ new Set();
4491
+ const legacyPayloadKeys = new Set(
4492
+ Object.keys(payload).filter(
4493
+ (key) => LEGACY_LOCALSTORAGE_KEYS.includes(key)
4494
+ )
4495
+ );
4496
+ const hasKey = (key) => legacyPayloadKeys.has(key);
4497
+ const markSkippedIfPresent = (key, consumed) => {
4498
+ if (!hasKey(key)) {
4499
+ return;
4500
+ }
4501
+ if (consumed) {
4502
+ consumedKeys.add(key);
4503
+ } else {
4504
+ skippedKeys.add(key);
4505
+ }
4506
+ };
4507
+ const settingsStorage = payload["settings-storage"];
4508
+ if (isRecord5(settingsStorage)) {
4509
+ const nextExcludeFolders = Array.isArray(settingsStorage.excludeFolders) ? settingsStorage.excludeFolders.filter((item) => typeof item === "string") : void 0;
4510
+ const nextBeep = typeof settingsStorage.enableTaskCompleteBeep === "boolean" ? settingsStorage.enableTaskCompleteBeep : void 0;
4511
+ const nextSleep = typeof settingsStorage.preventSleepDuringTasks === "boolean" ? settingsStorage.preventSleepDuringTasks : void 0;
4512
+ patch.preferences = {
4513
+ excludeFolders: nextExcludeFolders,
4514
+ enableTaskCompleteBeep: nextBeep,
4515
+ preventSleepDuringTasks: nextSleep
4516
+ };
4517
+ markSkippedIfPresent(
4518
+ "settings-storage",
4519
+ nextExcludeFolders !== void 0 || nextBeep !== void 0 || nextSleep !== void 0
4520
+ );
4521
+ } else {
4522
+ markSkippedIfPresent("settings-storage", false);
4523
+ }
4524
+ const provider = payload.provider;
4525
+ if (isRecord5(provider)) {
4526
+ const list = Array.isArray(provider.providers) ? provider.providers.filter(isRecord5).map((item) => ({
4527
+ id: asString3(item.id) ?? "",
4528
+ name: asString3(item.name) ?? "",
4529
+ models: Array.isArray(item.models) ? item.models.filter((model) => typeof model === "string") : [],
4530
+ apiKey: asString3(item.apiKey) ?? void 0,
4531
+ baseUrl: asString3(item.baseUrl) ?? void 0
4532
+ })).filter((item) => item.id && item.name) : void 0;
4533
+ const overridesByPath = isRecord5(provider.selectionsByCwd) ? provider.selectionsByCwd : void 0;
4534
+ patch.providers = {
4535
+ list,
4536
+ selectedProviderId: asString3(provider.selectedProviderId) ?? void 0,
4537
+ defaultModel: asString3(provider.defaultModel ?? provider.selectedModel),
4538
+ defaultReasoningEffort: typeof provider.defaultReasoningEffort === "string" ? provider.defaultReasoningEffort : typeof provider.reasoningEffort === "string" ? provider.reasoningEffort : void 0,
4539
+ overridesByPath
4540
+ };
4541
+ markSkippedIfPresent(
4542
+ "provider",
4543
+ list !== void 0 || asString3(provider.selectedProviderId) !== null || asString3(provider.defaultModel ?? provider.selectedModel) !== null || typeof provider.defaultReasoningEffort === "string" || typeof provider.reasoningEffort === "string" || overridesByPath !== void 0
4544
+ );
4545
+ } else {
4546
+ markSkippedIfPresent("provider", false);
4547
+ }
4548
+ const sandbox = payload["sandbox-storage"];
4549
+ if (isRecord5(sandbox)) {
4550
+ const defaultMode = asString3(sandbox.defaultMode ?? sandbox.mode) ?? void 0;
4551
+ const defaultApprovalPolicy = asString3(sandbox.defaultApprovalPolicy ?? sandbox.approvalPolicy) ?? void 0;
4552
+ const overridesByPath = isRecord5(sandbox.selectionsByCwd) ? sandbox.selectionsByCwd : void 0;
4553
+ patch.sandbox = {
4554
+ defaultMode,
4555
+ defaultApprovalPolicy,
4556
+ overridesByPath
4557
+ };
4558
+ markSkippedIfPresent(
4559
+ "sandbox-storage",
4560
+ defaultMode !== void 0 || defaultApprovalPolicy !== void 0 || overridesByPath !== void 0
4561
+ );
4562
+ } else {
4563
+ markSkippedIfPresent("sandbox-storage", false);
4564
+ }
4565
+ const projectSettings = payload["project-settings-storage"];
4566
+ if (isRecord5(projectSettings) && isRecord5(projectSettings.settingsByPath)) {
4567
+ patch.projectSettingsByPath = projectSettings.settingsByPath;
4568
+ markSkippedIfPresent("project-settings-storage", true);
4569
+ } else {
4570
+ markSkippedIfPresent("project-settings-storage", false);
4571
+ }
4572
+ const folder = payload["folder-storage"];
4573
+ if (isRecord5(folder)) {
4574
+ const folderHistory = Array.isArray(folder.folderHistory) ? folder.folderHistory.filter(isRecord5) : void 0;
4575
+ const pinnedPaths = Array.isArray(folder.pinnedPaths) ? folder.pinnedPaths.filter((item) => typeof item === "string") : void 0;
4576
+ patch.preferences = {
4577
+ ...patch.preferences ?? {},
4578
+ folderHistory,
4579
+ pinnedPaths
4580
+ };
4581
+ markSkippedIfPresent("folder-storage", folderHistory !== void 0 || pinnedPaths !== void 0);
4582
+ } else {
4583
+ markSkippedIfPresent("folder-storage", false);
4584
+ }
4585
+ const categories = payload["conversation-categories-storage"];
4586
+ let consumedCategories = false;
4587
+ if (isRecord5(categories)) {
4588
+ if (isRecord5(categories.categoriesByCwd)) {
4589
+ patch.conversationCategoriesByCwd = categories.categoriesByCwd;
4590
+ consumedCategories = true;
4591
+ }
4592
+ if (isRecord5(categories.conversationCategoryByCwd)) {
4593
+ patch.conversationCategoryAssignmentsByCwd = categories.conversationCategoryByCwd;
4594
+ consumedCategories = true;
4595
+ }
4596
+ }
4597
+ markSkippedIfPresent("conversation-categories-storage", consumedCategories);
4598
+ const legacyAutoRoll = payload["codex:auto-roll-settings"];
4599
+ const autoRoll = pickAutoRoll(legacyAutoRoll);
4600
+ if (autoRoll) {
4601
+ patch.autoRoll = {
4602
+ enabled: autoRoll.enabled,
4603
+ warningThreshold: autoRoll.warningThreshold,
4604
+ switchThreshold: autoRoll.switchThreshold
4605
+ };
4606
+ markSkippedIfPresent("codex:auto-roll-settings", true);
4607
+ } else {
4608
+ markSkippedIfPresent("codex:auto-roll-settings", false);
4609
+ }
4610
+ return {
4611
+ patch,
4612
+ consumedKeys: Array.from(consumedKeys),
4613
+ skippedKeys: Array.from(skippedKeys)
4614
+ };
4615
+ }
4616
+ async function removeIfExists(target) {
4617
+ await import_node_fs7.promises.rm(target, { recursive: true, force: true });
4618
+ }
4619
+ async function cleanupLegacyCanonicalSources() {
4620
+ const homeDir = resolveHomeDir2();
4621
+ await removeIfExists(import_node_path9.default.join(homeDir, SQLITE_STORAGE_DIR));
4622
+ await removeIfExists(resolveLegacyPath(LEGACY_SETTINGS_FILE));
4623
+ await removeIfExists(resolveLegacyPath(LEGACY_SETTINGS_BACKUP_FILE));
4624
+ await removeIfExists(resolveLegacyPath(LEGACY_SYNC_STATE_FILE));
4625
+ await removeIfExists(resolveLegacyPath(LEGACY_LICENSE_SECRET_FILE));
4626
+ await removeIfExists(resolveLegacyPath(LEGACY_SKILLS_DIR, LEGACY_SKILLS_REPOS_FILE));
4627
+ const profileHomesRoot = resolveLegacyPath(LEGACY_PROFILE_HOMES_DIR);
4628
+ try {
4629
+ const profileHomes = await import_node_fs7.promises.readdir(profileHomesRoot, { withFileTypes: true });
4630
+ for (const profileHome of profileHomes) {
4631
+ if (!profileHome.isDirectory()) {
4632
+ continue;
4633
+ }
4634
+ const profileDir = import_node_path9.default.join(profileHomesRoot, profileHome.name);
4635
+ let files = [];
4636
+ try {
4637
+ files = await import_node_fs7.promises.readdir(profileDir);
4638
+ } catch {
4639
+ continue;
4640
+ }
4641
+ for (const file of files) {
4642
+ if (!file.startsWith("profile.json")) {
4643
+ continue;
4644
+ }
4645
+ await removeIfExists(import_node_path9.default.join(profileDir, file));
4646
+ }
4647
+ }
4648
+ } catch (error) {
4649
+ logWarn("Failed cleaning legacy profile metadata:", {
4650
+ profileHomesRoot,
4651
+ error: error instanceof Error ? error.message : String(error)
4652
+ });
4653
+ }
4654
+ const skillsRoot = resolveLegacyPath(LEGACY_SKILLS_DIR);
4655
+ try {
4656
+ const skillDirs = await import_node_fs7.promises.readdir(skillsRoot, { withFileTypes: true });
4657
+ for (const entry of skillDirs) {
4658
+ if (!entry.isDirectory() || entry.name.startsWith(".")) {
4659
+ continue;
4660
+ }
4661
+ await removeIfExists(import_node_path9.default.join(skillsRoot, entry.name, LEGACY_SKILL_MANIFEST));
4662
+ }
4663
+ } catch (error) {
4664
+ logWarn("Failed cleaning legacy skills metadata:", {
4665
+ skillsRoot,
4666
+ error: error instanceof Error ? error.message : String(error)
4667
+ });
4668
+ }
4669
+ }
4670
+ async function runStorageMigrationV1() {
4671
+ const current = await getAppState();
4672
+ if (current.migration.status === "complete" || current.migration.status === "pending_local_storage") {
4673
+ return current;
4674
+ }
4675
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
4676
+ try {
4677
+ await migrateLegacyDirectoriesToUserData();
4678
+ const patches = await Promise.all([
4679
+ loadLegacySettingsPatch(),
4680
+ loadLegacySyncPatch(),
4681
+ loadLegacyProfilesPatch(),
4682
+ loadLegacySkillsPatch()
4683
+ ]);
4684
+ const mergedPatch = patches.reduce((acc, patch) => {
4685
+ return {
4686
+ ...acc,
4687
+ ...patch,
4688
+ app: { ...acc.app ?? {}, ...patch.app ?? {} },
4689
+ license: { ...acc.license ?? {}, ...patch.license ?? {} },
4690
+ autoRoll: { ...acc.autoRoll ?? {}, ...patch.autoRoll ?? {} },
4691
+ providers: { ...acc.providers ?? {}, ...patch.providers ?? {} },
4692
+ sandbox: { ...acc.sandbox ?? {}, ...patch.sandbox ?? {} },
4693
+ preferences: { ...acc.preferences ?? {}, ...patch.preferences ?? {} },
4694
+ sync: { ...acc.sync ?? {}, ...patch.sync ?? {} },
4695
+ profilesByName: { ...acc.profilesByName ?? {}, ...patch.profilesByName ?? {} },
4696
+ projectSettingsByPath: {
4697
+ ...acc.projectSettingsByPath ?? {},
4698
+ ...patch.projectSettingsByPath ?? {}
4699
+ },
4700
+ conversationCategoriesByCwd: {
4701
+ ...acc.conversationCategoriesByCwd ?? {},
4702
+ ...patch.conversationCategoriesByCwd ?? {}
4703
+ },
4704
+ conversationCategoryAssignmentsByCwd: {
4705
+ ...acc.conversationCategoryAssignmentsByCwd ?? {},
4706
+ ...patch.conversationCategoryAssignmentsByCwd ?? {}
4707
+ },
4708
+ skills: {
4709
+ ...acc.skills ?? {},
4710
+ ...patch.skills ?? {},
4711
+ sources: patch.skills?.sources ?? acc.skills?.sources,
4712
+ installsBySlug: {
4713
+ ...acc.skills?.installsBySlug ?? {},
4714
+ ...patch.skills?.installsBySlug ?? {}
4715
+ }
4716
+ }
4717
+ };
4718
+ }, {});
4719
+ return await updateAppState((state) => ({
4720
+ ...state,
4721
+ ...mergedPatch,
4722
+ app: { ...state.app, ...mergedPatch.app ?? {} },
4723
+ license: { ...state.license, ...mergedPatch.license ?? {} },
4724
+ autoRoll: { ...state.autoRoll, ...mergedPatch.autoRoll ?? {} },
4725
+ providers: {
4726
+ ...state.providers,
4727
+ ...mergedPatch.providers ?? {},
4728
+ overridesByPath: {
4729
+ ...state.providers.overridesByPath,
4730
+ ...mergedPatch.providers?.overridesByPath ?? {}
4731
+ }
4732
+ },
4733
+ sandbox: {
4734
+ ...state.sandbox,
4735
+ ...mergedPatch.sandbox ?? {},
4736
+ overridesByPath: {
4737
+ ...state.sandbox.overridesByPath,
4738
+ ...mergedPatch.sandbox?.overridesByPath ?? {}
4739
+ }
4740
+ },
4741
+ preferences: { ...state.preferences, ...mergedPatch.preferences ?? {} },
4742
+ sync: { ...state.sync, ...mergedPatch.sync ?? {} },
4743
+ profilesByName: {
4744
+ ...state.profilesByName,
4745
+ ...mergedPatch.profilesByName ?? {}
4746
+ },
4747
+ projectSettingsByPath: {
4748
+ ...state.projectSettingsByPath,
4749
+ ...mergedPatch.projectSettingsByPath ?? {}
4750
+ },
4751
+ conversationCategoriesByCwd: {
4752
+ ...state.conversationCategoriesByCwd,
4753
+ ...mergedPatch.conversationCategoriesByCwd ?? {}
4754
+ },
4755
+ conversationCategoryAssignmentsByCwd: {
4756
+ ...state.conversationCategoryAssignmentsByCwd,
4757
+ ...mergedPatch.conversationCategoryAssignmentsByCwd ?? {}
4758
+ },
4759
+ skills: {
4760
+ ...state.skills,
4761
+ ...mergedPatch.skills ?? {},
4762
+ installsBySlug: {
4763
+ ...state.skills.installsBySlug,
4764
+ ...mergedPatch.skills?.installsBySlug ?? {}
4765
+ }
4766
+ },
4767
+ migration: {
4768
+ ...state.migration,
4769
+ status: "pending_local_storage",
4770
+ startedAt: state.migration.startedAt ?? startedAt,
4771
+ completedAt: null,
4772
+ localStorageImportedAt: null,
4773
+ lastError: null
4774
+ }
4775
+ }), {
4776
+ mode: "replace",
4777
+ allowBeforeMigrationComplete: true
4778
+ });
4779
+ } catch (error) {
4780
+ const message = error instanceof Error ? error.message : String(error);
4781
+ await updateAppState((state) => ({
4782
+ ...state,
4783
+ migration: {
4784
+ ...state.migration,
4785
+ status: "pending",
4786
+ startedAt: state.migration.startedAt ?? startedAt,
4787
+ lastError: message
4788
+ }
4789
+ }), {
4790
+ mode: "replace",
4791
+ allowBeforeMigrationComplete: true
4792
+ });
4793
+ throw error;
4794
+ }
4795
+ }
4796
+ async function importLegacyLocalStorageOnce(payload) {
4797
+ const current = await getAppState();
4798
+ if (current.migration.status === "complete") {
4799
+ return { completed: true, importedKeys: [], skippedKeys: [] };
4800
+ }
4801
+ if (current.migration.status !== "pending_local_storage") {
4802
+ return { completed: false, importedKeys: [], skippedKeys: [] };
4803
+ }
4804
+ if (!payload || !isRecord5(payload)) {
4805
+ return { completed: false, importedKeys: [], skippedKeys: [] };
4806
+ }
4807
+ const { patch, consumedKeys, skippedKeys } = mergeLegacyLocalStoragePatch(payload);
4808
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
4809
+ const next = await updateAppState((state) => {
4810
+ if (state.migration.status !== "pending_local_storage") {
4811
+ return state;
4812
+ }
4813
+ return {
4814
+ ...state,
4815
+ ...patch,
4816
+ app: { ...state.app, ...patch.app ?? {} },
4817
+ autoRoll: { ...state.autoRoll, ...patch.autoRoll ?? {} },
4818
+ license: { ...state.license, ...patch.license ?? {} },
4819
+ providers: {
4820
+ ...state.providers,
4821
+ ...patch.providers ?? {},
4822
+ overridesByPath: {
4823
+ ...state.providers.overridesByPath,
4824
+ ...patch.providers?.overridesByPath ?? {}
4825
+ }
4826
+ },
4827
+ sandbox: {
4828
+ ...state.sandbox,
4829
+ ...patch.sandbox ?? {},
4830
+ overridesByPath: {
4831
+ ...state.sandbox.overridesByPath,
4832
+ ...patch.sandbox?.overridesByPath ?? {}
4833
+ }
4834
+ },
4835
+ preferences: { ...state.preferences, ...patch.preferences ?? {} },
4836
+ projectSettingsByPath: {
4837
+ ...state.projectSettingsByPath,
4838
+ ...patch.projectSettingsByPath ?? {}
4839
+ },
4840
+ conversationCategoriesByCwd: {
4841
+ ...state.conversationCategoriesByCwd,
4842
+ ...patch.conversationCategoriesByCwd ?? {}
4843
+ },
4844
+ conversationCategoryAssignmentsByCwd: {
4845
+ ...state.conversationCategoryAssignmentsByCwd,
4846
+ ...patch.conversationCategoryAssignmentsByCwd ?? {}
4847
+ },
4848
+ migration: {
4849
+ ...state.migration,
4850
+ status: "complete",
4851
+ completedAt,
4852
+ localStorageImportedAt: completedAt,
4853
+ lastError: null
4854
+ }
4855
+ };
4856
+ }, {
4857
+ mode: "replace",
4858
+ allowBeforeMigrationComplete: true
4859
+ });
4860
+ if (next.migration.status !== "complete") {
4861
+ return { completed: false, importedKeys: [], skippedKeys: [] };
4862
+ }
4863
+ await cleanupLegacyCanonicalSources();
4864
+ return { completed: true, importedKeys: consumedKeys, skippedKeys };
4865
+ }
4866
+
4074
4867
  // src/index.ts
4075
- var VERSION = true ? "2.4.2" : "0.0.0";
4868
+ var VERSION = true ? "2.4.4" : "0.0.0";
4869
+ var cliStorageReadyPromise = null;
4870
+ async function ensureCliStorageReady() {
4871
+ if (cliStorageReadyPromise) {
4872
+ return cliStorageReadyPromise;
4873
+ }
4874
+ cliStorageReadyPromise = (async () => {
4875
+ await initializeAppState(getUserDataDir());
4876
+ const migrated = await runStorageMigrationV1();
4877
+ if (migrated.migration.status === "pending_local_storage") {
4878
+ await importLegacyLocalStorageOnce({});
4879
+ }
4880
+ const state = await getAppState();
4881
+ if (state.migration.status !== "complete") {
4882
+ throw new Error(
4883
+ `Storage migration is not complete (status: ${state.migration.status}). Open CodexUse desktop once and try again.`
4884
+ );
4885
+ }
4886
+ })().catch((error) => {
4887
+ cliStorageReadyPromise = null;
4888
+ throw error;
4889
+ });
4890
+ return cliStorageReadyPromise;
4891
+ }
4076
4892
  function printHelp() {
4077
4893
  console.log(`CodexUse CLI v${VERSION}
4078
4894
 
@@ -4591,12 +5407,15 @@ async function main() {
4591
5407
  const rest = args.slice(1);
4592
5408
  switch (command) {
4593
5409
  case "profile":
5410
+ await ensureCliStorageReady();
4594
5411
  await handleProfile(rest);
4595
5412
  return;
4596
5413
  case "license":
5414
+ await ensureCliStorageReady();
4597
5415
  await handleLicense(rest);
4598
5416
  return;
4599
5417
  case "sync":
5418
+ await ensureCliStorageReady();
4600
5419
  await handleSync(rest);
4601
5420
  return;
4602
5421
  default: