Skip to content

[codex] add OpenCode TUI prompt status#146

Merged
ndycode merged 9 commits into
mainfrom
codex/opencode-tui-status-bar
Apr 24, 2026
Merged

[codex] add OpenCode TUI prompt status#146
ndycode merged 9 commits into
mainfrom
codex/opencode-tui-status-bar

Conversation

@ndycode
Copy link
Copy Markdown
Owner

@ndycode ndycode commented Apr 24, 2026

Summary

  • adds a separate OpenCode TUI plugin export for the prompt-right status indicator
  • shows compact reasoning variant plus remaining 5h/weekly quota beside the model label
  • reuses the codex-limits usage parser/fetch path and installs the TUI plugin into tui.json

Validation

  • npm run typecheck
  • npm run lint
  • npm test
  • npm run build
  • npm pack --dry-run
  • node import smoke test for ./dist/tui.js

Summary by CodeRabbit

  • New Features

    • Codex quota status now displays in TUI with real-time remaining usage, limits, and reset times
    • Quota information updates automatically and can be viewed in detail via a command
    • Added quota caching for improved performance
  • Tests

    • Added comprehensive test coverage for new quota display, caching, and configuration features

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

this pr adds a new tui.ts plugin export that displays real-time codex quota in the opencode session_prompt_right slot, backed by a shared disk cache (tui-quota-cache.ts) updated from response headers on every api call. inline usage logic from codex-limits.ts is cleanly extracted into lib/codex-usage.ts and reused by both paths.

Confidence Score: 5/5

safe to merge — all remaining findings are p2 style/cleanup; no correctness bugs found

codex-usage.ts extraction is faithful, atomic writes use the established windows-retry helper, the header parse path is fire-and-forget with full error suppression, and the duplicate function copies are cosmetic

tui.ts (1Hz disk polling, module-level inFlightRefresh, missing integration test coverage) and lib/tui-quota-cache.ts (formatWindowLabel duplication)

Important Files Changed

Filename Overview
tui.ts new TUI plugin entry point — quota polling, shared disk-cache read path, event-driven refresh, session_prompt_right slot registration; module-level inFlightRefresh and 1Hz disk reads warrant attention
lib/tui-quota-cache.ts new shared disk cache — atomic writes with windows retry, dedup write skipping, robust JSON validation; formatWindowLabel duplicates formatUsageWindowLabel from codex-usage.ts
lib/tui-status.ts new TUI status formatters — width-adaptive candidate selection for prompt-right text, tone resolution, details view; formatReset duplicates formatUsageReset from codex-usage.ts
lib/codex-usage.ts new shared module extracted from codex-limits.ts — usage fetch, token refresh, fingerprinting, payload parsing; clean extraction
lib/tools/codex-limits.ts ~370 lines of inline usage logic removed and replaced with calls to shared codex-usage.ts; functional parity preserved
lib/tools/codex-switch.ts clears TUI quota cache after account switch so prompt status immediately reflects the new account
index.ts hooks recordPromptQuotaHeaders (fire-and-forget) and clearPromptQuotaCache into the fetch/account-removal paths; errors caught and debug-logged

Sequence Diagram

sequenceDiagram
    participant API as Codex API
    participant idx as index.ts (plugin)
    participant cache as tui-quota-cache.ts
    participant tui as tui.ts (TUI plugin)
    participant slot as session_prompt_right slot

    idx->>API: fetch (completion request)
    API-->>idx: response + x-codex-* headers
    idx->>cache: parseTuiQuotaSnapshotFromHeaders()
    cache-->>idx: TuiQuotaSnapshot
    idx->>cache: writeTuiQuotaSnapshot() [atomic rename, windows retry]

    tui->>tui: pollSharedQuotaCache() [1Hz]
    tui->>cache: readTuiQuotaSnapshot()
    cache-->>tui: TuiQuotaSnapshot (fingerprint matched)
    tui->>slot: applyQuota() then formatPromptStatusText()

    tui->>API: refreshQuotaStatusInner() [5min or event-driven]
    API-->>tui: UsagePayload
    tui->>cache: writeTuiQuotaSnapshot() [source: usage]
    tui->>slot: update prompt-right text + fg color (tone)
Loading

Fix All in Codex

Prompt To Fix All With AI
This is a comment left during a code review.
Path: lib/tui-quota-cache.ts
Line: 107-118

Comment:
**duplicate `formatWindowLabel` — import from `codex-usage.ts` instead**

`lib/tui-quota-cache.ts` defines a private `formatWindowLabel` that is byte-for-byte identical to the already-exported `formatUsageWindowLabel` in `lib/codex-usage.ts`. having two copies means future changes to the label logic only get applied in one place — e.g. adding a new magnitude bucket would silently miss the header-parsed path.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: lib/tui-status.ts
Line: 345-367

Comment:
**`formatReset` duplicates `formatUsageReset` from `codex-usage.ts`**

the `formatReset` function here is identical to `formatUsageReset` already exported from `lib/codex-usage.ts`. `tui-status.ts` could import it directly to avoid divergence risk. `formatResetTime` (time-only, no date) is genuinely new and fine as-is.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: tui.ts
Line: 311-341

Comment:
**1Hz `loadAccounts()` disk read — windows i/o risk**

`pollSharedQuotaCache` fires every `ACCOUNT_POLL_INTERVAL_MS = 1_000` ms and calls `resolveActiveQuotaFingerprint()``loadAccounts()`, a json file read. on windows, frequent reads against a path the main plugin process may also be writing to can hit sharing-mode conflicts or antivirus-induced delays. consider raising the interval to 3–5 s or debouncing after a successful shared-cache hit.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: tui.ts
Line: 176-240

Comment:
**missing vitest coverage for shared-cache read path in `refreshQuotaStatusInner`**

the `shared = await readSharedQuotaStatus(api, fingerprint)` branch — where a valid snapshot is found on disk and returned without a network call — has no unit test. a lightweight `TuiPluginApi` stub would protect the fingerprint-matching and stale-fallback logic.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: tui.ts
Line: 46-48

Comment:
**concurrency note: module-level `inFlightRefresh` shared across all `createPromptStatus` instances**

`inFlightRefresh` is a module-level singleton. if `createPromptStatus` is ever mounted twice in the same process (test fixture, hot-reload), the second call reuses a pending promise from the first instance's `api` context. worth a comment — stale `applyQuota` closures from disposed instances can still fire when the shared promise settles.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (3): Last reviewed commit: "fix: avoid blocking on quota cache write..." | Re-trigger Greptile

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 24, 2026

📝 Walkthrough

Walkthrough

This PR adds TUI (terminal user interface) support for displaying Codex quota status with new modules for quota snapshot caching, usage payload parsing, and TUI-specific formatting. The existing Codex limits tool is refactored to delegate usage concerns to a centralized module, and installation/dependency management is updated.

Changes

Cohort / File(s) Summary
Configuration & Build
eslint.config.js, tsconfig.json
Updated file globs to include new tui.ts entry point for TypeScript compilation and ESLint processing.
Core TUI Infrastructure
lib/tui-quota-cache.ts, lib/tui-status.ts
New modules providing quota snapshot persistence with versioned JSON caching, quota limit parsing from HTTP headers, and TUI-specific formatting (status text, tone resolution, detailed quota descriptions, reasoning variant inference).
Usage & Limits Refactoring
lib/codex-usage.ts, lib/tools/codex-limits.ts, lib/tools/codex-switch.ts, index.ts
New centralized usage module with parsing, fetching, and access-token refresh logic replaces inline implementations in codex-limits tool; quota cache maintenance integrated into plugin initialization and account-switch flow.
Installation & Dependencies
package.json, scripts/install-oc-codex-multi-auth-core.js
Added ESM exports for main and ./tui subpaths; bumped @opencode-ai/plugin and added UI runtime dependencies; installer now manages tui.json configuration with merge/backup logic.
TUI Plugin Implementation
tui.ts
New plugin module rendering Codex quota status in prompt UI slots with cached snapshots, periodic polling, event-driven refresh debouncing, in-flight request deduplication, and a quota-details alert command.
Tests
test/codex-usage.test.ts, test/tui-quota-cache.test.ts, test/tui-refresh-events.test.ts, test/tui-status.test.ts, test/install-oc-codex-multi-auth.test.ts
New test suites covering usage payload parsing, quota cache persistence, TUI refresh event logic, quota status formatting/tone resolution, reasoning variant resolution, and installer TUI config merging.

Sequence Diagram(s)

sequenceDiagram
    participant TUI as TUI Plugin
    participant Cache as Quota Cache
    participant Usage as Usage Module
    participant API as Codex API
    participant Storage as Account Storage
    
    TUI->>Cache: Load cached snapshot
    alt Snapshot found
        TUI->>TUI: Render with cached quota
    else Cache miss or stale
        TUI->>Usage: Ensure access token (refresh if needed)
        Usage->>Storage: Check/update credentials
        Storage-->>Usage: Account data
        Usage->>API: GET /wham/usage
        API-->>Usage: Usage payload + headers
        Usage->>Usage: Parse payload → limits
        Usage->>Cache: Write snapshot to disk
        Usage-->>TUI: Parsed quota limits
        TUI->>TUI: Render with new quota
    end
    Note over TUI: Periodic poll & debounced event triggers
Loading
sequenceDiagram
    participant Client as Account Switch
    participant TUI as TUI Plugin
    participant Cache as Quota Cache
    
    Client->>TUI: Account selection persisted
    TUI->>Cache: Clear snapshot (try/catch wrapped)
    Cache-->>TUI: Cleared or error logged
    TUI->>TUI: Return success (cache clear non-blocking)
    Note over Client,Cache: Next quota fetch recomputes from API
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 Beneath the prompt, a quota gleams,
Cached snapshots dance in digital dreams!
With headers parsed and limits stored,
The TUI's tale of usage poured.
No more refetch, just smart display—
This quota plugin saves the day!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title '[codex] add OpenCode TUI prompt status' accurately describes the main feature being added—a new TUI plugin for displaying Codex quota and reasoning variant status.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed PR description includes summary of changes, testing validation steps, and compliance confirmation checkboxes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/opencode-tui-status-bar

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ndycode ndycode marked this pull request as ready for review April 24, 2026 16:17
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (9)
scripts/install-oc-codex-multi-auth-core.js (1)

144-152: LGTM — merge helper is correct and consistent.

mergeTuiConfig correctly preserves unknown top-level keys (notably plugin_enabled), backfills a default $schema, and routes the plugin array through the same normalizePluginList used for opencode.json, so legacy oc-chatgpt-multi-auth entries, @version pins, and absolute file:///node_modules paths are all collapsed to the canonical oc-codex-multi-auth entry. Using the same normalizer here is sound because the TUI plugin is a named export of the same package.

Optional micro-refactor: the existing + next pair performs two spreads when one would do. Feel free to ignore.

♻️ Optional simplification
 function mergeTuiConfig(existingConfig) {
-	const existing = isPlainObject(existingConfig) ? { ...existingConfig } : {};
-	const next = { ...existing };
+	const next = isPlainObject(existingConfig) ? { ...existingConfig } : {};
 	if (typeof next.$schema !== "string" || !next.$schema.trim()) {
 		next.$schema = "https://opencode.ai/tui.json";
 	}
-	next.plugin = normalizePluginList(existing.plugin);
+	next.plugin = normalizePluginList(next.plugin);
 	return next;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/install-oc-codex-multi-auth-core.js` around lines 144 - 152, The
function mergeTuiConfig currently creates two spreads (const existing = ... ? {
...existingConfig } : {}; const next = { ...existing };) which is redundant;
simplify by eliminating one spread and deriving next directly from
existingConfig (or from existing when preserving the plain-object guard) while
keeping the same behavior: preserve unknown top-level keys, backfill $schema
when missing, and pass the plugin field through normalizePluginList; update
mergeTuiConfig to reference the same symbols ($schema, plugin,
normalizePluginList) but remove the unnecessary double-copy.
test/tui-refresh-events.test.ts (2)

32-32: Hardcoded Windows paths may read odd on Unix CI.

path: { cwd: "C:\\repo", root: "C:\\repo" } is fine because the field isn't asserted on, but using a neutral path (e.g. /repo) keeps fixtures platform-agnostic and matches typical CI runners.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tui-refresh-events.test.ts` at line 32, The test fixture in
test/tui-refresh-events.test.ts uses hardcoded Windows-style paths in the object
property path (path: { cwd: "C:\\repo", root: "C:\\repo" }); change those to a
platform-agnostic path (e.g., cwd: "/repo", root: "/repo") so the fixture reads
naturally on Unix CI and avoids platform-specific artifacts while keeping
behavior identical since the field isn't asserted on.

17-123: Consider adding coverage for session.idle, session.error, and tool error states.

The implementation of shouldRefreshQuotaForEvent (per the context snippet) also returns true for session.idle, session.error, and message.part.updated tool parts with state.status === "error". The current tests only exercise session.status (idle/busy), step-finish parts, and tool completed. A regression that, say, flipped session.error to not refresh would slip through.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tui-refresh-events.test.ts` around lines 17 - 123, Add tests that assert
shouldRefreshQuotaForEvent returns true for session statuses of type "idle" and
"error" and for tool parts whose state.status === "error"; specifically, in the
same test suite that contains the existing cases, create a session.status event
with properties.status.type = "idle" and another with properties.status.type =
"error" and assert shouldRefreshQuotaForEvent(...) === true, and create a
message.part.updated event for a tool part where part.state.status === "error"
(mirroring the existing toolCompleted shape) and assert it returns true;
reference the shouldRefreshQuotaForEvent function and reuse the event object
shapes (session.status and message.part.updated) used elsewhere in the file so
the new assertions cover these missing branches.
lib/tools/codex-switch.ts (1)

150-156: Duplicated cache-clear logic with inconsistent log level.

This block re-implements the same try/catch pattern as clearPromptQuotaCache in index.ts (lines 602–610), but logs at warn level here vs debug there. Two concerns:

  1. Log-level divergence: the same failure is treated as a warning in one path and noise in the other — consumers can't reason about severity consistently.
  2. Duplication: both call sites have identical error-swallowing intent. Consider exposing clearPromptQuotaCache (or a thin helper) through ToolContext so both the codex-switch tool and the account.select event handler share one implementation.
♻️ Proposed fix: align log level and delegate to a shared helper
-			try {
-				await clearTuiQuotaSnapshot();
-			} catch (cacheError) {
-				logWarn("Failed to clear TUI quota cache after account switch", {
-					error: String(cacheError),
-				});
-			}
+			// Delegate to the shared helper exposed via ToolContext to keep the
+			// tool path and the account.select event handler in sync.
+			await ctx.clearPromptQuotaCache?.();

Then expose clearPromptQuotaCache through ToolContext in index.ts and lib/tools/index.ts.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/tools/codex-switch.ts` around lines 150 - 156, The try/catch in
codex-switch.ts that calls clearTuiQuotaSnapshot duplicates the error-swallowing
logic from clearPromptQuotaCache (index.ts) and uses a different log level;
remove the duplicate by delegating to a single shared function: expose
clearPromptQuotaCache (or a thin wrapper) on ToolContext so the codex-switch
tool and the account.select handler both call ToolContext.clearPromptQuotaCache,
and ensure both callers use the same log level (change the codex-switch call to
rely on the helper's debug-level logging rather than logging a warn locally).
Update codex-switch.ts to call the exposed ToolContext method and delete the
local try/catch around clearTuiQuotaSnapshot.
package.json (1)

5-16: Consider mirroring main/types via the exports map only.

Given the exports field now authoritatively defines the . entry, the top-level main/types fields become redundant for Node resolvers that honor exports, but are still useful as a fallback for older tooling/bundlers. No change required — flagging so you can decide whether to keep both or drop one pair once minimum consumer versions are known.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 5 - 16, The package.json currently has top-level
"main" and "types" alongside an "exports" map that defines the "." entry; update
package.json so the top-level "main" and "types" either mirror the same targets
as the "." export (i.e., set "main" -> "./dist/index.js" and "types" ->
"./dist/index.d.ts" to match the exports) or remove the top-level "main"/"types"
pair entirely if you decide to rely solely on the "exports" map, making sure the
"./tui" export remains unchanged; reference the "main", "types", "exports", "."
and "./tui" keys when applying the change.
index.ts (1)

602-631: Helpers look correct; minor log-level consistency suggestion.

clearPromptQuotaCache and recordPromptQuotaHeaders both defensively swallow errors and log at debug, which is appropriate for a non-critical telemetry path. Note that lib/tools/codex-switch.ts (line 152–155) logs the same clear failure at warn — please pick one level and align both sites. See my comment on codex-switch.ts for a broader DRY suggestion.

Also, TuiQuotaAccount is declared via Parameters<typeof createUsageAccountFingerprint>[0] & { index: number; email?: string; accountLabel?: string }. If createUsageAccountFingerprint's parameter already includes email/accountLabel, the intersection is redundant; if it doesn't, widening here is fine. Worth a quick check.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@index.ts` around lines 602 - 631, The helper functions clearPromptQuotaCache
and recordPromptQuotaHeaders currently log errors with logDebug while the
similar clear logic in codex-switch (clearFailure path) uses logWarn; choose one
level and make them consistent (e.g., change logDebug -> logWarn in
clearPromptQuotaCache/recordPromptQuotaHeaders or change the codex-switch usage
to logDebug) so both sites use the same severity; update the calls in
clearPromptQuotaCache and recordPromptQuotaHeaders (and the corresponding clear
path in codex-switch) accordingly. Also inspect the TuiQuotaAccount type
(declared as Parameters<typeof createUsageAccountFingerprint>[0] & { index:
number; email?: string; accountLabel?: string }) and remove redundant
email/accountLabel from the intersection if createUsageAccountFingerprint
already includes them, or keep the widening only if those props are missing.
Ensure you update only the referenced functions/types: clearPromptQuotaCache,
recordPromptQuotaHeaders, and the TuiQuotaAccount
declaration/createUsageAccountFingerprint usage.
lib/tui-status.ts (1)

279-301: formatReset duplicates formatUsageReset from lib/codex-usage.ts.

This helper is identical to formatUsageReset (lib/codex-usage.ts Lines 112–137). Import the canonical version instead of maintaining two copies — divergence here would cause inconsistency between the tools-tab reset strings and the TUI details dialog strings.

♻️ Suggested change
 import type { Config } from "@opencode-ai/sdk/v2";
+import { formatUsageReset } from "./codex-usage.js";
@@
-function formatReset(resetAtMs: number | undefined): string | undefined {
-	if (!resetAtMs || !Number.isFinite(resetAtMs) || resetAtMs <= 0) {
-		return undefined;
-	}
-	const date = new Date(resetAtMs);
-	if (!Number.isFinite(date.getTime())) return undefined;
-	const now = new Date();
-	const sameDay =
-		now.getFullYear() === date.getFullYear() &&
-		now.getMonth() === date.getMonth() &&
-		now.getDate() === date.getDate();
-	const time = date.toLocaleTimeString(undefined, {
-		hour: "2-digit",
-		minute: "2-digit",
-		hour12: false,
-	});
-	if (sameDay) return time;
-	const day = date.toLocaleDateString(undefined, {
-		month: "short",
-		day: "2-digit",
-	});
-	return `${time} on ${day}`;
-}
+const formatReset = formatUsageReset;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/tui-status.ts` around lines 279 - 301, The function formatReset in
lib/tui-status.ts duplicates formatUsageReset from lib/codex-usage.ts; remove
the local formatReset implementation and import the canonical formatUsageReset
from lib/codex-usage.ts, then replace usages of formatReset with
formatUsageReset (or re-export/alias it as formatReset if the local name must be
preserved) to avoid duplication and keep reset-string formatting consistent
across the codebase.
tui.ts (1)

288-295: 1s account polling reads accounts from disk every second.

ACCOUNT_POLL_INTERVAL_MS = 1_000 drives loadAccounts() on every tick for the lifetime of the TUI session (~3600 disk reads/hour per active slot). OS page cache largely absorbs this, but it's still wasted work compared to an event-driven path or a slower poll cadence (e.g., 5–10s would still feel responsive for account-switch detection, and the explicit codex.switch flow could additionally clear/touch the snapshot file to trigger faster convergence).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tui.ts` around lines 288 - 295, The 1s polling loop driven by
ACCOUNT_POLL_INTERVAL_MS causes frequent disk reads via
resolveActiveQuotaFingerprint()/loadAccounts(); change the polling to a less
aggressive default (e.g., 5_000–10_000 ms) or make ACCOUNT_POLL_INTERVAL_MS
configurable, and prefer an event-driven approach (use a filesystem watcher or
trigger a touch from the explicit codex.switch flow) so
resolveActiveQuotaFingerprint() is only run when necessary; update the
setInterval that creates accountInterval and the code paths that call
refresh()/setQuota() to rely on the new cadence or the explicit trigger.
lib/tui-quota-cache.ts (1)

97-114: Deduplicate formatWindowLabel / getLeftPercent with lib/codex-usage.ts.

These helpers are verbatim copies of formatUsageWindowLabel (lib/codex-usage.ts Lines 97–110) and getUsageLeftPercent (lib/codex-usage.ts Lines 89–95). Keeping two implementations in sync is easy to get wrong; one should import from the shared module.

♻️ Suggested deduplication
 import { renameWithWindowsRetry } from "./storage/atomic-write.js";
+import {
+	formatUsageWindowLabel,
+	getUsageLeftPercent,
+} from "./codex-usage.js";
 import type { CompactQuotaLimit } from "./tui-status.js";
@@
-function formatWindowLabel(windowMinutes: number | undefined): string {
-	if (
-		!windowMinutes ||
-		!Number.isFinite(windowMinutes) ||
-		windowMinutes <= 0
-	) {
-		return "quota";
-	}
-	if (windowMinutes % 1440 === 0) return `${windowMinutes / 1440}d`;
-	if (windowMinutes % 60 === 0) return `${windowMinutes / 60}h`;
-	return `${windowMinutes}m`;
-}
-
-function getLeftPercent(usedPercent: number | undefined): number | null {
-	return typeof usedPercent === "number" && Number.isFinite(usedPercent)
-		? Math.max(0, Math.min(100, Math.round(100 - usedPercent)))
-		: null;
-}
+const getLeftPercent = (usedPercent: number | undefined): number | null =>
+	getUsageLeftPercent(usedPercent) ?? null;

Then replace the formatWindowLabel call site on Line 138 with formatUsageWindowLabel.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/tui-quota-cache.ts` around lines 97 - 114, Remove the duplicated helpers
formatWindowLabel and getLeftPercent and instead import the canonical functions
formatUsageWindowLabel and getUsageLeftPercent from the codex-usage module;
update all local call sites that currently use formatWindowLabel to call
formatUsageWindowLabel and those using getLeftPercent to call
getUsageLeftPercent, and ensure the imports are added to the top of the file and
any local references/variable names adjusted accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@index.ts`:
- Line 2147: The call to recordPromptQuotaHeaders is awaiting a function that
already handles its own errors, adding unnecessary latency to the request hot
path; remove the await and invoke it in a fire-and-forget manner (ensure the
returned promise is handled to avoid unhandled rejections) so responses aren't
blocked by disk I/O. Also update writeTuiQuotaSnapshot to reduce race/overwrite
noise under concurrency by adding a short debounce/throttle or "skip-if-recent"
guard (use an in-memory last-write timestamp keyed by account or global) so
rapid parallel requests don't each perform an atomic write and cause
last-write-wins churn.

---

Nitpick comments:
In `@index.ts`:
- Around line 602-631: The helper functions clearPromptQuotaCache and
recordPromptQuotaHeaders currently log errors with logDebug while the similar
clear logic in codex-switch (clearFailure path) uses logWarn; choose one level
and make them consistent (e.g., change logDebug -> logWarn in
clearPromptQuotaCache/recordPromptQuotaHeaders or change the codex-switch usage
to logDebug) so both sites use the same severity; update the calls in
clearPromptQuotaCache and recordPromptQuotaHeaders (and the corresponding clear
path in codex-switch) accordingly. Also inspect the TuiQuotaAccount type
(declared as Parameters<typeof createUsageAccountFingerprint>[0] & { index:
number; email?: string; accountLabel?: string }) and remove redundant
email/accountLabel from the intersection if createUsageAccountFingerprint
already includes them, or keep the widening only if those props are missing.
Ensure you update only the referenced functions/types: clearPromptQuotaCache,
recordPromptQuotaHeaders, and the TuiQuotaAccount
declaration/createUsageAccountFingerprint usage.

In `@lib/tools/codex-switch.ts`:
- Around line 150-156: The try/catch in codex-switch.ts that calls
clearTuiQuotaSnapshot duplicates the error-swallowing logic from
clearPromptQuotaCache (index.ts) and uses a different log level; remove the
duplicate by delegating to a single shared function: expose
clearPromptQuotaCache (or a thin wrapper) on ToolContext so the codex-switch
tool and the account.select handler both call ToolContext.clearPromptQuotaCache,
and ensure both callers use the same log level (change the codex-switch call to
rely on the helper's debug-level logging rather than logging a warn locally).
Update codex-switch.ts to call the exposed ToolContext method and delete the
local try/catch around clearTuiQuotaSnapshot.

In `@lib/tui-quota-cache.ts`:
- Around line 97-114: Remove the duplicated helpers formatWindowLabel and
getLeftPercent and instead import the canonical functions formatUsageWindowLabel
and getUsageLeftPercent from the codex-usage module; update all local call sites
that currently use formatWindowLabel to call formatUsageWindowLabel and those
using getLeftPercent to call getUsageLeftPercent, and ensure the imports are
added to the top of the file and any local references/variable names adjusted
accordingly.

In `@lib/tui-status.ts`:
- Around line 279-301: The function formatReset in lib/tui-status.ts duplicates
formatUsageReset from lib/codex-usage.ts; remove the local formatReset
implementation and import the canonical formatUsageReset from
lib/codex-usage.ts, then replace usages of formatReset with formatUsageReset (or
re-export/alias it as formatReset if the local name must be preserved) to avoid
duplication and keep reset-string formatting consistent across the codebase.

In `@package.json`:
- Around line 5-16: The package.json currently has top-level "main" and "types"
alongside an "exports" map that defines the "." entry; update package.json so
the top-level "main" and "types" either mirror the same targets as the "."
export (i.e., set "main" -> "./dist/index.js" and "types" -> "./dist/index.d.ts"
to match the exports) or remove the top-level "main"/"types" pair entirely if
you decide to rely solely on the "exports" map, making sure the "./tui" export
remains unchanged; reference the "main", "types", "exports", "." and "./tui"
keys when applying the change.

In `@scripts/install-oc-codex-multi-auth-core.js`:
- Around line 144-152: The function mergeTuiConfig currently creates two spreads
(const existing = ... ? { ...existingConfig } : {}; const next = { ...existing
};) which is redundant; simplify by eliminating one spread and deriving next
directly from existingConfig (or from existing when preserving the plain-object
guard) while keeping the same behavior: preserve unknown top-level keys,
backfill $schema when missing, and pass the plugin field through
normalizePluginList; update mergeTuiConfig to reference the same symbols
($schema, plugin, normalizePluginList) but remove the unnecessary double-copy.

In `@test/tui-refresh-events.test.ts`:
- Line 32: The test fixture in test/tui-refresh-events.test.ts uses hardcoded
Windows-style paths in the object property path (path: { cwd: "C:\\repo", root:
"C:\\repo" }); change those to a platform-agnostic path (e.g., cwd: "/repo",
root: "/repo") so the fixture reads naturally on Unix CI and avoids
platform-specific artifacts while keeping behavior identical since the field
isn't asserted on.
- Around line 17-123: Add tests that assert shouldRefreshQuotaForEvent returns
true for session statuses of type "idle" and "error" and for tool parts whose
state.status === "error"; specifically, in the same test suite that contains the
existing cases, create a session.status event with properties.status.type =
"idle" and another with properties.status.type = "error" and assert
shouldRefreshQuotaForEvent(...) === true, and create a message.part.updated
event for a tool part where part.state.status === "error" (mirroring the
existing toolCompleted shape) and assert it returns true; reference the
shouldRefreshQuotaForEvent function and reuse the event object shapes
(session.status and message.part.updated) used elsewhere in the file so the new
assertions cover these missing branches.

In `@tui.ts`:
- Around line 288-295: The 1s polling loop driven by ACCOUNT_POLL_INTERVAL_MS
causes frequent disk reads via resolveActiveQuotaFingerprint()/loadAccounts();
change the polling to a less aggressive default (e.g., 5_000–10_000 ms) or make
ACCOUNT_POLL_INTERVAL_MS configurable, and prefer an event-driven approach (use
a filesystem watcher or trigger a touch from the explicit codex.switch flow) so
resolveActiveQuotaFingerprint() is only run when necessary; update the
setInterval that creates accountInterval and the code paths that call
refresh()/setQuota() to rely on the new cadence or the explicit trigger.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9803d516-e98c-40fc-b46a-6586c471bf00

📥 Commits

Reviewing files that changed from the base of the PR and between 74be624 and 34fc53c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (16)
  • eslint.config.js
  • index.ts
  • lib/codex-usage.ts
  • lib/tools/codex-limits.ts
  • lib/tools/codex-switch.ts
  • lib/tui-quota-cache.ts
  • lib/tui-status.ts
  • package.json
  • scripts/install-oc-codex-multi-auth-core.js
  • test/codex-usage.test.ts
  • test/install-oc-codex-multi-auth.test.ts
  • test/tui-quota-cache.test.ts
  • test/tui-refresh-events.test.ts
  • test/tui-status.test.ts
  • tsconfig.json
  • tui.ts

Comment thread index.ts Outdated
Comment thread tui.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant