codex-team 0.0.1 → 0.0.2
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/README.md +2 -3
- package/dist/cli.cjs +74 -69
- package/dist/main.cjs +74 -69
- package/dist/main.js +74 -69
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,14 +16,13 @@ After install, use the `codexm` command.
|
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
codexm current
|
|
19
|
-
codexm list
|
|
19
|
+
codexm list [name]
|
|
20
20
|
codexm save <name>
|
|
21
21
|
codexm update
|
|
22
22
|
codexm switch <name>
|
|
23
23
|
codexm remove <name> --yes
|
|
24
24
|
codexm rename <old> <new>
|
|
25
25
|
codexm quota refresh [name]
|
|
26
|
-
codexm quota list
|
|
27
26
|
codexm doctor
|
|
28
27
|
```
|
|
29
28
|
|
|
@@ -35,7 +34,7 @@ Use `--json` on query and mutation commands when you need machine-readable outpu
|
|
|
35
34
|
2. Save the current auth snapshot with `codexm save <name>`.
|
|
36
35
|
3. Repeat for other accounts.
|
|
37
36
|
4. Switch between saved accounts with `codexm switch <name>`.
|
|
38
|
-
5. Refresh and inspect quota usage with `codexm
|
|
37
|
+
5. Refresh and inspect quota usage with `codexm list` or `codexm quota refresh`.
|
|
39
38
|
|
|
40
39
|
## Development
|
|
41
40
|
|
package/dist/cli.cjs
CHANGED
|
@@ -409,6 +409,7 @@ var __webpack_modules__ = {
|
|
|
409
409
|
const FILE_MODE = 384;
|
|
410
410
|
const SCHEMA_VERSION = 1;
|
|
411
411
|
const ACCOUNT_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
412
|
+
const QUOTA_REFRESH_CONCURRENCY = 3;
|
|
412
413
|
function defaultPaths(homeDir = (0, external_node_os_namespaceObject.homedir)()) {
|
|
413
414
|
const codexDir = (0, external_node_path_namespaceObject.join)(homeDir, ".codex");
|
|
414
415
|
const codexTeamDir = (0, external_node_path_namespaceObject.join)(homeDir, ".codex-team");
|
|
@@ -759,17 +760,36 @@ var __webpack_modules__ = {
|
|
|
759
760
|
const { accounts } = await this.listAccounts();
|
|
760
761
|
const targets = targetName ? accounts.filter((account)=>account.name === targetName) : accounts;
|
|
761
762
|
if (targetName && 0 === targets.length) throw new Error(`Account "${targetName}" does not exist.`);
|
|
763
|
+
const results = new Array(targets.length);
|
|
764
|
+
let nextIndex = 0;
|
|
765
|
+
const workerCount = Math.min(QUOTA_REFRESH_CONCURRENCY, targets.length);
|
|
766
|
+
await Promise.all(Array.from({
|
|
767
|
+
length: workerCount
|
|
768
|
+
}, async ()=>{
|
|
769
|
+
while(true){
|
|
770
|
+
const index = nextIndex;
|
|
771
|
+
nextIndex += 1;
|
|
772
|
+
if (index >= targets.length) return;
|
|
773
|
+
const account = targets[index];
|
|
774
|
+
try {
|
|
775
|
+
const refreshed = await this.refreshQuotaForAccount(account.name);
|
|
776
|
+
results[index] = {
|
|
777
|
+
success: await this.quotaSummaryForAccount(refreshed.account)
|
|
778
|
+
};
|
|
779
|
+
} catch (error) {
|
|
780
|
+
results[index] = {
|
|
781
|
+
failure: {
|
|
782
|
+
name: account.name,
|
|
783
|
+
error: error.message
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}));
|
|
762
789
|
const successes = [];
|
|
763
790
|
const failures = [];
|
|
764
|
-
for (const
|
|
765
|
-
|
|
766
|
-
successes.push(await this.quotaSummaryForAccount(refreshed.account));
|
|
767
|
-
} catch (error) {
|
|
768
|
-
failures.push({
|
|
769
|
-
name: account.name,
|
|
770
|
-
error: error.message
|
|
771
|
-
});
|
|
772
|
-
}
|
|
791
|
+
for (const result of results)if (result) if ("success" in result) successes.push(result.success);
|
|
792
|
+
else failures.push(result.failure);
|
|
773
793
|
return {
|
|
774
794
|
successes,
|
|
775
795
|
failures
|
|
@@ -885,11 +905,10 @@ var __webpack_modules__ = {
|
|
|
885
905
|
|
|
886
906
|
Usage:
|
|
887
907
|
codexm current [--json]
|
|
888
|
-
codexm list [--json]
|
|
908
|
+
codexm list [name] [--json]
|
|
889
909
|
codexm save <name> [--force] [--json]
|
|
890
910
|
codexm update [--json]
|
|
891
911
|
codexm quota refresh [name] [--json]
|
|
892
|
-
codexm quota list [--json]
|
|
893
912
|
codexm switch <name> [--json]
|
|
894
913
|
codexm remove <name> [--yes] [--json]
|
|
895
914
|
codexm rename <old> <new> [--json]
|
|
@@ -911,47 +930,6 @@ Account names must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.
|
|
|
911
930
|
for (const warning of status.warnings)lines.push(`Warning: ${warning}`);
|
|
912
931
|
return lines.join("\n");
|
|
913
932
|
}
|
|
914
|
-
function describeAccounts(accounts, warnings) {
|
|
915
|
-
if (0 === accounts.length) return 0 === warnings.length ? "No saved accounts." : warnings.map((warning)=>`Warning: ${warning}`).join("\n");
|
|
916
|
-
const table = formatTable(accounts.map((account)=>({
|
|
917
|
-
name: account.name,
|
|
918
|
-
account_id: maskAccountId(account.account_id),
|
|
919
|
-
auth_mode: account.auth_mode,
|
|
920
|
-
saved: account.created_at,
|
|
921
|
-
switched: account.last_switched_at ?? "-",
|
|
922
|
-
flags: account.duplicateAccountId ? "duplicate-account-id" : "-"
|
|
923
|
-
})), [
|
|
924
|
-
{
|
|
925
|
-
key: "name",
|
|
926
|
-
label: "NAME"
|
|
927
|
-
},
|
|
928
|
-
{
|
|
929
|
-
key: "account_id",
|
|
930
|
-
label: "ACCOUNT ID"
|
|
931
|
-
},
|
|
932
|
-
{
|
|
933
|
-
key: "auth_mode",
|
|
934
|
-
label: "AUTH MODE"
|
|
935
|
-
},
|
|
936
|
-
{
|
|
937
|
-
key: "saved",
|
|
938
|
-
label: "SAVED AT"
|
|
939
|
-
},
|
|
940
|
-
{
|
|
941
|
-
key: "switched",
|
|
942
|
-
label: "LAST SWITCHED"
|
|
943
|
-
},
|
|
944
|
-
{
|
|
945
|
-
key: "flags",
|
|
946
|
-
label: "FLAGS"
|
|
947
|
-
}
|
|
948
|
-
]);
|
|
949
|
-
const lines = [
|
|
950
|
-
table
|
|
951
|
-
];
|
|
952
|
-
for (const warning of warnings)lines.push(`Warning: ${warning}`);
|
|
953
|
-
return lines.join("\n");
|
|
954
|
-
}
|
|
955
933
|
function describeDoctor(report) {
|
|
956
934
|
const lines = [
|
|
957
935
|
report.healthy ? "Doctor checks passed." : "Doctor checks found issues.",
|
|
@@ -970,17 +948,43 @@ Account names must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.
|
|
|
970
948
|
if (!window?.reset_at) return "-";
|
|
971
949
|
return external_dayjs_default().utc(window.reset_at).tz(external_dayjs_default().tz.guess()).format("MM-DD HH:mm");
|
|
972
950
|
}
|
|
951
|
+
function computeAvailability(account) {
|
|
952
|
+
if ("ok" !== account.status) return null;
|
|
953
|
+
const usedPercents = [
|
|
954
|
+
account.five_hour?.used_percent,
|
|
955
|
+
account.one_week?.used_percent
|
|
956
|
+
].filter((value)=>"number" == typeof value);
|
|
957
|
+
if (0 === usedPercents.length) return null;
|
|
958
|
+
if (usedPercents.some((value)=>value >= 100)) return "unavailable";
|
|
959
|
+
if (usedPercents.some((value)=>100 - value < 10)) return "almost unavailable";
|
|
960
|
+
return "available";
|
|
961
|
+
}
|
|
962
|
+
function toCliQuotaSummary(account) {
|
|
963
|
+
const { status, ...rest } = account;
|
|
964
|
+
return {
|
|
965
|
+
...rest,
|
|
966
|
+
available: computeAvailability(account),
|
|
967
|
+
refresh_status: status
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
function toCliQuotaRefreshResult(result) {
|
|
971
|
+
return {
|
|
972
|
+
successes: result.successes.map(toCliQuotaSummary),
|
|
973
|
+
failures: result.failures
|
|
974
|
+
};
|
|
975
|
+
}
|
|
973
976
|
function describeQuotaAccounts(accounts, warnings) {
|
|
974
977
|
if (0 === accounts.length) return 0 === warnings.length ? "No saved accounts." : warnings.map((warning)=>`Warning: ${warning}`).join("\n");
|
|
975
978
|
const table = formatTable(accounts.map((account)=>({
|
|
976
979
|
name: account.name,
|
|
977
980
|
account_id: maskAccountId(account.account_id),
|
|
978
981
|
plan_type: account.plan_type ?? "-",
|
|
982
|
+
available: computeAvailability(account) ?? "-",
|
|
979
983
|
five_hour: formatUsagePercent(account.five_hour),
|
|
980
984
|
five_hour_reset: formatResetAt(account.five_hour),
|
|
981
985
|
one_week: formatUsagePercent(account.one_week),
|
|
982
986
|
one_week_reset: formatResetAt(account.one_week),
|
|
983
|
-
|
|
987
|
+
refresh_status: account.status
|
|
984
988
|
})), [
|
|
985
989
|
{
|
|
986
990
|
key: "name",
|
|
@@ -994,6 +998,10 @@ Account names must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.
|
|
|
994
998
|
key: "plan_type",
|
|
995
999
|
label: "PLAN TYPE"
|
|
996
1000
|
},
|
|
1001
|
+
{
|
|
1002
|
+
key: "available",
|
|
1003
|
+
label: "AVAILABLE"
|
|
1004
|
+
},
|
|
997
1005
|
{
|
|
998
1006
|
key: "five_hour",
|
|
999
1007
|
label: "5H USED"
|
|
@@ -1011,8 +1019,8 @@ Account names must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.
|
|
|
1011
1019
|
label: "1W RESET AT"
|
|
1012
1020
|
},
|
|
1013
1021
|
{
|
|
1014
|
-
key: "
|
|
1015
|
-
label: "STATUS"
|
|
1022
|
+
key: "refresh_status",
|
|
1023
|
+
label: "REFRESH STATUS"
|
|
1016
1024
|
}
|
|
1017
1025
|
]);
|
|
1018
1026
|
const lines = [
|
|
@@ -1068,10 +1076,11 @@ Account names must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.
|
|
|
1068
1076
|
}
|
|
1069
1077
|
case "list":
|
|
1070
1078
|
{
|
|
1071
|
-
const
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1079
|
+
const targetName = parsed.positionals[0];
|
|
1080
|
+
const result = await store.refreshAllQuotas(targetName);
|
|
1081
|
+
if (json) writeJson(streams.stdout, toCliQuotaRefreshResult(result));
|
|
1082
|
+
else streams.stdout.write(`${describeQuotaRefresh(result)}\n`);
|
|
1083
|
+
return 0 === result.failures.length ? 0 : 1;
|
|
1075
1084
|
}
|
|
1076
1085
|
case "save":
|
|
1077
1086
|
{
|
|
@@ -1099,7 +1108,8 @@ Account names must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.
|
|
|
1099
1108
|
try {
|
|
1100
1109
|
const quotaResult = await store.refreshQuotaForAccount(result.account.name);
|
|
1101
1110
|
const quotaList = await store.listQuotaSummaries();
|
|
1102
|
-
|
|
1111
|
+
const matched = quotaList.accounts.find((account)=>account.name === quotaResult.account.name) ?? null;
|
|
1112
|
+
quota = matched ? toCliQuotaSummary(matched) : null;
|
|
1103
1113
|
} catch (error) {
|
|
1104
1114
|
warnings.push(error.message);
|
|
1105
1115
|
}
|
|
@@ -1124,20 +1134,14 @@ Account names must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.
|
|
|
1124
1134
|
case "quota":
|
|
1125
1135
|
{
|
|
1126
1136
|
const quotaCommand = parsed.positionals[0];
|
|
1127
|
-
if ("list" === quotaCommand) {
|
|
1128
|
-
const result = await store.listQuotaSummaries();
|
|
1129
|
-
if (json) writeJson(streams.stdout, result);
|
|
1130
|
-
else streams.stdout.write(`${describeQuotaAccounts(result.accounts, result.warnings)}\n`);
|
|
1131
|
-
return 0;
|
|
1132
|
-
}
|
|
1133
1137
|
if ("refresh" === quotaCommand) {
|
|
1134
1138
|
const targetName = parsed.positionals[1];
|
|
1135
1139
|
const result = await store.refreshAllQuotas(targetName);
|
|
1136
|
-
if (json) writeJson(streams.stdout, result);
|
|
1140
|
+
if (json) writeJson(streams.stdout, toCliQuotaRefreshResult(result));
|
|
1137
1141
|
else streams.stdout.write(`${describeQuotaRefresh(result)}\n`);
|
|
1138
1142
|
return 0 === result.failures.length ? 0 : 1;
|
|
1139
1143
|
}
|
|
1140
|
-
throw new Error("Usage: codexm quota
|
|
1144
|
+
throw new Error("Usage: codexm quota refresh [name] [--json]");
|
|
1141
1145
|
}
|
|
1142
1146
|
case "switch":
|
|
1143
1147
|
{
|
|
@@ -1148,7 +1152,8 @@ Account names must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.
|
|
|
1148
1152
|
try {
|
|
1149
1153
|
await store.refreshQuotaForAccount(result.account.name);
|
|
1150
1154
|
const quotaList = await store.listQuotaSummaries();
|
|
1151
|
-
|
|
1155
|
+
const matched = quotaList.accounts.find((account)=>account.name === result.account.name) ?? null;
|
|
1156
|
+
quota = matched ? toCliQuotaSummary(matched) : null;
|
|
1152
1157
|
} catch (error) {
|
|
1153
1158
|
result.warnings.push(error.message);
|
|
1154
1159
|
}
|
package/dist/main.cjs
CHANGED
|
@@ -439,6 +439,7 @@ const DIRECTORY_MODE = 448;
|
|
|
439
439
|
const FILE_MODE = 384;
|
|
440
440
|
const SCHEMA_VERSION = 1;
|
|
441
441
|
const ACCOUNT_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
442
|
+
const QUOTA_REFRESH_CONCURRENCY = 3;
|
|
442
443
|
function defaultPaths(homeDir = (0, external_node_os_namespaceObject.homedir)()) {
|
|
443
444
|
const codexDir = (0, external_node_path_namespaceObject.join)(homeDir, ".codex");
|
|
444
445
|
const codexTeamDir = (0, external_node_path_namespaceObject.join)(homeDir, ".codex-team");
|
|
@@ -789,17 +790,36 @@ class AccountStore {
|
|
|
789
790
|
const { accounts } = await this.listAccounts();
|
|
790
791
|
const targets = targetName ? accounts.filter((account)=>account.name === targetName) : accounts;
|
|
791
792
|
if (targetName && 0 === targets.length) throw new Error(`Account "${targetName}" does not exist.`);
|
|
793
|
+
const results = new Array(targets.length);
|
|
794
|
+
let nextIndex = 0;
|
|
795
|
+
const workerCount = Math.min(QUOTA_REFRESH_CONCURRENCY, targets.length);
|
|
796
|
+
await Promise.all(Array.from({
|
|
797
|
+
length: workerCount
|
|
798
|
+
}, async ()=>{
|
|
799
|
+
while(true){
|
|
800
|
+
const index = nextIndex;
|
|
801
|
+
nextIndex += 1;
|
|
802
|
+
if (index >= targets.length) return;
|
|
803
|
+
const account = targets[index];
|
|
804
|
+
try {
|
|
805
|
+
const refreshed = await this.refreshQuotaForAccount(account.name);
|
|
806
|
+
results[index] = {
|
|
807
|
+
success: await this.quotaSummaryForAccount(refreshed.account)
|
|
808
|
+
};
|
|
809
|
+
} catch (error) {
|
|
810
|
+
results[index] = {
|
|
811
|
+
failure: {
|
|
812
|
+
name: account.name,
|
|
813
|
+
error: error.message
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}));
|
|
792
819
|
const successes = [];
|
|
793
820
|
const failures = [];
|
|
794
|
-
for (const
|
|
795
|
-
|
|
796
|
-
successes.push(await this.quotaSummaryForAccount(refreshed.account));
|
|
797
|
-
} catch (error) {
|
|
798
|
-
failures.push({
|
|
799
|
-
name: account.name,
|
|
800
|
-
error: error.message
|
|
801
|
-
});
|
|
802
|
-
}
|
|
821
|
+
for (const result of results)if (result) if ("success" in result) successes.push(result.success);
|
|
822
|
+
else failures.push(result.failure);
|
|
803
823
|
return {
|
|
804
824
|
successes,
|
|
805
825
|
failures
|
|
@@ -915,11 +935,10 @@ function printHelp(stream) {
|
|
|
915
935
|
|
|
916
936
|
Usage:
|
|
917
937
|
codexm current [--json]
|
|
918
|
-
codexm list [--json]
|
|
938
|
+
codexm list [name] [--json]
|
|
919
939
|
codexm save <name> [--force] [--json]
|
|
920
940
|
codexm update [--json]
|
|
921
941
|
codexm quota refresh [name] [--json]
|
|
922
|
-
codexm quota list [--json]
|
|
923
942
|
codexm switch <name> [--json]
|
|
924
943
|
codexm remove <name> [--yes] [--json]
|
|
925
944
|
codexm rename <old> <new> [--json]
|
|
@@ -941,47 +960,6 @@ function describeCurrentStatus(status) {
|
|
|
941
960
|
for (const warning of status.warnings)lines.push(`Warning: ${warning}`);
|
|
942
961
|
return lines.join("\n");
|
|
943
962
|
}
|
|
944
|
-
function describeAccounts(accounts, warnings) {
|
|
945
|
-
if (0 === accounts.length) return 0 === warnings.length ? "No saved accounts." : warnings.map((warning)=>`Warning: ${warning}`).join("\n");
|
|
946
|
-
const table = formatTable(accounts.map((account)=>({
|
|
947
|
-
name: account.name,
|
|
948
|
-
account_id: maskAccountId(account.account_id),
|
|
949
|
-
auth_mode: account.auth_mode,
|
|
950
|
-
saved: account.created_at,
|
|
951
|
-
switched: account.last_switched_at ?? "-",
|
|
952
|
-
flags: account.duplicateAccountId ? "duplicate-account-id" : "-"
|
|
953
|
-
})), [
|
|
954
|
-
{
|
|
955
|
-
key: "name",
|
|
956
|
-
label: "NAME"
|
|
957
|
-
},
|
|
958
|
-
{
|
|
959
|
-
key: "account_id",
|
|
960
|
-
label: "ACCOUNT ID"
|
|
961
|
-
},
|
|
962
|
-
{
|
|
963
|
-
key: "auth_mode",
|
|
964
|
-
label: "AUTH MODE"
|
|
965
|
-
},
|
|
966
|
-
{
|
|
967
|
-
key: "saved",
|
|
968
|
-
label: "SAVED AT"
|
|
969
|
-
},
|
|
970
|
-
{
|
|
971
|
-
key: "switched",
|
|
972
|
-
label: "LAST SWITCHED"
|
|
973
|
-
},
|
|
974
|
-
{
|
|
975
|
-
key: "flags",
|
|
976
|
-
label: "FLAGS"
|
|
977
|
-
}
|
|
978
|
-
]);
|
|
979
|
-
const lines = [
|
|
980
|
-
table
|
|
981
|
-
];
|
|
982
|
-
for (const warning of warnings)lines.push(`Warning: ${warning}`);
|
|
983
|
-
return lines.join("\n");
|
|
984
|
-
}
|
|
985
963
|
function describeDoctor(report) {
|
|
986
964
|
const lines = [
|
|
987
965
|
report.healthy ? "Doctor checks passed." : "Doctor checks found issues.",
|
|
@@ -1000,17 +978,43 @@ function formatResetAt(window) {
|
|
|
1000
978
|
if (!window?.reset_at) return "-";
|
|
1001
979
|
return external_dayjs_default().utc(window.reset_at).tz(external_dayjs_default().tz.guess()).format("MM-DD HH:mm");
|
|
1002
980
|
}
|
|
981
|
+
function computeAvailability(account) {
|
|
982
|
+
if ("ok" !== account.status) return null;
|
|
983
|
+
const usedPercents = [
|
|
984
|
+
account.five_hour?.used_percent,
|
|
985
|
+
account.one_week?.used_percent
|
|
986
|
+
].filter((value)=>"number" == typeof value);
|
|
987
|
+
if (0 === usedPercents.length) return null;
|
|
988
|
+
if (usedPercents.some((value)=>value >= 100)) return "unavailable";
|
|
989
|
+
if (usedPercents.some((value)=>100 - value < 10)) return "almost unavailable";
|
|
990
|
+
return "available";
|
|
991
|
+
}
|
|
992
|
+
function toCliQuotaSummary(account) {
|
|
993
|
+
const { status, ...rest } = account;
|
|
994
|
+
return {
|
|
995
|
+
...rest,
|
|
996
|
+
available: computeAvailability(account),
|
|
997
|
+
refresh_status: status
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
function toCliQuotaRefreshResult(result) {
|
|
1001
|
+
return {
|
|
1002
|
+
successes: result.successes.map(toCliQuotaSummary),
|
|
1003
|
+
failures: result.failures
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1003
1006
|
function describeQuotaAccounts(accounts, warnings) {
|
|
1004
1007
|
if (0 === accounts.length) return 0 === warnings.length ? "No saved accounts." : warnings.map((warning)=>`Warning: ${warning}`).join("\n");
|
|
1005
1008
|
const table = formatTable(accounts.map((account)=>({
|
|
1006
1009
|
name: account.name,
|
|
1007
1010
|
account_id: maskAccountId(account.account_id),
|
|
1008
1011
|
plan_type: account.plan_type ?? "-",
|
|
1012
|
+
available: computeAvailability(account) ?? "-",
|
|
1009
1013
|
five_hour: formatUsagePercent(account.five_hour),
|
|
1010
1014
|
five_hour_reset: formatResetAt(account.five_hour),
|
|
1011
1015
|
one_week: formatUsagePercent(account.one_week),
|
|
1012
1016
|
one_week_reset: formatResetAt(account.one_week),
|
|
1013
|
-
|
|
1017
|
+
refresh_status: account.status
|
|
1014
1018
|
})), [
|
|
1015
1019
|
{
|
|
1016
1020
|
key: "name",
|
|
@@ -1024,6 +1028,10 @@ function describeQuotaAccounts(accounts, warnings) {
|
|
|
1024
1028
|
key: "plan_type",
|
|
1025
1029
|
label: "PLAN TYPE"
|
|
1026
1030
|
},
|
|
1031
|
+
{
|
|
1032
|
+
key: "available",
|
|
1033
|
+
label: "AVAILABLE"
|
|
1034
|
+
},
|
|
1027
1035
|
{
|
|
1028
1036
|
key: "five_hour",
|
|
1029
1037
|
label: "5H USED"
|
|
@@ -1041,8 +1049,8 @@ function describeQuotaAccounts(accounts, warnings) {
|
|
|
1041
1049
|
label: "1W RESET AT"
|
|
1042
1050
|
},
|
|
1043
1051
|
{
|
|
1044
|
-
key: "
|
|
1045
|
-
label: "STATUS"
|
|
1052
|
+
key: "refresh_status",
|
|
1053
|
+
label: "REFRESH STATUS"
|
|
1046
1054
|
}
|
|
1047
1055
|
]);
|
|
1048
1056
|
const lines = [
|
|
@@ -1098,10 +1106,11 @@ async function runCli(argv, options = {}) {
|
|
|
1098
1106
|
}
|
|
1099
1107
|
case "list":
|
|
1100
1108
|
{
|
|
1101
|
-
const
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1109
|
+
const targetName = parsed.positionals[0];
|
|
1110
|
+
const result = await store.refreshAllQuotas(targetName);
|
|
1111
|
+
if (json) writeJson(streams.stdout, toCliQuotaRefreshResult(result));
|
|
1112
|
+
else streams.stdout.write(`${describeQuotaRefresh(result)}\n`);
|
|
1113
|
+
return 0 === result.failures.length ? 0 : 1;
|
|
1105
1114
|
}
|
|
1106
1115
|
case "save":
|
|
1107
1116
|
{
|
|
@@ -1129,7 +1138,8 @@ async function runCli(argv, options = {}) {
|
|
|
1129
1138
|
try {
|
|
1130
1139
|
const quotaResult = await store.refreshQuotaForAccount(result.account.name);
|
|
1131
1140
|
const quotaList = await store.listQuotaSummaries();
|
|
1132
|
-
|
|
1141
|
+
const matched = quotaList.accounts.find((account)=>account.name === quotaResult.account.name) ?? null;
|
|
1142
|
+
quota = matched ? toCliQuotaSummary(matched) : null;
|
|
1133
1143
|
} catch (error) {
|
|
1134
1144
|
warnings.push(error.message);
|
|
1135
1145
|
}
|
|
@@ -1154,20 +1164,14 @@ async function runCli(argv, options = {}) {
|
|
|
1154
1164
|
case "quota":
|
|
1155
1165
|
{
|
|
1156
1166
|
const quotaCommand = parsed.positionals[0];
|
|
1157
|
-
if ("list" === quotaCommand) {
|
|
1158
|
-
const result = await store.listQuotaSummaries();
|
|
1159
|
-
if (json) writeJson(streams.stdout, result);
|
|
1160
|
-
else streams.stdout.write(`${describeQuotaAccounts(result.accounts, result.warnings)}\n`);
|
|
1161
|
-
return 0;
|
|
1162
|
-
}
|
|
1163
1167
|
if ("refresh" === quotaCommand) {
|
|
1164
1168
|
const targetName = parsed.positionals[1];
|
|
1165
1169
|
const result = await store.refreshAllQuotas(targetName);
|
|
1166
|
-
if (json) writeJson(streams.stdout, result);
|
|
1170
|
+
if (json) writeJson(streams.stdout, toCliQuotaRefreshResult(result));
|
|
1167
1171
|
else streams.stdout.write(`${describeQuotaRefresh(result)}\n`);
|
|
1168
1172
|
return 0 === result.failures.length ? 0 : 1;
|
|
1169
1173
|
}
|
|
1170
|
-
throw new Error("Usage: codexm quota
|
|
1174
|
+
throw new Error("Usage: codexm quota refresh [name] [--json]");
|
|
1171
1175
|
}
|
|
1172
1176
|
case "switch":
|
|
1173
1177
|
{
|
|
@@ -1178,7 +1182,8 @@ async function runCli(argv, options = {}) {
|
|
|
1178
1182
|
try {
|
|
1179
1183
|
await store.refreshQuotaForAccount(result.account.name);
|
|
1180
1184
|
const quotaList = await store.listQuotaSummaries();
|
|
1181
|
-
|
|
1185
|
+
const matched = quotaList.accounts.find((account)=>account.name === result.account.name) ?? null;
|
|
1186
|
+
quota = matched ? toCliQuotaSummary(matched) : null;
|
|
1182
1187
|
} catch (error) {
|
|
1183
1188
|
result.warnings.push(error.message);
|
|
1184
1189
|
}
|
package/dist/main.js
CHANGED
|
@@ -399,6 +399,7 @@ const DIRECTORY_MODE = 448;
|
|
|
399
399
|
const FILE_MODE = 384;
|
|
400
400
|
const SCHEMA_VERSION = 1;
|
|
401
401
|
const ACCOUNT_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
402
|
+
const QUOTA_REFRESH_CONCURRENCY = 3;
|
|
402
403
|
function defaultPaths(homeDir = homedir()) {
|
|
403
404
|
const codexDir = join(homeDir, ".codex");
|
|
404
405
|
const codexTeamDir = join(homeDir, ".codex-team");
|
|
@@ -749,17 +750,36 @@ class AccountStore {
|
|
|
749
750
|
const { accounts } = await this.listAccounts();
|
|
750
751
|
const targets = targetName ? accounts.filter((account)=>account.name === targetName) : accounts;
|
|
751
752
|
if (targetName && 0 === targets.length) throw new Error(`Account "${targetName}" does not exist.`);
|
|
753
|
+
const results = new Array(targets.length);
|
|
754
|
+
let nextIndex = 0;
|
|
755
|
+
const workerCount = Math.min(QUOTA_REFRESH_CONCURRENCY, targets.length);
|
|
756
|
+
await Promise.all(Array.from({
|
|
757
|
+
length: workerCount
|
|
758
|
+
}, async ()=>{
|
|
759
|
+
while(true){
|
|
760
|
+
const index = nextIndex;
|
|
761
|
+
nextIndex += 1;
|
|
762
|
+
if (index >= targets.length) return;
|
|
763
|
+
const account = targets[index];
|
|
764
|
+
try {
|
|
765
|
+
const refreshed = await this.refreshQuotaForAccount(account.name);
|
|
766
|
+
results[index] = {
|
|
767
|
+
success: await this.quotaSummaryForAccount(refreshed.account)
|
|
768
|
+
};
|
|
769
|
+
} catch (error) {
|
|
770
|
+
results[index] = {
|
|
771
|
+
failure: {
|
|
772
|
+
name: account.name,
|
|
773
|
+
error: error.message
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}));
|
|
752
779
|
const successes = [];
|
|
753
780
|
const failures = [];
|
|
754
|
-
for (const
|
|
755
|
-
|
|
756
|
-
successes.push(await this.quotaSummaryForAccount(refreshed.account));
|
|
757
|
-
} catch (error) {
|
|
758
|
-
failures.push({
|
|
759
|
-
name: account.name,
|
|
760
|
-
error: error.message
|
|
761
|
-
});
|
|
762
|
-
}
|
|
781
|
+
for (const result of results)if (result) if ("success" in result) successes.push(result.success);
|
|
782
|
+
else failures.push(result.failure);
|
|
763
783
|
return {
|
|
764
784
|
successes,
|
|
765
785
|
failures
|
|
@@ -875,11 +895,10 @@ function printHelp(stream) {
|
|
|
875
895
|
|
|
876
896
|
Usage:
|
|
877
897
|
codexm current [--json]
|
|
878
|
-
codexm list [--json]
|
|
898
|
+
codexm list [name] [--json]
|
|
879
899
|
codexm save <name> [--force] [--json]
|
|
880
900
|
codexm update [--json]
|
|
881
901
|
codexm quota refresh [name] [--json]
|
|
882
|
-
codexm quota list [--json]
|
|
883
902
|
codexm switch <name> [--json]
|
|
884
903
|
codexm remove <name> [--yes] [--json]
|
|
885
904
|
codexm rename <old> <new> [--json]
|
|
@@ -901,47 +920,6 @@ function describeCurrentStatus(status) {
|
|
|
901
920
|
for (const warning of status.warnings)lines.push(`Warning: ${warning}`);
|
|
902
921
|
return lines.join("\n");
|
|
903
922
|
}
|
|
904
|
-
function describeAccounts(accounts, warnings) {
|
|
905
|
-
if (0 === accounts.length) return 0 === warnings.length ? "No saved accounts." : warnings.map((warning)=>`Warning: ${warning}`).join("\n");
|
|
906
|
-
const table = formatTable(accounts.map((account)=>({
|
|
907
|
-
name: account.name,
|
|
908
|
-
account_id: maskAccountId(account.account_id),
|
|
909
|
-
auth_mode: account.auth_mode,
|
|
910
|
-
saved: account.created_at,
|
|
911
|
-
switched: account.last_switched_at ?? "-",
|
|
912
|
-
flags: account.duplicateAccountId ? "duplicate-account-id" : "-"
|
|
913
|
-
})), [
|
|
914
|
-
{
|
|
915
|
-
key: "name",
|
|
916
|
-
label: "NAME"
|
|
917
|
-
},
|
|
918
|
-
{
|
|
919
|
-
key: "account_id",
|
|
920
|
-
label: "ACCOUNT ID"
|
|
921
|
-
},
|
|
922
|
-
{
|
|
923
|
-
key: "auth_mode",
|
|
924
|
-
label: "AUTH MODE"
|
|
925
|
-
},
|
|
926
|
-
{
|
|
927
|
-
key: "saved",
|
|
928
|
-
label: "SAVED AT"
|
|
929
|
-
},
|
|
930
|
-
{
|
|
931
|
-
key: "switched",
|
|
932
|
-
label: "LAST SWITCHED"
|
|
933
|
-
},
|
|
934
|
-
{
|
|
935
|
-
key: "flags",
|
|
936
|
-
label: "FLAGS"
|
|
937
|
-
}
|
|
938
|
-
]);
|
|
939
|
-
const lines = [
|
|
940
|
-
table
|
|
941
|
-
];
|
|
942
|
-
for (const warning of warnings)lines.push(`Warning: ${warning}`);
|
|
943
|
-
return lines.join("\n");
|
|
944
|
-
}
|
|
945
923
|
function describeDoctor(report) {
|
|
946
924
|
const lines = [
|
|
947
925
|
report.healthy ? "Doctor checks passed." : "Doctor checks found issues.",
|
|
@@ -960,17 +938,43 @@ function formatResetAt(window) {
|
|
|
960
938
|
if (!window?.reset_at) return "-";
|
|
961
939
|
return dayjs.utc(window.reset_at).tz(dayjs.tz.guess()).format("MM-DD HH:mm");
|
|
962
940
|
}
|
|
941
|
+
function computeAvailability(account) {
|
|
942
|
+
if ("ok" !== account.status) return null;
|
|
943
|
+
const usedPercents = [
|
|
944
|
+
account.five_hour?.used_percent,
|
|
945
|
+
account.one_week?.used_percent
|
|
946
|
+
].filter((value)=>"number" == typeof value);
|
|
947
|
+
if (0 === usedPercents.length) return null;
|
|
948
|
+
if (usedPercents.some((value)=>value >= 100)) return "unavailable";
|
|
949
|
+
if (usedPercents.some((value)=>100 - value < 10)) return "almost unavailable";
|
|
950
|
+
return "available";
|
|
951
|
+
}
|
|
952
|
+
function toCliQuotaSummary(account) {
|
|
953
|
+
const { status, ...rest } = account;
|
|
954
|
+
return {
|
|
955
|
+
...rest,
|
|
956
|
+
available: computeAvailability(account),
|
|
957
|
+
refresh_status: status
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
function toCliQuotaRefreshResult(result) {
|
|
961
|
+
return {
|
|
962
|
+
successes: result.successes.map(toCliQuotaSummary),
|
|
963
|
+
failures: result.failures
|
|
964
|
+
};
|
|
965
|
+
}
|
|
963
966
|
function describeQuotaAccounts(accounts, warnings) {
|
|
964
967
|
if (0 === accounts.length) return 0 === warnings.length ? "No saved accounts." : warnings.map((warning)=>`Warning: ${warning}`).join("\n");
|
|
965
968
|
const table = formatTable(accounts.map((account)=>({
|
|
966
969
|
name: account.name,
|
|
967
970
|
account_id: maskAccountId(account.account_id),
|
|
968
971
|
plan_type: account.plan_type ?? "-",
|
|
972
|
+
available: computeAvailability(account) ?? "-",
|
|
969
973
|
five_hour: formatUsagePercent(account.five_hour),
|
|
970
974
|
five_hour_reset: formatResetAt(account.five_hour),
|
|
971
975
|
one_week: formatUsagePercent(account.one_week),
|
|
972
976
|
one_week_reset: formatResetAt(account.one_week),
|
|
973
|
-
|
|
977
|
+
refresh_status: account.status
|
|
974
978
|
})), [
|
|
975
979
|
{
|
|
976
980
|
key: "name",
|
|
@@ -984,6 +988,10 @@ function describeQuotaAccounts(accounts, warnings) {
|
|
|
984
988
|
key: "plan_type",
|
|
985
989
|
label: "PLAN TYPE"
|
|
986
990
|
},
|
|
991
|
+
{
|
|
992
|
+
key: "available",
|
|
993
|
+
label: "AVAILABLE"
|
|
994
|
+
},
|
|
987
995
|
{
|
|
988
996
|
key: "five_hour",
|
|
989
997
|
label: "5H USED"
|
|
@@ -1001,8 +1009,8 @@ function describeQuotaAccounts(accounts, warnings) {
|
|
|
1001
1009
|
label: "1W RESET AT"
|
|
1002
1010
|
},
|
|
1003
1011
|
{
|
|
1004
|
-
key: "
|
|
1005
|
-
label: "STATUS"
|
|
1012
|
+
key: "refresh_status",
|
|
1013
|
+
label: "REFRESH STATUS"
|
|
1006
1014
|
}
|
|
1007
1015
|
]);
|
|
1008
1016
|
const lines = [
|
|
@@ -1058,10 +1066,11 @@ async function runCli(argv, options = {}) {
|
|
|
1058
1066
|
}
|
|
1059
1067
|
case "list":
|
|
1060
1068
|
{
|
|
1061
|
-
const
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1069
|
+
const targetName = parsed.positionals[0];
|
|
1070
|
+
const result = await store.refreshAllQuotas(targetName);
|
|
1071
|
+
if (json) writeJson(streams.stdout, toCliQuotaRefreshResult(result));
|
|
1072
|
+
else streams.stdout.write(`${describeQuotaRefresh(result)}\n`);
|
|
1073
|
+
return 0 === result.failures.length ? 0 : 1;
|
|
1065
1074
|
}
|
|
1066
1075
|
case "save":
|
|
1067
1076
|
{
|
|
@@ -1089,7 +1098,8 @@ async function runCli(argv, options = {}) {
|
|
|
1089
1098
|
try {
|
|
1090
1099
|
const quotaResult = await store.refreshQuotaForAccount(result.account.name);
|
|
1091
1100
|
const quotaList = await store.listQuotaSummaries();
|
|
1092
|
-
|
|
1101
|
+
const matched = quotaList.accounts.find((account)=>account.name === quotaResult.account.name) ?? null;
|
|
1102
|
+
quota = matched ? toCliQuotaSummary(matched) : null;
|
|
1093
1103
|
} catch (error) {
|
|
1094
1104
|
warnings.push(error.message);
|
|
1095
1105
|
}
|
|
@@ -1114,20 +1124,14 @@ async function runCli(argv, options = {}) {
|
|
|
1114
1124
|
case "quota":
|
|
1115
1125
|
{
|
|
1116
1126
|
const quotaCommand = parsed.positionals[0];
|
|
1117
|
-
if ("list" === quotaCommand) {
|
|
1118
|
-
const result = await store.listQuotaSummaries();
|
|
1119
|
-
if (json) writeJson(streams.stdout, result);
|
|
1120
|
-
else streams.stdout.write(`${describeQuotaAccounts(result.accounts, result.warnings)}\n`);
|
|
1121
|
-
return 0;
|
|
1122
|
-
}
|
|
1123
1127
|
if ("refresh" === quotaCommand) {
|
|
1124
1128
|
const targetName = parsed.positionals[1];
|
|
1125
1129
|
const result = await store.refreshAllQuotas(targetName);
|
|
1126
|
-
if (json) writeJson(streams.stdout, result);
|
|
1130
|
+
if (json) writeJson(streams.stdout, toCliQuotaRefreshResult(result));
|
|
1127
1131
|
else streams.stdout.write(`${describeQuotaRefresh(result)}\n`);
|
|
1128
1132
|
return 0 === result.failures.length ? 0 : 1;
|
|
1129
1133
|
}
|
|
1130
|
-
throw new Error("Usage: codexm quota
|
|
1134
|
+
throw new Error("Usage: codexm quota refresh [name] [--json]");
|
|
1131
1135
|
}
|
|
1132
1136
|
case "switch":
|
|
1133
1137
|
{
|
|
@@ -1138,7 +1142,8 @@ async function runCli(argv, options = {}) {
|
|
|
1138
1142
|
try {
|
|
1139
1143
|
await store.refreshQuotaForAccount(result.account.name);
|
|
1140
1144
|
const quotaList = await store.listQuotaSummaries();
|
|
1141
|
-
|
|
1145
|
+
const matched = quotaList.accounts.find((account)=>account.name === result.account.name) ?? null;
|
|
1146
|
+
quota = matched ? toCliQuotaSummary(matched) : null;
|
|
1142
1147
|
} catch (error) {
|
|
1143
1148
|
result.warnings.push(error.message);
|
|
1144
1149
|
}
|