codex-team 0.0.7 → 0.0.9
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 +3 -3
- package/dist/cli.cjs +113 -57
- package/dist/main.cjs +113 -57
- package/dist/main.js +113 -57
- package/package.json +1 -1
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.
|
|
46
|
+
rE: "0.0.9"
|
|
47
47
|
};
|
|
48
48
|
const external_node_crypto_namespaceObject = require("node:crypto");
|
|
49
49
|
const promises_namespaceObject = require("node:fs/promises");
|
|
@@ -78,10 +78,44 @@ function isSupportedChatGPTAuthMode(authMode) {
|
|
|
78
78
|
const normalized = normalizeAuthMode(authMode);
|
|
79
79
|
return "chatgpt" === normalized || "chatgpt_auth_tokens" === normalized;
|
|
80
80
|
}
|
|
81
|
+
function extractAuthClaim(payload) {
|
|
82
|
+
const value = payload["https://api.openai.com/auth"];
|
|
83
|
+
return isRecord(value) ? value : void 0;
|
|
84
|
+
}
|
|
85
|
+
function extractStringClaim(payload, key) {
|
|
86
|
+
const value = payload[key];
|
|
87
|
+
return "string" == typeof value && "" !== value.trim() ? value : void 0;
|
|
88
|
+
}
|
|
89
|
+
function extractSnapshotJwtPayloads(snapshot) {
|
|
90
|
+
const tokens = snapshot.tokens ?? {};
|
|
91
|
+
const payloads = [];
|
|
92
|
+
for (const tokenName of [
|
|
93
|
+
"id_token",
|
|
94
|
+
"access_token"
|
|
95
|
+
]){
|
|
96
|
+
const token = tokens[tokenName];
|
|
97
|
+
if ("string" == typeof token && "" !== token.trim()) try {
|
|
98
|
+
payloads.push(decodeJwtPayload(token));
|
|
99
|
+
} catch {}
|
|
100
|
+
}
|
|
101
|
+
return payloads;
|
|
102
|
+
}
|
|
103
|
+
function getSnapshotUserId(snapshot) {
|
|
104
|
+
for (const payload of extractSnapshotJwtPayloads(snapshot)){
|
|
105
|
+
const authClaim = extractAuthClaim(payload);
|
|
106
|
+
const chatGPTUserId = authClaim?.chatgpt_user_id;
|
|
107
|
+
if ("string" == typeof chatGPTUserId && "" !== chatGPTUserId.trim()) return chatGPTUserId;
|
|
108
|
+
const userId = extractStringClaim(payload, "user_id");
|
|
109
|
+
if (userId) return userId;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
81
112
|
function fingerprintApiKey(apiKey) {
|
|
82
113
|
return (0, external_node_crypto_namespaceObject.createHash)("sha256").update(apiKey).digest("hex").slice(0, 16);
|
|
83
114
|
}
|
|
84
|
-
function
|
|
115
|
+
function composeIdentity(accountId, userId) {
|
|
116
|
+
return "string" == typeof userId && "" !== userId.trim() ? `${accountId}:${userId}` : accountId;
|
|
117
|
+
}
|
|
118
|
+
function getSnapshotAccountId(snapshot) {
|
|
85
119
|
if (isApiKeyAuthMode(snapshot.auth_mode)) {
|
|
86
120
|
const apiKey = snapshot.OPENAI_API_KEY;
|
|
87
121
|
if ("string" != typeof apiKey || "" === apiKey.trim()) throw new Error('Field "OPENAI_API_KEY" must be a non-empty string for apikey auth.');
|
|
@@ -91,6 +125,12 @@ function getSnapshotIdentity(snapshot) {
|
|
|
91
125
|
if ("string" != typeof accountId || "" === accountId.trim()) throw new Error('Field "tokens.account_id" must be a non-empty string.');
|
|
92
126
|
return accountId;
|
|
93
127
|
}
|
|
128
|
+
function getSnapshotIdentity(snapshot) {
|
|
129
|
+
return composeIdentity(getSnapshotAccountId(snapshot), isSupportedChatGPTAuthMode(snapshot.auth_mode) ? getSnapshotUserId(snapshot) : void 0);
|
|
130
|
+
}
|
|
131
|
+
function getMetaIdentity(meta) {
|
|
132
|
+
return composeIdentity(meta.account_id, meta.user_id);
|
|
133
|
+
}
|
|
94
134
|
function defaultQuotaSnapshot() {
|
|
95
135
|
return {
|
|
96
136
|
status: "stale"
|
|
@@ -168,7 +208,8 @@ function createSnapshotMeta(name, snapshot, now, existingCreatedAt) {
|
|
|
168
208
|
return {
|
|
169
209
|
name,
|
|
170
210
|
auth_mode: snapshot.auth_mode,
|
|
171
|
-
account_id:
|
|
211
|
+
account_id: getSnapshotAccountId(snapshot),
|
|
212
|
+
user_id: isSupportedChatGPTAuthMode(snapshot.auth_mode) ? getSnapshotUserId(snapshot) : void 0,
|
|
172
213
|
created_at: existingCreatedAt ?? timestamp,
|
|
173
214
|
updated_at: timestamp,
|
|
174
215
|
last_switched_at: null,
|
|
@@ -189,6 +230,7 @@ function parseSnapshotMeta(raw) {
|
|
|
189
230
|
name: asNonEmptyString(parsed.name, "name"),
|
|
190
231
|
auth_mode: asNonEmptyString(parsed.auth_mode, "auth_mode"),
|
|
191
232
|
account_id: asNonEmptyString(parsed.account_id, "account_id"),
|
|
233
|
+
user_id: asOptionalString(parsed.user_id, "user_id"),
|
|
192
234
|
created_at: asNonEmptyString(parsed.created_at, "created_at"),
|
|
193
235
|
updated_at: asNonEmptyString(parsed.updated_at, "updated_at"),
|
|
194
236
|
last_switched_at: lastSwitchedAt,
|
|
@@ -217,11 +259,11 @@ const USER_AGENT = "codexm/0.1";
|
|
|
217
259
|
function quota_client_isRecord(value) {
|
|
218
260
|
return "object" == typeof value && null !== value && !Array.isArray(value);
|
|
219
261
|
}
|
|
220
|
-
function
|
|
262
|
+
function quota_client_extractAuthClaim(payload) {
|
|
221
263
|
const value = payload["https://api.openai.com/auth"];
|
|
222
264
|
return quota_client_isRecord(value) ? value : void 0;
|
|
223
265
|
}
|
|
224
|
-
function
|
|
266
|
+
function quota_client_extractStringClaim(payload, key) {
|
|
225
267
|
const value = payload[key];
|
|
226
268
|
return "string" == typeof value && "" !== value.trim() ? value : void 0;
|
|
227
269
|
}
|
|
@@ -234,7 +276,7 @@ function parsePlanType(snapshot) {
|
|
|
234
276
|
const token = tokens[tokenName];
|
|
235
277
|
if ("string" == typeof token && "" !== token.trim()) try {
|
|
236
278
|
const payload = decodeJwtPayload(token);
|
|
237
|
-
const authClaim =
|
|
279
|
+
const authClaim = quota_client_extractAuthClaim(payload);
|
|
238
280
|
const planType = authClaim?.chatgpt_plan_type;
|
|
239
281
|
if ("string" == typeof planType && "" !== planType.trim()) return planType;
|
|
240
282
|
} catch {}
|
|
@@ -258,7 +300,7 @@ function extractChatGPTAuth(snapshot) {
|
|
|
258
300
|
const token = tokens[tokenName];
|
|
259
301
|
if ("string" == typeof token && "" !== token.trim()) try {
|
|
260
302
|
const payload = decodeJwtPayload(token);
|
|
261
|
-
const authClaim =
|
|
303
|
+
const authClaim = quota_client_extractAuthClaim(payload);
|
|
262
304
|
if (!accountId) {
|
|
263
305
|
const maybeAccountId = authClaim?.chatgpt_account_id;
|
|
264
306
|
if ("string" == typeof maybeAccountId && "" !== maybeAccountId.trim()) accountId = maybeAccountId;
|
|
@@ -267,8 +309,8 @@ function extractChatGPTAuth(snapshot) {
|
|
|
267
309
|
const maybePlanType = authClaim?.chatgpt_plan_type;
|
|
268
310
|
if ("string" == typeof maybePlanType && "" !== maybePlanType.trim()) planType = maybePlanType;
|
|
269
311
|
}
|
|
270
|
-
issuer ??=
|
|
271
|
-
clientId ??=
|
|
312
|
+
issuer ??= quota_client_extractStringClaim(payload, "iss");
|
|
313
|
+
clientId ??= quota_client_extractStringClaim(payload, "client_id") ?? quota_client_extractStringClaim(payload, "azp") ?? ("string" == typeof payload.aud ? payload.aud : void 0);
|
|
272
314
|
} catch {}
|
|
273
315
|
}
|
|
274
316
|
if (!supported) return {
|
|
@@ -538,6 +580,13 @@ async function pathExists(path) {
|
|
|
538
580
|
async function readJsonFile(path) {
|
|
539
581
|
return (0, promises_namespaceObject.readFile)(path, "utf8");
|
|
540
582
|
}
|
|
583
|
+
function canAutoMigrateLegacyChatGPTMeta(meta, snapshot) {
|
|
584
|
+
if (!isSupportedChatGPTAuthMode(meta.auth_mode) || !isSupportedChatGPTAuthMode(snapshot.auth_mode)) return false;
|
|
585
|
+
if ("string" == typeof meta.user_id && "" !== meta.user_id.trim()) return false;
|
|
586
|
+
const snapshotUserId = getSnapshotUserId(snapshot);
|
|
587
|
+
if (!snapshotUserId) return false;
|
|
588
|
+
return meta.account_id === getSnapshotAccountId(snapshot);
|
|
589
|
+
}
|
|
541
590
|
async function detectRunningCodexProcesses() {
|
|
542
591
|
try {
|
|
543
592
|
const { stdout } = await execFile("ps", [
|
|
@@ -635,6 +684,8 @@ class AccountStore {
|
|
|
635
684
|
return {
|
|
636
685
|
name: account.name,
|
|
637
686
|
account_id: account.account_id,
|
|
687
|
+
user_id: account.user_id ?? null,
|
|
688
|
+
identity: account.identity,
|
|
638
689
|
plan_type: planType,
|
|
639
690
|
credits_balance: account.quota.credits_balance ?? null,
|
|
640
691
|
status: account.quota.status,
|
|
@@ -675,11 +726,21 @@ class AccountStore {
|
|
|
675
726
|
readJsonFile(metaPath),
|
|
676
727
|
readAuthSnapshotFile(authPath)
|
|
677
728
|
]);
|
|
678
|
-
|
|
729
|
+
let meta = parseSnapshotMeta(rawMeta);
|
|
679
730
|
if (meta.name !== name) throw new Error(`Account metadata name mismatch for "${name}".`);
|
|
680
|
-
|
|
731
|
+
const snapshotIdentity = getSnapshotIdentity(snapshot);
|
|
732
|
+
if (getMetaIdentity(meta) !== snapshotIdentity) if (canAutoMigrateLegacyChatGPTMeta(meta, snapshot)) {
|
|
733
|
+
meta = {
|
|
734
|
+
...meta,
|
|
735
|
+
account_id: getSnapshotAccountId(snapshot),
|
|
736
|
+
user_id: getSnapshotUserId(snapshot)
|
|
737
|
+
};
|
|
738
|
+
await this.writeAccountMeta(name, meta);
|
|
739
|
+
} else throw new Error(`Account metadata account_id mismatch for "${name}".`);
|
|
740
|
+
if (getMetaIdentity(meta) !== snapshotIdentity) throw new Error(`Account metadata account_id mismatch for "${name}".`);
|
|
681
741
|
return {
|
|
682
742
|
...meta,
|
|
743
|
+
identity: getMetaIdentity(meta),
|
|
683
744
|
authPath,
|
|
684
745
|
metaPath,
|
|
685
746
|
configPath: await pathExists(this.accountConfigPath(name)) ? this.accountConfigPath(name) : null,
|
|
@@ -699,12 +760,12 @@ class AccountStore {
|
|
|
699
760
|
warnings.push(`Account "${entry.name}" is invalid: ${error.message}`);
|
|
700
761
|
}
|
|
701
762
|
const counts = new Map();
|
|
702
|
-
for (const account of accounts)counts.set(account.
|
|
763
|
+
for (const account of accounts)counts.set(account.identity, (counts.get(account.identity) ?? 0) + 1);
|
|
703
764
|
accounts.sort((left, right)=>left.name.localeCompare(right.name));
|
|
704
765
|
return {
|
|
705
766
|
accounts: accounts.map((account)=>({
|
|
706
767
|
...account,
|
|
707
|
-
duplicateAccountId: (counts.get(account.
|
|
768
|
+
duplicateAccountId: (counts.get(account.identity) ?? 0) > 1
|
|
708
769
|
})),
|
|
709
770
|
warnings
|
|
710
771
|
};
|
|
@@ -715,6 +776,8 @@ class AccountStore {
|
|
|
715
776
|
exists: false,
|
|
716
777
|
auth_mode: null,
|
|
717
778
|
account_id: null,
|
|
779
|
+
user_id: null,
|
|
780
|
+
identity: null,
|
|
718
781
|
matched_accounts: [],
|
|
719
782
|
managed: false,
|
|
720
783
|
duplicate_match: false,
|
|
@@ -722,11 +785,15 @@ class AccountStore {
|
|
|
722
785
|
};
|
|
723
786
|
const snapshot = await readAuthSnapshotFile(this.paths.currentAuthPath);
|
|
724
787
|
const currentIdentity = getSnapshotIdentity(snapshot);
|
|
725
|
-
const
|
|
788
|
+
const currentAccountId = getSnapshotAccountId(snapshot);
|
|
789
|
+
const currentUserId = getSnapshotUserId(snapshot) ?? null;
|
|
790
|
+
const matchedAccounts = accounts.filter((account)=>account.identity === currentIdentity).map((account)=>account.name);
|
|
726
791
|
return {
|
|
727
792
|
exists: true,
|
|
728
793
|
auth_mode: snapshot.auth_mode,
|
|
729
|
-
account_id:
|
|
794
|
+
account_id: currentAccountId,
|
|
795
|
+
user_id: currentUserId,
|
|
796
|
+
identity: currentIdentity,
|
|
730
797
|
matched_accounts: matchedAccounts,
|
|
731
798
|
managed: matchedAccounts.length > 0,
|
|
732
799
|
duplicate_match: matchedAccounts.length > 1,
|
|
@@ -744,9 +811,16 @@ class AccountStore {
|
|
|
744
811
|
const authPath = this.accountAuthPath(name);
|
|
745
812
|
const metaPath = this.accountMetaPath(name);
|
|
746
813
|
const configPath = this.accountConfigPath(name);
|
|
814
|
+
const identity = getSnapshotIdentity(snapshot);
|
|
747
815
|
const accountExists = await pathExists(accountDir);
|
|
748
816
|
const existingMeta = accountExists && await pathExists(metaPath) ? parseSnapshotMeta(await readJsonFile(metaPath)) : void 0;
|
|
749
817
|
if (accountExists && !force) throw new Error(`Account "${name}" already exists. Use --force to overwrite it.`);
|
|
818
|
+
const { accounts } = await this.listAccounts();
|
|
819
|
+
const duplicateIdentityAccounts = accounts.filter((account)=>account.name !== name && account.identity === identity);
|
|
820
|
+
if (duplicateIdentityAccounts.length > 0) {
|
|
821
|
+
const joinedNames = duplicateIdentityAccounts.map((account)=>`"${account.name}"`).join(", ");
|
|
822
|
+
throw new Error(`Identity ${identity} is already managed by ${joinedNames}.`);
|
|
823
|
+
}
|
|
750
824
|
this.validateConfigSnapshot(name, snapshot, rawConfig);
|
|
751
825
|
await ensureDirectory(accountDir, DIRECTORY_MODE);
|
|
752
826
|
await atomicWriteFile(authPath, `${rawSnapshot.trimEnd()}\n`);
|
|
@@ -817,7 +891,7 @@ class AccountStore {
|
|
|
817
891
|
await atomicWriteFile(this.paths.currentConfigPath, this.sanitizeConfigForAccountAuth(currentRawConfig));
|
|
818
892
|
}
|
|
819
893
|
const writtenSnapshot = await readAuthSnapshotFile(this.paths.currentAuthPath);
|
|
820
|
-
if (getSnapshotIdentity(writtenSnapshot) !== account.
|
|
894
|
+
if (getSnapshotIdentity(writtenSnapshot) !== account.identity) throw new Error(`Switch verification failed for account "${name}".`);
|
|
821
895
|
const meta = parseSnapshotMeta(await readJsonFile(account.metaPath));
|
|
822
896
|
meta.last_switched_at = new Date().toISOString();
|
|
823
897
|
meta.updated_at = meta.last_switched_at;
|
|
@@ -861,7 +935,8 @@ class AccountStore {
|
|
|
861
935
|
await this.syncCurrentAuthIfMatching(result.authSnapshot);
|
|
862
936
|
}
|
|
863
937
|
meta.auth_mode = result.authSnapshot.auth_mode;
|
|
864
|
-
meta.account_id =
|
|
938
|
+
meta.account_id = getSnapshotAccountId(result.authSnapshot);
|
|
939
|
+
meta.user_id = getSnapshotUserId(result.authSnapshot);
|
|
865
940
|
meta.updated_at = now.toISOString();
|
|
866
941
|
meta.quota = result.quota;
|
|
867
942
|
await this.writeAccountMeta(name, meta);
|
|
@@ -974,7 +1049,7 @@ class AccountStore {
|
|
|
974
1049
|
if ((511 & authStat.mode) !== FILE_MODE) issues.push(`Account "${account.name}" auth permissions must be 600.`);
|
|
975
1050
|
if ((511 & metaStat.mode) !== FILE_MODE) issues.push(`Account "${account.name}" metadata permissions must be 600.`);
|
|
976
1051
|
if ("apikey" === account.auth_mode && !account.configPath) issues.push(`Account "${account.name}" is missing config.toml snapshot required for apikey auth.`);
|
|
977
|
-
if (account.duplicateAccountId) warnings.push(`Account "${account.name}" shares identity ${account.
|
|
1052
|
+
if (account.duplicateAccountId) warnings.push(`Account "${account.name}" shares identity ${account.identity} with another saved account.`);
|
|
978
1053
|
}
|
|
979
1054
|
let currentAuthPresent = false;
|
|
980
1055
|
if (await pathExists(this.paths.currentAuthPath)) {
|
|
@@ -1042,12 +1117,10 @@ Usage:
|
|
|
1042
1117
|
codexm list [name] [--json]
|
|
1043
1118
|
codexm save <name> [--force] [--json]
|
|
1044
1119
|
codexm update [--json]
|
|
1045
|
-
codexm quota refresh [name] [--json]
|
|
1046
1120
|
codexm switch <name> [--json]
|
|
1047
1121
|
codexm switch --auto [--dry-run] [--json]
|
|
1048
1122
|
codexm remove <name> [--yes] [--json]
|
|
1049
1123
|
codexm rename <old> <new> [--json]
|
|
1050
|
-
codexm doctor [--json]
|
|
1051
1124
|
|
|
1052
1125
|
Account names must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.
|
|
1053
1126
|
`);
|
|
@@ -1057,7 +1130,7 @@ function describeCurrentStatus(status) {
|
|
|
1057
1130
|
if (status.exists) {
|
|
1058
1131
|
lines.push("Current auth: present");
|
|
1059
1132
|
lines.push(`Auth mode: ${status.auth_mode}`);
|
|
1060
|
-
lines.push(`Identity: ${maskAccountId(status.
|
|
1133
|
+
lines.push(`Identity: ${maskAccountId(status.identity ?? "")}`);
|
|
1061
1134
|
if (0 === status.matched_accounts.length) lines.push("Managed account: no (unmanaged)");
|
|
1062
1135
|
else if (1 === status.matched_accounts.length) lines.push(`Managed account: ${status.matched_accounts[0]}`);
|
|
1063
1136
|
else lines.push(`Managed account: multiple (${status.matched_accounts.join(", ")})`);
|
|
@@ -1065,16 +1138,6 @@ function describeCurrentStatus(status) {
|
|
|
1065
1138
|
for (const warning of status.warnings)lines.push(`Warning: ${warning}`);
|
|
1066
1139
|
return lines.join("\n");
|
|
1067
1140
|
}
|
|
1068
|
-
function describeDoctor(report) {
|
|
1069
|
-
const lines = [
|
|
1070
|
-
report.healthy ? "Doctor checks passed." : "Doctor checks found issues.",
|
|
1071
|
-
`Saved accounts: ${report.account_count}`,
|
|
1072
|
-
`Current auth present: ${report.current_auth_present ? "yes" : "no"}`
|
|
1073
|
-
];
|
|
1074
|
-
for (const issue of report.issues)lines.push(`Issue: ${issue}`);
|
|
1075
|
-
for (const warning of report.warnings)lines.push(`Warning: ${warning}`);
|
|
1076
|
-
return lines.join("\n");
|
|
1077
|
-
}
|
|
1078
1141
|
function formatUsagePercent(window) {
|
|
1079
1142
|
if (!window) return "-";
|
|
1080
1143
|
return `${window.used_percent}%`;
|
|
@@ -1120,6 +1183,7 @@ function toAutoSwitchCandidate(account) {
|
|
|
1120
1183
|
return {
|
|
1121
1184
|
name: account.name,
|
|
1122
1185
|
account_id: account.account_id,
|
|
1186
|
+
identity: account.identity,
|
|
1123
1187
|
plan_type: account.plan_type,
|
|
1124
1188
|
available: computeAvailability(account),
|
|
1125
1189
|
refresh_status: "ok",
|
|
@@ -1152,7 +1216,7 @@ function rankAutoSwitchCandidates(accounts) {
|
|
|
1152
1216
|
}
|
|
1153
1217
|
function describeAutoSwitchSelection(candidate, dryRun, backupPath, warnings) {
|
|
1154
1218
|
const lines = [
|
|
1155
|
-
dryRun ? `Best account: "${candidate.name}" (${maskAccountId(candidate.
|
|
1219
|
+
dryRun ? `Best account: "${candidate.name}" (${maskAccountId(candidate.identity)}).` : `Auto-switched to "${candidate.name}" (${maskAccountId(candidate.identity)}).`,
|
|
1156
1220
|
`Score: ${candidate.effective_score}`,
|
|
1157
1221
|
`5H remaining: ${candidate.remain_5h}%`,
|
|
1158
1222
|
`1W remaining (5H-equivalent): ${candidate.remain_1w_eq_5h}%`
|
|
@@ -1163,7 +1227,7 @@ function describeAutoSwitchSelection(candidate, dryRun, backupPath, warnings) {
|
|
|
1163
1227
|
}
|
|
1164
1228
|
function describeAutoSwitchNoop(candidate, warnings) {
|
|
1165
1229
|
const lines = [
|
|
1166
|
-
`Current account "${candidate.name}" (${maskAccountId(candidate.
|
|
1230
|
+
`Current account "${candidate.name}" (${maskAccountId(candidate.identity)}) is already the best available account.`,
|
|
1167
1231
|
`Score: ${candidate.effective_score}`,
|
|
1168
1232
|
`5H remaining: ${candidate.remain_5h}%`,
|
|
1169
1233
|
`1W remaining (5H-equivalent): ${candidate.remain_1w_eq_5h}%`
|
|
@@ -1175,7 +1239,7 @@ function describeQuotaAccounts(accounts, warnings) {
|
|
|
1175
1239
|
if (0 === accounts.length) return 0 === warnings.length ? "No saved accounts." : warnings.map((warning)=>`Warning: ${warning}`).join("\n");
|
|
1176
1240
|
const table = formatTable(accounts.map((account)=>({
|
|
1177
1241
|
name: account.name,
|
|
1178
|
-
account_id: maskAccountId(account.
|
|
1242
|
+
account_id: maskAccountId(account.identity),
|
|
1179
1243
|
plan_type: account.plan_type ?? "-",
|
|
1180
1244
|
available: computeAvailability(account) ?? "-",
|
|
1181
1245
|
five_hour: formatUsagePercent(account.five_hour),
|
|
@@ -1300,11 +1364,13 @@ async function runCli(argv, options = {}) {
|
|
|
1300
1364
|
account: {
|
|
1301
1365
|
name: account.name,
|
|
1302
1366
|
account_id: account.account_id,
|
|
1367
|
+
user_id: account.user_id ?? null,
|
|
1368
|
+
identity: account.identity,
|
|
1303
1369
|
auth_mode: account.auth_mode
|
|
1304
1370
|
}
|
|
1305
1371
|
};
|
|
1306
1372
|
if (json) writeJson(streams.stdout, payload);
|
|
1307
|
-
else streams.stdout.write(`Saved account "${account.name}" (${maskAccountId(account.
|
|
1373
|
+
else streams.stdout.write(`Saved account "${account.name}" (${maskAccountId(account.identity)}).\n`);
|
|
1308
1374
|
return 0;
|
|
1309
1375
|
}
|
|
1310
1376
|
case "update":
|
|
@@ -1326,6 +1392,8 @@ async function runCli(argv, options = {}) {
|
|
|
1326
1392
|
account: {
|
|
1327
1393
|
name: result.account.name,
|
|
1328
1394
|
account_id: result.account.account_id,
|
|
1395
|
+
user_id: result.account.user_id ?? null,
|
|
1396
|
+
identity: result.account.identity,
|
|
1329
1397
|
auth_mode: result.account.auth_mode
|
|
1330
1398
|
},
|
|
1331
1399
|
quota,
|
|
@@ -1333,23 +1401,11 @@ async function runCli(argv, options = {}) {
|
|
|
1333
1401
|
};
|
|
1334
1402
|
if (json) writeJson(streams.stdout, payload);
|
|
1335
1403
|
else {
|
|
1336
|
-
streams.stdout.write(`Updated managed account "${result.account.name}" (${maskAccountId(result.account.
|
|
1404
|
+
streams.stdout.write(`Updated managed account "${result.account.name}" (${maskAccountId(result.account.identity)}).\n`);
|
|
1337
1405
|
for (const warning of warnings)streams.stdout.write(`Warning: ${warning}\n`);
|
|
1338
1406
|
}
|
|
1339
1407
|
return 0;
|
|
1340
1408
|
}
|
|
1341
|
-
case "quota":
|
|
1342
|
-
{
|
|
1343
|
-
const quotaCommand = parsed.positionals[0];
|
|
1344
|
-
if ("refresh" === quotaCommand) {
|
|
1345
|
-
const targetName = parsed.positionals[1];
|
|
1346
|
-
const result = await store.refreshAllQuotas(targetName);
|
|
1347
|
-
if (json) writeJson(streams.stdout, toCliQuotaRefreshResult(result));
|
|
1348
|
-
else streams.stdout.write(`${describeQuotaRefresh(result)}\n`);
|
|
1349
|
-
return 0 === result.failures.length ? 0 : 1;
|
|
1350
|
-
}
|
|
1351
|
-
throw new Error("Usage: codexm quota refresh [name] [--json]");
|
|
1352
|
-
}
|
|
1353
1409
|
case "switch":
|
|
1354
1410
|
{
|
|
1355
1411
|
const auto = parsed.flags.has("--auto");
|
|
@@ -1388,7 +1444,8 @@ async function runCli(argv, options = {}) {
|
|
|
1388
1444
|
reason: "already_current_best",
|
|
1389
1445
|
account: {
|
|
1390
1446
|
name: selected.name,
|
|
1391
|
-
account_id: selected.account_id
|
|
1447
|
+
account_id: selected.account_id,
|
|
1448
|
+
identity: selected.identity
|
|
1392
1449
|
},
|
|
1393
1450
|
selected,
|
|
1394
1451
|
candidates,
|
|
@@ -1408,6 +1465,8 @@ async function runCli(argv, options = {}) {
|
|
|
1408
1465
|
account: {
|
|
1409
1466
|
name: result.account.name,
|
|
1410
1467
|
account_id: result.account.account_id,
|
|
1468
|
+
user_id: result.account.user_id ?? null,
|
|
1469
|
+
identity: result.account.identity,
|
|
1411
1470
|
auth_mode: result.account.auth_mode
|
|
1412
1471
|
},
|
|
1413
1472
|
selected,
|
|
@@ -1437,6 +1496,8 @@ async function runCli(argv, options = {}) {
|
|
|
1437
1496
|
account: {
|
|
1438
1497
|
name: result.account.name,
|
|
1439
1498
|
account_id: result.account.account_id,
|
|
1499
|
+
user_id: result.account.user_id ?? null,
|
|
1500
|
+
identity: result.account.identity,
|
|
1440
1501
|
auth_mode: result.account.auth_mode
|
|
1441
1502
|
},
|
|
1442
1503
|
quota,
|
|
@@ -1445,7 +1506,7 @@ async function runCli(argv, options = {}) {
|
|
|
1445
1506
|
};
|
|
1446
1507
|
if (json) writeJson(streams.stdout, payload);
|
|
1447
1508
|
else {
|
|
1448
|
-
streams.stdout.write(`Switched to "${result.account.name}" (${maskAccountId(result.account.
|
|
1509
|
+
streams.stdout.write(`Switched to "${result.account.name}" (${maskAccountId(result.account.identity)}).\n`);
|
|
1449
1510
|
if (result.backup_path) streams.stdout.write(`Backup: ${result.backup_path}\n`);
|
|
1450
1511
|
for (const warning of result.warnings)streams.stdout.write(`Warning: ${warning}\n`);
|
|
1451
1512
|
}
|
|
@@ -1487,19 +1548,14 @@ async function runCli(argv, options = {}) {
|
|
|
1487
1548
|
account: {
|
|
1488
1549
|
name: account.name,
|
|
1489
1550
|
account_id: account.account_id,
|
|
1551
|
+
user_id: account.user_id ?? null,
|
|
1552
|
+
identity: account.identity,
|
|
1490
1553
|
auth_mode: account.auth_mode
|
|
1491
1554
|
}
|
|
1492
1555
|
});
|
|
1493
1556
|
else streams.stdout.write(`Renamed "${oldName}" to "${newName}".\n`);
|
|
1494
1557
|
return 0;
|
|
1495
1558
|
}
|
|
1496
|
-
case "doctor":
|
|
1497
|
-
{
|
|
1498
|
-
const report = await store.doctor();
|
|
1499
|
-
if (json) writeJson(streams.stdout, report);
|
|
1500
|
-
else streams.stdout.write(`${describeDoctor(report)}\n`);
|
|
1501
|
-
return report.healthy ? 0 : 1;
|
|
1502
|
-
}
|
|
1503
1559
|
default:
|
|
1504
1560
|
throw new Error(`Unknown command "${parsed.command}".`);
|
|
1505
1561
|
}
|