Repository navigation
fix: accept the Win-CodexBar CLI's JSON, and stop one failed provider discarding the whole report - #18
Conversation
… 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`.
|
| 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
Reviews (1): Last reviewed commit: "fix: accept the Win-CodexBar CLI's JSON,..." | Re-trigger Greptile
|
Thanks for the contribution. I pushed commit
I also added focused regression tests for both cases. These changes keep the existing provider-neutral API and snapshot architecture unchanged. |
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
identityblock, and a failing provider'serroras 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 sawparsing codexbar outputinstead 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:
reset_at,omitzero0001-01-01T00:00:00Z;fmtResetreads any non-empty value as a real date and renders "resets now" forever, never reaching thereset_descriptionfallback. This fixes the same bug on macOS whenever upstream omitsresetsAt.firstUsefulLine+NO_COLOR--no-color, so the escapes had to go too. Upstream's swift-log writes a+0000offset, whichtime.Parse(RFC3339)rejects — macOS stderr selection is provably unchanged.cmd.WaitDelayWaitwhile any child still holds the output pipe — that could wedge the poller behindpollMu.parseConfiguredCommandstrings.Fieldsshattered 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.Testing
End to end against the real
codexbar-cli.exe0.55.0 through the production runner:Before this change the same command produced zero windows and a parse error.
-shuffle=on, and with aTEMPpath containing spaces.go vetclean; cross-compiles for all five platforms inmanifest.yaml;node --test16/16;go.mod/go.sumuntouched.stripSGRfails the stderr tests, removingWaitDelaymakes 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:
TestExtractTarGzandTestDownloaderEnsure_DownloadsVerifiesCachesassert an exec bit Go never reports there (mode 0666), andTestWithStderrshelled out tosh. The first two are nowGOOS-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
CodexBarCLI-v<version>-windows-x64.zipas 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.pinnedVersionstays 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
identityblock, 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".reset_atis omitted when zero, so "resets now" no longer shows forever; this also fixes macOS when upstream omitsresetsAt.WaitDelayboundsWaitafter a deadline kill so a child holding the output pipe can't wedge the poller.sh.Written for commit 2b70b8c. Summary will update on new commits.