Skip to content

fix(cli): return structured results from configure and auth login/logout in machine output modes - #141

Open
TristanSpeakEasy wants to merge 4 commits into
feat/cli-configure-clearfrom
fix/cli-settings-machine-output
Open

TristanSpeakEasy wants to merge 4 commits into
feat/cli-configure-clearfrom
fix/cli-settings-machine-output

Conversation

@TristanSpeakEasy

@TristanSpeakEasy TristanSpeakEasy commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Stacked on #140 (the cleared field reports values removed with configure --clear, and auth logout uses the config.DeleteStoredSecret helper from #140). Retarget to main once #140 merges.

Why

In machine output modes (-o json, -o yaml, -o toon, --jq, agent mode) a successful live configure, auth login or auth logout still printed prose such as Configuration saved to ... to stdout. The --dry-run path of the same commands already returns a structured no-op object, and whoami already returns a structured result, so scripts got a parseable answer from the preview but not from the real run.

What changed

On success, in machine mode the commands return an output.LocalResult instead of prose. Human output is unchanged.

  • configure: {"config_file": ..., "keychain_stored": bool, "cleared": [...]}. keychain_stored is present when the API declares secret credentials; cleared only when --clear removed something. This applies whether or not interactive features are generated.
  • configure resolves the output mode and format before it saves, via a new output.PinOutputFormat. Otherwise configure --default-output-format json (or clearing a saved json default) would change how its own result is rendered.
  • auth login: {"config_file": ..., "keychain_stored": bool}.
  • auth logout: {"config_file": ..., "cleared": true, "keychain_cleared": bool}. Logout still clears every credential from the config file, but if the OS keychain refuses to delete one it now returns an error naming the credential instead of reporting success, so keychain_cleared: true means the keychain deletes worked. An unavailable or unresponsive keychain is reported as skipped as before (keychain_cleared: false).
  • Primary tests for configure --clear JSON output (with a saved json default being cleared), auth logout JSON output, and a failed keychain delete on logout.
  • Review SDK regenerated; changeset added.

Example:

$ cli configure --api-version v1 -o json
{"config_file":"/home/user/.config/cli/config.yaml","keychain_stored":false}
$ cli configure --clear api-version -o json
{"cleared":["api-version"],"config_file":"/home/user/.config/cli/config.yaml","keychain_stored":false}

Testing

  • TARGET=review make test-cli and TARGET=primary make test-cli: pass.
  • make check-template-cli: passes.
  • Generated the review CLI with interactiveAuth: false and interactiveMode: false: builds, and configure -o json ends with the structured result.
  • Manually on a generated CLI: configure set and --clear under -o json, and auth logout -o json.

Public-safety check

  • This change contains no credentials, customer documents, private repository URLs, private filesystem paths, or unredacted private logs.
  • Title, body, comments, and commit messages name no customers or customer-derived identifiers, private paths or trackers, or workflow provenance, and are understandable without private context (.claude/skills/public-repo-communication/SKILL.md).
  • Generated fixtures and review SDK changes are public-safe.
  • I reviewed git diff --check.

@TristanSpeakEasy
TristanSpeakEasy requested a review from a team as a code owner October 23, 2026 00:48
@TristanSpeakEasy
TristanSpeakEasy requested review from speakeasybot and removed request for a team October 23, 2026 00:48

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 6 files

Confidence score: 3/5

  • In templates/templates/cli/configure.go.stmpl, explicit interactive mode can emit form prompts before the JSON result, making --output-format json invalid machine-readable output. Reject this combination before rendering the form.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="templates/templates/cli/configure.go.stmpl">

<violation number="1" location="templates/templates/cli/configure.go.stmpl:175">
P2: Explicit interactive mode can still run the form before this machine result is emitted, so `--output-format json` receives prompts before the JSON object and becomes invalid machine output. Reject this combination or suppress the form whenever a machine format is selected.</violation>
</file>

Shadow auto-approve: would not auto-approve because issues were found.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread zSDKs/sdk-cli/internal/cli/auth.go
}

{{- if isAnyInteractiveEnabled}}
if output.IsMachineMode(cmd) {

@cubic-dev-ai cubic-dev-ai Bot Oct 23, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Explicit interactive mode can still run the form before this machine result is emitted, so --output-format json receives prompts before the JSON object and becomes invalid machine output. Reject this combination or suppress the form whenever a machine format is selected.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At templates/templates/cli/configure.go.stmpl, line 175:

<comment>Explicit interactive mode can still run the form before this machine result is emitted, so `--output-format json` receives prompts before the JSON object and becomes invalid machine output. Reject this combination or suppress the form whenever a machine format is selected.</comment>

<file context>
@@ -171,6 +171,18 @@ func runConfigureCmd(cmd *cobra.Command, args []string) error {
     }
 
+    {{- if isAnyInteractiveEnabled}}
+    if output.IsMachineMode(cmd) {
+        result := map[string]any{"config_file": config.GetConfigPath()}
+        {{- if hasSecretCLIFields}}
</file context>
Fix with cubic

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Leaving this as is. The form only runs when the user explicitly asks for it with --interactive (or the CLI defaults to interactive and no value flags are passed), and combining that with -o json is a conflicting request. Forms render on the terminal, and the JSON result is still the only thing configure writes on completion. Scripts should pass value flags or --no-interactive, which skip the form.

Comment thread zSDKs/sdk-cli/internal/cli/configure.go Outdated
Comment thread templates/templates/cli/configure.go.stmpl Outdated

@AshGodfrey AshGodfrey left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verified on a regenerated CLI: configure, auth login and auth logout return the structured envelope under json, yaml, toon, agent mode and --jq, prose is unchanged otherwise, and the output format is pinned before the saved default changes. Merge after #140 and retarget to main.

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