Skip to content

feat: add interactive TUI dashboard command#372

Open
yasunogithub wants to merge 2 commits intoentireio:mainfrom
yasunogithub:yasu/add-dashboard-tui
Open

feat: add interactive TUI dashboard command#372
yasunogithub wants to merge 2 commits intoentireio:mainfrom
yasunogithub:yasu/add-dashboard-tui

Conversation

@yasunogithub
Copy link

Summary

  • Add entire dashboard command with four tabs: Sessions, Checkpoints, Active Sessions, and Settings
  • Built with bubbletea/lipgloss TUI framework with accessible text-mode fallback (ACCESSIBLE=1)
  • Includes checkpoint rewind with PreviewRewind safety check for untracked file deletion warnings
  • Rune-safe filter input handling for multi-byte character support
  • Header-pinning scroll in Active tab for consistent UX across all tabs

Test plan

  • Run mise run fmt && mise run lint && mise run test:ci — all pass
  • Run entire dashboard and navigate all four tabs
  • Test filter input with multi-byte characters (e.g., Japanese)
  • Test rewind from Checkpoints tab confirms before proceeding
  • Test ACCESSIBLE=1 entire dashboard for accessible text mode
  • Verify scroll behavior in Active tab with many sessions (headers stay pinned)

🤖 Generated with Claude Code

Add `entire dashboard` with four tabs (Sessions, Checkpoints, Active,
Settings) using bubbletea/lipgloss. Includes accessible text-mode
fallback, filter search, checkpoint rewind with PreviewRewind safety
check, and rune-safe input handling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 1e466c84838a
Copilot AI review requested due to automatic review settings February 17, 2026 11:38
@yasunogithub yasunogithub requested a review from a team as a code owner February 17, 2026 11:38
Copy link
Contributor

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

This PR adds an interactive TUI dashboard command (entire dashboard) built with the bubbletea/lipgloss framework. The dashboard provides a consolidated view of sessions, checkpoints, active sessions, and settings across four navigable tabs. It includes accessibility support via a text-mode fallback when ACCESSIBLE=1 is set, and implements checkpoint rewind functionality with safety warnings for untracked file deletions.

Changes:

  • Adds new entire dashboard command with full-screen TUI and accessible text-mode fallback
  • Implements four dashboard tabs: Sessions, Checkpoints, Active Sessions, and Settings with filtering and detail views
  • Integrates checkpoint rewind workflow with PreviewRewind safety checks for file deletion warnings
  • Promotes bubbletea and lipgloss from indirect to direct dependencies in go.mod

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
go.mod Promotes bubbletea and lipgloss to direct dependencies
cmd/entire/cli/strategy/registry.go Removes nolint:ireturn comments (will cause linter failures)
cmd/entire/cli/strategy/manual_commit.go Removes nolint:ireturn comments (will cause linter failures)
cmd/entire/cli/strategy/auto_commit.go Removes nolint:ireturn comments (will cause linter failures)
cmd/entire/cli/root.go Registers new dashboard command
cmd/entire/cli/dashboard_cmd.go Command entry point with accessibility check and rewind flow
cmd/entire/cli/dashboard/styles.go Dracula theme colors for consistent TUI styling
cmd/entire/cli/dashboard/settings_tab.go Settings display tab with configuration and agent status
cmd/entire/cli/dashboard/sessions_tab.go Sessions tab with rune-safe filtering and detail views
cmd/entire/cli/dashboard/data.go Async data loading commands and utility functions
cmd/entire/cli/dashboard/dashboard.go Main bubbletea model with tab navigation and lifecycle
cmd/entire/cli/dashboard/checkpoints_tab.go Checkpoints tab with filtering and rewind confirmation
cmd/entire/cli/dashboard/active_tab.go Active sessions tab with header-pinning scroll
cmd/entire/cli/dashboard/accessible.go Text-based accessible mode fallback

@@ -61,7 +61,7 @@ const DefaultStrategyName = StrategyNameManualCommit

// Default returns the default strategy.
// Falls back to returning nil if no strategies are registered.
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The nolint:ireturn comment should not be removed here. This function returns the Strategy interface, which is not in the ireturn allow list in .golangci.yaml. The linter will fail without this comment. The original comment correctly explained this is intentional for the registry pattern.

Suggested change
// Falls back to returning nil if no strategies are registered.
// Falls back to returning nil if no strategies are registered.
//nolint:ireturn // Strategy is returned by design for the registry pattern; not in ireturn allow list

Copilot uses AI. Check for mistakes.
//

func NewManualCommitStrategy() Strategy { //nolint:ireturn // factory returns interface by design
func NewManualCommitStrategy() Strategy {
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The nolint:ireturn comment should not be removed here. This function returns the Strategy interface, which is not in the ireturn allow list in .golangci.yaml. The linter will fail without this comment.

Copilot uses AI. Check for mistakes.
// NewShadowStrategy creates a new manual-commit strategy instance.
// This legacy constructor delegates to NewManualCommitStrategy.
//

Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The nolint:ireturn comment should not be removed here. This function returns the Strategy interface, which is not in the ireturn allow list in .golangci.yaml. The linter will fail without this comment.

Suggested change
//nolint:ireturn // Strategy is not in the ireturn allow list; constructors return the interface

Copilot uses AI. Check for mistakes.
@@ -84,7 +84,7 @@ func (s *AutoCommitStrategy) getCheckpointStore() (*checkpoint.GitStore, error)
// NewAutoCommitStrategy creates a new AutoCommitStrategy instance
//

Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The nolint:ireturn comment should not be removed here. This function returns the Strategy interface, which is not in the ireturn allow list in .golangci.yaml. The linter will fail without this comment.

Suggested change
//nolint:ireturn // factory intentionally returns Strategy interface (not in ireturn allow list)

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +126
func newDashboardCmd() *cobra.Command {
return &cobra.Command{
Use: "dashboard",
Short: "Open interactive session dashboard",
Long: `Interactive TUI dashboard for browsing sessions, checkpoints,
active sessions, and settings.

Navigate with Tab/Shift+Tab between tabs, j/k or arrow keys to move,
Enter to view details, and q to quit.

In the Checkpoints tab, press r to rewind to a selected checkpoint.`,
RunE: func(cmd *cobra.Command, _ []string) error {
// Check if we're in a git repository
if _, err := paths.RepoRoot(); err != nil {
cmd.SilenceUsage = true
fmt.Fprintln(cmd.ErrOrStderr(), "Not a git repository. Please run from within a git repository.")
return NewSilentError(errors.New("not a git repository"))
}

// Check if Entire is disabled
if checkDisabledGuard(cmd.OutOrStdout()) {
return nil
}

// Accessible mode uses text-based menu
if IsAccessibleMode() {
return dashboard.RunAccessible(cmd.OutOrStdout())
}

// Run TUI dashboard
rewindReq, err := dashboard.Run()
if err != nil {
return fmt.Errorf("dashboard error: %w", err)
}

// Handle rewind request from dashboard
if rewindReq != nil {
return performRewindFromDashboard(cmd, rewindReq.PointID)
}

return nil
},
}
}

// performRewindFromDashboard executes a rewind after the dashboard TUI exits.
func performRewindFromDashboard(cmd *cobra.Command, pointID string) error {
strat := GetStrategy()

// Check if rewind is possible
canRewind, reason, err := strat.CanRewind()
if err != nil {
return fmt.Errorf("failed to check rewind status: %w", err)
}
if !canRewind {
fmt.Fprintln(cmd.OutOrStdout(), reason)
return nil
}

// Find the matching rewind point
points, err := strat.GetRewindPoints(100)
if err != nil {
return fmt.Errorf("failed to get rewind points: %w", err)
}

var target *strategy.RewindPoint
for i := range points {
if points[i].ID == pointID {
target = &points[i]
break
}
}

if target == nil {
return fmt.Errorf("rewind point %s not found", pointID)
}

// Preview rewind to show warnings about files that will be deleted
preview, previewErr := strat.PreviewRewind(*target)
if previewErr == nil && preview != nil && len(preview.FilesToDelete) > 0 {
fmt.Fprintf(cmd.ErrOrStderr(), "\nWarning: The following untracked files will be DELETED:\n")
for _, f := range preview.FilesToDelete {
fmt.Fprintf(cmd.ErrOrStderr(), " - %s\n", f)
}
fmt.Fprintf(cmd.ErrOrStderr(), "\n")
}

// Perform the rewind
if err := strat.Rewind(*target); err != nil {
return fmt.Errorf("rewind failed: %w", err)
}

fmt.Fprintln(cmd.OutOrStdout(), "Successfully rewound to checkpoint.")

// Print resume command if agent info available
if target.Agent != "" {
resumeCmd := formatResumeCommand(target.Agent, target.SessionID)
if resumeCmd != "" {
fmt.Fprintf(cmd.OutOrStdout(), "\nTo resume: %s\n", resumeCmd)
}
}

return nil
}

// formatResumeCommand generates the resume command for an agent.
func formatResumeCommand(agentType agent.AgentType, sessionID string) string {
ag, err := agent.GetByAgentType(agentType)
if err != nil {
return ""
}
return ag.FormatResumeCommand(sessionID)
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

Missing test coverage for the dashboard command and package. The repository has comprehensive test coverage for other commands (e.g., status_test.go, clean_test.go, setup_test.go). The dashboard command should have similar test coverage for:

  • Command registration and basic execution
  • Error handling (not in git repo, disabled guard)
  • Accessible mode vs TUI mode
  • Rewind flow from dashboard
  • Data loading functions
  • Filter and navigation logic in tab models

At minimum, add tests for the command entry point and error paths in dashboard_cmd.go.

Copilot uses AI. Check for mistakes.
@@ -24,7 +24,7 @@ func Register(name string, factory Factory) {

// Get retrieves a strategy by name.
// Returns an error if the strategy is not registered.
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The nolint:ireturn comment should not be removed here. This function returns the Strategy interface, which is not in the ireturn allow list in .golangci.yaml (lines 98-110). The linter will fail without this comment. The original comment correctly explained this is intentional for the registry pattern.

Suggested change
// Returns an error if the strategy is not registered.
// Returns an error if the strategy is not registered.
//nolint:ireturn // returning Strategy interface is intentional for the registry-based strategy pattern

Copilot uses AI. Check for mistakes.
Add strategy.Strategy to the ireturn allow list in .golangci.yaml,
replacing scattered //nolint:ireturn comments on factory functions.
Add comprehensive test coverage for the dashboard package and command.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: f3278aa07808
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments