fix(export): stop shadowing the global -o/--output format flag - #51
Merged
Merged
Conversation
`export tasks` defined its own -o/--output as the destination *file*, which shadowed the global format flag every other command uses. `cu export tasks -o json` therefore wrote a file literally named "json" instead of emitting JSON — the flag a user learned everywhere else silently did something else. The destination file moves to --file/-F, freeing -o. Freeing it is only half the fix. Leaving -o unread would trade one silent failure for another: a user asking for JSON would get the default CSV with no warning. So export now honours it as a synonym for --format, since they select the same thing. Anything export cannot produce — "table", "yaml", a filename — is a loud error naming the supported set, and a path-shaped value additionally points at --file, which is the predictable mistake this rename creates. Disagreeing --format and --output is an error rather than a precedence rule. Picking a winner is exactly how silently-wrong output happens, and there is no reading of `--format csv -o json` that is obviously intended. The existing flag test asserted the local "output" flag existed, encoding the bug; it now asserts the opposite and fails if the shadow is reintroduced. Fixes #28 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ZEGsLHBQ2GzP6v48i4hXz
timimsms
added a commit
that referenced
this pull request
Aug 30, 2026
Brings in #50 and #51. One conflict, in the export flag block, where this branch's --include-closed/--subtasks met #51 moving the destination file off -o/--output onto --file/-F. Both sides kept: the new filters stay, and -o is left to the global format flag as #51 intends. Resolved as a merge rather than a rebase because another session owns this branch; force-pushing rewritten history over it is the one operation that could destroy work in progress. Docs regenerated for the combined flag set — the auto-merged page still advertised -o as the output file, which is no longer true. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ZEGsLHBQ2GzP6v48i4hXz
4 tasks
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.
Summary
export tasksdefined its own-o/--outputas the destination file, shadowing the global format flag every other command uses. So the flag a user learned everywhere else silently did something different here:The destination file moves to
--file/-F, which frees-o.Freeing
-ois only half the fixSimply not reading
-owould trade one silent failure for another — a user who asked for JSON would receive the default CSV with no warning. That is the same class of bug, just quieter. So export honours it as a synonym for--format, since for this command they select the same thing:Three deliberate calls in there:
Anything export cannot produce is a loud error, not a fallback.
tableandyamlare valid globally but meaningless for a task export; silently degrading to CSV is what this release is trying to stamp out.A path-shaped value points at
--file. Reaching for the old-o <file>is the predictable mistake this rename creates, so the error says where the flag went instead of just rejecting the value.Disagreeing
--formatand--outputis an error, not a precedence rule. There is no reading of--format csv -o jsonthat is obviously intended, and picking a winner is precisely how silently-wrong output happens.Verification
Every case above was run against a built binary, not just unit-tested — including confirming that
-o jsonnow creates no file and that--file out.jsonwrites one. Those runs went through a live workspace, so the "26 tasks exported" path is real rather than mocked.Ten unit tests cover
resolveExportFormat(defaults, both spellings, themdalias, case-insensitivity, agreement, conflict, unsupported values, the--filehint). The existing flag test asserted the localoutputflag existed, encoding the bug — it now asserts the opposite, and I confirmed it fails if the shadow is reintroduced rather than passing vacuously.Docs regenerated; only
cu_export_tasks.mdcarries substantive changes, and the datestamp-only pages were reverted per the convention from #47. The page now correctly shows-ounder Global Flags as the format flag.Found while verifying — not fixed here
--filerejects absolute paths:export.gorefuses any path thatfilepath.IsAbsor contains.., which also rules out--file ~/exports/tasks.csv. There is no untrusted input here — the user is naming a file on their own machine — so the traversal check is guarding nothing while blocking the most natural usage. It predates this PR, but the rename makes it more prominent, since--fileis now the advertised way to write a file.I left it out because removing the check means handling gosec G304, which deserves its own decision rather than riding along on a flag rename. The repo already has the pattern for it (
// #nosec G304 - <justification>, used incache.goandconfig.go), so the fix is small. Happy to do it as a follow-up.Checklist
go build,go vet,gofmt, full suite passcu docs markdown --dir docs/site/commands)