Skip to content

feat(tui): polish command output#98

Merged
Vasanthdev2004 merged 2 commits into
mainfrom
feat/tui-command-polish
Jun 6, 2026
Merged

feat(tui): polish command output#98
Vasanthdev2004 merged 2 commits into
mainfrom
feat/tui-command-polish

Conversation

@Vasanthdev2004

@Vasanthdev2004 Vasanthdev2004 commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds reusable TUI command output formatting with status, sections, fields, rows, hints, and redaction.
  • Groups slash-command help and drives startup chips from command metadata.
  • Polishes /model, /provider, /config, /context, /permissions, /resume, /compact, /style, /effort, and debug/theme shell-state outputs.
  • Moves command readout code out of model.go into focused command view helpers.

Tests

  • go test ./internal/tui
  • go test ./...
  • go build ./cmd/zero

Review Notes

  • /provider uses redacted provider snapshots so credential-bearing base URLs are not leaked.
  • Startup remains minimal; no extra context/history/session panels are shown.

Summary by CodeRabbit

  • New Features

    • Commands now render as structured views with status indicators, grouped sections, hints, and compacted text
    • Help is organized into grouped command sections with stable ordering; startup command chips are deterministic
    • Session, model, compact, provider, context, permissions, and debug views show richer, clearer summaries; secrets/tokens are redacted
  • Tests

    • Added broad tests validating command output formatting, status mappings, help grouping, startup ordering, and redaction behavior

@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Zero automated PR review

Verdict: No blockers found

Blockers

  • None found.

Validation

  • [pass] Diff hygiene: git diff --check
  • [pass] Tests: go test ./...
  • [pass] Build: go run ./cmd/zero-release build
  • [pass] Smoke build: go run ./cmd/zero-release smoke

Scope

Head: 1ff1d53401ac
Changed files (15): internal/tui/command_center.go, internal/tui/command_output.go, internal/tui/command_output_test.go, internal/tui/command_polish_test.go, internal/tui/command_views.go, internal/tui/commands.go, internal/tui/commands_test.go, internal/tui/model.go, internal/tui/model_catalog.go, internal/tui/model_test.go, internal/tui/rendering.go, internal/tui/session.go, and 3 more

This deterministic review checks validation status and basic diff hygiene. A human reviewer still owns product judgment and design quality.

@anandh8x anandh8x left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What's good

  • Unified commandOutput framework reduces duplication. Every TUI command output is now a commandOutput struct (Title, Status, Sections, Hints) rendered by formatCommandOutput. Adding a new command is just filling in the struct — no more strings.Join([]string{...}, "\n") sprawl across model.go, session_controls.go, command_center.go, and friends.

  • commandStatus enum is precise. ok / warning / blocked / info covers the real semantic states. normalizeCommandStatus defaults unknown to info so a future status addition doesn't break rendering. The data is in place for a future enhancement to theme the status line per value.

  • Secret redaction is centralized and tested. \bsk-[A-Za-z0-9._-]+\b in commandOutputSecretPatterns catches sk-... tokens. Applied in compactCommandOutputText which is called for every text segment (title, field key/value, line, row, hint). The test feeds "sk-sensitive approved shell" and asserts it becomes "[REDACTED] approved shell". Defense-in-depth: the internal/redaction package is the primary layer; this is a fallback for tokens that escaped.

  • Whitespace compaction and empty-skipping are consistent. strings.Join(strings.Fields(text), " ") collapses all whitespace. The test " use /doctor for details\r\nsoon ""use /doctor for details soon" locks the behavior. Empty/whitespace-only fields, lines, and rows are dropped — so a nil sections list renders as just the title + status line, not a tree of blanks.

  • Grouping /help output is a real UX win. The 5 groups (Model, Session, Runtime, Tools, Meta) make the help scannable. commandGroupOrder() is the single source of truth for the group order. TestFormatCommandHelpLinesGroupsCommandsByStableOrder asserts the order is preserved end-to-end, and TestHelpCommandRendersGroupedSections asserts the new /help shape (with the "submit plain text" hint replacing the old "Submit text to ask the assistant").

  • startupOrder metadata replaces hard-coded list. The previous []string{"/plan", "/debug", "/tools", "/model", "/provider"} is now driven by commandDefinition.startupOrder. Adding a new startup chip is one field. TestCommandDefinitionsExposeStartupChipsInStableOrder uses reflection to verify the chip order matches the metadata, catching future field renames.

  • Cross-PR integration with zerocommands is clean. /provider uses zerocommands.ProviderSnapshotFromProfile (PR #82/#90), so URL userinfo and api_key= query param redaction happens at the snapshot layer. /permissions still uses zerocommands.SandboxGrantSnapshots (PR #89), so grant reason redaction is inherited. TestProviderCommandRedactsCredentialBearingBaseURL confirms https://user:super-secret@proxy.local/v1?api_key=query-secrethttps://proxy.local/v1?api_key=[REDACTED]. Good layering — the TUI doesn't re-implement snapshot logic.

  • Removing "shell-only" placeholder text is a real product-quality improvement. The old "X is registered in the Go TUI shell but is not wired yet" was honest but unhelpful. The new "This control is available in the TUI but does not have a backend setting yet" is still honest, more specific, and less jarring. TestCompactCommandAvoidsShellOnlyPlaceholder and TestCompactCommandRecordsShellRequest both lock the new strings and assert the old placeholders are gone.

  • compactText now describes product state. Old output: "Compact\nstatus: ...\nbackend: not wired yet" or "request recorded for future compaction backend.". New output: structured State + Backend sections, "summary: ...", "requested: yes/no", "state: pending integration", and a hint "compaction request is tracked for this TUI session". The boolText helper gives a clean requested: yes rather than a free-form phrase.

  • Redaction is applied uniformly via compactCommandOutputText. Every text segment (title, field, line, row, hint) goes through the same compaction + redaction path. A future secret format addition is one regex entry, and the test pattern (TestFormatCommandOutputRedactsTokenLikeText) generalizes to any token pattern.

  • transcriptHasMarkedModelEntry test fix is correct. The previous check strings.HasPrefix(line, "* ") would fail on the new 2-space indented output. The fix trims first. Defensive test pattern.

  • Test coverage is comprehensive. New command_output_test.go (5 tests), commands_test.go (2 tests with reflection), and command_polish_test.go (5 tests for product-state output). Existing TestCompactCommandRecordsShellRequest updated to lock the new strings.

Observations (non-blocking)

  1. Redaction pattern is narrow. Only sk-... is matched. Other formats (AWS, GitHub ghp_..., JWTs, etc.) are not caught. The internal/redaction package has broader patterns; a future enhancement could call it directly from compactCommandOutputText or expand the regex list.

  2. Status is not visually distinguished in the rendered output. formatCommandOutput emits status: <value> as a plain text line. A future enhancement could theme the status line (red for blocked, amber for warning, green for ok). The data is there; the styling is not.

  3. Redundant lines in some command outputs. /permissions has both "Permission mode:" and "mode:". /provider has both "active:" and "provider:". /model has both "Active model:" and "model:". /context has both "tools:" and "registered tools:". A cleanup pass could drop the duplicate. Minor.

  4. A tool name or command starting with sk- would be mis-redacted. The \b word boundary helps, but sk-looker-integration would also be redacted. Unlikely in practice, but worth noting for future edge cases.

  5. shellOnlyCommandText is no longer "shell-only". The function name is now misleading. A rename to placeholderCommandText or pendingCommandText would be clearer.

  6. No test for nil sections / nil fields slices in formatCommandOutput. The existing tests cover empty/whitespace values but not nil slices. A future test could lock the nil-handling behavior.

  7. No benchmark for formatCommandOutput. The regex is compiled at package init (compile-once), so the hot path is fast. A small benchmark would catch future regressions where someone adds an O(n) string allocation per call.

  8. /compact still says "state: pending integration" — itself a placeholder. The test name TestCompactCommandAvoidsShellOnlyPlaceholder is accurate (it asserts the old text is gone), but the new text is still a placeholder. A future slice could implement compaction and replace it with real state.

  9. No test for startupOrder ties. startupCommandNames uses sort.SliceStable with a secondary sort on name to break ties. The test only exercises all-unique orders. A test with two commands sharing startupOrder would lock the tie-breaker.

  10. formatGroupedCommandHelpLines is only used in one place (as the body of formatCommandHelpLines). The two functions are redundant — formatCommandHelpLines could be deleted and callers updated. Minor.

  11. commands_test.go reflection test is a meta-test. It verifies the startupOrder field exists and is int. A simpler test that asserts the chip order would suffice, but the reflection version catches field renames. Defensive.

  12. No test for commandHelpLinesForGroup with an empty group. If a group has no commands, the lines are not emitted (handled by the len(groupLines) == 0 check). A test would lock the behavior.

  13. The \b word boundary in the redaction regex requires the token to be preceded and followed by a non-word character. That works for sk-foo bar but not for prefixsk-foo. The current usage is fine (tokens are usually standalone), but a future edge case to consider.

  14. commandGroupTitle returns string(group) as the default. For an unknown group, the rendered title would be "commandGroup99"-style. The test doesn't exercise the unknown-group case. A future test could assert the default behavior.

  15. /plan description is "Show planning mode status." Accurate but doesn't explain what planning mode is. A hint like "use /plan to view or toggle planning mode" would help discoverability.

  16. No test for the formatCommandSection empty sections case. A section with no fields, lines, rows, or hints renders as just the title. A test would lock the behavior.

  17. The formatCommandOutput always emits a status: line, even if status is empty (which normalizeCommandStatus converts to info). A future optimization could omit the line if status is info and no sections are present. Not a concern at the current scale.

Approving — the slice is well-executed. The unified commandOutput framework reduces duplication, the redaction layer is a useful safety net, the help grouping is a real UX win, the startup chip metadata replaces a hard-coded list, the cross-PR integration with zerocommands is clean, and the "shell-only" placeholder text is replaced with softer language. The tests are comprehensive. The follow-ups are minor (narrow redaction pattern, status theming, redundant lines in some command outputs, function rename for shellOnlyCommandText).

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Complex PR? Review this PR in Change Stack to move by importance, not file order.

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0e4b2c17-ebea-4ce7-bb51-ae1f697dd67c

📥 Commits

Reviewing files that changed from the base of the PR and between 2eab434 and 1ff1d53.

📒 Files selected for processing (7)
  • internal/tui/command_output.go
  • internal/tui/command_output_test.go
  • internal/tui/command_polish_test.go
  • internal/tui/command_views.go
  • internal/tui/model_test.go
  • internal/tui/session_controls.go
  • internal/tui/session_controls_test.go
💤 Files with no reviewable changes (1)
  • internal/tui/session_controls.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • internal/tui/session_controls_test.go
  • internal/tui/model_test.go
  • internal/tui/command_output_test.go
  • internal/tui/command_output.go
  • internal/tui/command_views.go
  • internal/tui/command_polish_test.go

Walkthrough

Introduce a structured commandOutput model and formatter, migrate TUI view methods and command help/startup metadata to use it, and add unit/integration tests for formatting, redaction, help grouping, and stable startup ordering.

Changes

TUI Command Output Refactoring

Layer / File(s) Summary
Command output types & formatter
internal/tui/command_output.go
Adds commandOutput, commandSection, commandField, commandRow, status constants, formatCommandOutput, formatCommandSection, normalizeCommandStatus, and whitespace/redaction compaction utilities.
Formatter unit tests
internal/tui/command_output_test.go
Tests covering full rendering (title/status/fields/rows/hints), status mappings, plain lines vs bullets, token redaction, and whitespace compaction/skipping empty items.
Command view implementations
internal/tui/command_views.go
Implements model methods to render Tools, Permissions, Provider, Model, Context, Config, and Debug as structured commandOutput responses, handling nil stores and errors.
Command definitions, help & startup ordering
internal/tui/commands.go
Extends commandDefinition with aliases and startupOrder, updates definitions to named fields, reworks grouped help formatting (including aliases), and implements startupCommandNames() for deterministic startup chips.
Help & startup tests
internal/tui/commands_test.go
Tests that grouped help lines are ordered stably and that startup chips come from startupCommandNames() in a deterministic order.
Session, resume, model list & rendering changes
internal/tui/session.go, internal/tui/session_controls.go, internal/tui/command_center.go, internal/tui/model_catalog.go, internal/tui/rendering.go, internal/tui/startup.go, internal/tui/model_test.go
Migrate /resume, /effort, /style, /compact, model list, shell-only warning, and help text to use renderCommandOutput with statuses, sections, and hints; update commandChips() to use startupCommandNames() and small test helper whitespace handling.
Integration / polish tests
internal/tui/command_polish_test.go, internal/tui/session_controls_test.go
End-to-end tests validating grouped help output, provider/config stable status and redaction, context/permissions product-state rendering, and /compact output avoids placeholder backend/wiring messages.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Gitlawb/zero#63: touches internal/tui/command_center.go and resume rendering changes.
  • Gitlawb/zero#69: session persistence and /resume hydration logic related to this PR's resume output changes.
  • Gitlawb/zero#57: earlier command/help system updates that overlap with this PR's help/metadata refactor.

Suggested reviewers

  • gnanam1990
  • anandh8x
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(tui): polish command output' directly and accurately describes the main change—refactoring TUI command output formatting to be more polished and structured across multiple commands.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tui-command-polish

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

🧹 Nitpick comments (3)
internal/tui/command_views.go (1)

127-141: 💤 Low value

Minor redundancy in field label.

Line 134 outputs "Active model:" within a section already titled "Active", creating redundancy ("Active\n Active model: ..."). Consider shortening the field label to just "model:" for consistency with other views.

♻️ Optional simplification
 			Title: "Active",
 			Lines: []string{
-				"Active model: " + displayValue(m.modelName, "none"),
+				"model: " + displayValue(m.modelName, "none"),
 				"provider: " + displayValue(m.providerName, "none"),
 				"effort: " + m.effortDisplay(),
 			},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/tui/command_views.go` around lines 127 - 141, The "Active model: "
label in the modelText function is redundant given the enclosing section title
"Active"; update the field label in modelText (inside commandOutput -> Sections
-> Lines) to a shorter form such as "model: " (matching casing used elsewhere)
so the section reads "Active" with a line "model: <value>" instead of "Active
model: <value>" for consistency with other views.
internal/tui/command_output.go (2)

8-10: ⚡ Quick win

Secret pattern may not cover all provider key formats.

The regex \bsk-[A-Za-z0-9._-]+\b only matches OpenAI-style keys starting with sk-. Other providers use different prefixes (e.g., Anthropic keys may use different formats). If the goal is comprehensive credential redaction across all providers, consider expanding the pattern list.

🔐 Suggested pattern additions
 var commandOutputSecretPatterns = []*regexp.Regexp{
 	regexp.MustCompile(`\bsk-[A-Za-z0-9._-]+\b`),
+	regexp.MustCompile(`\bant-api-[A-Za-z0-9_-]+\b`),
+	regexp.MustCompile(`\bBearer\s+[A-Za-z0-9._-]+\b`),
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/tui/command_output.go` around lines 8 - 10, The redaction list in
commandOutputSecretPatterns only covers the OpenAI-style sk- token format, so
expand the pattern set to include other provider key prefixes/formats used in
command output redaction. Update the regexp slice in command_output.go and keep
the matching centralized there so command output sanitization in
commandOutputSecretPatterns covers all supported credentials.

123-125: Unused helper: remove or justify commandFieldLine

internal/tui/command_output.go defines commandFieldLine (lines 123-125), and no other references/call sites were found, so it’s dead code unless planned for future use. Remove it, or add a TODO/use it in the current TUI rendering path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/tui/command_output.go` around lines 123 - 125, The function
commandFieldLine is unused and should be removed or justified: either delete the
commandFieldLine function entirely to eliminate dead code, or if it’s intended
for future use, add a clear TODO comment above it and actually integrate it into
the TUI rendering path (replace current manual key/value formatting with
commandFieldLine in the component that builds command output lines, using
compactCommandOutputText and displayValue), ensuring there are call sites
referencing commandFieldLine so it’s not orphaned.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/tui/command_views.go`:
- Around line 100-104: The profileLines slice currently contains a duplicate use
of m.providerName for both "active:" and "provider:"; update the slice so each
entry is unique by removing or replacing the duplicate—e.g., keep only one line
referencing m.providerName ("provider: " + displayValue(m.providerName, "none"))
and ensure "active:" is either removed or replaced with the correct field (if
there is an active profile field, use that instead). Locate the profileLines
declaration and adjust the elements accordingly, keeping displayValue(...) and
m.modelName unchanged.
- Around line 170-176: The "Tools" view emits the same toolCount twice (Lines
contains both fmt.Sprintf("tools: %d", toolCount) and fmt.Sprintf("registered
tools: %d", toolCount)); remove the duplicate entry and leave a single
descriptive line (e.g., keep only fmt.Sprintf("registered tools: %d", toolCount)
or "tools") inside the Lines slice for the struct literal so the tool count is
shown once; reference the Lines slice and the toolCount variable in the block
that builds the "Tools" Title.
- Around line 47-50: The stateLines slice in internal/tui/command_views.go
contains a duplicated permission mode entry; remove one of the two entries so
only a single line representing m.permissionMode remains (e.g., keep "Permission
mode: "+string(m.permissionMode) and delete the other "mode:
"+string(m.permissionMode)) to eliminate the unintended duplicate output in the
UI.

In `@internal/tui/session_controls.go`:
- Around line 167-173: The compactText method currently ignores the requested
parameter because it sets status := commandStatusInfo then immediately
overwrites status to commandStatusWarning in both branches; update compactText
so that when requested is true it assigns commandStatusWarning and when false it
assigns commandStatusInfo (or if the intended behavior is always warning, remove
the conditional and set status := commandStatusWarning), referencing the
compactText function and the commandStatusInfo/commandStatusWarning constants to
fix the logic so requested actually changes the status.

---

Nitpick comments:
In `@internal/tui/command_output.go`:
- Around line 8-10: The redaction list in commandOutputSecretPatterns only
covers the OpenAI-style sk- token format, so expand the pattern set to include
other provider key prefixes/formats used in command output redaction. Update the
regexp slice in command_output.go and keep the matching centralized there so
command output sanitization in commandOutputSecretPatterns covers all supported
credentials.
- Around line 123-125: The function commandFieldLine is unused and should be
removed or justified: either delete the commandFieldLine function entirely to
eliminate dead code, or if it’s intended for future use, add a clear TODO
comment above it and actually integrate it into the TUI rendering path (replace
current manual key/value formatting with commandFieldLine in the component that
builds command output lines, using compactCommandOutputText and displayValue),
ensuring there are call sites referencing commandFieldLine so it’s not orphaned.

In `@internal/tui/command_views.go`:
- Around line 127-141: The "Active model: " label in the modelText function is
redundant given the enclosing section title "Active"; update the field label in
modelText (inside commandOutput -> Sections -> Lines) to a shorter form such as
"model: " (matching casing used elsewhere) so the section reads "Active" with a
line "model: <value>" instead of "Active model: <value>" for consistency with
other views.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e35a5887-0899-4b80-a610-81aaae2b5aaf

📥 Commits

Reviewing files that changed from the base of the PR and between 699df01 and 2eab434.

📒 Files selected for processing (15)
  • internal/tui/command_center.go
  • internal/tui/command_output.go
  • internal/tui/command_output_test.go
  • internal/tui/command_polish_test.go
  • internal/tui/command_views.go
  • internal/tui/commands.go
  • internal/tui/commands_test.go
  • internal/tui/model.go
  • internal/tui/model_catalog.go
  • internal/tui/model_test.go
  • internal/tui/rendering.go
  • internal/tui/session.go
  • internal/tui/session_controls.go
  • internal/tui/session_controls_test.go
  • internal/tui/startup.go
💤 Files with no reviewable changes (1)
  • internal/tui/model.go

Comment thread internal/tui/command_views.go
Comment thread internal/tui/command_views.go
Comment thread internal/tui/command_views.go
Comment thread internal/tui/session_controls.go
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