Skip to content

Phase 2: bubbletea review screen for setup import - #129

Merged
yourconscience merged 3 commits into
mainfrom
setup-review-tui
Jul 19, 2026
Merged

Phase 2: bubbletea review screen for setup import#129
yourconscience merged 3 commits into
mainfrom
setup-review-tui

Conversation

@yourconscience

@yourconscience yourconscience commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • New unified review TUI replacing sequential y/n import prompts when setup runs in a real terminal
  • One row per detected item: surface, name, per-harness presence glyphs, (differ) marker, tri-state action
  • Keys: ↑↓/jk navigate, space cycles share/keep/skip, ←→ picks the canonical source for differing items, a/s bulk share/skip, enter applies, q aborts (abort skips import, setup continues)
  • Items identical across all harnesses are auto-shared without review (shown in the header)
  • DetectionResult gains a Resolved list so the apply phase knows which items were auto-resolved
  • Apply maps decisions back to existing scan candidates (copyDirMissing, role Convert, upsertCanonicalMCPServer); keep/skip leave native content untouched
  • Non-TTY/piped stdin falls back to the existing prompt flow unchanged
  • Deps: bubbletea v1.3.10, lipgloss v1.1.0, go-isatty (already in graph)
  • Includes the --json banner fix also open as move setup banner after --json early return #128 (identical change, merges cleanly either way)

Phase 2 of #126.

Test plan

  • go test ./... passes (8 new model/apply tests + detection tests updated)
  • CI green
  • Manual: run dotagents setup in a terminal with native skills present, verify table, actions, abort

Summary by Sourcery

Introduce a unified terminal-based review screen for native content import during setup, with auto-resolution of identical items and mapping of review decisions back into the existing import mechanisms.

New Features:

  • Add a Bubbletea-based TUI review screen for setup-time native import when running in a real terminal.
  • Support tri-state per-item actions (share, keep, skip) and source selection for differing items across harnesses.
  • Automatically share items that are identical across all harnesses and surface them via the DetectionResult.Resolved field.

Enhancements:

  • Gate the new review flow behind a TTY check, preserving the existing prompt-based import for non-interactive runs.
  • Summarize review outcomes after applying decisions, reporting shared, kept, and skipped counts.

Build:

  • Bump Go toolchain version to 1.24.2 and add Bubbletea, Lipgloss, and go-isatty (plus related indirect dependencies) to the module.

Tests:

  • Add unit tests for the review model interactions, decision generation, and apply logic across skills, roles, and MCPs.
  • Extend detection tests to cover population of the new Resolved list and its auto-resolve behavior.

@sourcery-ai

sourcery-ai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Reviewer's Guide

Implements a Bubbletea-based TUI review screen for setup import, adds detection metadata for auto-resolved items, and wires decisions into the existing import pipeline while preserving non-TTY behavior, plus dependency and test coverage updates.

Sequence diagram for setup import review TUI flow

sequenceDiagram
    actor User
    participant runSetup
    participant runDetection
    participant runReviewImport
    participant applyReviewDecisions

    User->>runSetup: runSetup
    runSetup->>runSetup: reviewTTYAvailable
    alt TTY available
        runSetup->>runDetection: runDetection
        runSetup->>runReviewImport: runReviewImport
        runReviewImport->>runReviewImport: tea.NewProgram
        runReviewImport->>runReviewImport: Program.Run
        alt user applies
            runReviewImport->>applyReviewDecisions: applyReviewDecisions
            applyReviewDecisions->>applyReviewDecisions: copyDirMissing / importRoleCandidate / upsertCanonicalMCPServer
        else user aborts
            runReviewImport->>runSetup: errReviewAborted
        end
    else non-TTY
        runSetup->>applyReviewDecisions: importNativeContent
    end
Loading

File-Level Changes

Change Details Files
Introduce Bubbletea/Lipgloss-based interactive review screen for native imports during setup when running in a real TTY.
  • Add reviewModel, reviewRow, reviewDecision types and Bubbletea update/view logic for navigating items, cycling actions, and choosing canonical sources.
  • Render a tabular review UI with per-harness presence glyphs, differ marker, and tri-state share/keep/skip actions styled via Lipgloss.
  • Include auto-resolved identical items in the decisions output as implicit share actions using their first source.
cmd/dotagents/review.go
Wire the review TUI into the setup flow and apply review decisions to skills, roles, and MCP servers.
  • Gate TUI usage on real stdin/stdout TTY detection via reviewTTYAvailable and fall back to existing importNativeContent for non-TTY or piped input.
  • Run Bubbletea program with the reviewModel, interpret abort vs apply, and summarize shared/kept/skipped counts to stdout.
  • Map share decisions to existing primitives: copyDirMissing for skills, role Convert and file creation via importRoleCandidate, and upsertCanonicalMCPServer for MCP servers, with helper lookup functions for role/MCP candidates.
cmd/dotagents/setup.go
cmd/dotagents/review_apply.go
Extend detection results to track auto-resolved (identical) items for use by the review and apply phases.
  • Add Resolved slice to DetectionResult and JSON tag, keeping AutoResolved as a separate count for JSON consumers.
  • Populate Resolved with identical items in runDetection while incrementing AutoResolved.
  • Update detection tests to assert the presence and contents of Resolved alongside AutoResolved and Items.
cmd/dotagents/detect.go
cmd/dotagents/detect_test.go
Add focused unit tests for the review model behavior and review decision application.
  • Test key handling for action cycling, bulk share/skip, navigation bounds, source cycling, abort behavior, and inclusion of resolved items in decisions.
  • Test applyReviewDecisions for skills (copying directories and honoring skip) and roles/MCPs (writing role files and upserting MCP servers into config).
cmd/dotagents/review_test.go
Update module dependencies to support the new TUI implementation.
  • Bump Go version in go.mod and add Bubbletea, Lipgloss, and go-isatty as direct dependencies.
  • Add the indirect dependencies required by Bubbletea/Lipgloss (ANSI/terminal helpers and width/Unicode utilities) to go.mod and go.sum.
  • Include go.work changes corresponding to the dependency updates.
go.mod
go.sum
go.work

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-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.

Hey - I've found 2 issues, and left some high level feedback:

  • In newReviewModel, consider deriving the resolved count from len(detection.Resolved) instead of detection.AutoResolved so the model stays consistent if the way auto-resolved items are tracked changes in the future.
  • In runReviewImport, the bubbletea program is hard-wired to the real stdio while the rest of setup uses streams; if you ever need to support alternative IO (e.g., testing harnesses or wrapped streams) it may be cleaner to pass a custom tea.ProgramOptions wired to streams instead of os.Stdin/os.Stdout.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `newReviewModel`, consider deriving the `resolved` count from `len(detection.Resolved)` instead of `detection.AutoResolved` so the model stays consistent if the way auto-resolved items are tracked changes in the future.
- In `runReviewImport`, the bubbletea program is hard-wired to the real stdio while the rest of setup uses `streams`; if you ever need to support alternative IO (e.g., testing harnesses or wrapped streams) it may be cleaner to pass a custom `tea.ProgramOptions` wired to `streams` instead of `os.Stdin`/`os.Stdout`.

## Individual Comments

### Comment 1
<location path="cmd/dotagents/review.go" line_range="81" />
<code_context>
+
+func (m reviewModel) Init() tea.Cmd { return nil }
+
+func (m reviewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+	keyMsg, ok := msg.(tea.KeyMsg)
+	if !ok {
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Avoid hard-coding the number of review actions when cycling with the space key.

Using `% 3` tightly couples the cycling logic to the current count of `reviewAction` values and will break if more actions are added. Derive the modulo value from the enum (e.g. `numActions := int(actionSkip) + 1` or a `const numReviewActions`) so the logic stays aligned with the definition.

Suggested implementation:

```golang
	m.action = reviewAction((int(m.action) + 1) % numReviewActions)

```

Define the modulo value based on the reviewAction enum so it stays aligned when new actions are added. For example, near the reviewAction enum definition in cmd/dotagents/review.go, add:

    const numReviewActions = int(actionSkip) + 1

(or equivalently derive it from the highest enum value), and ensure the name matches the usage in the updated line above.
</issue_to_address>

### Comment 2
<location path="cmd/dotagents/detect_test.go" line_range="183" />
<code_context>
 	if result.AutoResolved != 1 {
 		t.Fatalf("expected 1 auto-resolved (shared-skill), got %d", result.AutoResolved)
 	}
+	if len(result.Resolved) != 1 || result.Resolved[0].Name != "shared-skill" {
+		t.Fatalf("expected shared-skill in Resolved, got %+v", result.Resolved)
+	}
</code_context>
<issue_to_address>
**suggestion (testing):** Consider also asserting that AutoResolved matches len(Resolved) to lock in the intended invariant.

DetectionResult’s comment states AutoResolved is retained for JSON consumers and mirrors Resolved. This test checks AutoResolved and that Resolved contains the expected item, but not that AutoResolved == len(Resolved). Adding that assertion here would enforce the invariant and help catch future desyncs between the two fields.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread cmd/dotagents/review.go
Comment thread cmd/dotagents/detect_test.go

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a701b59267

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

continue
}
server := mcp.Server
server.Agents = []string{mcp.Origin}

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 Badge Target shared MCP imports at every detected source

When an MCP server is found in multiple harnesses, the decision retains only the selected/first Source, and this line scopes the canonical server to that one origin. Since desiredMCPServersForAgent honors server.Agents, subsequent syncs manage only that harness and leave the other detected copies unmanaged—even for items the UI reports as “shared automatically.” Preserve all detected source harnesses as targets while using the selected source only for the server payload.

Useful? React with 👍 / 👎.

Comment thread cmd/dotagents/review.go
Comment on lines +152 to +158
for i, row := range m.rows {
line := fmt.Sprintf(" %-7s %-*s %s %s", row.item.Surface, nameWidth, row.item.Name, m.presence(row), m.actionCell(row))
if i == m.cursor {
line = reviewCursorStyle.Render(line)
}
b.WriteString(line + "\n")
}

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 Badge Add scrolling for review lists taller than the terminal

When the number of detected items exceeds the terminal height, View renders every row and the model neither handles tea.WindowSizeMsg nor maintains a viewport. The cursor can therefore move to rows that are outside the visible terminal area, preventing users with larger inventories from seeing which item or source they are changing before applying the import.

Useful? React with 👍 / 👎.

@yourconscience
yourconscience merged commit 42b1466 into main Jul 19, 2026
4 checks passed
@yourconscience
yourconscience deleted the setup-review-tui branch July 19, 2026 07:43
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.

1 participant