Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/commands/list.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

```shell
codex-auth list
codex-auth list --active
codex-auth list --live
codex-auth list --api
codex-auth list --skip-api
Expand All @@ -20,6 +21,7 @@ codex-auth list --skip-api
## Refresh Modes

- Default mode performs foreground usage and account-name API refresh.
- `--active` refreshes usage only for the active account before rendering and skips account-name API refresh. Other rows use stored registry snapshots.
- `--api` is accepted as an explicit equivalent to default mode.
- `--skip-api` forbids remote API calls for this command.
- `--live` keeps refreshing the terminal view and requires a TTY.
Expand Down
5 changes: 5 additions & 0 deletions src/cli/commands/list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ pub fn parse(allocator: std.mem.Allocator, args: []const [:0]const u8) !types.Pa
opts.live = true;
continue;
}
if (std.mem.eql(u8, arg, "--active")) {
if (opts.active_only) return common.usageErrorResult(allocator, .list, "duplicate `--active` for `list`.", .{});
opts.active_only = true;
continue;
}
if (std.mem.eql(u8, arg, "--api")) {
switch (opts.api_mode) {
.default => opts.api_mode = .force_api,
Expand Down
6 changes: 4 additions & 2 deletions src/cli/help.zig
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub fn writeHelp(
try writeCommandSummary(out, use_color, "--help, -h", "Show this help");
try writeCommandSummary(out, use_color, "help <command>", "Show command-specific help");
try writeCommandSummary(out, use_color, "--version, -V", "Show version");
try writeCommandSummary(out, use_color, "list [--live] [--api|--skip-api]", "List available accounts");
try writeCommandSummary(out, use_color, "list [--live] [--active] [--api|--skip-api]", "List available accounts");
try writeCommandSummary(out, use_color, "status", "Show auto-switch and service status");
try writeCommandSummary(out, use_color, "login [--device-auth]", "Login and add the current account");
try writeCommandSummary(out, use_color, "import", "Import auth files or rebuild registry");
Expand Down Expand Up @@ -202,7 +202,7 @@ fn writeUsageLines(out: *std.Io.Writer, topic: HelpTopic) !void {
try out.writeAll(" codex-auth --help\n");
try out.writeAll(" codex-auth help <command>\n");
},
.list => try out.writeAll(" codex-auth list [--live] [--api|--skip-api]\n"),
.list => try out.writeAll(" codex-auth list [--live] [--active] [--api|--skip-api]\n"),
.status => try out.writeAll(" codex-auth status\n"),
.login => {
try out.writeAll(" codex-auth login\n");
Expand Down Expand Up @@ -267,6 +267,7 @@ fn writeOptionLines(out: *std.Io.Writer, topic: HelpTopic) !void {
switch (topic) {
.list => {
try out.writeAll(" --live Open a live-updating table.\n");
try out.writeAll(" --active Refresh only the active account before rendering.\n");
try out.writeAll(" --api Load usage and account data from APIs.\n");
try out.writeAll(" --skip-api Load usage and account data from local data only (may be inaccurate).\n");
},
Expand Down Expand Up @@ -330,6 +331,7 @@ fn writeExampleLines(out: *std.Io.Writer, topic: HelpTopic) !void {
},
.list => {
try out.writeAll(" codex-auth list\n");
try out.writeAll(" codex-auth list --active\n");
try out.writeAll(" codex-auth list --live\n");
try out.writeAll(" codex-auth list --api\n");
try out.writeAll(" codex-auth list --skip-api\n");
Expand Down
1 change: 1 addition & 0 deletions src/cli/types.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub const ApiMode = enum {
pub const ListOptions = struct {
live: bool = false,
api_mode: ApiMode = .default,
active_only: bool = false,
};
pub const LoginOptions = struct {
device_auth: bool = false,
Expand Down
7 changes: 4 additions & 3 deletions src/workflows/list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const maybeRefreshForegroundAccountNamesWithAccountApiEnabled = account_names.ma
const ensureLiveTty = preflight.ensureLiveTty;
const apiModeUsesApi = preflight.apiModeUsesApi;
const ensureForegroundNodeAvailableWithApiEnabled = preflight.ensureForegroundNodeAvailableWithApiEnabled;
const refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabled = usage_refresh.refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabled;
const refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledAndActiveOnly = usage_refresh.refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledAndActiveOnly;
const loadInitialLiveSelectionDisplay = live_flow.loadInitialLiveSelectionDisplay;
const SwitchLiveRuntime = live_flow.SwitchLiveRuntime;
const switchLiveRuntimeMaybeStartRefresh = live_flow.switchLiveRuntimeMaybeStartRefresh;
Expand Down Expand Up @@ -74,7 +74,7 @@ pub fn handleList(allocator: std.mem.Allocator, codex_home: []const u8, opts: cl
}

const usage_api_enabled = apiModeUsesApi(reg.api.usage, opts.api_mode);
const account_api_enabled = apiModeUsesApi(reg.api.account, opts.api_mode);
const account_api_enabled = apiModeUsesApi(reg.api.account, opts.api_mode) and !opts.active_only;

try ensureForegroundNodeAvailableWithApiEnabled(
allocator,
Expand All @@ -85,11 +85,12 @@ pub fn handleList(allocator: std.mem.Allocator, codex_home: []const u8, opts: cl
account_api_enabled,
);

var usage_state = try refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabled(
var usage_state = try refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledAndActiveOnly(
allocator,
codex_home,
&reg,
usage_api_enabled,
opts.active_only,
);
defer usage_state.deinit(allocator);
try maybeRefreshForegroundAccountNamesWithAccountApiEnabled(
Expand Down
2 changes: 2 additions & 0 deletions src/workflows/root.zig
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ pub const max_usage_override_display_width = usage_refresh.max_usage_override_di
pub const formatStatusOverrideAlloc = usage_refresh.formatStatusOverrideAlloc;
pub const refreshForegroundUsageForDisplayWithApiFetcher = usage_refresh.refreshForegroundUsageForDisplayWithApiFetcher;
pub const refreshForegroundUsageForDisplay = usage_refresh.refreshForegroundUsageForDisplay;
pub const refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledAndActiveOnly = usage_refresh.refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledAndActiveOnly;
pub const refreshForegroundUsageForDisplayWithApiFetcherWithPoolInit = usage_refresh.refreshForegroundUsageForDisplayWithApiFetcherWithPoolInit;
pub const refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnabledAndPersistAndActiveOnly = usage_refresh.refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnabledAndPersistAndActiveOnly;
const refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabled = usage_refresh.refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabled;
const refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnabledAndPersist = usage_refresh.refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnabledAndPersist;
pub const initForegroundUsagePool = usage_refresh.initForegroundUsagePool;
Expand Down
134 changes: 125 additions & 9 deletions src/workflows/usage.zig
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ pub fn refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabled(
reg: *registry.Registry,
usage_api_enabled: bool,
) !ForegroundUsageRefreshState {
return refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledWithBatchFailurePolicy(
return refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledAndActiveOnly(
allocator,
codex_home,
reg,
Expand All @@ -131,14 +131,49 @@ pub fn refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabled(
);
}

pub fn refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledAndActiveOnly(
allocator: std.mem.Allocator,
codex_home: []const u8,
reg: *registry.Registry,
usage_api_enabled: bool,
active_only: bool,
) !ForegroundUsageRefreshState {
return refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledWithBatchFailurePolicyAndActiveOnly(
allocator,
codex_home,
reg,
usage_api_enabled,
false,
active_only,
);
}

pub fn refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledWithBatchFailurePolicy(
allocator: std.mem.Allocator,
codex_home: []const u8,
reg: *registry.Registry,
usage_api_enabled: bool,
batch_fetch_failures_are_fatal: bool,
) !ForegroundUsageRefreshState {
return refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnabled(
return refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledWithBatchFailurePolicyAndActiveOnly(
allocator,
codex_home,
reg,
usage_api_enabled,
batch_fetch_failures_are_fatal,
false,
);
}

pub fn refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledWithBatchFailurePolicyAndActiveOnly(
allocator: std.mem.Allocator,
codex_home: []const u8,
reg: *registry.Registry,
usage_api_enabled: bool,
batch_fetch_failures_are_fatal: bool,
active_only: bool,
) !ForegroundUsageRefreshState {
return refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnabledAndActiveOnly(
allocator,
codex_home,
reg,
Expand All @@ -147,6 +182,7 @@ pub fn refreshForegroundUsageForDisplayWithBatchFetcherUsingApiEnabledWithBatchF
initForegroundUsagePool,
usage_api_enabled,
batch_fetch_failures_are_fatal,
active_only,
);
}

Expand Down Expand Up @@ -179,7 +215,31 @@ pub fn refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnable
usage_api_enabled: bool,
batch_fetch_failures_are_fatal: bool,
) !ForegroundUsageRefreshState {
return refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnabledAndPersist(
return refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnabledAndActiveOnly(
allocator,
codex_home,
reg,
usage_fetcher,
batch_fetcher,
pool_init,
usage_api_enabled,
batch_fetch_failures_are_fatal,
false,
);
}

pub fn refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnabledAndActiveOnly(
allocator: std.mem.Allocator,
codex_home: []const u8,
reg: *registry.Registry,
usage_fetcher: UsageFetchDetailedFn,
batch_fetcher: ?UsageBatchFetchDetailedFn,
pool_init: ForegroundUsagePoolInitFn,
usage_api_enabled: bool,
batch_fetch_failures_are_fatal: bool,
active_only: bool,
) !ForegroundUsageRefreshState {
return refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnabledAndPersistAndActiveOnly(
allocator,
codex_home,
reg,
Expand All @@ -189,6 +249,7 @@ pub fn refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnable
usage_api_enabled,
batch_fetch_failures_are_fatal,
true,
active_only,
);
}

Expand All @@ -202,6 +263,32 @@ pub fn refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnable
usage_api_enabled: bool,
batch_fetch_failures_are_fatal: bool,
persist_registry: bool,
) !ForegroundUsageRefreshState {
return refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnabledAndPersistAndActiveOnly(
allocator,
codex_home,
reg,
usage_fetcher,
batch_fetcher,
pool_init,
usage_api_enabled,
batch_fetch_failures_are_fatal,
persist_registry,
false,
);
}

pub fn refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnabledAndPersistAndActiveOnly(
allocator: std.mem.Allocator,
codex_home: []const u8,
reg: *registry.Registry,
usage_fetcher: UsageFetchDetailedFn,
batch_fetcher: ?UsageBatchFetchDetailedFn,
pool_init: ForegroundUsagePoolInitFn,
usage_api_enabled: bool,
batch_fetch_failures_are_fatal: bool,
persist_registry: bool,
active_only: bool,
) !ForegroundUsageRefreshState {
var state = try initForegroundUsageRefreshState(allocator, reg.accounts.items.len);
errdefer state.deinit(allocator);
Expand All @@ -215,6 +302,8 @@ pub fn refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnable
}

if (reg.accounts.items.len == 0) return state;
const active_account_key = if (active_only) reg.active_account_key else null;
if (active_only and active_account_key == null) return state;

const worker_results = try allocator.alloc(ForegroundUsageWorkerResult, reg.accounts.items.len);
defer {
Expand All @@ -232,6 +321,10 @@ pub fn refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnable
defer fetch_account_indices.deinit(auth_path_arena);

for (reg.accounts.items, 0..) |account, idx| {
if (active_only) {
const key = active_account_key.?;
if (!std.mem.eql(u8, account.account_key, key)) continue;
}
if (skipsChatGptUsage(&account)) continue;
try fetch_account_indices.append(auth_path_arena, idx);
}
Expand Down Expand Up @@ -276,11 +369,12 @@ pub fn refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnable
batch_result.snapshot = null;
}
} else {
var use_concurrent_usage_refresh = reg.accounts.items.len > 1;
const refresh_job_count: usize = if (active_only) 1 else reg.accounts.items.len;
var use_concurrent_usage_refresh = refresh_job_count > 1;
if (use_concurrent_usage_refresh) {
pool_init(
allocator,
@min(reg.accounts.items.len, foreground_usage_refresh_concurrency),
@min(refresh_job_count, foreground_usage_refresh_concurrency),
) catch |err| switch (err) {
error.OutOfMemory => return err,
else => use_concurrent_usage_refresh = false,
Expand All @@ -294,14 +388,20 @@ pub fn refreshForegroundUsageForDisplayWithApiFetchersWithPoolInitUsingApiEnable
reg,
usage_fetcher,
worker_results,
active_account_key,
active_only,
);
} else {
runForegroundUsageRefreshWorkersSerially(allocator, codex_home, reg, usage_fetcher, worker_results);
runForegroundUsageRefreshWorkersSerially(allocator, codex_home, reg, usage_fetcher, worker_results, active_account_key, active_only);
}
}

var registry_changed = false;
for (worker_results, 0..) |*worker_result, idx| {
if (active_only) {
const key = active_account_key.?;
if (!std.mem.eql(u8, reg.accounts.items[idx].account_key, key)) continue;
}
const outcome = &state.outcomes[idx];
outcome.* = .{
.attempted = true,
Expand Down Expand Up @@ -354,12 +454,18 @@ const ForegroundUsageWorkerQueue = struct {
reg: *registry.Registry,
usage_fetcher: UsageFetchDetailedFn,
results: []ForegroundUsageWorkerResult,
active_account_key: ?[]const u8,
active_only: bool,
next_index: std.atomic.Value(usize) = .init(0),

fn run(self: *ForegroundUsageWorkerQueue) void {
while (true) {
const idx = self.next_index.fetchAdd(1, .monotonic);
if (idx >= self.reg.accounts.items.len) return;
if (self.active_only) {
const key = self.active_account_key.?;
if (!std.mem.eql(u8, self.reg.accounts.items[idx].account_key, key)) continue;
}

foregroundUsageRefreshWorker(
self.allocator,
Expand All @@ -379,10 +485,12 @@ fn runForegroundUsageRefreshWorkersConcurrently(
reg: *registry.Registry,
usage_fetcher: UsageFetchDetailedFn,
results: []ForegroundUsageWorkerResult,
active_account_key: ?[]const u8,
active_only: bool,
) !void {
const worker_count = @min(reg.accounts.items.len, foreground_usage_refresh_concurrency);
const worker_count = @min(if (active_only) 1 else reg.accounts.items.len, foreground_usage_refresh_concurrency);
if (worker_count <= 1) {
runForegroundUsageRefreshWorkersSerially(allocator, codex_home, reg, usage_fetcher, results);
runForegroundUsageRefreshWorkersSerially(allocator, codex_home, reg, usage_fetcher, results, active_account_key, active_only);
return;
}

Expand All @@ -392,6 +500,8 @@ fn runForegroundUsageRefreshWorkersConcurrently(
.reg = reg,
.usage_fetcher = usage_fetcher,
.results = results,
.active_account_key = active_account_key,
.active_only = active_only,
};

const helper_count = worker_count - 1;
Expand Down Expand Up @@ -420,8 +530,14 @@ fn runForegroundUsageRefreshWorkersSerially(
reg: *registry.Registry,
usage_fetcher: UsageFetchDetailedFn,
results: []ForegroundUsageWorkerResult,
active_account_key: ?[]const u8,
active_only: bool,
) void {
for (reg.accounts.items, 0..) |_, idx| {
for (reg.accounts.items, 0..) |account, idx| {
if (active_only) {
const key = active_account_key.?;
if (!std.mem.eql(u8, account.account_key, key)) continue;
}
foregroundUsageRefreshWorker(allocator, codex_home, reg, idx, usage_fetcher, results);
}
}
Expand Down
Loading
Loading