@modelprofile.com/authswitch 2.1.3 → 2.3.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_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/accounts.d.ts +3 -0
- package/dist_ts/accounts.js +37 -1
- package/dist_ts/classes.accountlist.d.ts +4 -0
- package/dist_ts/classes.accountlist.js +18 -12
- package/dist_ts/classes.claudecodeharness.d.ts +3 -1
- package/dist_ts/classes.claudecodeharness.js +5 -3
- package/dist_ts/classes.cli.d.ts +5 -0
- package/dist_ts/classes.cli.js +31 -8
- package/dist_ts/classes.credentialstore.d.ts +8 -1
- package/dist_ts/classes.credentialstore.js +24 -8
- package/dist_ts/classes.fileharness.d.ts +14 -0
- package/dist_ts/classes.fileharness.js +36 -3
- package/dist_ts/classes.limits.d.ts +24 -0
- package/dist_ts/classes.limits.js +178 -0
- package/dist_ts/classes.opencodeharness.d.ts +2 -0
- package/dist_ts/classes.opencodeharness.js +4 -2
- package/dist_ts/helpers.d.ts +9 -0
- package/dist_ts/helpers.js +12 -1
- package/dist_ts/interfaces.list.d.ts +51 -0
- package/package.json +3 -4
- package/readme.md +90 -10
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/accounts.ts +29 -0
- package/ts/classes.accountlist.ts +22 -10
- package/ts/classes.claudecodeharness.ts +4 -2
- package/ts/classes.cli.ts +28 -7
- package/ts/classes.credentialstore.ts +19 -7
- package/ts/classes.fileharness.ts +32 -2
- package/ts/classes.limits.ts +187 -0
- package/ts/classes.opencodeharness.ts +3 -1
- package/ts/helpers.ts +12 -0
- package/ts/interfaces.list.ts +55 -0
- package/.smartconfig.json +0 -34
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { compactSince, compactUntil, orderedUsageWindows } from './accounts.js';
|
|
3
|
+
import { consoleHeading, consoleTable } from './classes.accountlist.js';
|
|
4
|
+
import { dim, plainText } from './formatting.js';
|
|
5
|
+
const UNAVAILABLE = 'n/a';
|
|
6
|
+
const NONE = 'none';
|
|
7
|
+
/**
|
|
8
|
+
* Provider naming stays data-driven.
|
|
9
|
+
*
|
|
10
|
+
* A harness that owns exactly one credential slot is its own provider; one that owns several (an
|
|
11
|
+
* OpenCode installation with an OpenAI and an Anthropic login) has to say which slot a row is about.
|
|
12
|
+
*/
|
|
13
|
+
const providerName = (harnessArg, accountArg) => {
|
|
14
|
+
const slots = new Set(harnessArg.accounts.map(account => account.slotId).filter((slot) => slot !== undefined));
|
|
15
|
+
return accountArg?.slotId !== undefined && slots.size > 1
|
|
16
|
+
? `${plainText(harnessArg.label)} / ${plainText(accountArg.slotId)}`
|
|
17
|
+
: plainText(harnessArg.label);
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Why an account contributes no numbers.
|
|
21
|
+
*
|
|
22
|
+
* The provider's own explanation is preferred over ours, and a failed lookup is never presented as a
|
|
23
|
+
* missing capability: the two have different fixes.
|
|
24
|
+
*/
|
|
25
|
+
const missingLimitReason = (accountArg) => {
|
|
26
|
+
if (accountArg.status.problems.length)
|
|
27
|
+
return accountArg.status.problems.map(plainText).join(' ');
|
|
28
|
+
const availability = accountArg.status.facts.filter(fact => fact.section === 'Availability').map(fact => plainText(fact.value));
|
|
29
|
+
if (accountArg.status.summary?.usageWindows === undefined) {
|
|
30
|
+
return availability[0] ?? 'This login does not expose a usage or quota API.';
|
|
31
|
+
}
|
|
32
|
+
return 'The provider reported no usage window for this account.';
|
|
33
|
+
};
|
|
34
|
+
const accountKeys = (harnessArg, accountArg) => ({
|
|
35
|
+
harnessId: harnessArg.id,
|
|
36
|
+
provider: providerName(harnessArg, accountArg),
|
|
37
|
+
account: plainText(accountArg.label),
|
|
38
|
+
accountId: accountArg.id,
|
|
39
|
+
...(accountArg.slotId === undefined ? {} : { slotId: plainText(accountArg.slotId) }),
|
|
40
|
+
});
|
|
41
|
+
const harnessProblem = (harnessArg) => harnessArg.problems.length ? harnessArg.problems.map(plainText).join(' ') : null;
|
|
42
|
+
/** Provider then account, keeping each account's windows in the order the adapter ranked them. */
|
|
43
|
+
const byProviderThenAccount = (rowsArg) => [...rowsArg].sort((left, right) => left.provider.localeCompare(right.provider)
|
|
44
|
+
|| (left.account ?? '').localeCompare(right.account ?? ''));
|
|
45
|
+
const noteFor = (rowArg) => rowArg.unavailableReason === null ? null
|
|
46
|
+
: `${rowArg.provider}${rowArg.account === null ? '' : ` · ${rowArg.account}`}: ${rowArg.unavailableReason}`;
|
|
47
|
+
const collectNotes = (rowsArg) => [...new Set(rowsArg.map(noteFor).filter((note) => note !== null))];
|
|
48
|
+
/**
|
|
49
|
+
* One row per account and limit type, projected from the account list.
|
|
50
|
+
*
|
|
51
|
+
* Nothing here talks to a provider: the list is already the read-only, per-account-isolated lookup,
|
|
52
|
+
* so a single failing account costs its own rows a number and nothing else.
|
|
53
|
+
*/
|
|
54
|
+
export const accountLimits = (listArg) => {
|
|
55
|
+
const now = Date.parse(listArg.generatedAt);
|
|
56
|
+
const rows = [];
|
|
57
|
+
for (const harness of listArg.harnesses) {
|
|
58
|
+
const problem = harnessProblem(harness);
|
|
59
|
+
const empty = {
|
|
60
|
+
limitType: null, scope: null, windowSeconds: null, usedPercent: null, resetAt: null, resetsIn: UNAVAILABLE,
|
|
61
|
+
};
|
|
62
|
+
if (problem !== null) {
|
|
63
|
+
rows.push({ harnessId: harness.id, provider: providerName(harness), account: null, accountId: null, isActive: false, ...empty, unavailableReason: problem });
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (!harness.accounts.length) {
|
|
67
|
+
rows.push({ harnessId: harness.id, provider: providerName(harness), account: null, accountId: null, isActive: false, ...empty,
|
|
68
|
+
unavailableReason: harness.saveUnavailableReason === null ? 'No accounts are known for this harness.' : plainText(harness.saveUnavailableReason) });
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
for (const account of harness.accounts) {
|
|
72
|
+
const windows = orderedUsageWindows(account.status.summary?.usageWindows);
|
|
73
|
+
if (!windows.length) {
|
|
74
|
+
rows.push({ ...accountKeys(harness, account), isActive: account.isActive, ...empty, unavailableReason: missingLimitReason(account) });
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
for (const window of windows) {
|
|
78
|
+
rows.push({
|
|
79
|
+
...accountKeys(harness, account), isActive: account.isActive,
|
|
80
|
+
limitType: plainText(window.label), scope: window.scope ?? 'account', windowSeconds: window.durationSeconds,
|
|
81
|
+
usedPercent: window.usedPercent, resetAt: window.resetAt, resetsIn: compactUntil(window.resetAt, now, UNAVAILABLE),
|
|
82
|
+
unavailableReason: null,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const limits = byProviderThenAccount(rows);
|
|
88
|
+
return { schemaVersion: 1, generatedAt: listArg.generatedAt, complete: listArg.complete, limits, notes: collectNotes(limits) };
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* One row per active credential slot.
|
|
92
|
+
*
|
|
93
|
+
* A harness with no active login still gets a row: "nothing is active here" is an answer, and
|
|
94
|
+
* silently dropping the provider would read as "this provider does not exist".
|
|
95
|
+
*/
|
|
96
|
+
export const activeAccounts = (listArg) => {
|
|
97
|
+
const now = Date.parse(listArg.generatedAt);
|
|
98
|
+
const rows = [];
|
|
99
|
+
for (const harness of listArg.harnesses) {
|
|
100
|
+
const problem = harnessProblem(harness);
|
|
101
|
+
if (problem !== null) {
|
|
102
|
+
rows.push({ harnessId: harness.id, provider: providerName(harness), account: null, accountId: null, savedAt: null, savedAgo: UNAVAILABLE, source: 'none', unavailableReason: problem });
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const active = harness.accounts.filter(account => account.isActive);
|
|
106
|
+
if (!active.length) {
|
|
107
|
+
const stashed = harness.accounts.filter(account => account.isStashed);
|
|
108
|
+
rows.push({
|
|
109
|
+
harnessId: harness.id, provider: providerName(harness), account: null, accountId: null,
|
|
110
|
+
savedAt: null, savedAgo: UNAVAILABLE, source: stashed.length ? 'stash only' : 'none',
|
|
111
|
+
unavailableReason: harness.saveUnavailableReason !== null ? plainText(harness.saveUnavailableReason)
|
|
112
|
+
: stashed.length ? `No login is active; ${stashed.length} saved account(s) can be activated with authswitch ${plainText(harness.id)} use.`
|
|
113
|
+
: `No login is active and none is saved. ${plainText(harness.loginHint)}`,
|
|
114
|
+
});
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
for (const account of active) {
|
|
118
|
+
rows.push({
|
|
119
|
+
...accountKeys(harness, account),
|
|
120
|
+
savedAt: account.savedAt, savedAgo: compactSince(account.savedAt, now, UNAVAILABLE),
|
|
121
|
+
source: 'credential file',
|
|
122
|
+
unavailableReason: account.isStashed ? null : 'This active login is not saved yet; authswitch cannot restore it after a switch.',
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const active = byProviderThenAccount(rows);
|
|
127
|
+
return { schemaVersion: 1, generatedAt: listArg.generatedAt, complete: listArg.complete, active, notes: collectNotes(active) };
|
|
128
|
+
};
|
|
129
|
+
const percent = (rowArg) => rowArg.usedPercent === null ? UNAVAILABLE : `${rowArg.usedPercent}%`;
|
|
130
|
+
/** Condensed presentation for `authswitch limits` and `authswitch active`. */
|
|
131
|
+
export class CondensedRenderer {
|
|
132
|
+
out;
|
|
133
|
+
constructor(out) {
|
|
134
|
+
this.out = out;
|
|
135
|
+
}
|
|
136
|
+
notes(notesArg, prefixArg) {
|
|
137
|
+
if (!notesArg.length)
|
|
138
|
+
return;
|
|
139
|
+
process.stdout.write('\n');
|
|
140
|
+
for (const note of notesArg)
|
|
141
|
+
process.stdout.write(`${dim(`${prefixArg}${note}`)}\n`);
|
|
142
|
+
}
|
|
143
|
+
async renderLimits(limitsArg) {
|
|
144
|
+
consoleHeading('Account limits');
|
|
145
|
+
if (!limitsArg.limits.length) {
|
|
146
|
+
process.stdout.write(`${dim('No harnesses registered.')}\n`);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
await consoleTable(this.out, limitsArg.limits, [
|
|
150
|
+
{ key: 'provider', title: 'Provider', value: row => row.provider },
|
|
151
|
+
{ key: 'account', title: 'Account', value: row => row.account ?? UNAVAILABLE, style: row => ({ bold: row.isActive }) },
|
|
152
|
+
{ key: 'limit', title: 'Limit type', value: row => row.limitType ?? UNAVAILABLE },
|
|
153
|
+
{ key: 'used', title: 'Used %', value: percent, align: 'right',
|
|
154
|
+
style: row => ({ foreground: row.usedPercent === null ? 'orange' : row.usedPercent >= 100 ? 'red' : undefined }) },
|
|
155
|
+
{ key: 'reset', title: 'Resets in', value: row => row.resetsIn, align: 'right' },
|
|
156
|
+
]);
|
|
157
|
+
this.notes(limitsArg.notes, 'n/a — ');
|
|
158
|
+
}
|
|
159
|
+
async renderActive(activeArg) {
|
|
160
|
+
consoleHeading('Active accounts');
|
|
161
|
+
if (!activeArg.active.length) {
|
|
162
|
+
process.stdout.write(`${dim('No harnesses registered.')}\n`);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
await consoleTable(this.out, activeArg.active, [
|
|
166
|
+
{ key: 'provider', title: 'Provider', value: row => row.provider },
|
|
167
|
+
{ key: 'account', title: 'Account', value: row => row.account ?? NONE,
|
|
168
|
+
style: row => ({ bold: row.account !== null, foreground: row.account === null ? 'orange' : undefined }) },
|
|
169
|
+
// The absolute timestamp stays in --json; one screen is worth more here than one more column.
|
|
170
|
+
{ key: 'saved', title: 'Saved', value: row => row.savedAt === null ? (row.account === null ? UNAVAILABLE : 'not saved') : `${row.savedAgo} ago`, align: 'right',
|
|
171
|
+
style: row => ({ foreground: row.savedAt === null && row.account !== null ? 'orange' : undefined }) },
|
|
172
|
+
{ key: 'source', title: 'Source', value: row => row.source,
|
|
173
|
+
style: row => ({ foreground: row.source === 'credential file' ? 'green' : 'orange' }) },
|
|
174
|
+
]);
|
|
175
|
+
this.notes(activeArg.notes, 'note — ');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5saW1pdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLmxpbWl0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNoRixPQUFPLEVBQUUsY0FBYyxFQUFFLFlBQVksRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRXhFLE9BQU8sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFJakQsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDO0FBQzFCLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQztBQUVwQjs7Ozs7R0FLRztBQUNILE1BQU0sWUFBWSxHQUFHLENBQUMsVUFBK0IsRUFBRSxVQUEyQixFQUFVLEVBQUU7SUFDNUYsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFrQixFQUFFLENBQUMsSUFBSSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDL0gsT0FBTyxVQUFVLEVBQUUsTUFBTSxLQUFLLFNBQVMsSUFBSSxLQUFLLENBQUMsSUFBSSxHQUFHLENBQUM7UUFDdkQsQ0FBQyxDQUFDLEdBQUcsU0FBUyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsTUFBTSxTQUFTLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFO1FBQ3BFLENBQUMsQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQ2xDLENBQUMsQ0FBQztBQUVGOzs7OztHQUtHO0FBQ0gsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLFVBQTBCLEVB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
|
|
@@ -23,6 +23,8 @@ export declare class OpenCodeHarness extends FileHarness {
|
|
|
23
23
|
private readonly fetcher?;
|
|
24
24
|
constructor(options?: IOpenCodeHarnessOptions);
|
|
25
25
|
protected beforeMutation(): void;
|
|
26
|
+
/** Every provider entry lives in one file, so its bytes are the whole stability proof. */
|
|
27
|
+
protected nativeSources(): (string | null)[];
|
|
26
28
|
/** Public identity only, for reconciling a host's OpenAI association after native refresh/restart. */
|
|
27
29
|
activeOpenAiAccountId(): string | undefined;
|
|
28
30
|
beginLogin(options?: IHarnessLoginOptions): Promise<import("./interfaces.harness.js").IHarnessLoginHandle>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as plugins from './plugins.js';
|
|
2
2
|
import { FileHarness } from './classes.fileharness.js';
|
|
3
|
-
import { CredentialStore, credentialHash, credentialRecord, credentialText, readCredentialDocument, requireHarnessStopped } from './classes.credentialstore.js';
|
|
3
|
+
import { CredentialStore, credentialHash, credentialRecord, credentialText, readCredentialDocument, readCredentialRaw, requireHarnessStopped } from './classes.credentialstore.js';
|
|
4
4
|
import { CodexAccountStatus } from './classes.codexstatus.js';
|
|
5
5
|
import { writeSecretFileAtomically } from './helpers.js';
|
|
6
6
|
import { beginSavedOpenAiLogin, openCodeCredentialFromLogin } from './classes.login.js';
|
|
@@ -27,6 +27,8 @@ export class OpenCodeHarness extends FileHarness {
|
|
|
27
27
|
this.checkStopped = options.checkStopped ?? (() => requireHarnessStopped('opencode'));
|
|
28
28
|
}
|
|
29
29
|
beforeMutation() { this.checkStopped(); }
|
|
30
|
+
/** Every provider entry lives in one file, so its bytes are the whole stability proof. */
|
|
31
|
+
nativeSources() { return [readCredentialRaw(this.file)]; }
|
|
30
32
|
/** Public identity only, for reconciling a host's OpenAI association after native refresh/restart. */
|
|
31
33
|
activeOpenAiAccountId() {
|
|
32
34
|
const account = this.snapshot().accounts.find(item => item.slotId === 'openai');
|
|
@@ -122,4 +124,4 @@ export class OpenCodeHarness extends FileHarness {
|
|
|
122
124
|
], problems: [] };
|
|
123
125
|
}
|
|
124
126
|
}
|
|
125
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
127
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5vcGVuY29kZWhhcm5lc3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLm9wZW5jb2RlaGFybmVzcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsV0FBVyxFQUFnRCxNQUFNLDBCQUEwQixDQUFDO0FBQ3JHLE9BQU8sRUFBRSxlQUFlLEVBQUUsY0FBYyxFQUFFLGdCQUFnQixFQUFFLGNBQWMsRUFBRSxzQkFBc0IsRUFBRSxpQkFBaUIsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ25MLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzlELE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUV6RCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN4RixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFXNUMsb0dBQW9HO0FBQ3BHLE1BQU0sT0FBTyxlQUFnQixTQUFRLFdBQVc7SUFDOUIsRUFBRSxHQUFHLFVBQVUsQ0FBQztJQUNoQixLQUFLLEdBQUcsVUFBVSxDQUFDO0lBQ25CLFNBQVMsR0FBRyx3RkFBd0YsQ0FBQztJQUNyRyxjQUFjLEdBQTRCLENBQUMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3RHLEtBQUssQ0FBa0I7SUFDekIsSUFBSSxDQUFTO0lBQ2IsR0FBRyxDQUFvQjtJQUN2QixNQUFNLENBQXFCO0lBQzNCLFlBQVksQ0FBYTtJQUN6QixPQUFPLENBQWdCO0lBRXhDLFlBQVksVUFBbUMsRUFBRTtRQUMvQyxLQUFLLEVBQUUsQ0FBQztRQUNSLElBQUksQ0FB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
|
package/dist_ts/helpers.d.ts
CHANGED
|
@@ -17,6 +17,15 @@ import type { IRemoteControlEnrollment, TEnrollmentState } from './interfaces.js
|
|
|
17
17
|
* content or the new one, never a partial write.
|
|
18
18
|
*/
|
|
19
19
|
export declare const writeSecretFileAtomically: (destinationPathArg: string, contentArg: string) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Blocks the calling thread for `millisecondsArg`.
|
|
22
|
+
*
|
|
23
|
+
* Credential reads are synchronous all the way down, so a retry that re-reads
|
|
24
|
+
* immediately can land inside the very same in-flight write it is retrying past.
|
|
25
|
+
* `Atomics.wait` on a private buffer is the only synchronous pause Node offers,
|
|
26
|
+
* and the callers bound both the count and the duration.
|
|
27
|
+
*/
|
|
28
|
+
export declare const pauseSynchronously: (millisecondsArg: number) => void;
|
|
20
29
|
/**
|
|
21
30
|
* Trims third-party process output down to something safe to put in an error
|
|
22
31
|
* message: one line, length-capped, and never empty.
|
package/dist_ts/helpers.js
CHANGED
|
@@ -48,6 +48,17 @@ export const writeSecretFileAtomically = (destinationPathArg, contentArg) => {
|
|
|
48
48
|
}
|
|
49
49
|
plugins.fs.chmodSync(destinationPathArg, 0o600);
|
|
50
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Blocks the calling thread for `millisecondsArg`.
|
|
53
|
+
*
|
|
54
|
+
* Credential reads are synchronous all the way down, so a retry that re-reads
|
|
55
|
+
* immediately can land inside the very same in-flight write it is retrying past.
|
|
56
|
+
* `Atomics.wait` on a private buffer is the only synchronous pause Node offers,
|
|
57
|
+
* and the callers bound both the count and the duration.
|
|
58
|
+
*/
|
|
59
|
+
export const pauseSynchronously = (millisecondsArg) => {
|
|
60
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, millisecondsArg);
|
|
61
|
+
};
|
|
51
62
|
/**
|
|
52
63
|
* Trims third-party process output down to something safe to put in an error
|
|
53
64
|
* message: one line, length-capped, and never empty.
|
|
@@ -89,4 +100,4 @@ export const describeCodexFailure = (binaryArg, stdoutArg, stderrArg, spawnError
|
|
|
89
100
|
}
|
|
90
101
|
return summariseProcessOutput(stdoutArg, stderrArg, spawnErrorArg);
|
|
91
102
|
};
|
|
92
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
103
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2hlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFHeEM7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFDSCxNQUFNLENBQUMsTUFBTSx5QkFBeUIsR0FBRyxDQUN2QyxrQkFBMEIsRUFDMUIsVUFBa0IsRUFDWixFQUFFO0lBQ1IsTUFBTSxRQUFRLEdBQUcsR0FBRyxrQkFBa0IsaUJBQWlCLENBQUM7SUFDeEQsd0VBQXdFO0lBQ3hFLDBFQUEwRTtJQUMxRSxzREFBc0Q7SUFDdEQsSUFBSSxPQUFPLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1FBQ3BDLE9BQU8sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFFRCxJQUFJLE1BQU0sR0FBa0IsSUFBSSxDQUFDO0lBQ2pDLElBQUksQ0FBQztRQUNILE1BQU0sR0FBRyxPQUFPLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3BELE9BQU8sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNyQyxPQUFPLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsVUFBVSxFQUFFLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDbkUsT0FBTyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDN0IsT0FBTyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDN0IsTUFBTSxHQUFHLElBQUksQ0FBQztRQUNkLE9BQU8sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO0lBQ3RELENBQUM7SUFBQyxPQUFPLFFBQVEsRUFBRSxDQUFDO1FBQ2xCLElBQUksTUFBTSxLQUFLLElBQUksRUFBRSxDQUFDO1lBQ3BCLElBQUksQ0FBQztnQkFDSCxPQUFPLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUMvQixDQUFDO1lBQUMsTUFBTSxDQUFDO2dCQUNQLDRDQUE0QztZQUM5QyxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzdDLE1BQU0sUUFBUSxDQUFDO0lBQ2pCLENBQUM7SUFDRCxPQUFPLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxrQkFBa0IsRUFBRSxLQUFLLENBQUMsQ0FBQztBQUNsRCxDQUFDLENBQUM7QUFFRjs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxlQUF1QixFQUFRLEVBQUU7SUFDbEUsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLFVBQVUsQ0FBQyxJQUFJLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxlQUFlLENBQUMsQ0FBQztBQUNoRixDQUFDLENBQUM7QUFFRjs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBRyxDQUNwQyxTQUFpQixFQUNqQixTQUFpQixFQUNqQixhQUE0QixFQUNwQixFQUFFO0lBQ1YsTUFBTSxTQUFTLEdBQUcsQ0FBQyxhQUFhLElBQUksU0FBUyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQyxJQUFJLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNoRixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDZixPQUFPLFdBQVcsQ0FBQztJQUNyQixDQUFDO0lBQ0QsTUFBTSxTQUFTLEdBQUcsU0FBUyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQzNGLE1BQU0sU0FBUyxHQUFHLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNuQyxPQUFPLFNBQVMsQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztBQUM5RSxDQUFDLENBQUM7QUFFRjs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsQ0FBQyxhQUF1QyxFQUFvQixFQUFFO0lBQzNGLElBQUksYUFBYSxDQUFDLG9CQUFvQixLQUFLLElBQUksRUFBRSxDQUFDO1FBQ2hELE9BQU8sVUFBVSxDQUFDO0lBQ3BCLENBQUM7SUFDRCxPQUFPLGFBQWEsQ0FBQyxvQkFBb0IsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDO0FBQzFFLENBQUMsQ0FBQztBQUVGLDZEQUE2RDtBQUM3RCxNQUFNLENBQUMsTUFBTSxXQUFXLEdBQUcsQ0FBQyxjQUEwQyxFQUFVLEVBQUUsQ0FDaEYsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDLGFBQWEsRUFBRSxFQUFFLENBQUMsZUFBZSxDQUFDLGFBQWEsQ0FBQyxLQUFLLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQztBQUUvRjs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxDQUNsQyxTQUFpQixFQUNqQixTQUFpQixFQUNqQixTQUFpQixFQUNqQixhQUE0QixFQUNwQixFQUFFO0lBQ1YsSUFBSSxhQUFhLElBQUksWUFBWSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDO1FBQ3RELE9BQU8sNklBQTZJLENBQUM7SUFDdkosQ0FBQztJQUNELElBQUksYUFBYSxJQUFJLFNBQVMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztRQUNuRCxPQUFPLGtCQUFrQixTQUFTLCtFQUErRSxDQUFDO0lBQ3BILENBQUM7SUFDRCxPQUFPLHNCQUFzQixDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsYUFBYSxDQUFDLENBQUM7QUFDckUsQ0FBQyxDQUFDIn0=
|
|
@@ -17,3 +17,54 @@ export interface IHarnessAccountList {
|
|
|
17
17
|
/** A state lookup failure is distinct from an empty account list. */
|
|
18
18
|
problems: string[];
|
|
19
19
|
}
|
|
20
|
+
/** Credential-free, versioned output of limits --json. One entry per account and limit type. */
|
|
21
|
+
export interface IAccountLimits {
|
|
22
|
+
schemaVersion: 1;
|
|
23
|
+
generatedAt: string;
|
|
24
|
+
complete: boolean;
|
|
25
|
+
limits: IAccountLimitRow[];
|
|
26
|
+
/** Why a row has no numbers. Never a substitute for a value. */
|
|
27
|
+
notes: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface IAccountLimitRow {
|
|
30
|
+
harnessId: string;
|
|
31
|
+
/** Harness label, qualified by the credential slot when the harness owns several. */
|
|
32
|
+
provider: string;
|
|
33
|
+
/** The account's public label, which is its email wherever the provider reports one. */
|
|
34
|
+
account: string | null;
|
|
35
|
+
accountId: string | null;
|
|
36
|
+
slotId?: string;
|
|
37
|
+
isActive: boolean;
|
|
38
|
+
/** The provider's own window name, or null when no limit data is available. */
|
|
39
|
+
limitType: string | null;
|
|
40
|
+
scope: 'account' | 'feature' | null;
|
|
41
|
+
windowSeconds: number | null;
|
|
42
|
+
/** Never inferred: null means the provider reported no percentage, not zero usage. */
|
|
43
|
+
usedPercent: number | null;
|
|
44
|
+
resetAt: string | null;
|
|
45
|
+
/** Human countdown for the same `resetAt`, relative to `generatedAt`. */
|
|
46
|
+
resetsIn: string;
|
|
47
|
+
unavailableReason: string | null;
|
|
48
|
+
}
|
|
49
|
+
/** Credential-free, versioned output of active --json. One entry per active credential slot. */
|
|
50
|
+
export interface IActiveAccounts {
|
|
51
|
+
schemaVersion: 1;
|
|
52
|
+
generatedAt: string;
|
|
53
|
+
complete: boolean;
|
|
54
|
+
active: IActiveAccountRow[];
|
|
55
|
+
notes: string[];
|
|
56
|
+
}
|
|
57
|
+
export interface IActiveAccountRow {
|
|
58
|
+
harnessId: string;
|
|
59
|
+
provider: string;
|
|
60
|
+
account: string | null;
|
|
61
|
+
accountId: string | null;
|
|
62
|
+
slotId?: string;
|
|
63
|
+
/** When authswitch last saved this login; null when it was never stashed. */
|
|
64
|
+
savedAt: string | null;
|
|
65
|
+
/** Human elapsed time for the same `savedAt`, relative to `generatedAt`. */
|
|
66
|
+
savedAgo: string;
|
|
67
|
+
/** Where the shown account comes from. Whether it is also saved is the `savedAt` field's answer. */
|
|
68
|
+
source: 'credential file' | 'stash only' | 'none';
|
|
69
|
+
unavailableReason: string | null;
|
|
70
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modelprofile.com/authswitch",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Manage Codex, OpenCode and Claude Code accounts with guided switching and live usage status",
|
|
6
6
|
"main": "dist_ts/index.js",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@git.zone/tsbuild": "^4.4.3",
|
|
27
27
|
"@git.zone/tsrun": "^2.0.6",
|
|
28
|
-
"@git.zone/tstest": "^6.
|
|
29
|
-
"@types/node": "
|
|
28
|
+
"@git.zone/tstest": "^6.1.1",
|
|
29
|
+
"@types/node": "26.5.0"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@modelprofile.com/flexharness-models": "^7.0.1",
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
"ts/**/*",
|
|
38
38
|
"dist_ts/**/*",
|
|
39
39
|
"cli.js",
|
|
40
|
-
".smartconfig.json",
|
|
41
40
|
"readme.md"
|
|
42
41
|
],
|
|
43
42
|
"browserslist": [
|
package/readme.md
CHANGED
|
@@ -16,11 +16,7 @@ Remote control makes that worse. A ChatGPT client pairs with the local Codex app
|
|
|
16
16
|
|
|
17
17
|
## Install
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
pnpm config set @modelprofile.com:registry https://verdaccio.lossless.digital
|
|
23
|
-
```
|
|
19
|
+
The package is published to npmjs:
|
|
24
20
|
|
|
25
21
|
```bash
|
|
26
22
|
pnpm install -g @modelprofile.com/authswitch
|
|
@@ -57,6 +53,8 @@ authswitch --tui # full-screen account management
|
|
|
57
53
|
authswitch codex --tui # start the dashboard on Codex
|
|
58
54
|
authswitch list # all known accounts across registered harnesses, with live status
|
|
59
55
|
authswitch list --json # complete account/status document for scripts
|
|
56
|
+
authswitch limits # every account and limit type: used % and reset countdown
|
|
57
|
+
authswitch active # which account each provider is using right now
|
|
60
58
|
authswitch codex stash # save the active credential under its account email
|
|
61
59
|
authswitch codex list # Codex accounts, including an unsaved active login, with live status
|
|
62
60
|
authswitch codex use [email] # activate one; prompts when no email is given
|
|
@@ -69,7 +67,7 @@ authswitch opencode stash openai --keep
|
|
|
69
67
|
authswitch opencode use alice@example.com
|
|
70
68
|
authswitch opencode login openai # device login; save the new account without switching
|
|
71
69
|
authswitch codex login # save a new Codex account without disturbing the current login
|
|
72
|
-
authswitch claude stash --keep # save a Claude Code subscriber login
|
|
70
|
+
authswitch claude stash --keep # save a Claude Code subscriber login, while it keeps running
|
|
73
71
|
authswitch claude list --json
|
|
74
72
|
authswitch claude use alice@example.com
|
|
75
73
|
```
|
|
@@ -82,8 +80,15 @@ authswitch coordination, the CLI delegates credential changes to AGL. AGL owns
|
|
|
82
80
|
stopping and restarting its OpenCode runtime. Idle changes need no additional
|
|
83
81
|
restart confirmation; active work requires consent to wait for it to finish.
|
|
84
82
|
Unmanaged native processes must still be exited manually: a terminal session
|
|
85
|
-
cannot safely be reconstructed from its PID.
|
|
86
|
-
|
|
83
|
+
cannot safely be reconstructed from its PID. `stash --keep` is the exception --
|
|
84
|
+
it only reads the native credential files and writes to authswitch's own store,
|
|
85
|
+
so it works while OpenCode or Claude Code is running, and it is refused only if
|
|
86
|
+
those files keep changing while they are read. The operations that replace a
|
|
87
|
+
native login -- `stash` without `--keep`, `use`, and backend activation --
|
|
88
|
+
still require the harness stopped, because a running one holds the outgoing
|
|
89
|
+
token in memory and would write it back over the incoming login at its next
|
|
90
|
+
refresh. Status lookups remain read-only and work while harnesses are running.
|
|
91
|
+
`preuse` remains a Codex capability.
|
|
87
92
|
|
|
88
93
|
`authswitch codex login` and `authswitch opencode login openai` use the shared
|
|
89
94
|
OpenAI device login flow. They display a verification link and code, then save
|
|
@@ -303,12 +308,87 @@ marked unverified. Renewal/cancellation dates are shown only when an adapter can
|
|
|
303
308
|
provide live billing data. Codex uses the desktop app's account-check endpoint for
|
|
304
309
|
automatic renewal, explicit renewal/cancellation dates and subscription expiry.
|
|
305
310
|
|
|
311
|
+
### Condensed views
|
|
312
|
+
|
|
313
|
+
`authswitch limits` answers "how much is left, and when does it come back" in one
|
|
314
|
+
table. It is one row per account **and** limit type, sorted by provider and then by
|
|
315
|
+
account email, with a two-unit countdown (`2h 13m`, `3d 4h`, `45m`, `<1m`, `due`):
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
Account limits
|
|
319
|
+
┌──────────────────────┬─────────────────────────┬───────────────────────┬────────┬───────────────┐
|
|
320
|
+
│ Provider │ Account │ Limit type │ Used % │ Resets in │
|
|
321
|
+
├──────────────────────┼─────────────────────────┼───────────────────────┼────────┼───────────────┤
|
|
322
|
+
│ Claude Code │ phil@example.com │ Claude weekly │ 88% │ 4d 3h │
|
|
323
|
+
│ Claude Code │ phil@example.com │ Claude five-hour │ 63% │ 1h 2m │
|
|
324
|
+
│ Claude Code │ phil@example.com │ Opus weekly │ 100% │ 4d 3h │
|
|
325
|
+
│ Codex │ alice@example.com │ Codex secondary │ 12% │ 3d 4h │
|
|
326
|
+
│ Codex │ alice@example.com │ Codex primary │ 37% │ 2h 13m │
|
|
327
|
+
│ Codex │ alice@example.com │ Code review secondary │ 100% │ 3h 59m │
|
|
328
|
+
│ Codex │ bob@example.com │ n/a │ n/a │ n/a │
|
|
329
|
+
│ OpenCode / anthropic │ anthropic API key 20e75 │ n/a │ n/a │ n/a │
|
|
330
|
+
│ │ 1c3b707 │ │ │ │
|
|
331
|
+
│ OpenCode / openai │ alice@example.com │ Codex primary │ 0% │ not scheduled │
|
|
332
|
+
└──────────────────────┴─────────────────────────┴───────────────────────┴────────┴───────────────┘
|
|
333
|
+
|
|
334
|
+
n/a — Codex · bob@example.com: Subscription and limits: Login expired or was rejected.
|
|
335
|
+
n/a — OpenCode / anthropic · anthropic API key 20e751c3b707: This provider login does not expose a supported subscription or quota API.
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
A number is never invented. An account whose provider exposes no quota API, whose
|
|
339
|
+
lookup failed, or whose login cannot be read shows `n/a` in **Used %** and
|
|
340
|
+
**Resets in**, and the footnote under the table says why — one line per distinct
|
|
341
|
+
reason. A provider is never dropped from the table for lacking data, and one failed
|
|
342
|
+
account never blanks another's numbers. `not scheduled` means the provider reported
|
|
343
|
+
usage without a reset deadline; it is not the same as `n/a`.
|
|
344
|
+
|
|
345
|
+
Limit types are the provider's own window names, ordered general-before-feature and
|
|
346
|
+
weekly-first within an account. The provider column names the harness, qualified by
|
|
347
|
+
the credential slot when a harness owns several (`OpenCode / openai`).
|
|
348
|
+
|
|
349
|
+
`authswitch active` answers "what am I logged in as" for every harness at once:
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
Active accounts
|
|
353
|
+
┌──────────────────────┬────────────────────────────────┬────────────┬─────────────────┐
|
|
354
|
+
│ Provider │ Account │ Saved │ Source │
|
|
355
|
+
├──────────────────────┼────────────────────────────────┼────────────┼─────────────────┤
|
|
356
|
+
│ Claude Code │ phil@example.com │ 45m ago │ credential file │
|
|
357
|
+
│ Codex │ alice@example.com │ 2h 13m ago │ credential file │
|
|
358
|
+
│ Flex │ none │ n/a │ none │
|
|
359
|
+
│ OpenCode / anthropic │ anthropic API key 20e751c3b707 │ 30d ago │ credential file │
|
|
360
|
+
│ OpenCode / openai │ alice@example.com │ not saved │ credential file │
|
|
361
|
+
└──────────────────────┴────────────────────────────────┴────────────┴─────────────────┘
|
|
362
|
+
|
|
363
|
+
note — OpenCode / openai · alice@example.com: This active login is not saved yet; authswitch cannot restore it after a switch.
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Source** is where the shown login comes from: `credential file` is the harness's
|
|
367
|
+
own live credential, `stash only` means nothing is active and only saved copies
|
|
368
|
+
exist, `none` means neither. **Saved** is how long ago `authswitch` last saved that
|
|
369
|
+
login, or `not saved` — which is also the warning that a switch could not bring it
|
|
370
|
+
back. A harness with no active login keeps its row and explains itself in a note.
|
|
371
|
+
|
|
372
|
+
Both commands accept a harness qualifier (`authswitch claude limits`) and `--json`.
|
|
373
|
+
Both are read-only: they never activate, save or clear a login, they need no harness
|
|
374
|
+
stopped, and every provider lookup is bounded by the same 10-second timeout and
|
|
375
|
+
isolated per account as `authswitch list`.
|
|
376
|
+
|
|
306
377
|
### JSON output
|
|
307
378
|
|
|
308
379
|
`authswitch list --json`, `authswitch codex list --json`, and the `ls` alias write
|
|
309
380
|
one JSON document to stdout, with no color, tables or progress messages. `--json`
|
|
310
|
-
may appear before or after the command and requires `list
|
|
311
|
-
combined with a mutation or interactive mode. Unknown
|
|
381
|
+
may appear before or after the command and requires `list`, `ls`, `limits` or
|
|
382
|
+
`active`. It cannot be combined with a mutation or interactive mode. Unknown
|
|
383
|
+
arguments to these commands exit with 2.
|
|
384
|
+
|
|
385
|
+
`limits --json` emits `IAccountLimits` and `active --json` emits `IActiveAccounts`:
|
|
386
|
+
the same rows as the tables, plus the machine-readable fields the tables condense —
|
|
387
|
+
`accountId`, `slotId`, `scope`, `windowSeconds`, the ISO `resetAt` beside the human
|
|
388
|
+
`resetsIn`, the ISO `savedAt` beside the human `savedAgo`, and the per-row
|
|
389
|
+
`unavailableReason` that the footnotes summarise. Both carry `schemaVersion: 1`, the
|
|
390
|
+
shared `generatedAt` snapshot every countdown is relative to, and `complete`, which
|
|
391
|
+
is false when any account or harness could not be read.
|
|
312
392
|
|
|
313
393
|
The exported `IAccountList` contract contains:
|
|
314
394
|
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts/accounts.ts
CHANGED
|
@@ -19,6 +19,35 @@ export const until = (timestampArg: string | null, nowArg: number): string => {
|
|
|
19
19
|
const hours = Math.floor(minutes % 1440 / 60);
|
|
20
20
|
return [days ? `${days}d` : '', hours ? `${hours}h` : '', minutes % 60 ? `${minutes % 60}min` : ''].filter(Boolean).join(' ');
|
|
21
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* A two-unit countdown for condensed tables: `2h 13m`, `3d 4h`, `45m`.
|
|
24
|
+
*
|
|
25
|
+
* `until` stays the long form used by the list view and the TUI. This one trades the third unit for
|
|
26
|
+
* a column that never wraps, and it never invents a deadline: an unknown or unparseable timestamp is
|
|
27
|
+
* reported as such rather than as zero time remaining.
|
|
28
|
+
*/
|
|
29
|
+
const twoUnits = (millisecondsArg: number): string => {
|
|
30
|
+
const minutes = Math.floor(millisecondsArg / 60000);
|
|
31
|
+
const days = Math.floor(minutes / 1440);
|
|
32
|
+
const hours = Math.floor(minutes % 1440 / 60);
|
|
33
|
+
if (days) return hours ? `${days}d ${hours}h` : `${days}d`;
|
|
34
|
+
if (hours) return minutes % 60 ? `${hours}h ${minutes % 60}m` : `${hours}h`;
|
|
35
|
+
return `${minutes}m`;
|
|
36
|
+
};
|
|
37
|
+
export const compactUntil = (timestampArg: string | null, nowArg: number, unavailableArg = 'n/a'): string => {
|
|
38
|
+
if (timestampArg === null) return 'not scheduled';
|
|
39
|
+
const remaining = Date.parse(timestampArg) - nowArg;
|
|
40
|
+
if (!Number.isFinite(remaining)) return unavailableArg;
|
|
41
|
+
if (remaining <= 0) return 'due';
|
|
42
|
+
return remaining < 60000 ? '<1m' : twoUnits(remaining);
|
|
43
|
+
};
|
|
44
|
+
/** The same two-unit form for a past timestamp, for "saved 3d 4h ago". */
|
|
45
|
+
export const compactSince = (timestampArg: string | null, nowArg: number, unavailableArg = 'n/a'): string => {
|
|
46
|
+
if (timestampArg === null) return unavailableArg;
|
|
47
|
+
const elapsed = nowArg - Date.parse(timestampArg);
|
|
48
|
+
if (!Number.isFinite(elapsed)) return unavailableArg;
|
|
49
|
+
return elapsed < 60000 ? 'just now' : twoUnits(elapsed);
|
|
50
|
+
};
|
|
22
51
|
export const accountPlan = (rowArg: IAccountRow): string => {
|
|
23
52
|
const subscription = rowArg.status?.summary?.subscription;
|
|
24
53
|
return subscription ? `${plainText(subscription.plan)}${subscription.source === 'stored' ? ' (stored; unverified)' : ' (live)'}` : rowArg.status ? 'Unavailable' : 'Loading';
|