Skip to content

refactor: decouple --output json from non-interactive mode#41

Merged
aaearon merged 1 commit intomainfrom
feat/decouple-json-output-from-tty
Apr 20, 2026
Merged

refactor: decouple --output json from non-interactive mode#41
aaearon merged 1 commit intomainfrom
feat/decouple-json-output-from-tty

Conversation

@aaearon
Copy link
Copy Markdown
Owner

@aaearon aaearon commented Apr 20, 2026

Closes #40

Summary

  • Removes the PersistentPreRunE override that forced ui.IsTerminalFunc to return false whenever --output json was set — this affected all commands globally
  • Collapses the JSON-specific error branch in resolveRequestIDInteractive to the standard ErrNotInteractive path
  • Deletes the now-obsolete TestResolveRequestIDInteractive_JSONMode test

Behaviour change

--output json is now a pure serialisation flag. Interactive pickers and prompts (e.g. grant request get -o json with no ID, grant request submit -o json without --target/--role) work in a TTY, writing prompts to stderr and JSON results to stdout. When stdin is genuinely not a TTY, all prompts still return ErrNotInteractive with the appropriate bypass-flag hint — unchanged.

Test plan

  • make test passes
  • make lint clean
  • grant request get -o json in a TTY → interactive picker opens; selected request prints as JSON
  • grant request get -o json < /dev/null → returns ErrNotInteractive with hint
  • grant request get <id> -o json → prints JSON (no regression)

Remove the PersistentPreRunE override that forced IsTerminalFunc to
return false whenever --output json was set. Interactive prompts now run
normally in a TTY regardless of output format; JSON serialisation and
TTY detection are fully orthogonal.

Also collapse the JSON-specific error branch in resolveRequestIDInteractive
to the standard ErrNotInteractive path, and delete the now-obsolete
TestResolveRequestIDInteractive_JSONMode test.
Copilot AI review requested due to automatic review settings April 20, 2026 18:34
@aaearon aaearon merged commit 54a37bd into main Apr 20, 2026
3 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Decouples --output json from interactivity so JSON is treated as a serialization format rather than forcing non-interactive behavior across all commands.

Changes:

  • Removed the root PersistentPreRunE hook that forced ui.IsTerminalFunc to report non-interactive mode when --output json is set.
  • Simplified resolveRequestIDInteractive to return the standard ui.ErrNotInteractive path (no JSON-specific error branch).
  • Updated docs/changelog and removed the now-obsolete JSON-mode request picker test.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
cmd/root.go Stops globally overriding terminal detection when --output json is used.
cmd/request_picker.go Removes JSON-specific non-interactive error handling in request ID picker resolution.
cmd/request_picker_test.go Deletes the JSON-mode-specific test case for request ID picker behavior.
CLAUDE.md Updates internal documentation to reflect JSON output no longer affecting interactivity.
CHANGELOG.md Notes the behavior change for --output json regarding interactive prompts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/root.go
Comment on lines 101 to 104
if outputFormat != "text" && outputFormat != "json" {
return fmt.Errorf("invalid output format %q: must be one of: text, json", outputFormat)
}
if isJSONOutput() {
ui.IsTerminalFunc = func(fd uintptr) bool { return false }
}
return nil
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

Now that --output json no longer forces non-interactive mode, some commands can enter interactive flows while still expecting machine-readable output. At least cmd/revoke.go prints human text to stdout on the “no active sessions” and “revocation canceled” paths, which will break consumers expecting JSON when -o json is set. Consider auditing interactive commands so that in JSON mode either (a) non-JSON messages go to stderr and stdout remains valid JSON, or (b) cancellation/empty states return a JSON payload (or a non-zero error) instead of plain text.

Copilot uses AI. Check for mistakes.
Comment thread cmd/root.go
}
return nil
},
RunE: runFn,
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

Behavior around --output json affecting interactivity is a cross-cutting contract change, but there isn’t a test guarding it anymore (the JSON-mode request picker test was removed). Add a regression test that executes a trivial command with --output json and asserts ui.IsTerminalFunc is not mutated / interactive detection remains unchanged, so future refactors don’t reintroduce global side effects.

Suggested change
RunE: runFn,
RunE: func(cmd *cobra.Command, args []string) error {
originalIsTerminalFunc := ui.IsTerminalFunc
defer func() {
ui.IsTerminalFunc = originalIsTerminalFunc
}()
return runFn(cmd, args)
},

Copilot uses AI. Check for mistakes.
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.

decouple --output json from non-interactive mode

2 participants