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.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.
|
|
12
|
+
rE: "0.0.9"
|
|
13
13
|
};
|
|
14
14
|
function isRecord(value) {
|
|
15
15
|
return "object" == typeof value && null !== value && !Array.isArray(value);
|
|
@@ -42,10 +42,44 @@ function isSupportedChatGPTAuthMode(authMode) {
|
|
|
42
42
|
const normalized = normalizeAuthMode(authMode);
|
|
43
43
|
return "chatgpt" === normalized || "chatgpt_auth_tokens" === normalized;
|
|
44
44
|
}
|
|
45
|
+
function extractAuthClaim(payload) {
|
|
46
|
+
const value = payload["https://api.openai.com/auth"];
|
|
47
|
+
return isRecord(value) ? value : void 0;
|
|
48
|
+
}
|
|
49
|
+
function extractStringClaim(payload, key) {
|
|
50
|
+
const value = payload[key];
|
|
51
|
+
return "string" == typeof value && "" !== value.trim() ? value : void 0;
|
|
52
|
+
}
|
|
53
|
+
function extractSnapshotJwtPayloads(snapshot) {
|
|
54
|
+
const tokens = snapshot.tokens ?? {};
|
|
55
|
+
const payloads = [];
|
|
56
|
+
for (const tokenName of [
|
|
57
|
+
"id_token",
|
|
58
|
+
"access_token"
|
|
59
|
+
]){
|
|
60
|
+
const token = tokens[tokenName];
|
|
61
|
+
if ("string" == typeof token && "" !== token.trim()) try {
|
|
62
|
+
payloads.push(decodeJwtPayload(token));
|
|
63
|
+
} catch {}
|
|
64
|
+
}
|
|
65
|
+
return payloads;
|
|
66
|
+
}
|
|
67
|
+
function getSnapshotUserId(snapshot) {
|
|
68
|
+
for (const payload of extractSnapshotJwtPayloads(snapshot)){
|
|
69
|
+
const authClaim = extractAuthClaim(payload);
|
|
70
|
+
const chatGPTUserId = authClaim?.chatgpt_user_id;
|
|
71
|
+
if ("string" == typeof chatGPTUserId && "" !== chatGPTUserId.trim()) return chatGPTUserId;
|
|
72
|
+
const userId = extractStringClaim(payload, "user_id");
|
|
73
|
+
if (userId) return userId;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
45
76
|
function fingerprintApiKey(apiKey) {
|
|
46
77
|
return createHash("sha256").update(apiKey).digest("hex").slice(0, 16);
|
|
47
78
|
}
|
|
48
|
-
function
|
|
79
|
+
function composeIdentity(accountId, userId) {
|
|
80
|
+
return "string" == typeof userId && "" !== userId.trim() ? `${accountId}:${userId}` : accountId;
|
|
81
|
+
}
|
|
82
|
+
function getSnapshotAccountId(snapshot) {
|
|
49
83
|
if (isApiKeyAuthMode(snapshot.auth_mode)) {
|
|
50
84
|
const apiKey = snapshot.OPENAI_API_KEY;
|
|
51
85
|
if ("string" != typeof apiKey || "" === apiKey.trim()) throw new Error('Field "OPENAI_API_KEY" must be a non-empty string for apikey auth.');
|
|
@@ -55,6 +89,12 @@ function getSnapshotIdentity(snapshot) {
|
|
|
55
89
|
if ("string" != typeof accountId || "" === accountId.trim()) throw new Error('Field "tokens.account_id" must be a non-empty string.');
|
|
56
90
|
return accountId;
|
|
57
91
|
}
|
|
92
|
+
function getSnapshotIdentity(snapshot) {
|
|
93
|
+
return composeIdentity(getSnapshotAccountId(snapshot), isSupportedChatGPTAuthMode(snapshot.auth_mode) ? getSnapshotUserId(snapshot) : void 0);
|
|
94
|
+
}
|
|
95
|
+
function getMetaIdentity(meta) {
|
|
96
|
+
return composeIdentity(meta.account_id, meta.user_id);
|
|
97
|
+
}
|
|
58
98
|
function defaultQuotaSnapshot() {
|
|
59
99
|
return {
|
|
60
100
|
status: "stale"
|
|
@@ -132,7 +172,8 @@ function createSnapshotMeta(name, snapshot, now, existingCreatedAt) {
|
|
|
132
172
|
return {
|
|
133
173
|
name,
|
|
134
174
|
auth_mode: snapshot.auth_mode,
|
|
135
|
-
account_id:
|
|
175
|
+
account_id: getSnapshotAccountId(snapshot),
|
|
176
|
+
user_id: isSupportedChatGPTAuthMode(snapshot.auth_mode) ? getSnapshotUserId(snapshot) : void 0,
|
|
136
177
|
created_at: existingCreatedAt ?? timestamp,
|
|
137
178
|
updated_at: timestamp,
|
|
138
179
|
last_switched_at: null,
|
|
@@ -153,6 +194,7 @@ function parseSnapshotMeta(raw) {
|
|
|
153
194
|
name: asNonEmptyString(parsed.name, "name"),
|
|
154
195
|
auth_mode: asNonEmptyString(parsed.auth_mode, "auth_mode"),
|
|
155
196
|
account_id: asNonEmptyString(parsed.account_id, "account_id"),
|
|
197
|
+
user_id: asOptionalString(parsed.user_id, "user_id"),
|
|
156
198
|
created_at: asNonEmptyString(parsed.created_at, "created_at"),
|
|
157
199
|
updated_at: asNonEmptyString(parsed.updated_at, "updated_at"),
|
|
158
200
|
last_switched_at: lastSwitchedAt,
|
|
@@ -177,11 +219,11 @@ const USER_AGENT = "codexm/0.1";
|
|
|
177
219
|
function quota_client_isRecord(value) {
|
|
178
220
|
return "object" == typeof value && null !== value && !Array.isArray(value);
|
|
179
221
|
}
|
|
180
|
-
function
|
|
222
|
+
function quota_client_extractAuthClaim(payload) {
|
|
181
223
|
const value = payload["https://api.openai.com/auth"];
|
|
182
224
|
return quota_client_isRecord(value) ? value : void 0;
|
|
183
225
|
}
|
|
184
|
-
function
|
|
226
|
+
function quota_client_extractStringClaim(payload, key) {
|
|
185
227
|
const value = payload[key];
|
|
186
228
|
return "string" == typeof value && "" !== value.trim() ? value : void 0;
|
|
187
229
|
}
|
|
@@ -194,7 +236,7 @@ function parsePlanType(snapshot) {
|
|
|
194
236
|
const token = tokens[tokenName];
|
|
195
237
|
if ("string" == typeof token && "" !== token.trim()) try {
|
|
196
238
|
const payload = decodeJwtPayload(token);
|
|
197
|
-
const authClaim =
|
|
239
|
+
const authClaim = quota_client_extractAuthClaim(payload);
|
|
198
240
|
const planType = authClaim?.chatgpt_plan_type;
|
|
199
241
|
if ("string" == typeof planType && "" !== planType.trim()) return planType;
|
|
200
242
|
} catch {}
|
|
@@ -218,7 +260,7 @@ function extractChatGPTAuth(snapshot) {
|
|
|
218
260
|
const token = tokens[tokenName];
|
|
219
261
|
if ("string" == typeof token && "" !== token.trim()) try {
|
|
220
262
|
const payload = decodeJwtPayload(token);
|
|
221
|
-
const authClaim =
|
|
263
|
+
const authClaim = quota_client_extractAuthClaim(payload);
|
|
222
264
|
if (!accountId) {
|
|
223
265
|
const maybeAccountId = authClaim?.chatgpt_account_id;
|
|
224
266
|
if ("string" == typeof maybeAccountId && "" !== maybeAccountId.trim()) accountId = maybeAccountId;
|
|
@@ -227,8 +269,8 @@ function extractChatGPTAuth(snapshot) {
|
|
|
227
269
|
const maybePlanType = authClaim?.chatgpt_plan_type;
|
|
228
270
|
if ("string" == typeof maybePlanType && "" !== maybePlanType.trim()) planType = maybePlanType;
|
|
229
271
|
}
|
|
230
|
-
issuer ??=
|
|
231
|
-
clientId ??=
|
|
272
|
+
issuer ??= quota_client_extractStringClaim(payload, "iss");
|
|
273
|
+
clientId ??= quota_client_extractStringClaim(payload, "client_id") ?? quota_client_extractStringClaim(payload, "azp") ?? ("string" == typeof payload.aud ? payload.aud : void 0);
|
|
232
274
|
} catch {}
|
|
233
275
|
}
|
|
234
276
|
if (!supported) return {
|
|
@@ -498,6 +540,13 @@ async function pathExists(path) {
|
|
|
498
540
|
async function readJsonFile(path) {
|
|
499
541
|
return readFile(path, "utf8");
|
|
500
542
|
}
|
|
543
|
+
function canAutoMigrateLegacyChatGPTMeta(meta, snapshot) {
|
|
544
|
+
if (!isSupportedChatGPTAuthMode(meta.auth_mode) || !isSupportedChatGPTAuthMode(snapshot.auth_mode)) return false;
|
|
545
|
+
if ("string" == typeof meta.user_id && "" !== meta.user_id.trim()) return false;
|
|
546
|
+
const snapshotUserId = getSnapshotUserId(snapshot);
|
|
547
|
+
if (!snapshotUserId) return false;
|
|
548
|
+
return meta.account_id === getSnapshotAccountId(snapshot);
|
|
549
|
+
}
|
|
501
550
|
async function detectRunningCodexProcesses() {
|
|
502
551
|
try {
|
|
503
552
|
const { stdout } = await account_store_execFile("ps", [
|
|
@@ -595,6 +644,8 @@ class AccountStore {
|
|
|
595
644
|
return {
|
|
596
645
|
name: account.name,
|
|
597
646
|
account_id: account.account_id,
|
|
647
|
+
user_id: account.user_id ?? null,
|
|
648
|
+
identity: account.identity,
|
|
598
649
|
plan_type: planType,
|
|
599
650
|
credits_balance: account.quota.credits_balance ?? null,
|
|
600
651
|
status: account.quota.status,
|
|
@@ -635,11 +686,21 @@ class AccountStore {
|
|
|
635
686
|
readJsonFile(metaPath),
|
|
636
687
|
readAuthSnapshotFile(authPath)
|
|
637
688
|
]);
|
|
638
|
-
|
|
689
|
+
let meta = parseSnapshotMeta(rawMeta);
|
|
639
690
|
if (meta.name !== name) throw new Error(`Account metadata name mismatch for "${name}".`);
|
|
640
|
-
|
|
691
|
+
const snapshotIdentity = getSnapshotIdentity(snapshot);
|
|
692
|
+
if (getMetaIdentity(meta) !== snapshotIdentity) if (canAutoMigrateLegacyChatGPTMeta(meta, snapshot)) {
|
|
693
|
+
meta = {
|
|
694
|
+
...meta,
|
|
695
|
+
account_id: getSnapshotAccountId(snapshot),
|
|
696
|
+
user_id: getSnapshotUserId(snapshot)
|
|
697
|
+
};
|
|
698
|
+
await this.writeAccountMeta(name, meta);
|
|
699
|
+
} else throw new Error(`Account metadata account_id mismatch for "${name}".`);
|
|
700
|
+
if (getMetaIdentity(meta) !== snapshotIdentity) throw new Error(`Account metadata account_id mismatch for "${name}".`);
|
|
641
701
|
return {
|
|
642
702
|
...meta,
|
|
703
|
+
identity: getMetaIdentity(meta),
|
|
643
704
|
authPath,
|
|
644
705
|
metaPath,
|
|
645
706
|
configPath: await pathExists(this.accountConfigPath(name)) ? this.accountConfigPath(name) : null,
|
|
@@ -659,12 +720,12 @@ class AccountStore {
|
|
|
659
720
|
warnings.push(`Account "${entry.name}" is invalid: ${error.message}`);
|
|
660
721
|
}
|
|
661
722
|
const counts = new Map();
|
|
662
|
-
for (const account of accounts)counts.set(account.
|
|
723
|
+
for (const account of accounts)counts.set(account.identity, (counts.get(account.identity) ?? 0) + 1);
|
|
663
724
|
accounts.sort((left, right)=>left.name.localeCompare(right.name));
|
|
664
725
|
return {
|
|
665
726
|
accounts: accounts.map((account)=>({
|
|
666
727
|
...account,
|
|
667
|
-
duplicateAccountId: (counts.get(account.
|
|
728
|
+
duplicateAccountId: (counts.get(account.identity) ?? 0) > 1
|
|
668
729
|
})),
|
|
669
730
|
warnings
|
|
670
731
|
};
|
|
@@ -675,6 +736,8 @@ class AccountStore {
|
|
|
675
736
|
exists: false,
|
|
676
737
|
auth_mode: null,
|
|
677
738
|
account_id: null,
|
|
739
|
+
user_id: null,
|
|
740
|
+
identity: null,
|
|
678
741
|
matched_accounts: [],
|
|
679
742
|
managed: false,
|
|
680
743
|
duplicate_match: false,
|
|
@@ -682,11 +745,15 @@ class AccountStore {
|
|
|
682
745
|
};
|
|
683
746
|
const snapshot = await readAuthSnapshotFile(this.paths.currentAuthPath);
|
|
684
747
|
const currentIdentity = getSnapshotIdentity(snapshot);
|
|
685
|
-
const
|
|
748
|
+
const currentAccountId = getSnapshotAccountId(snapshot);
|
|
749
|
+
const currentUserId = getSnapshotUserId(snapshot) ?? null;
|
|
750
|
+
const matchedAccounts = accounts.filter((account)=>account.identity === currentIdentity).map((account)=>account.name);
|
|
686
751
|
return {
|
|
687
752
|
exists: true,
|
|
688
753
|
auth_mode: snapshot.auth_mode,
|
|
689
|
-
account_id:
|
|
754
|
+
account_id: currentAccountId,
|
|
755
|
+
user_id: currentUserId,
|
|
756
|
+
identity: currentIdentity,
|
|
690
757
|
matched_accounts: matchedAccounts,
|
|
691
758
|
managed: matchedAccounts.length > 0,
|
|
692
759
|
duplicate_match: matchedAccounts.length > 1,
|
|
@@ -704,9 +771,16 @@ class AccountStore {
|
|
|
704
771
|
const authPath = this.accountAuthPath(name);
|
|
705
772
|
const metaPath = this.accountMetaPath(name);
|
|
706
773
|
const configPath = this.accountConfigPath(name);
|
|
774
|
+
const identity = getSnapshotIdentity(snapshot);
|
|
707
775
|
const accountExists = await pathExists(accountDir);
|
|
708
776
|
const existingMeta = accountExists && await pathExists(metaPath) ? parseSnapshotMeta(await readJsonFile(metaPath)) : void 0;
|
|
709
777
|
if (accountExists && !force) throw new Error(`Account "${name}" already exists. Use --force to overwrite it.`);
|
|
778
|
+
const { accounts } = await this.listAccounts();
|
|
779
|
+
const duplicateIdentityAccounts = accounts.filter((account)=>account.name !== name && account.identity === identity);
|
|
780
|
+
if (duplicateIdentityAccounts.length > 0) {
|
|
781
|
+
const joinedNames = duplicateIdentityAccounts.map((account)=>`"${account.name}"`).join(", ");
|
|
782
|
+
throw new Error(`Identity ${identity} is already managed by ${joinedNames}.`);
|
|
783
|
+
}
|
|
710
784
|
this.validateConfigSnapshot(name, snapshot, rawConfig);
|
|
711
785
|
await ensureDirectory(accountDir, DIRECTORY_MODE);
|
|
712
786
|
await atomicWriteFile(authPath, `${rawSnapshot.trimEnd()}\n`);
|
|
@@ -777,7 +851,7 @@ class AccountStore {
|
|
|
777
851
|
await atomicWriteFile(this.paths.currentConfigPath, this.sanitizeConfigForAccountAuth(currentRawConfig));
|
|
778
852
|
}
|
|
779
853
|
const writtenSnapshot = await readAuthSnapshotFile(this.paths.currentAuthPath);
|
|
780
|
-
if (getSnapshotIdentity(writtenSnapshot) !== account.
|
|
854
|
+
if (getSnapshotIdentity(writtenSnapshot) !== account.identity) throw new Error(`Switch verification failed for account "${name}".`);
|
|
781
855
|
const meta = parseSnapshotMeta(await readJsonFile(account.metaPath));
|
|
782
856
|
meta.last_switched_at = new Date().toISOString();
|
|
783
857
|
meta.updated_at = meta.last_switched_at;
|
|
@@ -821,7 +895,8 @@ class AccountStore {
|
|
|
821
895
|
await this.syncCurrentAuthIfMatching(result.authSnapshot);
|
|
822
896
|
}
|
|
823
897
|
meta.auth_mode = result.authSnapshot.auth_mode;
|
|
824
|
-
meta.account_id =
|
|
898
|
+
meta.account_id = getSnapshotAccountId(result.authSnapshot);
|
|
899
|
+
meta.user_id = getSnapshotUserId(result.authSnapshot);
|
|
825
900
|
meta.updated_at = now.toISOString();
|
|
826
901
|
meta.quota = result.quota;
|
|
827
902
|
await this.writeAccountMeta(name, meta);
|
|
@@ -934,7 +1009,7 @@ class AccountStore {
|
|
|
934
1009
|
if ((511 & authStat.mode) !== FILE_MODE) issues.push(`Account "${account.name}" auth permissions must be 600.`);
|
|
935
1010
|
if ((511 & metaStat.mode) !== FILE_MODE) issues.push(`Account "${account.name}" metadata permissions must be 600.`);
|
|
936
1011
|
if ("apikey" === account.auth_mode && !account.configPath) issues.push(`Account "${account.name}" is missing config.toml snapshot required for apikey auth.`);
|
|
937
|
-
if (account.duplicateAccountId) warnings.push(`Account "${account.name}" shares identity ${account.
|
|
1012
|
+
if (account.duplicateAccountId) warnings.push(`Account "${account.name}" shares identity ${account.identity} with another saved account.`);
|
|
938
1013
|
}
|
|
939
1014
|
let currentAuthPresent = false;
|
|
940
1015
|
if (await pathExists(this.paths.currentAuthPath)) {
|
|
@@ -1002,12 +1077,10 @@ Usage:
|
|
|
1002
1077
|
codexm list [name] [--json]
|
|
1003
1078
|
codexm save <name> [--force] [--json]
|
|
1004
1079
|
codexm update [--json]
|
|
1005
|
-
codexm quota refresh [name] [--json]
|
|
1006
1080
|
codexm switch <name> [--json]
|
|
1007
1081
|
codexm switch --auto [--dry-run] [--json]
|
|
1008
1082
|
codexm remove <name> [--yes] [--json]
|
|
1009
1083
|
codexm rename <old> <new> [--json]
|
|
1010
|
-
codexm doctor [--json]
|
|
1011
1084
|
|
|
1012
1085
|
Account names must match /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.
|
|
1013
1086
|
`);
|
|
@@ -1017,7 +1090,7 @@ function describeCurrentStatus(status) {
|
|
|
1017
1090
|
if (status.exists) {
|
|
1018
1091
|
lines.push("Current auth: present");
|
|
1019
1092
|
lines.push(`Auth mode: ${status.auth_mode}`);
|
|
1020
|
-
lines.push(`Identity: ${maskAccountId(status.
|
|
1093
|
+
lines.push(`Identity: ${maskAccountId(status.identity ?? "")}`);
|
|
1021
1094
|
if (0 === status.matched_accounts.length) lines.push("Managed account: no (unmanaged)");
|
|
1022
1095
|
else if (1 === status.matched_accounts.length) lines.push(`Managed account: ${status.matched_accounts[0]}`);
|
|
1023
1096
|
else lines.push(`Managed account: multiple (${status.matched_accounts.join(", ")})`);
|
|
@@ -1025,16 +1098,6 @@ function describeCurrentStatus(status) {
|
|
|
1025
1098
|
for (const warning of status.warnings)lines.push(`Warning: ${warning}`);
|
|
1026
1099
|
return lines.join("\n");
|
|
1027
1100
|
}
|
|
1028
|
-
function describeDoctor(report) {
|
|
1029
|
-
const lines = [
|
|
1030
|
-
report.healthy ? "Doctor checks passed." : "Doctor checks found issues.",
|
|
1031
|
-
`Saved accounts: ${report.account_count}`,
|
|
1032
|
-
`Current auth present: ${report.current_auth_present ? "yes" : "no"}`
|
|
1033
|
-
];
|
|
1034
|
-
for (const issue of report.issues)lines.push(`Issue: ${issue}`);
|
|
1035
|
-
for (const warning of report.warnings)lines.push(`Warning: ${warning}`);
|
|
1036
|
-
return lines.join("\n");
|
|
1037
|
-
}
|
|
1038
1101
|
function formatUsagePercent(window) {
|
|
1039
1102
|
if (!window) return "-";
|
|
1040
1103
|
return `${window.used_percent}%`;
|
|
@@ -1080,6 +1143,7 @@ function toAutoSwitchCandidate(account) {
|
|
|
1080
1143
|
return {
|
|
1081
1144
|
name: account.name,
|
|
1082
1145
|
account_id: account.account_id,
|
|
1146
|
+
identity: account.identity,
|
|
1083
1147
|
plan_type: account.plan_type,
|
|
1084
1148
|
available: computeAvailability(account),
|
|
1085
1149
|
refresh_status: "ok",
|
|
@@ -1112,7 +1176,7 @@ function rankAutoSwitchCandidates(accounts) {
|
|
|
1112
1176
|
}
|
|
1113
1177
|
function describeAutoSwitchSelection(candidate, dryRun, backupPath, warnings) {
|
|
1114
1178
|
const lines = [
|
|
1115
|
-
dryRun ? `Best account: "${candidate.name}" (${maskAccountId(candidate.
|
|
1179
|
+
dryRun ? `Best account: "${candidate.name}" (${maskAccountId(candidate.identity)}).` : `Auto-switched to "${candidate.name}" (${maskAccountId(candidate.identity)}).`,
|
|
1116
1180
|
`Score: ${candidate.effective_score}`,
|
|
1117
1181
|
`5H remaining: ${candidate.remain_5h}%`,
|
|
1118
1182
|
`1W remaining (5H-equivalent): ${candidate.remain_1w_eq_5h}%`
|
|
@@ -1123,7 +1187,7 @@ function describeAutoSwitchSelection(candidate, dryRun, backupPath, warnings) {
|
|
|
1123
1187
|
}
|
|
1124
1188
|
function describeAutoSwitchNoop(candidate, warnings) {
|
|
1125
1189
|
const lines = [
|
|
1126
|
-
`Current account "${candidate.name}" (${maskAccountId(candidate.
|
|
1190
|
+
`Current account "${candidate.name}" (${maskAccountId(candidate.identity)}) is already the best available account.`,
|
|
1127
1191
|
`Score: ${candidate.effective_score}`,
|
|
1128
1192
|
`5H remaining: ${candidate.remain_5h}%`,
|
|
1129
1193
|
`1W remaining (5H-equivalent): ${candidate.remain_1w_eq_5h}%`
|
|
@@ -1135,7 +1199,7 @@ function describeQuotaAccounts(accounts, warnings) {
|
|
|
1135
1199
|
if (0 === accounts.length) return 0 === warnings.length ? "No saved accounts." : warnings.map((warning)=>`Warning: ${warning}`).join("\n");
|
|
1136
1200
|
const table = formatTable(accounts.map((account)=>({
|
|
1137
1201
|
name: account.name,
|
|
1138
|
-
account_id: maskAccountId(account.
|
|
1202
|
+
account_id: maskAccountId(account.identity),
|
|
1139
1203
|
plan_type: account.plan_type ?? "-",
|
|
1140
1204
|
available: computeAvailability(account) ?? "-",
|
|
1141
1205
|
five_hour: formatUsagePercent(account.five_hour),
|
|
@@ -1260,11 +1324,13 @@ async function runCli(argv, options = {}) {
|
|
|
1260
1324
|
account: {
|
|
1261
1325
|
name: account.name,
|
|
1262
1326
|
account_id: account.account_id,
|
|
1327
|
+
user_id: account.user_id ?? null,
|
|
1328
|
+
identity: account.identity,
|
|
1263
1329
|
auth_mode: account.auth_mode
|
|
1264
1330
|
}
|
|
1265
1331
|
};
|
|
1266
1332
|
if (json) writeJson(streams.stdout, payload);
|
|
1267
|
-
else streams.stdout.write(`Saved account "${account.name}" (${maskAccountId(account.
|
|
1333
|
+
else streams.stdout.write(`Saved account "${account.name}" (${maskAccountId(account.identity)}).\n`);
|
|
1268
1334
|
return 0;
|
|
1269
1335
|
}
|
|
1270
1336
|
case "update":
|
|
@@ -1286,6 +1352,8 @@ async function runCli(argv, options = {}) {
|
|
|
1286
1352
|
account: {
|
|
1287
1353
|
name: result.account.name,
|
|
1288
1354
|
account_id: result.account.account_id,
|
|
1355
|
+
user_id: result.account.user_id ?? null,
|
|
1356
|
+
identity: result.account.identity,
|
|
1289
1357
|
auth_mode: result.account.auth_mode
|
|
1290
1358
|
},
|
|
1291
1359
|
quota,
|
|
@@ -1293,23 +1361,11 @@ async function runCli(argv, options = {}) {
|
|
|
1293
1361
|
};
|
|
1294
1362
|
if (json) writeJson(streams.stdout, payload);
|
|
1295
1363
|
else {
|
|
1296
|
-
streams.stdout.write(`Updated managed account "${result.account.name}" (${maskAccountId(result.account.
|
|
1364
|
+
streams.stdout.write(`Updated managed account "${result.account.name}" (${maskAccountId(result.account.identity)}).\n`);
|
|
1297
1365
|
for (const warning of warnings)streams.stdout.write(`Warning: ${warning}\n`);
|
|
1298
1366
|
}
|
|
1299
1367
|
return 0;
|
|
1300
1368
|
}
|
|
1301
|
-
case "quota":
|
|
1302
|
-
{
|
|
1303
|
-
const quotaCommand = parsed.positionals[0];
|
|
1304
|
-
if ("refresh" === quotaCommand) {
|
|
1305
|
-
const targetName = parsed.positionals[1];
|
|
1306
|
-
const result = await store.refreshAllQuotas(targetName);
|
|
1307
|
-
if (json) writeJson(streams.stdout, toCliQuotaRefreshResult(result));
|
|
1308
|
-
else streams.stdout.write(`${describeQuotaRefresh(result)}\n`);
|
|
1309
|
-
return 0 === result.failures.length ? 0 : 1;
|
|
1310
|
-
}
|
|
1311
|
-
throw new Error("Usage: codexm quota refresh [name] [--json]");
|
|
1312
|
-
}
|
|
1313
1369
|
case "switch":
|
|
1314
1370
|
{
|
|
1315
1371
|
const auto = parsed.flags.has("--auto");
|
|
@@ -1348,7 +1404,8 @@ async function runCli(argv, options = {}) {
|
|
|
1348
1404
|
reason: "already_current_best",
|
|
1349
1405
|
account: {
|
|
1350
1406
|
name: selected.name,
|
|
1351
|
-
account_id: selected.account_id
|
|
1407
|
+
account_id: selected.account_id,
|
|
1408
|
+
identity: selected.identity
|
|
1352
1409
|
},
|
|
1353
1410
|
selected,
|
|
1354
1411
|
candidates,
|
|
@@ -1368,6 +1425,8 @@ async function runCli(argv, options = {}) {
|
|
|
1368
1425
|
account: {
|
|
1369
1426
|
name: result.account.name,
|
|
1370
1427
|
account_id: result.account.account_id,
|
|
1428
|
+
user_id: result.account.user_id ?? null,
|
|
1429
|
+
identity: result.account.identity,
|
|
1371
1430
|
auth_mode: result.account.auth_mode
|
|
1372
1431
|
},
|
|
1373
1432
|
selected,
|
|
@@ -1397,6 +1456,8 @@ async function runCli(argv, options = {}) {
|
|
|
1397
1456
|
account: {
|
|
1398
1457
|
name: result.account.name,
|
|
1399
1458
|
account_id: result.account.account_id,
|
|
1459
|
+
user_id: result.account.user_id ?? null,
|
|
1460
|
+
identity: result.account.identity,
|
|
1400
1461
|
auth_mode: result.account.auth_mode
|
|
1401
1462
|
},
|
|
1402
1463
|
quota,
|
|
@@ -1405,7 +1466,7 @@ async function runCli(argv, options = {}) {
|
|
|
1405
1466
|
};
|
|
1406
1467
|
if (json) writeJson(streams.stdout, payload);
|
|
1407
1468
|
else {
|
|
1408
|
-
streams.stdout.write(`Switched to "${result.account.name}" (${maskAccountId(result.account.
|
|
1469
|
+
streams.stdout.write(`Switched to "${result.account.name}" (${maskAccountId(result.account.identity)}).\n`);
|
|
1409
1470
|
if (result.backup_path) streams.stdout.write(`Backup: ${result.backup_path}\n`);
|
|
1410
1471
|
for (const warning of result.warnings)streams.stdout.write(`Warning: ${warning}\n`);
|
|
1411
1472
|
}
|
|
@@ -1447,19 +1508,14 @@ async function runCli(argv, options = {}) {
|
|
|
1447
1508
|
account: {
|
|
1448
1509
|
name: account.name,
|
|
1449
1510
|
account_id: account.account_id,
|
|
1511
|
+
user_id: account.user_id ?? null,
|
|
1512
|
+
identity: account.identity,
|
|
1450
1513
|
auth_mode: account.auth_mode
|
|
1451
1514
|
}
|
|
1452
1515
|
});
|
|
1453
1516
|
else streams.stdout.write(`Renamed "${oldName}" to "${newName}".\n`);
|
|
1454
1517
|
return 0;
|
|
1455
1518
|
}
|
|
1456
|
-
case "doctor":
|
|
1457
|
-
{
|
|
1458
|
-
const report = await store.doctor();
|
|
1459
|
-
if (json) writeJson(streams.stdout, report);
|
|
1460
|
-
else streams.stdout.write(`${describeDoctor(report)}\n`);
|
|
1461
|
-
return report.healthy ? 0 : 1;
|
|
1462
|
-
}
|
|
1463
1519
|
default:
|
|
1464
1520
|
throw new Error(`Unknown command "${parsed.command}".`);
|
|
1465
1521
|
}
|