fix(review): fall back across GitButler JSON flag syntaxes (but 0.22.0) - #1216
Merged
Conversation
GitButler 0.22.0 removed the global --format flag in favor of --json (gitbutlerapp/gitbutler#15026), so `but --format json status` now dies with clap's unexpected-argument error and GitButler review sessions fail to start. 0.21.x accepts only --format json (gitbutlerapp/gitbutler#14061), so neither spelling works everywhere. Keep --format json as the primary invocation and, only when it fails with clap's narrow unexpected-argument rejection for the exact flag we passed, retry once with the other spelling. Real status failures never retry and keep failing loudly per the module's contract-error philosophy. The accepted spelling is remembered per runtime so 0.22.0 installs pay the failed probe once. Error strings now name the syntax actually used. Closes #1215
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TLDR:
plannotator reviewin a GitButler workspace dies on GitButler CLI 0.22.0 becausebut --format json statusis rejected witherror: unexpected argument '--format' found. The status call now retries exactly once withbut --json statuswhen, and only when, the failure is clap's unexpected-argument rejection of the flag we passed. Every other failure still fails loudly with no retry.Closes #1215
Verified upstream flag history
Checked directly against the
butCLI's clap definitions (crates/but/src/args/mod.rs) at therelease/0.21.0,release/0.21.2, andrelease/0.22.0tags of gitbutlerapp/gitbutler:--jsonflag. feat(cli)!: remove--jsonin favor of--format jsongitbutlerapp/gitbutler#14061 (merged 2026-06-05, shipped in 0.21.0) removed it in favor of a global--format <human|agent|shell|json|none>value flag. All of 0.21.0 through 0.21.2 accept only--format jsonand reject--jsonas an unexpected argument.--json". 0.22.0 accepts only a global boolean--jsonand rejects--formatas an unexpected argument.crates/but/src/retired_syntax.rs), but it only rewrites the retiredbut commitgrammar. It does not translate the global--formatflag, sobut --format json statusgenuinely fails on 0.22.0, exactly as reported.So each supported release rejects the other release's spelling, and both spellings must be handled. The JSON payload shape (
mergeBase,stacks,uncommittedChanges) is unchanged between the two flags, as the reporter observed.Design: narrow capability sniff, one retry, never on real failures
In
packages/shared/gitbutler-core.ts:but --format json statusstays the primary invocation, so 0.21.x installs see zero behavior change (it also matchesGITBUTLER_MIN_VERSION = "0.21.0", which is preserved: 0.21.x accepts the primary syntax, so no version bump is warranted).unexpected argument '--format'for the exact flag we passed, the other spelling (but --json status) is tried exactly once. The sniff is deliberately narrow: any other non-zero exit (locked database, real status failure, etc.) propagates unchanged as aGitButlerContractError, per the module's fail-loud contract philosophy. Retrying arbitrary failures could mask a real error behind a second, confusingly different one, and could double-run a command against a wedged repository.--formatprobe only once per session, and the sniff is symmetric from then on (if the preferred spelling ever stops parsing, the other is probed once).GitButler status (but --format json status) failed: ..., and the invalid-JSON parse error carries the same label).Pi
The reporter hit this on Pi.
gitbutler-coreis vendored to the Pi extension at build time byapps/pi-extension/vendor.sh(confirmed in its copy list), so the fix flows to Pi with no Pi-side changes; the Pi test suite passes against the regenerated vendor copy.Tests
New
GitButler status JSON flag fallbackdescribe block inpackages/shared/gitbutler-core.test.ts:--format json statusfails with the exact clap stderr, fallback runs--json status, parse succeeds, review context and workspace diff are built; the remembered spelling skips the failed probe after the cache TTL.--format json statusfails with an unrelated error (database locked), no retry happens (asserted on the recordedbutinvocations), and the contract error propagates.Results:
bun test packages/shared736 pass / 0 fail,bun test apps/pi-extension177 pass / 0 fail,bun run typecheckclean.Credit
Thanks @swushi for the report, the exact repro on 0.22.0, and for suggesting the capability-based dual-syntax approach this implements.
This fix was developed with AI assistance.