Skip to content

fix: support configurable Codex usage endpoints#2

Open
Daltonganger wants to merge 17 commits intomainfrom
fix/codex-openai-endpoint-config
Open

fix: support configurable Codex usage endpoints#2
Daltonganger wants to merge 17 commits intomainfrom
fix/codex-openai-endpoint-config

Conversation

@Daltonganger
Copy link
Copy Markdown
Owner

Summary

  • add OpenCode-config-driven Codex usage endpoint resolution with explicit override, derived external endpoint support, and safe default behavior
  • route codex-lb external usage requests through chatgpt_account_id while keeping existing account IDs for direct ChatGPT usage
  • add unit coverage for Codex endpoint selection and codex-lb external account ID mapping

Verification

  • xcodebuild build -project \"CopilotMonitor/CopilotMonitor.xcodeproj\" -scheme \"CopilotMonitor\" -configuration Debug -clonedSourcePackagesDirPath \"/Users/rubenbeuker/Library/Developer/Xcode/DerivedData/CopilotMonitor-aggycqisuzewkzczboobrrtuajll/SourcePackages\"
  • xcodebuild test -project \"CopilotMonitor/CopilotMonitor.xcodeproj\" -scheme \"CopilotMonitor\" -destination 'platform=macOS' -clonedSourcePackagesDirPath \"/Users/rubenbeuker/Library/Developer/Xcode/DerivedData/CopilotMonitor-aggycqisuzewkzczboobrrtuajll/SourcePackages\"
  • launched the Debug app build and checked /usr/bin/log show --last 2m --predicate 'subsystem == \"com.opencodeproviders\"'

Shaglock and others added 6 commits March 23, 2026 12:08
…support (opgginc#84)

* feat: add Copilot CLI Keychain token discovery and multi-account CLI support

Add macOS Keychain as a token source for GitHub Copilot, enabling
automatic discovery of credentials stored by `copilot-cli`. Rewrite the
CLI's CopilotCLIProvider to use TokenManager for multi-account support
(matching the GUI provider), and fix table column alignment for long
provider names.

* Fix duplicated "Token from" sections

* Address PR opgginc#84 feedback: remove dead state, parallelise token fetch, fix separator width, Add tests covering all three areas

Three changes from PR review feedback:

1. Remove unused `cachedUserEmail` (CopilotCLIProvider)
   The property was declared and assigned in the cookie branch of `fetch()`
   but never read. Remove the declaration and the assignment so the actor
   carries no stale mutable state.

2. Parallelise `fetchTokenInfos` (CopilotCLIProvider)
   The previous sequential `for` loop awaited each account's plan-info and
   user-login network requests one at a time. Replace it with
   `withTaskGroup` so every account fires its requests concurrently.
   The `dedupeTokenInfos` call at the end is preserved unchanged.
   For users with several Copilot accounts (e.g. personal + org), startup
   time for the Copilot row is now bounded by the slowest single request
   rather than the sum of all requests.

3. Dynamic metrics column width in TableFormatter (CLI)
   `formatSeparator` previously hardcoded a 30-character metrics column,
   which caused the separator line to be shorter than data rows whenever
   auth-source labels or long email addresses pushed the metrics string
   past 30 characters (e.g. "Browser Cookies (Chrome/Brave/Arc/Edge)").
   Add `computeMetricsWidth()`, which mirrors `computeProviderWidth()` and
   scans every rendered metrics string — including Gemini multi-account
   rows, generic multi-account rows with auth-source brackets, and
   single-account rows — to find the true maximum. Thread the computed
   value through `formatSeparator(providerWidth:metricsWidth:)` so the
   separator is always exactly as wide as the widest row.

Add tests covering all three areas:

- CLIFormatterTests: 8 new cases for TableFormatter
  · separator length equals header length for a single-account result
  · separator grows to accommodate long auth-source bracket labels
  · `accountLabel` uses `accountId` when present, falls back to `#N`
  · absolute-path auth sources are shortened to just the filename
  · tilde-path auth sources are shortened to just the filename
  · non-path auth sources (e.g. "Browser Cookies …") pass through verbatim
  · separator is ≥ every data row width for Gemini multi-account results

- CopilotProviderTests: 4 new cases for CopilotAuthSource / sourcePriority
  · all four enum cases exist with unique descriptions
  · each case's `description` string matches the expected value
    (including the newly-added `copilotCliKeychain` case)
  · relative priority ordering: opencodeAuth > copilotCliKeychain >
    vscodeHosts > vscodeApps
  · absolute priority values: 3, 2, 1, 0

* fix: address review feedback — shared APIValueParser, unlimited quota fix, priority test coupling

- Extract parseDoubleValue/parseIntValue into shared APIValueParser enum in ProviderResult.swift
  with NSNumber and String→numeric handling (AGENTS.md documented pattern)
- Fix unlimited quota_snapshots setting entitlement=0/remaining=0 → Int.max sentinel
  so downstream guard (limit > 0) passes and UI shows 0% usage correctly
- Move CopilotAuthSource.priority to the enum itself (TokenManager.swift)
  so both GUI+CLI providers delegate to single source of truth
- Update CopilotProviderTests to call .priority directly instead of mirrored lookup table

Co-authored-by: opencode (Sisyphus, oMo) <no-reply@opencode.ai>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: address bot review — clamping, Keychain parsing, PII log, multi-account test

- Remove unused loop index in readCopilotCliKeychainAccounts()
- Use lastIndex(of:) for Keychain account username parsing (robustness)
- Clamp remaining with max(0,...) in buildCandidateFromUsage for both CLI and GUI
- Change API error response log from .error to .debug with 256-char truncation (PII)
- Add testTableFormatterMultiAccountRowsAppear for 2-account code path coverage

Co-authored-by: opencode (Sisyphus, oMo) <no-reply@opencode.ai>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: address bot review round 2 — Int.max display, test coverage, PII log, dead code

- Guard Int.max sentinel in UI rendering: show "Unlimited" instead of raw number
- Add 2nd dummy account to 3 shortenAuthSource tests for multi-account path coverage
- Fix separator width assertion: >= instead of == (metricsWidth min 30 > header 11)
- Downgrade username log from .warning to .debug (PII)
- Remove duplicate priority(for:) function, use CopilotAuthSource.priority
- Fix 12→8 space indentation in dedupeCopilotAccounts

Co-authored-by: opencode (Sisyphus, oMo) <no-reply@opencode.ai>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: address bot review round 3 — test coverage, JSON Int.max guard

- Add 2nd account to testTableFormatterSeparatorWidthGrowsForLongAuthSource (multi-account path)
- Guard Int.max sentinel in JSONFormatter output: "unlimited" string instead of raw number

Co-authored-by: opencode (Sisyphus, oMo) <no-reply@opencode.ai>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: address bot review round 4 — usagePercentage guard, case-insensitive dedup, blank lines

- Guard usagePercentage for Int.max: return 0.0 for unlimited plans in JSON output
- Use caseInsensitiveCompare for login dedup in CLI dedupeTokenInfos (matches GUI)
- Remove triple blank lines (SwiftLint vertical_whitespace)

Co-authored-by: opencode (Sisyphus, oMo) <no-reply@opencode.ai>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

---------

Co-authored-by: Sangrak Choi <kars@kargn.as>
Co-authored-by: opencode (Sisyphus, oMo) <no-reply@opencode.ai>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add multi-source account discovery docs (OpenCode auth, Copilot CLI Keychain,
VS Code/Cursor config, browser cookies), multi-account CLI output examples,
and updated troubleshooting section for Copilot.

Co-authored-by: opencode (Sisyphus, oMo) <no-reply@opencode.ai>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

func codexUsageURL(for configuration: CodexEndpointConfiguration) -> URL {
switch configuration.mode {
case .directChatGPT:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The Roast: Using preconditionFailure for what's essentially a configuration sanity check is aggressive. If someone's config file gets corrupted, this will crash the app instead of gracefully falling back.

The Fix: Consider using fatalError() with a message or return an optional/Result type to handle the error gracefully.

Severity: suggestion

@kilo-code-bot
Copy link
Copy Markdown

kilo-code-bot bot commented Mar 23, 2026

Code Review Roast 🔥

Verdict: No Issues Found | Recommendation: Merge

The previous issue (preconditionFailure crashing on invalid config URL) has been addressed. The fix replaced the crash with proper error handling - logging an error and throwing a ProviderError.providerError instead. Clean work.

📊 Overall: Like finding a unicorn in production — I didn't think clean PRs existed anymore, but here we are.

Files Reviewed (6 files)
  • CopilotMonitor/CopilotMonitor/Providers/BraveSearchProvider.swift
  • CopilotMonitor/CopilotMonitor/Providers/CodexProvider.swift
  • CopilotMonitor/CopilotMonitor/Providers/TavilySearchProvider.swift
  • CopilotMonitor/CopilotMonitor/Services/TokenManager.swift
  • CopilotMonitor/CopilotMonitorTests/TokenManagerTests.swift
  • scripts/query-brave-search.sh
  • scripts/query-tavily-search.sh

@Daltonganger
Copy link
Copy Markdown
Owner Author

Addressed the review note in f3bc2e2 by replacing the with logged error handling plus a thrown provider error, so the app no longer crashes if the default Codex URL is ever invalid.

@Daltonganger
Copy link
Copy Markdown
Owner Author

Follow-up: this specifically replaces the crashing default-URL assertion with a logged error and a thrown provider error, so invalid configuration no longer terminates the app.

Ruben Beuker and others added 10 commits March 23, 2026 14:55
* Update Claude OAuth usage request headers

* Refresh Claude usage script and documentation
* feat: add Nano-GPT provider across app and CLI

Integrate Nano-GPT as a quota-based provider with daily/monthly reset tracking, local icon assets, and auth parsing support. Add UI/CLI wiring and tests so Nano-GPT usage, balances, and the  subscription preset are available end-to-end.

* perf: reuse static date formatters in NanoGptProvider to reduce allocations

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: add Antigravity accounts fallback

* fix: update Chutes quota usage display

* fix: use UTC month boundaries for Chutes usage

---------

Co-authored-by: Ruben Beuker <rubenbeuker@MacBook-Pro-van-Ruben.local>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Co-authored-by: Ruben Beuker <rubenbeuker@MacBook-Air-van-Ruben.local>
* Disable unavailable provider menu rows

* Add MiniMax coding plan provider support

* Document MiniMax provider usage and API behavior
* feat: add Nano-GPT provider across app and CLI

Integrate Nano-GPT as a quota-based provider with daily/monthly reset tracking, local icon assets, and auth parsing support. Add UI/CLI wiring and tests so Nano-GPT usage, balances, and the  subscription preset are available end-to-end.

* perf: reuse static date formatters in NanoGptProvider to reduce allocations

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: add Antigravity accounts fallback

* fix: add search config fallbacks

* fix: resolve lint violations in search config fallback

* fix: preserve brave search temp file cleanup

---------

Co-authored-by: Ruben Beuker <rubenbeuker@MacBook-Pro-van-Ruben.local>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Co-authored-by: Ruben Beuker <rubenbeuker@MacBook-Air-van-Ruben.local>
…ix/codex-openai-endpoint-config

# Conflicts:
#	CopilotMonitor/CopilotMonitor/Services/TokenManager.swift
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.

3 participants