opencode-usage 0.5.8 → 0.5.11
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 +7 -2
- package/dist/commander/services/plugin-adapters.d.ts +0 -5
- package/dist/index.js +68 -3
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -74,11 +74,16 @@ opencode-usage --commander
|
|
|
74
74
|
opencode-usage --commander --commander-port 5000
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+

|
|
78
|
+
|
|
77
79
|
The Commander provides a single-page web UI with:
|
|
78
80
|
|
|
79
|
-
- **Quota Status** - Per-provider account usage with progress bars, thresholds, and stale detection
|
|
80
|
-
- **
|
|
81
|
+
- **Quota Status** - Per-provider account usage with progress bars, configurable thresholds, and stale detection
|
|
82
|
+
- **Multi-Account** - Full multi-account support for Anthropic and Gemini providers
|
|
83
|
+
- **Usage Breakdown** - Daily/monthly token usage table with cost estimates, provider filter, and date range
|
|
81
84
|
- **Account Management** - Add, switch, remove, and re-authenticate accounts
|
|
85
|
+
- **Plugins** - Extensible plugin system for custom providers and integrations
|
|
86
|
+
- **Configuration** - Customizable thresholds, display preferences, and provider settings
|
|
82
87
|
- **Ping** - Verify account connectivity with live PONG/FAIL indicators
|
|
83
88
|
- **Dark mode** toggle
|
|
84
89
|
- Auto-refresh every 5 minutes
|
|
@@ -4,9 +4,4 @@
|
|
|
4
4
|
* Each command is registered via `registerCommand` so the command-runner can
|
|
5
5
|
* execute them as background jobs.
|
|
6
6
|
*/
|
|
7
|
-
/**
|
|
8
|
-
* Proactively refresh Codex tokens that haven't been refreshed in 24+ hours.
|
|
9
|
-
* Keeps tokens fresh so they never silently expire.
|
|
10
|
-
* Safe to call frequently — skips accounts refreshed recently.
|
|
11
|
-
*/
|
|
12
7
|
export declare function proactiveRefreshCodexTokens(): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -366,6 +366,56 @@ function getAccountIdFromJwt(claims) {
|
|
|
366
366
|
const auth = claims?.["https://api.openai.com/auth"];
|
|
367
367
|
return auth?.chatgpt_account_id ?? null;
|
|
368
368
|
}
|
|
369
|
+
async function tryReadCodexCliAuth() {
|
|
370
|
+
try {
|
|
371
|
+
const raw = JSON.parse(await Bun.file(CODEX_CLI_AUTH_PATH).text());
|
|
372
|
+
const tokens = raw.tokens;
|
|
373
|
+
if (!tokens?.access_token)
|
|
374
|
+
return null;
|
|
375
|
+
const accessClaims = decodeJwtPayload(tokens.access_token);
|
|
376
|
+
const idClaims = tokens.id_token ? decodeJwtPayload(tokens.id_token) : null;
|
|
377
|
+
const expiresAt = getExpiryFromJwt(accessClaims) ?? getExpiryFromJwt(idClaims) ?? 0;
|
|
378
|
+
if (expiresAt <= Date.now())
|
|
379
|
+
return null;
|
|
380
|
+
return {
|
|
381
|
+
accessToken: tokens.access_token,
|
|
382
|
+
refreshToken: tokens.refresh_token ?? "",
|
|
383
|
+
idToken: tokens.id_token ?? null,
|
|
384
|
+
accountId: getAccountIdFromJwt(idClaims) ?? getAccountIdFromJwt(accessClaims),
|
|
385
|
+
expiresAt
|
|
386
|
+
};
|
|
387
|
+
} catch {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async function tryImportFromCodexCli(alias, account, storePath) {
|
|
392
|
+
const cli = await tryReadCodexCliAuth();
|
|
393
|
+
if (!cli || !cli.refreshToken)
|
|
394
|
+
return false;
|
|
395
|
+
const pluginAccountId = account.accountId;
|
|
396
|
+
if (!pluginAccountId || cli.accountId !== pluginAccountId)
|
|
397
|
+
return false;
|
|
398
|
+
const pluginExpiry = typeof account.expiresAt === "number" ? account.expiresAt : 0;
|
|
399
|
+
if (cli.expiresAt <= pluginExpiry)
|
|
400
|
+
return false;
|
|
401
|
+
console.log(`[proactiveRefresh] ${alias}: importing fresher token from ~/.codex/auth.json`);
|
|
402
|
+
const freshStore = JSON.parse(await Bun.file(storePath).text());
|
|
403
|
+
const freshAccounts = freshStore.accounts ?? {};
|
|
404
|
+
const freshAcct = freshAccounts[alias];
|
|
405
|
+
if (!freshAcct)
|
|
406
|
+
return false;
|
|
407
|
+
freshAcct.accessToken = cli.accessToken;
|
|
408
|
+
freshAcct.refreshToken = cli.refreshToken;
|
|
409
|
+
if (cli.idToken)
|
|
410
|
+
freshAcct.idToken = cli.idToken;
|
|
411
|
+
freshAcct.expiresAt = cli.expiresAt;
|
|
412
|
+
freshAcct.lastRefresh = new Date().toISOString();
|
|
413
|
+
freshAcct.authInvalid = false;
|
|
414
|
+
await Bun.write(storePath, JSON.stringify(freshStore, null, 2));
|
|
415
|
+
const daysLeft = ((cli.expiresAt - Date.now()) / (24 * 60 * 60 * 1000)).toFixed(1);
|
|
416
|
+
console.log(`[proactiveRefresh] ${alias}: imported from CLI, expiry in ${daysLeft}d`);
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
369
419
|
async function refreshSingleCodexToken(alias, account, storePath) {
|
|
370
420
|
const refreshToken = account.refreshToken;
|
|
371
421
|
if (typeof refreshToken !== "string" || !refreshToken) {
|
|
@@ -385,7 +435,7 @@ async function refreshSingleCodexToken(alias, account, storePath) {
|
|
|
385
435
|
});
|
|
386
436
|
if (!res.ok) {
|
|
387
437
|
console.log(`[proactiveRefresh] ${alias}: refresh failed HTTP ${res.status} in ${Date.now() - t0}ms`);
|
|
388
|
-
return
|
|
438
|
+
return tryImportFromCodexCli(alias, account, storePath);
|
|
389
439
|
}
|
|
390
440
|
const tokens = await res.json();
|
|
391
441
|
const accessClaims = decodeJwtPayload(tokens.access_token);
|
|
@@ -415,6 +465,16 @@ async function refreshSingleCodexToken(alias, account, storePath) {
|
|
|
415
465
|
}
|
|
416
466
|
}
|
|
417
467
|
async function proactiveRefreshCodexTokens() {
|
|
468
|
+
if (_proactiveRefreshRunning)
|
|
469
|
+
return;
|
|
470
|
+
_proactiveRefreshRunning = true;
|
|
471
|
+
try {
|
|
472
|
+
await _proactiveRefreshCodexTokensInner();
|
|
473
|
+
} finally {
|
|
474
|
+
_proactiveRefreshRunning = false;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
async function _proactiveRefreshCodexTokensInner() {
|
|
418
478
|
const STORE_PATHS = [
|
|
419
479
|
join8(homedir6(), ".config", "opencode", "codex-multi-account-accounts.json"),
|
|
420
480
|
join8(homedir6(), ".config", "opencode", "codex-multi-accounts.json"),
|
|
@@ -437,6 +497,10 @@ async function proactiveRefreshCodexTokens() {
|
|
|
437
497
|
const now = Date.now();
|
|
438
498
|
let refreshed = 0;
|
|
439
499
|
for (const [alias, account] of Object.entries(accounts)) {
|
|
500
|
+
if (account.authInvalid === true) {
|
|
501
|
+
console.log(`[proactiveRefresh] ${alias}: authInvalid, skipping (needs reauth)`);
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
440
504
|
const expiresAt = typeof account.expiresAt === "number" ? account.expiresAt : 0;
|
|
441
505
|
const lastRefresh = typeof account.lastRefresh === "string" ? new Date(account.lastRefresh).getTime() : 0;
|
|
442
506
|
const timeSinceRefresh = now - lastRefresh;
|
|
@@ -619,7 +683,7 @@ function reauthCliCommand(provider) {
|
|
|
619
683
|
throw new Error(`Re-auth not supported for provider: ${provider}`);
|
|
620
684
|
return cmd;
|
|
621
685
|
}
|
|
622
|
-
var isBun4, PROVIDER_SOURCE, CODEX_TOKEN_URL = "https://auth.openai.com/oauth/token", CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann", REFRESH_COOLDOWN_MS, bunxQueue, REAUTH_PROVIDERS;
|
|
686
|
+
var isBun4, PROVIDER_SOURCE, CODEX_TOKEN_URL = "https://auth.openai.com/oauth/token", CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann", REFRESH_COOLDOWN_MS, CODEX_CLI_AUTH_PATH, _proactiveRefreshRunning = false, bunxQueue, REAUTH_PROVIDERS;
|
|
623
687
|
var init_plugin_adapters = __esm(() => {
|
|
624
688
|
init_command_runner();
|
|
625
689
|
init_config_service();
|
|
@@ -721,6 +785,7 @@ var init_plugin_adapters = __esm(() => {
|
|
|
721
785
|
}
|
|
722
786
|
});
|
|
723
787
|
REFRESH_COOLDOWN_MS = 24 * 60 * 60 * 1000;
|
|
788
|
+
CODEX_CLI_AUTH_PATH = join8(homedir6(), ".codex", "auth.json");
|
|
724
789
|
bunxQueue = new Map;
|
|
725
790
|
registerCommand({
|
|
726
791
|
id: "accounts.ping",
|
|
@@ -31158,4 +31223,4 @@ async function main2() {
|
|
|
31158
31223
|
var WATCH_INTERVAL_MS = 5 * 60 * 1000;
|
|
31159
31224
|
main2().catch(console.error);
|
|
31160
31225
|
|
|
31161
|
-
//# debugId=
|
|
31226
|
+
//# debugId=F9964D445D944A6564756E2164756E21
|