claudish 14.5.2 → 14.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +253 -48
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -4266,6 +4266,67 @@ var init_zod = __esm(() => {
|
|
|
4266
4266
|
init_external();
|
|
4267
4267
|
});
|
|
4268
4268
|
|
|
4269
|
+
// src/auth/accounts/account-label.ts
|
|
4270
|
+
function cleanPlan(plan) {
|
|
4271
|
+
const cleaned = (plan ?? "").toLowerCase().replace(/[^a-z0-9]/g, "").slice(0, PLAN_MAX);
|
|
4272
|
+
return cleaned || undefined;
|
|
4273
|
+
}
|
|
4274
|
+
function labelTaken(taken, label) {
|
|
4275
|
+
const wanted = label.toLowerCase();
|
|
4276
|
+
for (const existing of taken)
|
|
4277
|
+
if (existing.toLowerCase() === wanted)
|
|
4278
|
+
return true;
|
|
4279
|
+
return false;
|
|
4280
|
+
}
|
|
4281
|
+
function emailMatches(rowEmail, selector) {
|
|
4282
|
+
return rowEmail !== undefined && rowEmail.toLowerCase() === selector.toLowerCase();
|
|
4283
|
+
}
|
|
4284
|
+
function shellWord(label) {
|
|
4285
|
+
if (/^[\w@+.-]+$/.test(label))
|
|
4286
|
+
return label;
|
|
4287
|
+
return `'${label.replace(/'/g, `'\\''`)}'`;
|
|
4288
|
+
}
|
|
4289
|
+
function baseOf(input) {
|
|
4290
|
+
const fromEmail = (input.email ?? "").trim().toLowerCase().replace(/[^a-z0-9_@+.-]/g, "_").replace(/^\W+/, "");
|
|
4291
|
+
if (fromEmail)
|
|
4292
|
+
return fromEmail.slice(0, ACCOUNT_LABEL_MAX);
|
|
4293
|
+
return (input.chatgptAccountId ?? "").toLowerCase().replace(/[^a-z0-9_-]/g, "").replace(/^\W+/, "").slice(0, 8);
|
|
4294
|
+
}
|
|
4295
|
+
function fit(base, suffix) {
|
|
4296
|
+
return base.slice(0, ACCOUNT_LABEL_MAX - suffix.length).replace(/[.\-+@]+$/, "") + suffix;
|
|
4297
|
+
}
|
|
4298
|
+
function deriveAccountLabel(input) {
|
|
4299
|
+
const base = baseOf(input);
|
|
4300
|
+
if (!base)
|
|
4301
|
+
throw new Error("The login carries no email or account id; pass --label.");
|
|
4302
|
+
const taken = new Set;
|
|
4303
|
+
for (const label of input.taken)
|
|
4304
|
+
taken.add(label.toLowerCase());
|
|
4305
|
+
const plan = cleanPlan(input.plan);
|
|
4306
|
+
const planSuffix = plan ? `-${plan}` : "";
|
|
4307
|
+
function* candidates() {
|
|
4308
|
+
yield fit(base, "");
|
|
4309
|
+
if (plan)
|
|
4310
|
+
yield fit(base, planSuffix);
|
|
4311
|
+
for (let n = 2;n <= NUMBER_MAX; n++)
|
|
4312
|
+
yield fit(base, `${planSuffix}-${n}`);
|
|
4313
|
+
}
|
|
4314
|
+
for (const candidate of candidates()) {
|
|
4315
|
+
if (taken.has(candidate.toLowerCase()))
|
|
4316
|
+
continue;
|
|
4317
|
+
if (!ACCOUNT_LABEL_PATTERN.test(candidate)) {
|
|
4318
|
+
throw new Error(`The derived label "${candidate}" is not valid; pass --label.`);
|
|
4319
|
+
}
|
|
4320
|
+
return candidate;
|
|
4321
|
+
}
|
|
4322
|
+
throw new Error("Could not derive an unused label; pass --label.");
|
|
4323
|
+
}
|
|
4324
|
+
var ACCOUNT_LABEL_MAX = 64, ACCOUNT_LABEL_PATTERN, ACCOUNT_LABEL_RULE, PLAN_MAX = 16, NUMBER_MAX = 999;
|
|
4325
|
+
var init_account_label = __esm(() => {
|
|
4326
|
+
ACCOUNT_LABEL_PATTERN = /^\w[\w@+. -]{0,63}$/;
|
|
4327
|
+
ACCOUNT_LABEL_RULE = "An account label starts with a letter, digit or underscore and has at most 64 letters, " + "digits, spaces, and the characters _ @ + . -";
|
|
4328
|
+
});
|
|
4329
|
+
|
|
4269
4330
|
// src/auth/quota/codex-window-slots.ts
|
|
4270
4331
|
var CODEX_WINDOW_SLOTS;
|
|
4271
4332
|
var init_codex_window_slots = __esm(() => {
|
|
@@ -4326,6 +4387,7 @@ function requireWireApiForTransport(transport, wire, ctx) {
|
|
|
4326
4387
|
var CustomEndpointAuthSchemeSchema, WireValueSchema, WirePointerSchema, WireAssignmentSchema, CustomEndpointWireSchema, CustomEndpointSimpleSchema, CustomEndpointComplexSchema, CustomEndpointSchema, PredefinedEndpointsConfigSchema, AccountIdentitySchema, AccountStoreKindSchema, SubscriptionAccountSchema, CodexWindowSlotSchema, SubscriptionAccountsEntrySchema, SubscriptionAccountsSchema;
|
|
4327
4388
|
var init_config_schema = __esm(() => {
|
|
4328
4389
|
init_zod();
|
|
4390
|
+
init_account_label();
|
|
4329
4391
|
init_codex_window_slots();
|
|
4330
4392
|
CustomEndpointAuthSchemeSchema = _enum(["bearer", "x-api-key", "none"]);
|
|
4331
4393
|
WireValueSchema = union([string2(), number2(), boolean2()]);
|
|
@@ -4392,7 +4454,7 @@ var init_config_schema = __esm(() => {
|
|
|
4392
4454
|
AccountStoreKindSchema = _enum(["keychain", "file", "legacy-codex-file"]);
|
|
4393
4455
|
SubscriptionAccountSchema = object({
|
|
4394
4456
|
id: string2().regex(/^[a-z0-9]{12}$/, "account ids are generated, 12 lowercase alphanumerics"),
|
|
4395
|
-
label: string2().regex(
|
|
4457
|
+
label: string2().regex(ACCOUNT_LABEL_PATTERN, ACCOUNT_LABEL_RULE),
|
|
4396
4458
|
identity: AccountIdentitySchema.optional(),
|
|
4397
4459
|
store: AccountStoreKindSchema,
|
|
4398
4460
|
enabled: boolean2().optional(),
|
|
@@ -4586,12 +4648,12 @@ function isAccountProvider(value) {
|
|
|
4586
4648
|
function sameAccount(a, b) {
|
|
4587
4649
|
return a.provider === b.provider && a.id === b.id;
|
|
4588
4650
|
}
|
|
4589
|
-
var ACCOUNT_PROVIDERS, DEFAULT_SWITCH_AT = 0.9, ACCOUNT_ID_PATTERN, LEGACY_CODEX_ACCOUNT_ID = "legacy-codex"
|
|
4651
|
+
var ACCOUNT_PROVIDERS, DEFAULT_SWITCH_AT = 0.9, ACCOUNT_ID_PATTERN, LEGACY_CODEX_ACCOUNT_ID = "legacy-codex";
|
|
4590
4652
|
var init_types = __esm(() => {
|
|
4591
4653
|
init_errors3();
|
|
4654
|
+
init_account_label();
|
|
4592
4655
|
ACCOUNT_PROVIDERS = ["native-anthropic", "openai-codex"];
|
|
4593
4656
|
ACCOUNT_ID_PATTERN = /^[a-z0-9]{12}$/;
|
|
4594
|
-
ACCOUNT_LABEL_PATTERN = /^[\w][\w .-]{0,31}$/;
|
|
4595
4657
|
});
|
|
4596
4658
|
|
|
4597
4659
|
// src/auth/accounts/config-validation.ts
|
|
@@ -5332,7 +5394,7 @@ var init_onepassword_config = __esm(() => {
|
|
|
5332
5394
|
});
|
|
5333
5395
|
|
|
5334
5396
|
// src/version.ts
|
|
5335
|
-
var VERSION = "14.
|
|
5397
|
+
var VERSION = "14.6.0";
|
|
5336
5398
|
|
|
5337
5399
|
// src/redact.ts
|
|
5338
5400
|
function isPlaceholder(value) {
|
|
@@ -24516,7 +24578,7 @@ function vendorName(provider) {
|
|
|
24516
24578
|
}
|
|
24517
24579
|
function loginCommandFor(ref) {
|
|
24518
24580
|
const vendor = ref.provider === "openai-codex" ? "codex" : "claude";
|
|
24519
|
-
return `claudish account login ${vendor} ${ref.label}`;
|
|
24581
|
+
return `claudish account login ${vendor} ${shellWord(ref.label)}`;
|
|
24520
24582
|
}
|
|
24521
24583
|
function rethrowSelectionFailure(err) {
|
|
24522
24584
|
if (classifyConnectionError(err) || isAccountsError(err))
|
|
@@ -24927,6 +24989,7 @@ var LEASE_FAILURE_DEPRIORITIZE_MS = 60000, AccountChangedDuringLeaseError, pools
|
|
|
24927
24989
|
var init_pool = __esm(() => {
|
|
24928
24990
|
init_connection_error();
|
|
24929
24991
|
init_logger();
|
|
24992
|
+
init_account_label();
|
|
24930
24993
|
init_allowance_service();
|
|
24931
24994
|
init_exchange();
|
|
24932
24995
|
init_paths();
|
|
@@ -43758,7 +43821,7 @@ function assertLegacyCodexLogoutPermitted(configPath = activeConfigFile()) {
|
|
|
43758
43821
|
const rows = codexEntry(raw)?.accounts ?? [];
|
|
43759
43822
|
if (rows.length > 0) {
|
|
43760
43823
|
const legacy = rows.find((row) => row.store === "legacy-codex-file");
|
|
43761
|
-
throw new Error(legacy ? `The legacy Codex login is account ${legacy.label}. Remove it with ` + `\`claudish account remove codex ${legacy.label} --delete-file\`.` : "Codex accounts are managed by `claudish account`; remove one with " + "`claudish account remove codex <label>`.");
|
|
43824
|
+
throw new Error(legacy ? `The legacy Codex login is account ${legacy.label}. Remove it with ` + `\`claudish account remove codex ${shellWord(legacy.label)} --delete-file\`.` : "Codex accounts are managed by `claudish account`; remove one with " + "`claudish account remove codex <label>`.");
|
|
43762
43825
|
}
|
|
43763
43826
|
return { config: raw, result: undefined };
|
|
43764
43827
|
});
|
|
@@ -43783,10 +43846,23 @@ async function saveLegacyCodexLogin(write, opts = {}) {
|
|
|
43783
43846
|
}
|
|
43784
43847
|
}
|
|
43785
43848
|
}
|
|
43786
|
-
function display(identity) {
|
|
43849
|
+
function display(identity, label) {
|
|
43787
43850
|
const raw = identity.email || identity.chatgptAccountId || "identity unavailable";
|
|
43788
|
-
const shown = [...raw].filter((ch) =>
|
|
43789
|
-
|
|
43851
|
+
const shown = [...raw].filter((ch) => {
|
|
43852
|
+
const code = ch.charCodeAt(0);
|
|
43853
|
+
return code > 31 && !(code >= 127 && code <= 159);
|
|
43854
|
+
}).join("");
|
|
43855
|
+
const text = identity.email && label.toLowerCase() === identity.email.toLowerCase() ? "" : shown;
|
|
43856
|
+
if (!identity.plan)
|
|
43857
|
+
return text;
|
|
43858
|
+
return text ? `${text}, ${identity.plan}` : identity.plan;
|
|
43859
|
+
}
|
|
43860
|
+
function note(identity, label) {
|
|
43861
|
+
const text = display(identity, label);
|
|
43862
|
+
return text ? ` (${text})` : "";
|
|
43863
|
+
}
|
|
43864
|
+
function named(row) {
|
|
43865
|
+
return row.legacy ? `${row.label} (legacy login)` : `${row.label} (id ${row.id})`;
|
|
43790
43866
|
}
|
|
43791
43867
|
function stableIdentity(identity) {
|
|
43792
43868
|
const stable = identity.chatgptAccountId?.trim();
|
|
@@ -43796,8 +43872,16 @@ function stableIdentity(identity) {
|
|
|
43796
43872
|
return stable;
|
|
43797
43873
|
}
|
|
43798
43874
|
function validLabel(label) {
|
|
43799
|
-
if (!ACCOUNT_LABEL_PATTERN.test(label))
|
|
43800
|
-
throw new Error(
|
|
43875
|
+
if (!ACCOUNT_LABEL_PATTERN.test(label))
|
|
43876
|
+
throw new Error(ACCOUNT_LABEL_RULE);
|
|
43877
|
+
}
|
|
43878
|
+
function validSelector(selector) {
|
|
43879
|
+
const control = [...selector].some((ch) => {
|
|
43880
|
+
const code = ch.charCodeAt(0);
|
|
43881
|
+
return code <= 31 || code >= 127 && code <= 159;
|
|
43882
|
+
});
|
|
43883
|
+
if (selector.length < 1 || selector.length > 254 || control) {
|
|
43884
|
+
throw new Error("An account selector is a label or an email: 1 to 254 characters, no control characters.");
|
|
43801
43885
|
}
|
|
43802
43886
|
}
|
|
43803
43887
|
function asRecord(row) {
|
|
@@ -43848,16 +43932,41 @@ class CodexAccountManagement {
|
|
|
43848
43932
|
result: read(codexEntry(raw) ?? { generation: 0, accounts: [] })
|
|
43849
43933
|
}));
|
|
43850
43934
|
}
|
|
43851
|
-
|
|
43935
|
+
rowsOf(entry) {
|
|
43852
43936
|
const rows = entry.accounts.map(asRecord);
|
|
43853
43937
|
const legacy = this.synthesizedLegacy(entry);
|
|
43854
43938
|
if (legacy)
|
|
43855
43939
|
rows.push(legacy);
|
|
43940
|
+
return rows;
|
|
43941
|
+
}
|
|
43942
|
+
resolve(entry, target) {
|
|
43943
|
+
const rows = this.rowsOf(entry);
|
|
43856
43944
|
const matches = rows.filter((row) => (target.id === undefined || row.id === target.id) && (target.label === undefined || row.label === target.label));
|
|
43857
43945
|
if (matches.length === 1)
|
|
43858
43946
|
return matches[0];
|
|
43859
43947
|
throw new Error(matches.length > 1 ? "Ambiguous Codex account; name it with --id <generated-id>." : "No such Codex account; run `claudish account list`.");
|
|
43860
43948
|
}
|
|
43949
|
+
select(entry, target) {
|
|
43950
|
+
const rows = this.rowsOf(entry).filter((row) => target.id === undefined || row.id === target.id);
|
|
43951
|
+
const { selector } = target;
|
|
43952
|
+
if (selector === undefined) {
|
|
43953
|
+
if (rows.length === 1)
|
|
43954
|
+
return rows[0];
|
|
43955
|
+
throw new Error("No such Codex account; run `claudish account list`.");
|
|
43956
|
+
}
|
|
43957
|
+
const exact = rows.filter((row) => row.label === selector);
|
|
43958
|
+
if (exact.length === 1)
|
|
43959
|
+
return exact[0];
|
|
43960
|
+
if (exact.length > 1) {
|
|
43961
|
+
throw new Error("Ambiguous Codex account; name it with --id <generated-id>.");
|
|
43962
|
+
}
|
|
43963
|
+
const byEmail = rows.filter((row) => emailMatches(row.identity.email, selector));
|
|
43964
|
+
if (byEmail.length === 1)
|
|
43965
|
+
return byEmail[0];
|
|
43966
|
+
if (byEmail.length === 0)
|
|
43967
|
+
throw new Error("No such Codex account; run `claudish account list`.");
|
|
43968
|
+
throw new Error(`More than one Codex account has the email ${selector}: ${byEmail.map(named).join(", ")}. ` + "Name one by label, or pass --id <generated-id>." + (byEmail.some((row) => row.legacy) ? " The legacy login has no --id; name it by its label." : ""));
|
|
43969
|
+
}
|
|
43861
43970
|
newId(entry, reserved) {
|
|
43862
43971
|
for (let attempt = 0;attempt < 16; attempt++) {
|
|
43863
43972
|
const id = this.deps.newId?.() ?? randomBytes8(6).toString("hex");
|
|
@@ -43869,21 +43978,39 @@ class CodexAccountManagement {
|
|
|
43869
43978
|
throw new Error("Could not generate an unused account id.");
|
|
43870
43979
|
}
|
|
43871
43980
|
refuseDuplicate(entry, identity, label, except) {
|
|
43981
|
+
const rows = this.rowsOf(entry);
|
|
43982
|
+
for (const row of rows) {
|
|
43983
|
+
if (row.id !== except && row.label === label) {
|
|
43984
|
+
throw new Error(`A Codex account labelled ${label} already exists.`);
|
|
43985
|
+
}
|
|
43986
|
+
}
|
|
43987
|
+
this.refuseIdentity(rows, identity, except);
|
|
43988
|
+
}
|
|
43989
|
+
refuseIdentity(rows, identity, except) {
|
|
43872
43990
|
const stable = stableIdentity(identity);
|
|
43873
|
-
const rows = entry.accounts.map(asRecord);
|
|
43874
|
-
const legacy = this.synthesizedLegacy(entry);
|
|
43875
|
-
if (legacy)
|
|
43876
|
-
rows.push(legacy);
|
|
43877
43991
|
for (const row of rows) {
|
|
43878
43992
|
if (row.id === except)
|
|
43879
43993
|
continue;
|
|
43880
|
-
if (row.label === label)
|
|
43881
|
-
throw new Error(`A Codex account labelled ${label} already exists.`);
|
|
43882
43994
|
if (row.identity.chatgptAccountId === stable) {
|
|
43883
43995
|
throw new Error(`This Codex identity is already registered as ${row.label}.`);
|
|
43884
43996
|
}
|
|
43885
43997
|
}
|
|
43886
43998
|
}
|
|
43999
|
+
chooseLabel(rows, identity, explicit) {
|
|
44000
|
+
const taken = rows.map((row) => row.label);
|
|
44001
|
+
if (explicit !== undefined) {
|
|
44002
|
+
if (labelTaken(taken, explicit)) {
|
|
44003
|
+
throw new Error(`A Codex account labelled ${explicit} already exists.`);
|
|
44004
|
+
}
|
|
44005
|
+
return explicit;
|
|
44006
|
+
}
|
|
44007
|
+
return deriveAccountLabel({
|
|
44008
|
+
email: identity.email,
|
|
44009
|
+
plan: identity.plan,
|
|
44010
|
+
chatgptAccountId: identity.chatgptAccountId,
|
|
44011
|
+
taken
|
|
44012
|
+
});
|
|
44013
|
+
}
|
|
43887
44014
|
store(kind) {
|
|
43888
44015
|
return this.deps.store?.(kind) ?? storeFor(kind, this.env);
|
|
43889
44016
|
}
|
|
@@ -43936,30 +44063,35 @@ class CodexAccountManagement {
|
|
|
43936
44063
|
};
|
|
43937
44064
|
}
|
|
43938
44065
|
async run(command) {
|
|
43939
|
-
if (command.
|
|
43940
|
-
|
|
43941
|
-
|
|
44066
|
+
if (command.verb === "add") {
|
|
44067
|
+
if (command.label !== undefined)
|
|
44068
|
+
validLabel(command.label);
|
|
43942
44069
|
return this.add(command.label);
|
|
44070
|
+
}
|
|
44071
|
+
if (command.verb === "rename")
|
|
44072
|
+
validLabel(command.newLabel);
|
|
43943
44073
|
if (command.id !== undefined && !ACCOUNT_ID_PATTERN.test(command.id)) {
|
|
43944
44074
|
throw new Error("--id takes a generated account id, as `claudish account list --json` shows.");
|
|
43945
44075
|
}
|
|
43946
|
-
if (command.
|
|
43947
|
-
throw new Error("Name the Codex account by label, or with --id <generated-id>.");
|
|
44076
|
+
if (command.selector === undefined && command.id === undefined) {
|
|
44077
|
+
throw new Error("Name the Codex account by label or email, or with --id <generated-id>.");
|
|
43948
44078
|
}
|
|
43949
|
-
|
|
44079
|
+
if (command.selector !== undefined)
|
|
44080
|
+
validSelector(command.selector);
|
|
44081
|
+
const target = this.inspect((entry) => this.select(entry, command));
|
|
43950
44082
|
if (command.verb === "login")
|
|
43951
44083
|
return this.login(target);
|
|
44084
|
+
if (command.verb === "rename")
|
|
44085
|
+
return this.rename(target, command.newLabel);
|
|
43952
44086
|
if (command.verb === "remove")
|
|
43953
44087
|
return this.remove(target, command);
|
|
43954
44088
|
return this.setEnabled(target, command.verb === "enable");
|
|
43955
44089
|
}
|
|
43956
44090
|
async add(requestedLabel) {
|
|
43957
|
-
const label = requestedLabel ?? await (this.deps.label ?? (() => dist_default3({ message: "Codex account label:" })))();
|
|
43958
|
-
validLabel(label);
|
|
43959
44091
|
const initial = this.inspect((entry) => {
|
|
43960
44092
|
const legacy = this.synthesizedLegacy(entry);
|
|
43961
|
-
if (entry.
|
|
43962
|
-
throw new Error(`A Codex account labelled ${
|
|
44093
|
+
if (requestedLabel !== undefined && labelTaken(this.rowsOf(entry).map((r) => r.label), requestedLabel)) {
|
|
44094
|
+
throw new Error(`A Codex account labelled ${requestedLabel} already exists.`);
|
|
43963
44095
|
}
|
|
43964
44096
|
if (legacy && !legacy.identity.chatgptAccountId) {
|
|
43965
44097
|
throw new Error("The legacy Codex login records no account id, so enrolling it cannot be checked for duplicates. Run `claudish login codex` once to refresh it, then retry.");
|
|
@@ -43971,26 +44103,29 @@ class CodexAccountManagement {
|
|
|
43971
44103
|
}
|
|
43972
44104
|
const acceptedAt = new Date(this.now()).toISOString();
|
|
43973
44105
|
if (initial.legacy) {
|
|
43974
|
-
this.print(`This add also enrolls your working legacy login as ${initial.legacy.label}
|
|
44106
|
+
this.print(`This add also enrolls your working legacy login as ${initial.legacy.label}${note(initial.legacy.identity, initial.legacy.label)}, store legacy-codex-file. Its credential file stays where it is and is not copied.`);
|
|
43975
44107
|
}
|
|
43976
44108
|
const store = this.deps.newStore?.() ?? defaultAccountStore(this.env);
|
|
43977
|
-
this.print(`New Codex account ${
|
|
44109
|
+
this.print(`New Codex account${requestedLabel === undefined ? "" : ` ${requestedLabel}`}; store: ${store.kind}.` + (store.kind === "file" ? " Warning: its tokens are kept in plaintext files readable only by you (0600)." : ""));
|
|
43978
44110
|
const result = await (this.deps.pkce ?? loginCodexPkce)();
|
|
43979
44111
|
stableIdentity(result.identity);
|
|
43980
44112
|
const row = {
|
|
43981
44113
|
id: initial.id,
|
|
43982
|
-
label,
|
|
44114
|
+
label: "",
|
|
43983
44115
|
identity: result.identity,
|
|
43984
44116
|
store: store.kind,
|
|
43985
44117
|
enabled: true,
|
|
43986
44118
|
addedAt: new Date(this.now()).toISOString()
|
|
43987
44119
|
};
|
|
43988
44120
|
const record = asRecord(row);
|
|
44121
|
+
let finalLabel = "";
|
|
43989
44122
|
await this.gate(record, async (holds) => {
|
|
43990
44123
|
this.inspect((entry) => {
|
|
43991
44124
|
if (entry.accounts.some((a) => a.id === row.id))
|
|
43992
44125
|
throw new Error("The generated account id is taken; retry the add.");
|
|
43993
|
-
this.
|
|
44126
|
+
const rows = this.rowsOf(entry);
|
|
44127
|
+
this.refuseIdentity(rows, result.identity);
|
|
44128
|
+
this.chooseLabel(rows, result.identity, requestedLabel);
|
|
43994
44129
|
});
|
|
43995
44130
|
if (await store.read(record, { uncached: true })) {
|
|
43996
44131
|
throw new Error("A token item already exists for the generated account id; retry the add.");
|
|
@@ -44003,8 +44138,10 @@ class CodexAccountManagement {
|
|
|
44003
44138
|
this.fence(holds);
|
|
44004
44139
|
if (entry.accounts.some((a) => a.id === row.id))
|
|
44005
44140
|
throw new Error("The generated account id is taken; retry the add.");
|
|
44006
|
-
this.
|
|
44007
|
-
|
|
44141
|
+
const rows = this.rowsOf(entry);
|
|
44142
|
+
this.refuseIdentity(rows, result.identity);
|
|
44143
|
+
const label = this.chooseLabel(rows, result.identity, requestedLabel);
|
|
44144
|
+
const legacy = rows.find((r) => r.legacy);
|
|
44008
44145
|
if (legacy) {
|
|
44009
44146
|
if (legacy.identity.chatgptAccountId !== initial.legacy?.identity.chatgptAccountId) {
|
|
44010
44147
|
throw new Error("The legacy Codex login changed during the add; retry to confirm its enrollment.");
|
|
@@ -44018,15 +44155,18 @@ class CodexAccountManagement {
|
|
|
44018
44155
|
addedAt: legacy.addedAt
|
|
44019
44156
|
});
|
|
44020
44157
|
}
|
|
44021
|
-
entry.accounts.push(row);
|
|
44158
|
+
entry.accounts.push({ ...row, label });
|
|
44022
44159
|
entry.noticeAcceptedAt ??= acceptedAt;
|
|
44160
|
+
finalLabel = label;
|
|
44023
44161
|
});
|
|
44024
44162
|
} catch (error) {
|
|
44025
44163
|
await this.cleanupUnpublished(store, record, error);
|
|
44026
44164
|
}
|
|
44027
44165
|
});
|
|
44028
44166
|
await this.invalidate();
|
|
44029
|
-
return [
|
|
44167
|
+
return [
|
|
44168
|
+
`Added Codex account ${finalLabel}${note(result.identity, finalLabel)}; store: ${store.kind}.`
|
|
44169
|
+
];
|
|
44030
44170
|
}
|
|
44031
44171
|
async cleanupUnpublished(store, record, error) {
|
|
44032
44172
|
let published;
|
|
@@ -44052,9 +44192,9 @@ class CodexAccountManagement {
|
|
|
44052
44192
|
else
|
|
44053
44193
|
await (await Promise.resolve().then(() => (init_codex_oauth(), exports_codex_oauth))).CodexOAuth.getInstance().login();
|
|
44054
44194
|
await this.invalidate();
|
|
44055
|
-
return [`Codex account ${target
|
|
44195
|
+
return [`Codex account ${named(target)}: login saved.`];
|
|
44056
44196
|
}
|
|
44057
|
-
this.print(`Logging in Codex account ${target
|
|
44197
|
+
this.print(`Logging in Codex account ${named(target)}; store: ${target.store}.`);
|
|
44058
44198
|
const result = await (this.deps.pkce ?? loginCodexPkce)();
|
|
44059
44199
|
const stable = stableIdentity(result.identity);
|
|
44060
44200
|
if (target.identity.chatgptAccountId && stable !== target.identity.chatgptAccountId) {
|
|
@@ -44081,12 +44221,12 @@ class CodexAccountManagement {
|
|
|
44081
44221
|
});
|
|
44082
44222
|
await this.invalidate();
|
|
44083
44223
|
return [
|
|
44084
|
-
`Codex account ${target
|
|
44224
|
+
`Codex account ${named(target)}${note(result.identity, target.label)}: login saved; store: ${target.store}. A recorded needs-login mark clears on the account's next use.`
|
|
44085
44225
|
];
|
|
44086
44226
|
}
|
|
44087
44227
|
async setEnabled(target, enabled) {
|
|
44088
44228
|
if (target.legacy) {
|
|
44089
|
-
this.print(`This enrolls your legacy login ${target
|
|
44229
|
+
this.print(`This enrolls your legacy login ${named(target)}${note(target.identity, target.label)} as a configured account, store legacy-codex-file; its credential file stays where it is.`);
|
|
44090
44230
|
}
|
|
44091
44231
|
let changed = false;
|
|
44092
44232
|
let poolDisabled = false;
|
|
@@ -44115,7 +44255,7 @@ class CodexAccountManagement {
|
|
|
44115
44255
|
if (changed)
|
|
44116
44256
|
await this.invalidate();
|
|
44117
44257
|
const lines = [
|
|
44118
|
-
`Codex account ${target
|
|
44258
|
+
`Codex account ${named(target)} ${changed ? "" : "is already "}${enabled ? "enabled" : "disabled"}.`
|
|
44119
44259
|
];
|
|
44120
44260
|
if (!enabled) {
|
|
44121
44261
|
lines.push("Configured Codex accounts still reserve the subscription: with no enabled account, Codex requests fail visibly instead of using OPENAI_CODEX_API_KEY.");
|
|
@@ -44125,6 +44265,52 @@ class CodexAccountManagement {
|
|
|
44125
44265
|
}
|
|
44126
44266
|
return lines;
|
|
44127
44267
|
}
|
|
44268
|
+
async rename(target, newLabel) {
|
|
44269
|
+
if (target.legacy) {
|
|
44270
|
+
if (target.label === newLabel) {
|
|
44271
|
+
return [`Codex account ${named(target)} is already labelled ${newLabel}.`];
|
|
44272
|
+
}
|
|
44273
|
+
if (!target.identity.chatgptAccountId) {
|
|
44274
|
+
throw new Error("The legacy Codex login records no account id, so enrolling it cannot be checked for duplicates. Run `claudish login codex` once to refresh it, then retry.");
|
|
44275
|
+
}
|
|
44276
|
+
}
|
|
44277
|
+
let changed = false;
|
|
44278
|
+
await this.gate(target, async (holds) => {
|
|
44279
|
+
changed = mutateAccountsConfig(this.configPath(), PROVIDER, (entry) => {
|
|
44280
|
+
this.fence(holds);
|
|
44281
|
+
const current = this.resolve(entry, target.legacy ? { label: target.label } : { id: target.id });
|
|
44282
|
+
sameTarget(current, target);
|
|
44283
|
+
if (current.label === newLabel)
|
|
44284
|
+
return;
|
|
44285
|
+
const others = this.rowsOf(entry).filter((row) => row.id !== current.id).map((row) => row.label);
|
|
44286
|
+
if (labelTaken(others, newLabel)) {
|
|
44287
|
+
throw new Error(`A Codex account labelled ${newLabel} already exists.`);
|
|
44288
|
+
}
|
|
44289
|
+
if (current.legacy) {
|
|
44290
|
+
entry.accounts.push({
|
|
44291
|
+
id: this.newId(entry),
|
|
44292
|
+
label: newLabel,
|
|
44293
|
+
identity: current.identity,
|
|
44294
|
+
store: "legacy-codex-file",
|
|
44295
|
+
enabled: true,
|
|
44296
|
+
addedAt: current.addedAt
|
|
44297
|
+
});
|
|
44298
|
+
return;
|
|
44299
|
+
}
|
|
44300
|
+
const row = entry.accounts.find((a) => a.id === target.id);
|
|
44301
|
+
if (row)
|
|
44302
|
+
row.label = newLabel;
|
|
44303
|
+
});
|
|
44304
|
+
});
|
|
44305
|
+
if (changed)
|
|
44306
|
+
await this.invalidate();
|
|
44307
|
+
if (changed && target.legacy) {
|
|
44308
|
+
this.print(`This enrolled your legacy login ${named(target)}${note(target.identity, target.label)} as a configured account, store legacy-codex-file; its credential file stays where it is.`);
|
|
44309
|
+
}
|
|
44310
|
+
return [
|
|
44311
|
+
changed ? `Renamed Codex account ${named(target)} to ${newLabel}.` : `Codex account ${named(target)} is already labelled ${newLabel}.`
|
|
44312
|
+
];
|
|
44313
|
+
}
|
|
44128
44314
|
async remove(target, command) {
|
|
44129
44315
|
const legacyFile = target.store === "legacy-codex-file";
|
|
44130
44316
|
if (legacyFile && !command.deleteFile) {
|
|
@@ -44133,7 +44319,7 @@ class CodexAccountManagement {
|
|
|
44133
44319
|
if (!legacyFile && command.deleteFile) {
|
|
44134
44320
|
throw new Error(`--delete-file applies only to the legacy Codex login, not ${target.label}.`);
|
|
44135
44321
|
}
|
|
44136
|
-
if (!command.yes && !await this.ask(`Remove Codex account ${target
|
|
44322
|
+
if (!command.yes && !await this.ask(`Remove Codex account ${named(target)}${note(target.identity, target.label)}${legacyFile ? " and delete its legacy credential file" : ""}? Requests already in flight cannot be recalled.`)) {
|
|
44137
44323
|
return ["Cancelled; no account was removed."];
|
|
44138
44324
|
}
|
|
44139
44325
|
const warnings = [];
|
|
@@ -44175,7 +44361,7 @@ class CodexAccountManagement {
|
|
|
44175
44361
|
key: "OPENAI_CODEX_API_KEY if one is configured, otherwise none"
|
|
44176
44362
|
}[next];
|
|
44177
44363
|
return [
|
|
44178
|
-
`Removed Codex account ${target
|
|
44364
|
+
`Removed Codex account ${named(target)}${note(target.identity, target.label)}. Next Codex credential for new requests: ${nextText}.`,
|
|
44179
44365
|
...next === "key" ? ["Warning: new Codex requests may now use OPENAI_CODEX_API_KEY, billed per token."] : [],
|
|
44180
44366
|
...warnings
|
|
44181
44367
|
];
|
|
@@ -44189,6 +44375,7 @@ var init_management = __esm(() => {
|
|
|
44189
44375
|
init_dist12();
|
|
44190
44376
|
init_profile_config();
|
|
44191
44377
|
init_codex_pkce();
|
|
44378
|
+
init_account_label();
|
|
44192
44379
|
init_config_lock();
|
|
44193
44380
|
init_file_lock();
|
|
44194
44381
|
init_paths();
|
|
@@ -89664,10 +89851,12 @@ ${h("SUBCOMMANDS")}
|
|
|
89664
89851
|
${bold("Subscription accounts:")}
|
|
89665
89852
|
${green("claudish account list")} Configured subscription accounts, per claudish provider
|
|
89666
89853
|
${green("claudish account status")} ${yellow("[--json]")} Usage per window, thresholds and blockers
|
|
89667
|
-
${green("claudish account add codex")} ${yellow("[--label <label>]")} Log in a Codex account you own and add it
|
|
89854
|
+
${green("claudish account add codex")} ${yellow("[--label <label>]")} Log in a Codex account you own and add it ${dim("(label defaults to the login's email)")}
|
|
89668
89855
|
${green("claudish account login codex")} ${yellow("<label>")} Log the same Codex identity in again
|
|
89669
89856
|
${green("claudish account enable|disable codex")} ${yellow("<label>")} Include or skip it in selection
|
|
89857
|
+
${green("claudish account rename codex")} ${yellow("<label> <new-label>")} Give an account a new label
|
|
89670
89858
|
${green("claudish account remove codex")} ${yellow("<label> [--yes] [--delete-file]")}
|
|
89859
|
+
${dim("A <label> may also be the account's email.")}
|
|
89671
89860
|
${dim("--id <generated-id> may replace or confirm a label. Removing the legacy login (default)")}
|
|
89672
89861
|
${dim("requires --delete-file. New accounts use the macOS Keychain, or protected plaintext files")}
|
|
89673
89862
|
${dim("where there is none. No token input or export; Claude account mutations are not available.")}
|
|
@@ -104220,7 +104409,7 @@ function renderRow2(row, pool, now) {
|
|
|
104220
104409
|
lines.push(` ${warn2(formatReset(row.blocker.resetAt, now, row.blocker.estimated === true))}`);
|
|
104221
104410
|
}
|
|
104222
104411
|
if (row.blocker?.kind === "needs-reauth") {
|
|
104223
|
-
lines.push(` ${bad2("needs login")}: run \`claudish account login ${vendorOf(row.ref.provider)} ${row.record.label}\``);
|
|
104412
|
+
lines.push(` ${bad2("needs login")}: run \`claudish account login ${vendorOf(row.ref.provider)} ${shellWord(row.record.label)}\``);
|
|
104224
104413
|
if (row.state.needsReauth?.lastReason) {
|
|
104225
104414
|
lines.push(` ${dim4(row.state.needsReauth.lastReason)}`);
|
|
104226
104415
|
}
|
|
@@ -104295,7 +104484,7 @@ ${strong2(vendorOf(report.provider))}`);
|
|
|
104295
104484
|
if (!any) {
|
|
104296
104485
|
console.log(`
|
|
104297
104486
|
No subscription accounts are configured.`);
|
|
104298
|
-
console.log(dim4("A Codex login (`claudish login codex`) is shown here as `default (legacy file)` " + "once it exists; add an account with `claudish account add codex
|
|
104487
|
+
console.log(dim4("A Codex login (`claudish login codex`) is shown here as `default (legacy file)` " + "once it exists; add an account with `claudish account add codex`."));
|
|
104299
104488
|
}
|
|
104300
104489
|
console.log("");
|
|
104301
104490
|
}
|
|
@@ -104378,12 +104567,24 @@ function parseAccountMutation(args) {
|
|
|
104378
104567
|
throw usage2("account add codex takes no positional argument; use --label.");
|
|
104379
104568
|
return { verb: v, label: values.get("--label") };
|
|
104380
104569
|
}
|
|
104570
|
+
if (v === "rename") {
|
|
104571
|
+
const hasId = values.has("--id");
|
|
104572
|
+
if (positional.length === 2 || positional.length === 1 && hasId) {
|
|
104573
|
+
return {
|
|
104574
|
+
verb: v,
|
|
104575
|
+
selector: positional.length === 2 ? positional[0] : undefined,
|
|
104576
|
+
id: values.get("--id"),
|
|
104577
|
+
newLabel: positional[positional.length - 1]
|
|
104578
|
+
};
|
|
104579
|
+
}
|
|
104580
|
+
throw usage2("account rename codex needs <label> <new-label>, or --id <generated-id> <new-label>.");
|
|
104581
|
+
}
|
|
104381
104582
|
if (positional.length > 1)
|
|
104382
104583
|
throw usage2(`account ${v} codex names one account.`);
|
|
104383
104584
|
if (positional.length === 0 && !values.has("--id")) {
|
|
104384
104585
|
throw usage2(`account ${v} codex needs a label or --id <generated-id>.`);
|
|
104385
104586
|
}
|
|
104386
|
-
const target = {
|
|
104587
|
+
const target = { selector: positional[0], id: values.get("--id") };
|
|
104387
104588
|
if (v === "remove") {
|
|
104388
104589
|
return { verb: v, ...target, yes: flags.has("--yes"), deleteFile: flags.has("--delete-file") };
|
|
104389
104590
|
}
|
|
@@ -104488,8 +104689,11 @@ var ACCOUNT_HELP = `Usage:
|
|
|
104488
104689
|
claudish account forecast [--json] [--horizon <h|d>] [--provider codex]
|
|
104489
104690
|
claudish account add codex [--label <label>]
|
|
104490
104691
|
claudish account login|enable|disable codex <label> [--id <generated-id>]
|
|
104692
|
+
claudish account rename codex <label> <new-label> [--id <generated-id>]
|
|
104491
104693
|
claudish account remove codex <label> [--id <generated-id>] [--yes] [--delete-file]
|
|
104492
104694
|
|
|
104695
|
+
--label on add is optional and overrides the default, the login's email.
|
|
104696
|
+
A command that takes <label> also takes the account's email.
|
|
104493
104697
|
--id <generated-id> may replace or confirm the label; labels are unique per claudish provider.
|
|
104494
104698
|
Removing the legacy login (default, legacy-codex-file) requires --delete-file.
|
|
104495
104699
|
New accounts use the macOS Keychain, or protected plaintext files where there is none.
|
|
@@ -104503,13 +104707,14 @@ The allowance trajectory, alerts and sessions of a claudish provider's account p
|
|
|
104503
104707
|
--horizon <h|d> how far ahead to project, 1h to 7d (default 7d)
|
|
104504
104708
|
--provider codex the claudish provider (openai-codex); the only one with a model today`;
|
|
104505
104709
|
var init_account_command = __esm(() => {
|
|
104710
|
+
init_account_label();
|
|
104506
104711
|
init_policy2();
|
|
104507
104712
|
init_pool();
|
|
104508
104713
|
init_registry();
|
|
104509
104714
|
init_state_store();
|
|
104510
104715
|
init_types();
|
|
104511
104716
|
init_ansi();
|
|
104512
|
-
MUTATION_VERBS = ["add", "login", "enable", "disable", "remove"];
|
|
104717
|
+
MUTATION_VERBS = ["add", "login", "enable", "disable", "remove", "rename"];
|
|
104513
104718
|
});
|
|
104514
104719
|
|
|
104515
104720
|
// src/auth/antigravity-oauth.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudish",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.6.0",
|
|
4
4
|
"description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -71,10 +71,10 @@
|
|
|
71
71
|
"ai"
|
|
72
72
|
],
|
|
73
73
|
"optionalDependencies": {
|
|
74
|
-
"@claudish/magmux-darwin-arm64": "14.
|
|
75
|
-
"@claudish/magmux-darwin-x64": "14.
|
|
76
|
-
"@claudish/magmux-linux-arm64": "14.
|
|
77
|
-
"@claudish/magmux-linux-x64": "14.
|
|
74
|
+
"@claudish/magmux-darwin-arm64": "14.6.0",
|
|
75
|
+
"@claudish/magmux-darwin-x64": "14.6.0",
|
|
76
|
+
"@claudish/magmux-linux-arm64": "14.6.0",
|
|
77
|
+
"@claudish/magmux-linux-x64": "14.6.0"
|
|
78
78
|
},
|
|
79
79
|
"author": "Jack Rudenko <i@madappgang.com>",
|
|
80
80
|
"license": "MIT",
|