@carjms/codexswitch 0.3.4 → 0.3.5
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.ko.md +2 -1
- package/README.md +2 -1
- package/package.json +1 -1
- package/src/cli.js +50 -3
- package/src/util.js +1 -0
package/README.ko.md
CHANGED
|
@@ -203,7 +203,8 @@ cxs list # 계정별 5h/week 사용량 % 확인
|
|
|
203
203
|
| `cxs login [이름]` | 새 계정 로그인 후 저장 (기존 로그인 유지, 이름 생략 시 이메일 사용) |
|
|
204
204
|
| `cxs import [이름]` | 현재 `~/.codex`에 로그인된 계정을 저장소로 가져오기 |
|
|
205
205
|
| `cxs add-key <이름> [키]` | OpenAI API 키 계정 등록 (키 생략 시 `$OPENAI_API_KEY` 사용) |
|
|
206
|
-
| `cxs list` | 계정 목록: 활성
|
|
206
|
+
| `cxs list` | 계정 목록: 활성 표시, 이메일, 플랜, 우선순위, 한도 상태, 사용량 % |
|
|
207
|
+
| `cxs usage [이름]` | 계정별 사용량 대시보드: 5시간/주간 게이지 바, 리셋 카운트다운, 다음 로테이션 계정 (별칭: `status`) |
|
|
207
208
|
| `cxs use <이름>` | 활성 계정 전환 |
|
|
208
209
|
| `cxs current` | 현재 활성 계정 확인 |
|
|
209
210
|
| `cxs next` | 설정된 순서의 다음 계정으로 전환 (끝에 오면 처음으로 순환) |
|
package/README.md
CHANGED
|
@@ -205,7 +205,8 @@ cxs list # per-account 5h/week usage columns
|
|
|
205
205
|
| `cxs login [name]` | Log in to a new account and store it (existing login untouched; defaults to the email as the name) |
|
|
206
206
|
| `cxs import [name]` | Import the account currently in `~/.codex` |
|
|
207
207
|
| `cxs add-key <name> [key]` | Register an OpenAI API-key account (falls back to `$OPENAI_API_KEY`) |
|
|
208
|
-
| `cxs list` | List accounts: active marker
|
|
208
|
+
| `cxs list` | List accounts: active marker, email, plan, priority, limit status, usage % |
|
|
209
|
+
| `cxs usage [name]` | Per-account usage dashboard: 5h/weekly gauge bars, reset countdowns, next rotation pick (alias: `status`) |
|
|
209
210
|
| `cxs use <name>` | Switch the active account |
|
|
210
211
|
| `cxs current` | Show the active account |
|
|
211
212
|
| `cxs next` | Switch to the next account in rotation order (wraps around) |
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -14,7 +14,9 @@ Accounts
|
|
|
14
14
|
login [name] log in to a new account (isolated "codex login") and store it
|
|
15
15
|
import [name] import the account currently in ~/.codex/auth.json
|
|
16
16
|
add-key <name> [key] register an OpenAI API-key account (or read $OPENAI_API_KEY)
|
|
17
|
-
list list stored accounts (alias: accounts
|
|
17
|
+
list list stored accounts (alias: accounts)
|
|
18
|
+
usage [name] per-account 5h/weekly usage gauges with reset times
|
|
19
|
+
(alias: status)
|
|
18
20
|
use <name> make <name> the active account in ~/.codex
|
|
19
21
|
current show the active account
|
|
20
22
|
next switch to the next account in rotation order (wraps around)
|
|
@@ -341,6 +343,49 @@ function cmdModel(args) {
|
|
|
341
343
|
out(`default model set to "${meta.model}" (applied to run/exec)`);
|
|
342
344
|
}
|
|
343
345
|
|
|
346
|
+
// Per-account usage dashboard: gauge bars for the 5h / weekly windows with
|
|
347
|
+
// reset countdowns, based on what codex recorded in its session files.
|
|
348
|
+
function cmdUsage(args) {
|
|
349
|
+
const meta = store.loadMeta();
|
|
350
|
+
let accounts = store.listAccounts();
|
|
351
|
+
if (args[0]) {
|
|
352
|
+
accounts = accounts.filter((a) => a.name === args[0]);
|
|
353
|
+
if (accounts.length === 0) throw new Error(`no such account: ${args[0]}`);
|
|
354
|
+
}
|
|
355
|
+
if (accounts.length === 0) {
|
|
356
|
+
out('no accounts yet — add one with "codexswitch login" or "codexswitch import"');
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const now = Date.now();
|
|
360
|
+
const bar = (pct, threshold) => {
|
|
361
|
+
const width = 20;
|
|
362
|
+
const filled = Math.max(0, Math.min(width, Math.round((pct / 100) * width)));
|
|
363
|
+
const paint = pct >= threshold ? ui.red : pct >= 70 ? ui.yellow : ui.green;
|
|
364
|
+
return `[${paint('█'.repeat(filled))}${ui.dim('░'.repeat(width - filled))}]`;
|
|
365
|
+
};
|
|
366
|
+
const line = (label, win, threshold) => {
|
|
367
|
+
if (!win || typeof win.pct !== 'number') return ` ${label} ${ui.dim('no data')}`;
|
|
368
|
+
const pct = Math.round(win.pct);
|
|
369
|
+
const reset = win.resetAt && win.resetAt > now ? ` resets in ${fmtRemaining(win.resetAt)}` : '';
|
|
370
|
+
const overMark = win.pct >= threshold ? ` ${ui.red(`≥ threshold ${threshold}%`)}` : '';
|
|
371
|
+
return ` ${label} ${bar(win.pct, threshold)} ${String(pct).padStart(3)}%${ui.dim(reset)}${overMark}`;
|
|
372
|
+
};
|
|
373
|
+
for (const a of accounts) {
|
|
374
|
+
const mark = a.active ? ui.green('●') : ' ';
|
|
375
|
+
const state = a.disabled ? ui.red(' [disabled]') : a.limitedUntil && a.limitedUntil > now ? ui.yellow(` [limited ${fmtRemaining(a.limitedUntil)}]`) : '';
|
|
376
|
+
out(`${mark} ${ui.bold(a.name)}${ui.dim(` (${a.plan || a.email || '-'})`)}${state}`);
|
|
377
|
+
if (!a.usage) {
|
|
378
|
+
out(ui.dim(' no usage data yet — codex records it during runs (try "codexswitch run" once)'));
|
|
379
|
+
} else {
|
|
380
|
+
out(line('5h ', a.usage.p5h, meta.threshold5h));
|
|
381
|
+
out(line('weekly', a.usage.weekly, meta.thresholdWeekly));
|
|
382
|
+
if (a.usage.at) out(ui.dim(` measured ${fmtDate(a.usage.at)}`));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const next = store.pickAccount();
|
|
386
|
+
out(ui.dim(`\nrotation would pick: ${next ? next.name : '(none usable)'} · threshold 5h ${meta.threshold5h}% / weekly ${meta.thresholdWeekly}%`));
|
|
387
|
+
}
|
|
388
|
+
|
|
344
389
|
// Rotate-early thresholds: how full the 5h / weekly window may get before
|
|
345
390
|
// the account is skipped in rotation.
|
|
346
391
|
function cmdThreshold(args) {
|
|
@@ -424,7 +469,7 @@ function cmdNames() {
|
|
|
424
469
|
}
|
|
425
470
|
|
|
426
471
|
const COMMANDS =
|
|
427
|
-
'login import add-key list use current next run exec order model remove rename ' +
|
|
472
|
+
'login import add-key list usage use current next run exec order model remove rename ' +
|
|
428
473
|
'enable disable priority clear-limit cooldown threshold patterns export restore sync completion help';
|
|
429
474
|
|
|
430
475
|
function cmdCompletion(args) {
|
|
@@ -595,8 +640,10 @@ async function main(argv) {
|
|
|
595
640
|
return cmdImport(args), 0;
|
|
596
641
|
case 'list':
|
|
597
642
|
case 'accounts':
|
|
598
|
-
case 'status':
|
|
599
643
|
return cmdList(), 0;
|
|
644
|
+
case 'usage':
|
|
645
|
+
case 'status':
|
|
646
|
+
return cmdUsage(args), 0;
|
|
600
647
|
case 'use':
|
|
601
648
|
return cmdUse(args), 0;
|
|
602
649
|
case 'current':
|
package/src/util.js
CHANGED