Skip to content

fix: accept the Win-CodexBar CLI's JSON, and stop one failed provider discarding the whole report - #18

Merged
carlosflorencio merged 2 commits into
kdlbs:mainfrom
JnManso:fix/tolerant-codexbar-json
Aug 31, 2026
Merged

carlosflorencio merged 2 commits into
kdlbs:mainfrom
JnManso:fix/tolerant-codexbar-json

Conversation

@JnManso

@JnManso JnManso commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

Why

The codexbar CLI has no Windows build. Win-CodexBar is the only compatible CLI there, and it spells the usage payload differently from upstream: snake_case keys, no identity block, and a failing provider's error as a bare string rather than an object.

That last difference is not cosmetic. A string there failed the decode of the entire JSON array, so one unauthenticated provider discarded every healthy one alongside it. With codexbar_providers = all (a single CLI call) that means no data at all, and in either case the operator saw parsing codexbar output instead of the reason.

On a stock Windows machine 5 of the 8 default providers report exactly that way — codex, gemini, grok, opencodego, amp — all with exit code 0, so the plugin never even saw a run failure.

What

Both spellings decode as co-equal. Upstream may keep camelCase and the port may re-converge on it, so neither is treated as legacy: the camelCase pass stays the strict contract, and a best-effort snake_case pass fills in whatever it left zero. Best-effort matters — a wrongly-typed key in the fallback spelling must not discard the document it exists to rescue (TestParseCodexbar_BadSnakeValueIsNotFatal).

Everything else here is platform-neutral, and was found while testing against the port:

Change Why
reset_at,omitzero The zero time serialized as 0001-01-01T00:00:00Z; fmtReset reads any non-empty value as a real date and renders "resets now" forever, never reaching the reset_description fallback. This fixes the same bug on macOS whenever upstream omits resetsAt.
firstUsefulLine + NO_COLOR The port writes structured log lines to stderr, so a failure was reported as a cookie-decryption warning. Its logging layer colors stderr even through a pipe and even with --no-color, so the escapes had to go too. Upstream's swift-log writes a +0000 offset, which time.Parse(RFC3339) rejects — macOS stderr selection is provably unchanged.
cmd.WaitDelay Killing the process on a deadline does not unblock Wait while any child still holds the output pipe — that could wedge the poller behind pollMu.
parseConfiguredCommand strings.Fields shattered a configured path containing spaces, and the setting is documented as a path. Surrounding quotes are dropped first: that is what Explorer's "Copy as path" produces.
per-provider timeout message A killed process reports its exit status, not the deadline.

Testing

End to end against the real codexbar-cli.exe 0.55.0 through the production runner:

PROBE: installed=true version="0.55.0"
claude    plano="Claude Max 5x"    janelas=3
            5-hour         2.0%  reset=31 Aug 13:30
            weekly        12.0%  reset=04 Sep 09:00
            Fable only    15.0%  reset=04 Sep 09:00
copilot   AI credits     0.0%  reset=(omitted)  desc="0 AI credits used"
codex     unavailable: Provider not installed: Codex auth.json not found...

Before this change the same command produced zero windows and a parse error.

  • Full suite green on Windows in both PowerShell and Git Bash, with -shuffle=on, and with a TEMP path containing spaces.
  • go vet clean; cross-compiles for all five platforms in manifest.yaml; node --test 16/16; go.mod/go.sum untouched.
  • Each fix was mutation-tested: removing stripSGR fails the stderr tests, removing WaitDelay makes its test hang and fail. The stderr fixtures are verbatim captured bytes, escape sequences included — a hand-written transcription passed while production behaviour was broken.

Windows baseline

Three tests failed on Windows before this change: TestExtractTarGz and TestDownloaderEnsure_DownloadsVerifiesCaches assert an exec bit Go never reports there (mode 0666), and TestWithStderr shelled out to sh. The first two are now GOOS-gated (the download path is unix-only) and the third uses a portable helper-process. The suite is green on Windows for the first time.

Not in this PR

  • Windows resolution and auto-download. Win-CodexBar has just merged publishing CodexBarCLI-v<version>-windows-x64.zip as a release asset, so Windows will eventually get the same zero-install path as macOS/Linux. That needs zip extraction and a pinned checksum from a published release — neither exists yet.
  • pinnedVersion stays at 0.45.2: unix-only surface, unverifiable from a Windows host.

Summary by cubic

Accepts the Win-CodexBar CLI's JSON output — snake_case keys, no identity block, bare-string errors — so usage polling works on Windows. A bare-string error previously failed the whole array decode, so one failed provider discarded every healthy one alongside it and the operator saw "parsing codexbar output".

  • Both spellings decode as co-equal: camelCase stays the strict contract, snake_case is a best-effort fallback that ignores bad values rather than failing the document.
  • reset_at is omitted when zero, so "resets now" no longer shows forever; this also fixes macOS when upstream omits resetsAt.
  • stderr selection skips colored log lines and strips SGR escapes, so failures report the real cause, with upstream's swift-log output provably unchanged.
  • WaitDelay bounds Wait after a deadline kill so a child holding the output pipe can't wedge the poller.
  • A configured command that's a path on disk is taken whole (quotes dropped first), so Explorer-copied paths with spaces work.
  • Per-provider timeouts are reported as timeouts, and on-demand session failures now reach the session card instead of returning an empty report.
  • The Windows suite is green: exec-bit assertions are non-Windows-only, and stderr tests use a portable helper process instead of sh.

Written for commit 2b70b8c. Summary will update on new commits.

Review in cubic

… discarding the whole report

The codexbar CLI has no Windows build; the Win-CodexBar port is the only
compatible one there, and it spells the usage payload differently: snake_case
keys, no identity block, and a failing provider's `error` as a bare string
rather than an object. That last one is not cosmetic — a string there failed the
decode of the entire JSON array, so a single unauthenticated provider discarded
every healthy one alongside it, and the operator saw "parsing codexbar output"
instead of the reason.

Decode both spellings as co-equal. Upstream may keep camelCase and the port may
re-converge on it, so neither is treated as legacy: the camelCase pass stays the
strict contract, and a best-effort snake_case pass fills in whatever it left
zero — best-effort because a wrongly-typed key in the fallback spelling must not
discard the document it was meant to rescue.

Also, all platform-neutral and all found while testing against the port:

- Omit reset_at when the window has no reset time. The zero time serialized as
  "0001-01-01T00:00:00Z", which the UI reads as a real (long past) date and
  renders as "resets now" forever, never reaching the reset_description
  fallback. This fixes the same bug on macOS whenever upstream omits resetsAt.
- Lift the real cause out of stderr. The port writes structured log lines there,
  so a failure was reported as a cookie-decryption warning. Ask for NO_COLOR
  (its logging layer colors stderr even through a pipe, and even with
  --no-color) and skip lines whose first token is an RFC3339 timestamp —
  upstream's swift-log writes a "+0000" offset, which RFC3339 rejects, so its
  stderr selection is unchanged.
- Bound Wait after a context kill (WaitDelay). Killing the process does not
  unblock Wait while any child still holds the output pipe, which could wedge
  the poller behind pollMu.
- Take a configured command that is a path on disk whole, so it may contain
  spaces, dropping surrounding quotes first — what Explorer's "Copy as path"
  produces. The setting is documented as a path, and the Windows default install
  sits under a user profile directory.
- Report a per-provider timeout as one, instead of the exit status of the
  process the deadline killed.

The suite now passes on Windows, where three tests failed before this change:
two assert an exec bit Go never reports there, and one shelled out to `sh`.
@greptile-apps

greptile-apps Bot commented Aug 31, 2026

Copy link
Copy Markdown

Greptile Summary

The PR broadens CodexBar compatibility while making provider collection and diagnostics more resilient.

  • Accepts Win-CodexBar’s snake_case usage fields and string-valued provider errors without discarding healthy entries.
  • Omits unknown reset timestamps so reset descriptions remain usable.
  • Improves command-path parsing, stderr selection, timeout reporting, and leaked-pipe handling.
  • Makes affected process and downloader tests portable to Windows.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete changed-code defect identified.

The compatibility decoders preserve strict upstream parsing while treating Windows spellings as best-effort fallbacks, and the command-runner changes bound leaked pipes and improve diagnostics without changing the established operator-controlled execution boundary.

Important Files Changed

Filename Overview
server/plugin.go Adds bounded command waiting, cleaner stderr diagnostics, path-aware configured-command parsing, and explicit per-provider timeout messages without exposing a confirmed regression.
server/usage.go Adds tolerant Win-CodexBar decoding and omits zero reset timestamps while preserving the upstream camelCase contract.
server/plugin_test.go Adds portable helper-process coverage for stderr handling, leaked pipes, configured paths, and timeout reporting.
server/usage_test.go Covers captured Windows payloads, mixed provider errors, spelling precedence, malformed fallback values, and reset omission.
server/helper_process_test.go Provides a cross-platform subprocess fixture for real exit errors and inherited-pipe behavior.
server/download_test.go Skips Unix-only executable-bit and warm-cache assertions on Windows while retaining content and download verification.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Poll or refresh] --> B[Resolve configured CodexBar command]
  B --> C[Probe CLI]
  C --> D[Run provider queries with bounded waits]
  D --> E[Decode camelCase and snake_case payloads]
  E --> F[Usable provider records]
  E --> G[Per-provider unavailable records]
  F --> H[Shared usage report]
  G --> H
Loading

Reviews (1): Last reviewed commit: "fix: accept the Win-CodexBar CLI's JSON,..." | Re-trigger Greptile

@carlosflorencio
carlosflorencio self-requested a review August 31, 2026 07:49
@carlosflorencio

Copy link
Copy Markdown
Member

Thanks for the contribution. I pushed commit 2b70b8c with two small hardening fixes:

  • Preserve a quoted Windows CLI path as one argument when the path is missing, so probe diagnostics show the full path.
  • Return hard command errors from session on-demand reads through the existing error field.

I also added focused regression tests for both cases. These changes keep the existing provider-neutral API and snapshot architecture unchanged.

@carlosflorencio
carlosflorencio merged commit f073405 into kdlbs:main Aug 31, 2026
3 checks passed
@JnManso
JnManso deleted the fix/tolerant-codexbar-json branch August 31, 2026 09:43
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.

2 participants