codex-team 0.0.6 → 0.0.7

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/cli.cjs CHANGED
@@ -13,7 +13,7 @@ var __webpack_modules__ = {
13
13
  const utc_js_namespaceObject = require("dayjs/plugin/utc.js");
14
14
  var utc_js_default = /*#__PURE__*/ __webpack_require__.n(utc_js_namespaceObject);
15
15
  var package_namespaceObject = {
16
- rE: "0.0.6"
16
+ rE: "0.0.7"
17
17
  };
18
18
  const external_node_crypto_namespaceObject = require("node:crypto");
19
19
  const promises_namespaceObject = require("node:fs/promises");
@@ -456,6 +456,7 @@ var __webpack_modules__ = {
456
456
  codexDir,
457
457
  codexTeamDir,
458
458
  currentAuthPath: (0, external_node_path_namespaceObject.join)(codexDir, "auth.json"),
459
+ currentConfigPath: (0, external_node_path_namespaceObject.join)(codexDir, "config.toml"),
459
460
  accountsDir: (0, external_node_path_namespaceObject.join)(codexTeamDir, "accounts"),
460
461
  backupsDir: (0, external_node_path_namespaceObject.join)(codexTeamDir, "backups"),
461
462
  statePath: (0, external_node_path_namespaceObject.join)(codexTeamDir, "state.json")
@@ -548,12 +549,44 @@ var __webpack_modules__ = {
548
549
  accountMetaPath(name) {
549
550
  return (0, external_node_path_namespaceObject.join)(this.accountDirectory(name), "meta.json");
550
551
  }
552
+ accountConfigPath(name) {
553
+ return (0, external_node_path_namespaceObject.join)(this.accountDirectory(name), "config.toml");
554
+ }
551
555
  async writeAccountAuthSnapshot(name, snapshot) {
552
556
  await atomicWriteFile(this.accountAuthPath(name), stringifyJson(snapshot));
553
557
  }
554
558
  async writeAccountMeta(name, meta) {
555
559
  await atomicWriteFile(this.accountMetaPath(name), stringifyJson(meta));
556
560
  }
561
+ validateConfigSnapshot(name, snapshot, rawConfig) {
562
+ if ("apikey" !== snapshot.auth_mode) return;
563
+ if (!rawConfig) throw new Error(`Current ~/.codex/config.toml is required to save apikey account "${name}".`);
564
+ if (!/^\s*model_provider\s*=\s*["'][^"']+["']/mu.test(rawConfig)) throw new Error(`Current ~/.codex/config.toml is missing model_provider for apikey account "${name}".`);
565
+ if (!/^\s*base_url\s*=\s*["'][^"']+["']/mu.test(rawConfig)) throw new Error(`Current ~/.codex/config.toml is missing base_url for apikey account "${name}".`);
566
+ }
567
+ sanitizeConfigForAccountAuth(rawConfig) {
568
+ const lines = rawConfig.split(/\r?\n/u);
569
+ const result = [];
570
+ let skippingProviderSection = false;
571
+ for (const line of lines){
572
+ const trimmed = line.trim();
573
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
574
+ skippingProviderSection = /^\[model_providers\.[^\]]+\]$/u.test(trimmed);
575
+ if (skippingProviderSection) continue;
576
+ }
577
+ if (!skippingProviderSection) {
578
+ if (!/^\s*model_provider\s*=/u.test(line)) {
579
+ if (!/^\s*preferred_auth_method\s*=\s*["']apikey["']\s*$/u.test(line)) result.push(line);
580
+ }
581
+ }
582
+ }
583
+ return `${result.join("\n").replace(/\n{3,}/gu, "\n\n").trimEnd()}\n`;
584
+ }
585
+ async ensureEmptyAccountConfigSnapshot(name) {
586
+ const configPath = this.accountConfigPath(name);
587
+ await atomicWriteFile(configPath, "");
588
+ return configPath;
589
+ }
557
590
  async syncCurrentAuthIfMatching(snapshot) {
558
591
  if (!await pathExists(this.paths.currentAuthPath)) return;
559
592
  try {
@@ -619,6 +652,7 @@ var __webpack_modules__ = {
619
652
  ...meta,
620
653
  authPath,
621
654
  metaPath,
655
+ configPath: await pathExists(this.accountConfigPath(name)) ? this.accountConfigPath(name) : null,
622
656
  duplicateAccountId: false
623
657
  };
624
658
  }
@@ -675,14 +709,21 @@ var __webpack_modules__ = {
675
709
  if (!await pathExists(this.paths.currentAuthPath)) throw new Error("Current ~/.codex/auth.json does not exist.");
676
710
  const rawSnapshot = await readJsonFile(this.paths.currentAuthPath);
677
711
  const snapshot = parseAuthSnapshot(rawSnapshot);
712
+ const rawConfig = await pathExists(this.paths.currentConfigPath) ? await readJsonFile(this.paths.currentConfigPath) : null;
678
713
  const accountDir = this.accountDirectory(name);
679
714
  const authPath = this.accountAuthPath(name);
680
715
  const metaPath = this.accountMetaPath(name);
716
+ const configPath = this.accountConfigPath(name);
681
717
  const accountExists = await pathExists(accountDir);
682
718
  const existingMeta = accountExists && await pathExists(metaPath) ? parseSnapshotMeta(await readJsonFile(metaPath)) : void 0;
683
719
  if (accountExists && !force) throw new Error(`Account "${name}" already exists. Use --force to overwrite it.`);
720
+ this.validateConfigSnapshot(name, snapshot, rawConfig);
684
721
  await ensureDirectory(accountDir, DIRECTORY_MODE);
685
722
  await atomicWriteFile(authPath, `${rawSnapshot.trimEnd()}\n`);
723
+ if ("apikey" === snapshot.auth_mode && rawConfig) await atomicWriteFile(configPath, rawConfig.endsWith("\n") ? rawConfig : `${rawConfig}\n`);
724
+ else if (await pathExists(configPath)) await (0, promises_namespaceObject.rm)(configPath, {
725
+ force: true
726
+ });
686
727
  const meta = createSnapshotMeta(name, snapshot, new Date(), existingMeta?.created_at);
687
728
  meta.last_switched_at = existingMeta?.last_switched_at ?? null;
688
729
  meta.quota = existingMeta?.quota ?? meta.quota;
@@ -698,9 +739,15 @@ var __webpack_modules__ = {
698
739
  const name = current.matched_accounts[0];
699
740
  const currentRawSnapshot = await readJsonFile(this.paths.currentAuthPath);
700
741
  const currentSnapshot = parseAuthSnapshot(currentRawSnapshot);
742
+ const currentRawConfig = await pathExists(this.paths.currentConfigPath) ? await readJsonFile(this.paths.currentConfigPath) : null;
701
743
  const metaPath = this.accountMetaPath(name);
702
744
  const existingMeta = parseSnapshotMeta(await readJsonFile(metaPath));
745
+ this.validateConfigSnapshot(name, currentSnapshot, currentRawConfig);
703
746
  await atomicWriteFile(this.accountAuthPath(name), `${currentRawSnapshot.trimEnd()}\n`);
747
+ if ("apikey" === currentSnapshot.auth_mode && currentRawConfig) await atomicWriteFile(this.accountConfigPath(name), currentRawConfig.endsWith("\n") ? currentRawConfig : `${currentRawConfig}\n`);
748
+ else if (await pathExists(this.accountConfigPath(name))) await (0, promises_namespaceObject.rm)(this.accountConfigPath(name), {
749
+ force: true
750
+ });
704
751
  await atomicWriteFile(metaPath, stringifyJson({
705
752
  ...createSnapshotMeta(name, currentSnapshot, new Date(), existingMeta.created_at),
706
753
  last_switched_at: existingMeta.last_switched_at,
@@ -722,8 +769,23 @@ var __webpack_modules__ = {
722
769
  await (0, promises_namespaceObject.copyFile)(this.paths.currentAuthPath, backupPath);
723
770
  await chmodIfPossible(backupPath, FILE_MODE);
724
771
  }
772
+ if (await pathExists(this.paths.currentConfigPath)) {
773
+ const configBackupPath = (0, external_node_path_namespaceObject.join)(this.paths.backupsDir, "last-active-config.toml");
774
+ await (0, promises_namespaceObject.copyFile)(this.paths.currentConfigPath, configBackupPath);
775
+ await chmodIfPossible(configBackupPath, FILE_MODE);
776
+ }
725
777
  const rawAuth = await readJsonFile(account.authPath);
726
778
  await atomicWriteFile(this.paths.currentAuthPath, `${rawAuth.trimEnd()}\n`);
779
+ if ("apikey" === account.auth_mode && account.configPath) {
780
+ const rawConfig = await readJsonFile(account.configPath);
781
+ await atomicWriteFile(this.paths.currentConfigPath, rawConfig.endsWith("\n") ? rawConfig : `${rawConfig}\n`);
782
+ } else if ("apikey" === account.auth_mode) {
783
+ await this.ensureEmptyAccountConfigSnapshot(name);
784
+ warnings.push(`Saved apikey account "${name}" was missing config.toml snapshot. Created an empty snapshot; configure baseUrl manually if needed.`);
785
+ } else if (await pathExists(this.paths.currentConfigPath)) {
786
+ const currentRawConfig = await readJsonFile(this.paths.currentConfigPath);
787
+ await atomicWriteFile(this.paths.currentConfigPath, this.sanitizeConfigForAccountAuth(currentRawConfig));
788
+ }
727
789
  const writtenSnapshot = await readAuthSnapshotFile(this.paths.currentAuthPath);
728
790
  if (getSnapshotIdentity(writtenSnapshot) !== account.account_id) throw new Error(`Switch verification failed for account "${name}".`);
729
791
  const meta = parseSnapshotMeta(await readJsonFile(account.metaPath));
@@ -881,6 +943,7 @@ var __webpack_modules__ = {
881
943
  const metaStat = await (0, promises_namespaceObject.stat)(account.metaPath);
882
944
  if ((511 & authStat.mode) !== FILE_MODE) issues.push(`Account "${account.name}" auth permissions must be 600.`);
883
945
  if ((511 & metaStat.mode) !== FILE_MODE) issues.push(`Account "${account.name}" metadata permissions must be 600.`);
946
+ if ("apikey" === account.auth_mode && !account.configPath) issues.push(`Account "${account.name}" is missing config.toml snapshot required for apikey auth.`);
884
947
  if (account.duplicateAccountId) warnings.push(`Account "${account.name}" shares identity ${account.account_id} with another saved account.`);
885
948
  }
886
949
  let currentAuthPresent = false;
package/dist/main.cjs CHANGED
@@ -43,7 +43,7 @@ var timezone_js_default = /*#__PURE__*/ __webpack_require__.n(timezone_js_namesp
43
43
  const utc_js_namespaceObject = require("dayjs/plugin/utc.js");
44
44
  var utc_js_default = /*#__PURE__*/ __webpack_require__.n(utc_js_namespaceObject);
45
45
  var package_namespaceObject = {
46
- rE: "0.0.6"
46
+ rE: "0.0.7"
47
47
  };
48
48
  const external_node_crypto_namespaceObject = require("node:crypto");
49
49
  const promises_namespaceObject = require("node:fs/promises");
@@ -486,6 +486,7 @@ function defaultPaths(homeDir = (0, external_node_os_namespaceObject.homedir)())
486
486
  codexDir,
487
487
  codexTeamDir,
488
488
  currentAuthPath: (0, external_node_path_namespaceObject.join)(codexDir, "auth.json"),
489
+ currentConfigPath: (0, external_node_path_namespaceObject.join)(codexDir, "config.toml"),
489
490
  accountsDir: (0, external_node_path_namespaceObject.join)(codexTeamDir, "accounts"),
490
491
  backupsDir: (0, external_node_path_namespaceObject.join)(codexTeamDir, "backups"),
491
492
  statePath: (0, external_node_path_namespaceObject.join)(codexTeamDir, "state.json")
@@ -578,12 +579,44 @@ class AccountStore {
578
579
  accountMetaPath(name) {
579
580
  return (0, external_node_path_namespaceObject.join)(this.accountDirectory(name), "meta.json");
580
581
  }
582
+ accountConfigPath(name) {
583
+ return (0, external_node_path_namespaceObject.join)(this.accountDirectory(name), "config.toml");
584
+ }
581
585
  async writeAccountAuthSnapshot(name, snapshot) {
582
586
  await atomicWriteFile(this.accountAuthPath(name), stringifyJson(snapshot));
583
587
  }
584
588
  async writeAccountMeta(name, meta) {
585
589
  await atomicWriteFile(this.accountMetaPath(name), stringifyJson(meta));
586
590
  }
591
+ validateConfigSnapshot(name, snapshot, rawConfig) {
592
+ if ("apikey" !== snapshot.auth_mode) return;
593
+ if (!rawConfig) throw new Error(`Current ~/.codex/config.toml is required to save apikey account "${name}".`);
594
+ if (!/^\s*model_provider\s*=\s*["'][^"']+["']/mu.test(rawConfig)) throw new Error(`Current ~/.codex/config.toml is missing model_provider for apikey account "${name}".`);
595
+ if (!/^\s*base_url\s*=\s*["'][^"']+["']/mu.test(rawConfig)) throw new Error(`Current ~/.codex/config.toml is missing base_url for apikey account "${name}".`);
596
+ }
597
+ sanitizeConfigForAccountAuth(rawConfig) {
598
+ const lines = rawConfig.split(/\r?\n/u);
599
+ const result = [];
600
+ let skippingProviderSection = false;
601
+ for (const line of lines){
602
+ const trimmed = line.trim();
603
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
604
+ skippingProviderSection = /^\[model_providers\.[^\]]+\]$/u.test(trimmed);
605
+ if (skippingProviderSection) continue;
606
+ }
607
+ if (!skippingProviderSection) {
608
+ if (!/^\s*model_provider\s*=/u.test(line)) {
609
+ if (!/^\s*preferred_auth_method\s*=\s*["']apikey["']\s*$/u.test(line)) result.push(line);
610
+ }
611
+ }
612
+ }
613
+ return `${result.join("\n").replace(/\n{3,}/gu, "\n\n").trimEnd()}\n`;
614
+ }
615
+ async ensureEmptyAccountConfigSnapshot(name) {
616
+ const configPath = this.accountConfigPath(name);
617
+ await atomicWriteFile(configPath, "");
618
+ return configPath;
619
+ }
587
620
  async syncCurrentAuthIfMatching(snapshot) {
588
621
  if (!await pathExists(this.paths.currentAuthPath)) return;
589
622
  try {
@@ -649,6 +682,7 @@ class AccountStore {
649
682
  ...meta,
650
683
  authPath,
651
684
  metaPath,
685
+ configPath: await pathExists(this.accountConfigPath(name)) ? this.accountConfigPath(name) : null,
652
686
  duplicateAccountId: false
653
687
  };
654
688
  }
@@ -705,14 +739,21 @@ class AccountStore {
705
739
  if (!await pathExists(this.paths.currentAuthPath)) throw new Error("Current ~/.codex/auth.json does not exist.");
706
740
  const rawSnapshot = await readJsonFile(this.paths.currentAuthPath);
707
741
  const snapshot = parseAuthSnapshot(rawSnapshot);
742
+ const rawConfig = await pathExists(this.paths.currentConfigPath) ? await readJsonFile(this.paths.currentConfigPath) : null;
708
743
  const accountDir = this.accountDirectory(name);
709
744
  const authPath = this.accountAuthPath(name);
710
745
  const metaPath = this.accountMetaPath(name);
746
+ const configPath = this.accountConfigPath(name);
711
747
  const accountExists = await pathExists(accountDir);
712
748
  const existingMeta = accountExists && await pathExists(metaPath) ? parseSnapshotMeta(await readJsonFile(metaPath)) : void 0;
713
749
  if (accountExists && !force) throw new Error(`Account "${name}" already exists. Use --force to overwrite it.`);
750
+ this.validateConfigSnapshot(name, snapshot, rawConfig);
714
751
  await ensureDirectory(accountDir, DIRECTORY_MODE);
715
752
  await atomicWriteFile(authPath, `${rawSnapshot.trimEnd()}\n`);
753
+ if ("apikey" === snapshot.auth_mode && rawConfig) await atomicWriteFile(configPath, rawConfig.endsWith("\n") ? rawConfig : `${rawConfig}\n`);
754
+ else if (await pathExists(configPath)) await (0, promises_namespaceObject.rm)(configPath, {
755
+ force: true
756
+ });
716
757
  const meta = createSnapshotMeta(name, snapshot, new Date(), existingMeta?.created_at);
717
758
  meta.last_switched_at = existingMeta?.last_switched_at ?? null;
718
759
  meta.quota = existingMeta?.quota ?? meta.quota;
@@ -728,9 +769,15 @@ class AccountStore {
728
769
  const name = current.matched_accounts[0];
729
770
  const currentRawSnapshot = await readJsonFile(this.paths.currentAuthPath);
730
771
  const currentSnapshot = parseAuthSnapshot(currentRawSnapshot);
772
+ const currentRawConfig = await pathExists(this.paths.currentConfigPath) ? await readJsonFile(this.paths.currentConfigPath) : null;
731
773
  const metaPath = this.accountMetaPath(name);
732
774
  const existingMeta = parseSnapshotMeta(await readJsonFile(metaPath));
775
+ this.validateConfigSnapshot(name, currentSnapshot, currentRawConfig);
733
776
  await atomicWriteFile(this.accountAuthPath(name), `${currentRawSnapshot.trimEnd()}\n`);
777
+ if ("apikey" === currentSnapshot.auth_mode && currentRawConfig) await atomicWriteFile(this.accountConfigPath(name), currentRawConfig.endsWith("\n") ? currentRawConfig : `${currentRawConfig}\n`);
778
+ else if (await pathExists(this.accountConfigPath(name))) await (0, promises_namespaceObject.rm)(this.accountConfigPath(name), {
779
+ force: true
780
+ });
734
781
  await atomicWriteFile(metaPath, stringifyJson({
735
782
  ...createSnapshotMeta(name, currentSnapshot, new Date(), existingMeta.created_at),
736
783
  last_switched_at: existingMeta.last_switched_at,
@@ -752,8 +799,23 @@ class AccountStore {
752
799
  await (0, promises_namespaceObject.copyFile)(this.paths.currentAuthPath, backupPath);
753
800
  await chmodIfPossible(backupPath, FILE_MODE);
754
801
  }
802
+ if (await pathExists(this.paths.currentConfigPath)) {
803
+ const configBackupPath = (0, external_node_path_namespaceObject.join)(this.paths.backupsDir, "last-active-config.toml");
804
+ await (0, promises_namespaceObject.copyFile)(this.paths.currentConfigPath, configBackupPath);
805
+ await chmodIfPossible(configBackupPath, FILE_MODE);
806
+ }
755
807
  const rawAuth = await readJsonFile(account.authPath);
756
808
  await atomicWriteFile(this.paths.currentAuthPath, `${rawAuth.trimEnd()}\n`);
809
+ if ("apikey" === account.auth_mode && account.configPath) {
810
+ const rawConfig = await readJsonFile(account.configPath);
811
+ await atomicWriteFile(this.paths.currentConfigPath, rawConfig.endsWith("\n") ? rawConfig : `${rawConfig}\n`);
812
+ } else if ("apikey" === account.auth_mode) {
813
+ await this.ensureEmptyAccountConfigSnapshot(name);
814
+ warnings.push(`Saved apikey account "${name}" was missing config.toml snapshot. Created an empty snapshot; configure baseUrl manually if needed.`);
815
+ } else if (await pathExists(this.paths.currentConfigPath)) {
816
+ const currentRawConfig = await readJsonFile(this.paths.currentConfigPath);
817
+ await atomicWriteFile(this.paths.currentConfigPath, this.sanitizeConfigForAccountAuth(currentRawConfig));
818
+ }
757
819
  const writtenSnapshot = await readAuthSnapshotFile(this.paths.currentAuthPath);
758
820
  if (getSnapshotIdentity(writtenSnapshot) !== account.account_id) throw new Error(`Switch verification failed for account "${name}".`);
759
821
  const meta = parseSnapshotMeta(await readJsonFile(account.metaPath));
@@ -911,6 +973,7 @@ class AccountStore {
911
973
  const metaStat = await (0, promises_namespaceObject.stat)(account.metaPath);
912
974
  if ((511 & authStat.mode) !== FILE_MODE) issues.push(`Account "${account.name}" auth permissions must be 600.`);
913
975
  if ((511 & metaStat.mode) !== FILE_MODE) issues.push(`Account "${account.name}" metadata permissions must be 600.`);
976
+ if ("apikey" === account.auth_mode && !account.configPath) issues.push(`Account "${account.name}" is missing config.toml snapshot required for apikey auth.`);
914
977
  if (account.duplicateAccountId) warnings.push(`Account "${account.name}" shares identity ${account.account_id} with another saved account.`);
915
978
  }
916
979
  let currentAuthPresent = false;
package/dist/main.js CHANGED
@@ -9,7 +9,7 @@ import { basename, dirname, join } from "node:path";
9
9
  import { execFile } from "node:child_process";
10
10
  import { promisify } from "node:util";
11
11
  var package_namespaceObject = {
12
- rE: "0.0.6"
12
+ rE: "0.0.7"
13
13
  };
14
14
  function isRecord(value) {
15
15
  return "object" == typeof value && null !== value && !Array.isArray(value);
@@ -446,6 +446,7 @@ function defaultPaths(homeDir = homedir()) {
446
446
  codexDir,
447
447
  codexTeamDir,
448
448
  currentAuthPath: join(codexDir, "auth.json"),
449
+ currentConfigPath: join(codexDir, "config.toml"),
449
450
  accountsDir: join(codexTeamDir, "accounts"),
450
451
  backupsDir: join(codexTeamDir, "backups"),
451
452
  statePath: join(codexTeamDir, "state.json")
@@ -538,12 +539,44 @@ class AccountStore {
538
539
  accountMetaPath(name) {
539
540
  return join(this.accountDirectory(name), "meta.json");
540
541
  }
542
+ accountConfigPath(name) {
543
+ return join(this.accountDirectory(name), "config.toml");
544
+ }
541
545
  async writeAccountAuthSnapshot(name, snapshot) {
542
546
  await atomicWriteFile(this.accountAuthPath(name), stringifyJson(snapshot));
543
547
  }
544
548
  async writeAccountMeta(name, meta) {
545
549
  await atomicWriteFile(this.accountMetaPath(name), stringifyJson(meta));
546
550
  }
551
+ validateConfigSnapshot(name, snapshot, rawConfig) {
552
+ if ("apikey" !== snapshot.auth_mode) return;
553
+ if (!rawConfig) throw new Error(`Current ~/.codex/config.toml is required to save apikey account "${name}".`);
554
+ if (!/^\s*model_provider\s*=\s*["'][^"']+["']/mu.test(rawConfig)) throw new Error(`Current ~/.codex/config.toml is missing model_provider for apikey account "${name}".`);
555
+ if (!/^\s*base_url\s*=\s*["'][^"']+["']/mu.test(rawConfig)) throw new Error(`Current ~/.codex/config.toml is missing base_url for apikey account "${name}".`);
556
+ }
557
+ sanitizeConfigForAccountAuth(rawConfig) {
558
+ const lines = rawConfig.split(/\r?\n/u);
559
+ const result = [];
560
+ let skippingProviderSection = false;
561
+ for (const line of lines){
562
+ const trimmed = line.trim();
563
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
564
+ skippingProviderSection = /^\[model_providers\.[^\]]+\]$/u.test(trimmed);
565
+ if (skippingProviderSection) continue;
566
+ }
567
+ if (!skippingProviderSection) {
568
+ if (!/^\s*model_provider\s*=/u.test(line)) {
569
+ if (!/^\s*preferred_auth_method\s*=\s*["']apikey["']\s*$/u.test(line)) result.push(line);
570
+ }
571
+ }
572
+ }
573
+ return `${result.join("\n").replace(/\n{3,}/gu, "\n\n").trimEnd()}\n`;
574
+ }
575
+ async ensureEmptyAccountConfigSnapshot(name) {
576
+ const configPath = this.accountConfigPath(name);
577
+ await atomicWriteFile(configPath, "");
578
+ return configPath;
579
+ }
547
580
  async syncCurrentAuthIfMatching(snapshot) {
548
581
  if (!await pathExists(this.paths.currentAuthPath)) return;
549
582
  try {
@@ -609,6 +642,7 @@ class AccountStore {
609
642
  ...meta,
610
643
  authPath,
611
644
  metaPath,
645
+ configPath: await pathExists(this.accountConfigPath(name)) ? this.accountConfigPath(name) : null,
612
646
  duplicateAccountId: false
613
647
  };
614
648
  }
@@ -665,14 +699,21 @@ class AccountStore {
665
699
  if (!await pathExists(this.paths.currentAuthPath)) throw new Error("Current ~/.codex/auth.json does not exist.");
666
700
  const rawSnapshot = await readJsonFile(this.paths.currentAuthPath);
667
701
  const snapshot = parseAuthSnapshot(rawSnapshot);
702
+ const rawConfig = await pathExists(this.paths.currentConfigPath) ? await readJsonFile(this.paths.currentConfigPath) : null;
668
703
  const accountDir = this.accountDirectory(name);
669
704
  const authPath = this.accountAuthPath(name);
670
705
  const metaPath = this.accountMetaPath(name);
706
+ const configPath = this.accountConfigPath(name);
671
707
  const accountExists = await pathExists(accountDir);
672
708
  const existingMeta = accountExists && await pathExists(metaPath) ? parseSnapshotMeta(await readJsonFile(metaPath)) : void 0;
673
709
  if (accountExists && !force) throw new Error(`Account "${name}" already exists. Use --force to overwrite it.`);
710
+ this.validateConfigSnapshot(name, snapshot, rawConfig);
674
711
  await ensureDirectory(accountDir, DIRECTORY_MODE);
675
712
  await atomicWriteFile(authPath, `${rawSnapshot.trimEnd()}\n`);
713
+ if ("apikey" === snapshot.auth_mode && rawConfig) await atomicWriteFile(configPath, rawConfig.endsWith("\n") ? rawConfig : `${rawConfig}\n`);
714
+ else if (await pathExists(configPath)) await rm(configPath, {
715
+ force: true
716
+ });
676
717
  const meta = createSnapshotMeta(name, snapshot, new Date(), existingMeta?.created_at);
677
718
  meta.last_switched_at = existingMeta?.last_switched_at ?? null;
678
719
  meta.quota = existingMeta?.quota ?? meta.quota;
@@ -688,9 +729,15 @@ class AccountStore {
688
729
  const name = current.matched_accounts[0];
689
730
  const currentRawSnapshot = await readJsonFile(this.paths.currentAuthPath);
690
731
  const currentSnapshot = parseAuthSnapshot(currentRawSnapshot);
732
+ const currentRawConfig = await pathExists(this.paths.currentConfigPath) ? await readJsonFile(this.paths.currentConfigPath) : null;
691
733
  const metaPath = this.accountMetaPath(name);
692
734
  const existingMeta = parseSnapshotMeta(await readJsonFile(metaPath));
735
+ this.validateConfigSnapshot(name, currentSnapshot, currentRawConfig);
693
736
  await atomicWriteFile(this.accountAuthPath(name), `${currentRawSnapshot.trimEnd()}\n`);
737
+ if ("apikey" === currentSnapshot.auth_mode && currentRawConfig) await atomicWriteFile(this.accountConfigPath(name), currentRawConfig.endsWith("\n") ? currentRawConfig : `${currentRawConfig}\n`);
738
+ else if (await pathExists(this.accountConfigPath(name))) await rm(this.accountConfigPath(name), {
739
+ force: true
740
+ });
694
741
  await atomicWriteFile(metaPath, stringifyJson({
695
742
  ...createSnapshotMeta(name, currentSnapshot, new Date(), existingMeta.created_at),
696
743
  last_switched_at: existingMeta.last_switched_at,
@@ -712,8 +759,23 @@ class AccountStore {
712
759
  await copyFile(this.paths.currentAuthPath, backupPath);
713
760
  await chmodIfPossible(backupPath, FILE_MODE);
714
761
  }
762
+ if (await pathExists(this.paths.currentConfigPath)) {
763
+ const configBackupPath = join(this.paths.backupsDir, "last-active-config.toml");
764
+ await copyFile(this.paths.currentConfigPath, configBackupPath);
765
+ await chmodIfPossible(configBackupPath, FILE_MODE);
766
+ }
715
767
  const rawAuth = await readJsonFile(account.authPath);
716
768
  await atomicWriteFile(this.paths.currentAuthPath, `${rawAuth.trimEnd()}\n`);
769
+ if ("apikey" === account.auth_mode && account.configPath) {
770
+ const rawConfig = await readJsonFile(account.configPath);
771
+ await atomicWriteFile(this.paths.currentConfigPath, rawConfig.endsWith("\n") ? rawConfig : `${rawConfig}\n`);
772
+ } else if ("apikey" === account.auth_mode) {
773
+ await this.ensureEmptyAccountConfigSnapshot(name);
774
+ warnings.push(`Saved apikey account "${name}" was missing config.toml snapshot. Created an empty snapshot; configure baseUrl manually if needed.`);
775
+ } else if (await pathExists(this.paths.currentConfigPath)) {
776
+ const currentRawConfig = await readJsonFile(this.paths.currentConfigPath);
777
+ await atomicWriteFile(this.paths.currentConfigPath, this.sanitizeConfigForAccountAuth(currentRawConfig));
778
+ }
717
779
  const writtenSnapshot = await readAuthSnapshotFile(this.paths.currentAuthPath);
718
780
  if (getSnapshotIdentity(writtenSnapshot) !== account.account_id) throw new Error(`Switch verification failed for account "${name}".`);
719
781
  const meta = parseSnapshotMeta(await readJsonFile(account.metaPath));
@@ -871,6 +933,7 @@ class AccountStore {
871
933
  const metaStat = await stat(account.metaPath);
872
934
  if ((511 & authStat.mode) !== FILE_MODE) issues.push(`Account "${account.name}" auth permissions must be 600.`);
873
935
  if ((511 & metaStat.mode) !== FILE_MODE) issues.push(`Account "${account.name}" metadata permissions must be 600.`);
936
+ if ("apikey" === account.auth_mode && !account.configPath) issues.push(`Account "${account.name}" is missing config.toml snapshot required for apikey auth.`);
874
937
  if (account.duplicateAccountId) warnings.push(`Account "${account.name}" shares identity ${account.account_id} with another saved account.`);
875
938
  }
876
939
  let currentAuthPresent = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-team",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Manage multiple Codex ChatGPT auth snapshots and quota usage from the command line.",
5
5
  "license": "MIT",
6
6
  "type": "module",