Skip to content

Commit d981715

Browse files
committed
feat: expose account selection reasons
1 parent 7fe8e65 commit d981715

4 files changed

Lines changed: 45 additions & 1 deletion

File tree

lib/codex-manager/commands/report.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,13 @@ export async function runReportCommand(
481481
activeIndex: accountCount > 0 ? activeIndex + 1 : null,
482482
forecast: {
483483
summary: forecastSummary,
484-
recommendation,
484+
recommendation: {
485+
...recommendation,
486+
selectedReason:
487+
recommendation.recommendedIndex !== null
488+
? forecastResults[recommendation.recommendedIndex]?.reasons[0] ?? recommendation.reason
489+
: recommendation.reason,
490+
},
485491
probeErrors,
486492
accounts: serializeForecastResults(
487493
forecastResults,
@@ -491,6 +497,13 @@ export async function runReportCommand(
491497
),
492498
},
493499
};
500+
if (report.forecast.recommendation.recommendedIndex !== null) {
501+
const selectedIndex = report.forecast.recommendation.recommendedIndex;
502+
const selected = report.forecast.accounts[selectedIndex];
503+
if (selected) {
504+
selected.selected = true;
505+
}
506+
}
494507

495508
const cwd = deps.getCwd?.() ?? process.cwd();
496509
if (options.outPath) {

lib/codex-manager/commands/status.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import {
33
formatCooldown,
44
formatWaitTime,
55
} from "../../accounts.js";
6+
import {
7+
evaluateForecastAccounts,
8+
recommendForecastAccount,
9+
} from "../../forecast.js";
610
import type { ModelFamily } from "../../prompts/codex.js";
711
import type { AccountStorageV3 } from "../../storage.js";
812

@@ -40,8 +44,22 @@ export async function runStatusCommand(
4044

4145
const now = deps.getNow?.() ?? Date.now();
4246
const activeIndex = deps.resolveActiveIndex(storage, "codex");
47+
const forecastResults = evaluateForecastAccounts(
48+
storage.accounts.map((account, index) => ({
49+
index,
50+
account,
51+
isCurrent: index === activeIndex,
52+
now,
53+
})),
54+
);
55+
const recommendation = recommendForecastAccount(forecastResults);
4356
logInfo(`Accounts (${storage.accounts.length})`);
4457
logInfo(`Storage: ${path}`);
58+
if (recommendation.recommendedIndex !== null) {
59+
logInfo(
60+
`Selection reason: account ${recommendation.recommendedIndex + 1} (${recommendation.reason})`,
61+
);
62+
}
4563
logInfo("");
4664

4765
for (let i = 0; i < storage.accounts.length; i += 1) {
@@ -61,6 +79,10 @@ export async function runStatusCommand(
6179
? `used ${formatWaitTime(now - account.lastUsed)} ago`
6280
: "never used";
6381
logInfo(`${i + 1}. ${label}${markerLabel} ${lastUsed}`);
82+
const primaryReason = forecastResults[i]?.reasons[0];
83+
if (primaryReason) {
84+
logInfo(` reason: ${primaryReason}`);
85+
}
6486
}
6587

6688
return 0;

test/codex-manager-report-command.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,9 @@ describe("runReportCommand", () => {
257257
"token expired",
258258
);
259259
expect(jsonOutput.forecast.accounts[3]?.liveQuota?.planType).toBe("pro");
260+
expect(jsonOutput.forecast.recommendation.selectedReason).toEqual(
261+
expect.any(String),
262+
);
260263
});
261264

262265
it("reuses usable access tokens for live probes without forcing refresh", async () => {

test/codex-manager-status-command.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,17 @@ describe("runStatusCommand", () => {
6868
expect(deps.getStoragePath).toHaveBeenCalledTimes(1);
6969
expect(deps.logInfo).toHaveBeenCalledWith("Accounts (2)");
7070
expect(deps.logInfo).toHaveBeenCalledWith("Storage: /tmp/codex.json");
71+
expect(deps.logInfo).toHaveBeenCalledWith(
72+
expect.stringContaining("Selection reason: account 1"),
73+
);
7174
expect(deps.logInfo).toHaveBeenCalledWith(
7275
expect.stringContaining(
7376
"1. Account 1 (one@example.com) [current, rate-limited]",
7477
),
7578
);
79+
expect(deps.logInfo).toHaveBeenCalledWith(
80+
expect.stringContaining("reason:"),
81+
);
7682
expect(deps.logInfo).toHaveBeenCalledWith(
7783
expect.stringContaining(
7884
"2. Account 2 (two@example.com) [disabled, rate-limited]",

0 commit comments

Comments
 (0)