Skip to content

Refactor Wizard AgentSelectionScreen into directory module#1077

Merged
reachrazamair merged 3 commits into
rcfrom
refactoring
Jun 5, 2026
Merged

Refactor Wizard AgentSelectionScreen into directory module#1077
reachrazamair merged 3 commits into
rcfrom
refactoring

Conversation

@reachrazamair
Copy link
Copy Markdown
Contributor

@reachrazamair reachrazamair commented Jun 5, 2026

Summary

Refactors the Wizard AgentSelectionScreen from a monolithic screen file into a focused directory module matching the ConversationScreen refactor pattern.

Behavior is intended to remain unchanged: same WizardContext contract, agent detection flow, SSH remote behavior, provider configuration behavior, keyboard navigation, focus handling, announcements, copy, styling, and public import path.

Changes

  • Replaced src/renderer/components/Wizard/screens/AgentSelectionScreen.tsx with screens/AgentSelectionScreen/.
  • Added a local barrel export so existing imports through screens/index.ts continue to work.
  • Preserved public exports for AgentSelectionScreen, AGENT_TILES, AgentTile, and AgentLogo.
  • Split responsibilities into:
    • Presentational components for tile grid, header, footer, loading, SSH error, location select, logos, and configuration view.
    • Hooks for detection, SSH remotes, focus decisions, keyboard handling, and provider configuration.
    • Pure utils for tile metadata, availability, grid movement, config/env var helpers, and SSH config normalization.
  • Kept WizardContext, agent IPC, AgentConfigPanel, prompt services, and release docs unchanged.

Architecture Notes

  • The screen shell remains the coordinator for useWizard(), refs, view mode, transition state, and composition.
  • useAgentDetection owns detection, hidden-agent filtering, SSH connection-error detection, Claude Code auto-select, stale-result guards, and announcements.
  • useSshRemotes owns remote config loading, location sync, and remote selection forwarding.
  • useAgentSelectionKeyboard owns arrow, Tab, Shift+Tab, Enter, and Space behavior without global listeners.
  • useAgentConfigurationPanel owns config load/save, model load/refresh, custom path blur refresh, env var mutations, single-agent refresh, and unmount guards.
  • Shared useAgentConfiguration and SshRemoteSelector were not reused because their semantics differ from the onboarding wizard flow.

Test Coverage

Added 25 focused renderer tests:

Test file Tests Coverage
screens/AgentSelectionScreen/utils.test.ts 8 availability, selectable counts, SSH connection-error detection, announcements, grid movement, centering, env var helpers, SSH config normalization, placeholder config agent
screens/AgentSelectionScreen/components.test.tsx 7 logos, tile states, beta/customize/unavailable states, location select, header controls, footer states, loading panel, SSH error panel, config view callback wiring
screens/AgentSelectionScreen/hooks.test.tsx 10 local and SSH detection, hidden filtering, Claude auto-select, stale/thrown detection errors, SSH remote loading, focus decisions, keyboard navigation, config panel transitions, model refresh, custom path blur, persistence, env var handlers

Verification

  • npm run test -- src/__tests__/renderer/components/Wizard/screens/AgentSelectionScreen
    • 3 files / 25 tests passed
  • Targeted Wizard regression suite
    • 10 files / 235 tests passed
  • npm run format:check
    • passed
  • npm run lint
    • passed
  • npm run lint:eslint
    • passed
  • npm run test
    • full suite passed outside sandbox
    • 1,008 files passed, 1 skipped
    • 30,384 tests passed, 108 skipped

Summary by CodeRabbit

  • New Features

    • Rebuilt Agent Selection wizard with modular grid, tile badges, SVG logos, configuration view, SSH remote selector, model refresh, and persistent custom agent settings.
    • Improved keyboard navigation, focus management, and accessibility.
  • Refactor

    • Screen logic reorganized into discrete components, hooks, and utilities for detection, SSH, and configuration flows.
  • Tests

    • Comprehensive tests added for components, hooks, utilities, and configuration interactions.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 5, 2026

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

Run ID: ed5d22c3-5c5d-40fc-8f92-8b367f1e24a4

📥 Commits

Reviewing files that changed from the base of the PR and between afb51e3 and 899bde4.

📒 Files selected for processing (2)
  • src/__tests__/renderer/components/Wizard/screens/AgentSelectionScreen/hooks.test.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useSshRemotes.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useSshRemotes.ts
  • src/tests/renderer/components/Wizard/screens/AgentSelectionScreen/hooks.test.tsx

📝 Walkthrough

Walkthrough

Replace a monolithic AgentSelectionScreen with typed contracts, utilities, five custom hooks, focused presentational components, an orchestrating screen component, barrel exports, and Vitest test coverage.

Changes

AgentSelectionScreen Module Refactoring

Layer / File(s) Summary
Type definitions and utility foundations
src/renderer/components/Wizard/screens/AgentSelectionScreen/types.ts, src/.../utils/agentTiles.ts, src/.../utils/agentAvailability.ts, src/.../utils/agentConfigForms.ts, src/.../utils/agentGrid.ts, src/.../utils/sshConfig.ts
Type contracts, static AGENT_TILES, availability and announcement builders, env-var normalization/CRUD helpers, grid layout/navigation helpers, and SSH-wizard config translation functions.
Custom hooks for detection, SSH, focus, keyboard, config
src/.../hooks/useAgentDetection.ts, src/.../hooks/useSshRemotes.ts, src/.../hooks/useAgentSelectionFocus.ts, src/.../hooks/useAgentSelectionKeyboard.ts, src/.../hooks/useAgentConfigurationPanel.ts, src/.../hooks/index.ts
useAgentDetection runs maestro detection, emits announcements and SSH error state; useSshRemotes loads/syncs SSH remote config with wizard session; useAgentSelectionFocus focuses name input or tile based on selectable count; useAgentSelectionKeyboard returns a keydown handler for arrow/tab/enter/space; useAgentConfigurationPanel manages agent config state, models, persistence, and env-var handlers.
Presentational UI subcomponents
src/.../components/AgentSelectionHeader.tsx, .../AgentSelectionFooter.tsx, .../AgentLocationSelect.tsx, .../AgentLogo.tsx, .../AgentSelectionLoading.tsx, .../AgentGrid.tsx, .../AgentTileButton.tsx, .../SshConnectionErrorPanel.tsx, .../AgentConfigurationView.tsx, .../components/index.ts
Header (title, name input, ssh select), footer (continue + hints), location select, agent logo SVG/fallback, loading UI, tile grid and tile button with overlays, SSH error panel, configuration view with AgentConfigPanel wiring, and component barrel export.
Main screen component orchestration
src/renderer/components/Wizard/screens/AgentSelectionScreen/AgentSelectionScreen.tsx
Coordinates hooks and local UI state (focus, view mode, configuring id), conditional rendering for detecting/config mode/grid, and forwards callbacks/state to subcomponents.
Module barrel exports
src/renderer/components/Wizard/screens/AgentSelectionScreen/index.ts, src/.../hooks/index.ts, src/.../components/index.ts
Barrel modules re-export the screen, components, hooks, utilities, and types as the module public API.
Comprehensive test suite
src/__tests__/renderer/components/Wizard/screens/AgentSelectionScreen/utils.test.ts, .../components.test.tsx, .../hooks.test.tsx
Unit tests for utilities, hooks behavior (detection, SSH, focus, keyboard, config panel), and component rendering/interactions with mocked AgentConfigPanel and window.maestro APIs.

Sequence Diagram(s)

sequenceDiagram
  participant Screen as AgentSelectionScreen
  participant Detection as useAgentDetection
  participant Ssh as useSshRemotes
  participant Focus as useAgentSelectionFocus
  participant Keyboard as useAgentSelectionKeyboard
  participant ConfigPanel as useAgentConfigurationPanel
  Screen->>Detection: provide sshRemoteConfig, selectedAgent
  Detection->>Screen: isDetecting, detectedAgents, sshConnectionError, announcement
  Screen->>Ssh: sessionSshRemoteConfig
  Ssh->>Screen: sshRemotes, sshRemoteConfig
  Screen->>Focus: isDetecting, selectedAgent, detectedAgents
  Focus->>Screen: focusedTileIndex
  Screen->>Keyboard: focus state, tile refs -> keydown handler
  Screen->>ConfigPanel: configuringAgentId, selectedAgent
  ConfigPanel->>Screen: agentConfig, availableModels, handlers (open/close/blur/refresh)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

refactor, ready to merge

🐰 I hopped through code with nimble paws today,
Split a giant screen so each part may play,
Hooks and components tucked in neat little nests,
Tests check every corner — no more pests,
A carrot-coded refactor, hip-hip-hooray!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 pull request title 'Refactor Wizard AgentSelectionScreen into directory module' directly and clearly describes the main structural change in the changeset.
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 refactoring

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Jun 5, 2026

Greptile Summary

This PR refactors the monolithic AgentSelectionScreen.tsx (1,349 lines) into a directory module following the ConversationScreen pattern, with no intended behavioral changes. The extraction is clean and faithful to the original across detection, SSH remote handling, keyboard navigation, configuration panel, and grid layout logic.

  • Presentational components (AgentTileButton, AgentGrid, AgentConfigurationView, etc.) and five hooks (useAgentDetection, useSshRemotes, useAgentSelectionFocus, useAgentSelectionKeyboard, useAgentConfigurationPanel) correctly reproduce the original logic; all public exports (AgentSelectionScreen, AGENT_TILES, AgentTile, AgentLogo) remain accessible through the barrel.
  • 25 new focused renderer tests cover availability utils, component render states, hook behavior (detection, SSH errors, stale-unmount guards, keyboard nav, config panel transitions), and the full suite continues to pass.

Confidence Score: 4/5

Safe to merge; behavior is faithfully preserved across all paths including SSH remote detection, keyboard navigation, and agent configuration.

The refactor is a straight extraction with no logic changes. Two minor style issues were found — a no-op key prop on a component root element and an internal setter left in a hook's return value — neither of which affects runtime behavior.

useSshRemotes.ts (unnecessary setSshRemoteConfig export) and AgentTileButton.tsx (redundant key prop)

Important Files Changed

Filename Overview
src/renderer/components/Wizard/screens/AgentSelectionScreen/AgentSelectionScreen.tsx Screen shell correctly composes all extracted hooks and components; wiring matches the original monolith with no behavioral regressions found.
src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentDetection.ts Faithful extraction of detection logic including mounted-guard, SSH error handling, Claude auto-select, and announcement; sshRemoteConfigKey dep pattern preserved from original.
src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentConfigurationPanel.ts Config panel state correctly extracted; handleOpenConfig, handleCloseConfig, and all env-var mutations preserve original semantics.
src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useSshRemotes.ts SSH remote loading and sync logic correctly extracted; setSshRemoteConfig is unnecessarily exposed in the return value despite no callers using it directly.
src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentTileButton.tsx Tile rendering correctly extracted; contains a redundant key prop on the root button element that has no effect.
src/renderer/components/Wizard/screens/AgentSelectionScreen/utils/agentAvailability.ts Pure utility functions faithfully extracted; getConnectionErrors, hasSshConnectionFailure, and buildConfiguringAgent match original inline logic exactly.
src/renderer/components/Wizard/screens/AgentSelectionScreen/utils/sshConfig.ts SSH config helpers correctly model the tri-state sync logic (null = no-op, undefined = disable, config = enable).
src/renderer/components/Wizard/screens/AgentSelectionScreen/utils/agentGrid.ts Grid navigation and col-span centering logic matches original constants and inline expressions exactly.
src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentConfigurationView.tsx Config view correctly delegates all props to AgentConfigPanel; SSH location select conditional rendering preserved via AgentLocationSelect returning null when no remotes exist.
src/renderer/components/Wizard/screens/AgentSelectionScreen/index.ts Barrel re-exports AgentSelectionScreen, AgentLogo, AGENT_TILES, and AgentTile type, preserving all previously public symbols.
src/tests/renderer/components/Wizard/screens/AgentSelectionScreen/hooks.test.tsx 10 focused hook tests covering detection, SSH errors, stale unmount guard, remote loading, focus decisions, keyboard nav, config transitions, and env-var mutations.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[AgentSelectionScreen] --> B[useSshRemotes]
    A --> C[useAgentDetection]
    A --> D[useAgentSelectionFocus]
    A --> E[useAgentConfigurationPanel]
    A --> F[useAgentSelectionKeyboard]

    B -->|sshRemoteConfig| C
    C -->|detectedAgents, announce| E
    C -->|isDetecting, detectedAgents| D

    A -->|viewMode=grid| G[AgentSelectionHeader]
    A -->|viewMode=grid| H[AgentGrid]
    A -->|viewMode=grid| I[AgentSelectionFooter]
    A -->|sshConnectionError| J[SshConnectionErrorPanel]
    A -->|viewMode=config| K[AgentConfigurationView]
    A -->|isDetecting| L[AgentSelectionLoading]

    H --> M[AgentTileButton x N]
    K --> N2[AgentConfigPanel]
    G --> O[AgentLocationSelect]
    K --> P[AgentLocationSelect]
Loading

Reviews (1): Last reviewed commit: "refactor wizard agent selection screen" | Re-trigger Greptile

Comment on lines +36 to +39
return (
<button
key={tile.id}
ref={(element) => setTileRef(index, element)}
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 The key prop on a component's own root element has no effect in React — keys only participate in reconciliation when React processes a list in the parent. The meaningful key is already set on <AgentTileButton key={tile.id} ...> in AgentGrid. This key is dead code and can be removed.

Suggested change
return (
<button
key={tile.id}
ref={(element) => setTileRef(index, element)}
return (
<button
ref={(element) => setTileRef(index, element)}

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +74 to +79
return {
sshRemotes,
sshRemoteConfig,
setSshRemoteConfig,
handleSshRemoteChange,
};
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 setSshRemoteConfig is returned from the hook but no caller in the current codebase destructures or uses it — handleSshRemoteChange now covers both the local state update and the wizard context sync. Exporting an unused setter leaks internal state mutation and invites uncoordinated updates that skip the wizard context sync.

Suggested change
return {
sshRemotes,
sshRemoteConfig,
setSshRemoteConfig,
handleSshRemoteChange,
};
return {
sshRemotes,
sshRemoteConfig,
handleSshRemoteChange,
};

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (1)
src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentTileButton.tsx (1)

136-157: ⚡ Quick win

Unreachable keyboard handler due to tabIndex={-1}.

The "Customize" overlay has tabIndex={-1}, which excludes it from keyboard tab navigation. This means the onKeyDown handler at lines 143-147 will never fire during normal keyboard navigation, since the element cannot receive focus via Tab. The handler would only be invoked if something programmatically called .focus() on this element, which doesn't appear to happen.

Consider either:

  1. Remove the onKeyDown handler if keyboard access isn't intended (reduces dead code).
  2. Change to tabIndex={0} to make the customize action keyboard-accessible for users who cannot use a mouse.
  3. Document if this is intentionally preserving existing behavior.

The test coverage only validates click behavior, not keyboard interaction.

🤖 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
`@src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentTileButton.tsx`
around lines 136 - 157, The Customize overlay's keyboard handler (the onKeyDown
in the tile.supported block) is unreachable because tabIndex={-1} prevents focus
via Tab; either remove the onKeyDown if keyboard interaction isn't intended, or
change tabIndex to 0 to make it focusable and thus allow the onKeyDown to call
onOpenConfig(tile.id) when Enter/Space is pressed; update the element that
renders the overlay (the div containing Settings and "Customize" in
AgentTileButton) accordingly and ensure tab focus/ARIA behavior aligns with
onOpenConfig.
🤖 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
`@src/renderer/components/Wizard/screens/AgentSelectionScreen/AgentSelectionScreen.tsx`:
- Around line 97-117: showConfigView and showGridView start setTimeouts and call
state setters which can run after the component unmounts; store the timer IDs
(e.g., via a ref like timerRef) when calling setTimeout in both functions, clear
any existing timer before starting a new one, and add a useEffect cleanup that
clears the stored timer(s) on unmount so calls to setIsTransitioning,
setViewMode, setConfiguringAgentId, setFocusedTileIndex and
tileRefs.current[index]?.focus() won't run after unmount.

In
`@src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentConfigurationPanel.ts`:
- Around line 87-95: Replace the logger-only error handling in
useAgentConfigurationPanel's model-load try/catch (the block calling
getSshRemoteIdForDetection and window.maestro.agents.getModels, which currently
calls logger.error and setLoadingModels) to also call the Sentry utilities
(import captureException or captureMessage from src/utils/sentry.ts) with
contextual extras (agentId and whether sshRemoteId indicates remote mode) before
recovering UI state; do the same change for the other similar catch (the later
block around setAvailableModels/setLoadingModels) so both failure paths report
to Sentry with agent id + remote-mode context and then continue to call
setLoadingModels(false).

In
`@src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentDetection.ts`:
- Around line 40-45: refreshAgentDetection currently calls
window.maestro.agents.detect() which only probes local agents and ignores
SSH/remote context; change it to call the same detection API used for initial
detection that includes the current SSH context (e.g., pass the current
detection options/context object or call the shared
detectWithContext/detectRemote helper) so it returns remote agents when SSH is
enabled, update the useCallback dependency list to include that context (e.g.,
sshEnabled or detectionContext) and keep the post-processing via
getVisibleAgents followed by setDetectedAgents and setAvailableAgents.

In
`@src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentSelectionKeyboard.ts`:
- Around line 22-28: The Shift+Tab handler currently focuses the raw last index
(AGENT_TILES.length - 1) which can land on a non-interactive tile; update the
handler in useAgentSelectionKeyboard to find the last selectable tile instead
(iterate AGENT_TILES backwards, checking the tile's selectable/disabled/support
property used elsewhere in this module), then call
setFocusedTileIndex(foundIndex) and tileRefs.current?.[foundIndex]?.focus(); if
no selectable tile exists, avoid changing focus (or fall back to previous
behavior only if explicitly supported).

In
`@src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useSshRemotes.ts`:
- Around line 45-47: In useSshRemotes's catch block (where logger.error('Failed
to load SSH remotes:', undefined, error) is used) add an explicit Sentry
telemetry call: import and call captureException (or captureMessage with
context) from the sentry utilities and pass the caught error plus a context
object indicating the operation (e.g. "loadSSHRemotes" or "SSH remotes load")
and any relevant state (e.g. username/path or remotes length if available) so
the failure is reported to Sentry alongside the existing logger.error recovery
handling.

In
`@src/renderer/components/Wizard/screens/AgentSelectionScreen/utils/sshConfig.ts`:
- Around line 9-19: The getInitialSshRemoteConfig function can return an empty
string for remoteId due to the nullish coalescing operator, causing
inconsistency with getSyncedSshRemoteConfig and selectSshRemoteConfig which
treat empty string as falsy; change the remoteId assignment in
getInitialSshRemoteConfig to explicitly normalize empty strings to null (e.g.,
if sessionSshRemoteConfig.remoteId is undefined or an empty string then set
remoteId to null) so the returned AgentSshRemoteConfig always uses null for
missing/empty remoteId.

---

Nitpick comments:
In
`@src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentTileButton.tsx`:
- Around line 136-157: The Customize overlay's keyboard handler (the onKeyDown
in the tile.supported block) is unreachable because tabIndex={-1} prevents focus
via Tab; either remove the onKeyDown if keyboard interaction isn't intended, or
change tabIndex to 0 to make it focusable and thus allow the onKeyDown to call
onOpenConfig(tile.id) when Enter/Space is pressed; update the element that
renders the overlay (the div containing Settings and "Customize" in
AgentTileButton) accordingly and ensure tab focus/ARIA behavior aligns with
onOpenConfig.
🪄 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

Run ID: 42bedcd5-5963-45a3-bd59-30705cba67be

📥 Commits

Reviewing files that changed from the base of the PR and between b55d1c1 and 914ddb8.

📒 Files selected for processing (28)
  • src/__tests__/renderer/components/Wizard/screens/AgentSelectionScreen/components.test.tsx
  • src/__tests__/renderer/components/Wizard/screens/AgentSelectionScreen/hooks.test.tsx
  • src/__tests__/renderer/components/Wizard/screens/AgentSelectionScreen/utils.test.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/AgentSelectionScreen.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentConfigurationView.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentGrid.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentLocationSelect.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentLogo.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentSelectionFooter.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentSelectionHeader.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentSelectionLoading.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentTileButton.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/components/SshConnectionErrorPanel.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/components/index.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/index.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentConfigurationPanel.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentDetection.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentSelectionFocus.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentSelectionKeyboard.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useSshRemotes.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/index.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/types.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/utils/agentAvailability.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/utils/agentConfigForms.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/utils/agentGrid.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/utils/agentTiles.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/utils/sshConfig.ts
💤 Files with no reviewable changes (1)
  • src/renderer/components/Wizard/screens/AgentSelectionScreen.tsx

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useSshRemotes.ts (1)

42-45: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle non-throwing SSH config failures explicitly.

On Line 43, only the success case is handled. If window.maestro.sshRemote.getConfigs() resolves with success: false, the failure path is currently dropped with no logging/telemetry branch.

Suggested fix
 		async function loadSshRemotes() {
 			try {
 				const configsResult = await window.maestro.sshRemote.getConfigs();
-				if (mounted && configsResult.success && configsResult.configs) {
-					setSshRemotes(configsResult.configs);
+				if (!mounted) {
+					return;
+				}
+				if (configsResult.success && configsResult.configs) {
+					setSshRemotes(configsResult.configs);
+				} else {
+					const resolvedError = new Error(
+						configsResult.error ?? 'Failed to load SSH remotes'
+					);
+					logger.error('Failed to load SSH remotes:', undefined, resolvedError);
+					captureException(resolvedError, {
+						extra: {
+							operation: 'agentSelection:loadSshRemotes',
+							sessionRemoteEnabled: Boolean(sessionSshRemoteConfig?.enabled),
+							sessionRemoteId: sessionSshRemoteConfig?.remoteId ?? null,
+							hasWorkingDirOverride: Boolean(sessionSshRemoteConfig?.workingDirOverride),
+						},
+					});
 				}
 			} catch (error) {

As per coding guidelines, "Handle expected/recoverable errors explicitly (e.g., NETWORK_ERROR)." and "Do not silently swallow errors."

🤖 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
`@src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useSshRemotes.ts`
around lines 42 - 45, In useSshRemotes, the call to
window.maestro.sshRemote.getConfigs() only handles the success:true path and
silently ignores responses with success:false; update the logic to explicitly
handle the failure case returned by getConfigs() — e.g., when
configsResult.success is false, call your logging/telemetry utility and/or set
an error state (or clear ssh remotes via setSshRemotes([])) so failures aren’t
swallowed; use the existing variables (configsResult, setSshRemotes, mounted)
and include the error/reason from configsResult in the log/telemetry call.
🤖 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
`@src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useSshRemotes.ts`:
- Around line 64-68: The effect inside the useSshRemotes hook is refetching
remotes whenever any field on sessionSshRemoteConfig changes (caused by the
dependency array including sessionSshRemoteConfig?.workingDirOverride), turning
a mount-time load into repeated IPC fetches; update the loader effect
dependencies to only include the stable keys that should trigger a reload (e.g.,
sessionSshRemoteConfig?.remoteId and sessionSshRemoteConfig?.enabled) so changes
to transient fields like workingDirOverride do not retrigger the fetch, and
ensure the effect reads those specific properties (not the whole object) to keep
dependencies stable.

---

Outside diff comments:
In
`@src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useSshRemotes.ts`:
- Around line 42-45: In useSshRemotes, the call to
window.maestro.sshRemote.getConfigs() only handles the success:true path and
silently ignores responses with success:false; update the logic to explicitly
handle the failure case returned by getConfigs() — e.g., when
configsResult.success is false, call your logging/telemetry utility and/or set
an error state (or clear ssh remotes via setSshRemotes([])) so failures aren’t
swallowed; use the existing variables (configsResult, setSshRemotes, mounted)
and include the error/reason from configsResult in the log/telemetry call.
🪄 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

Run ID: e088ce1c-e019-4082-9de1-65b86f2c66b6

📥 Commits

Reviewing files that changed from the base of the PR and between 914ddb8 and afb51e3.

📒 Files selected for processing (10)
  • src/__tests__/renderer/components/Wizard/screens/AgentSelectionScreen/components.test.tsx
  • src/__tests__/renderer/components/Wizard/screens/AgentSelectionScreen/hooks.test.tsx
  • src/__tests__/renderer/components/Wizard/screens/AgentSelectionScreen/utils.test.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/AgentSelectionScreen.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentTileButton.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentConfigurationPanel.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentDetection.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentSelectionKeyboard.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useSshRemotes.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/utils/sshConfig.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentSelectionKeyboard.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/components/AgentTileButton.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/AgentSelectionScreen.tsx
  • src/tests/renderer/components/Wizard/screens/AgentSelectionScreen/utils.test.ts
  • src/tests/renderer/components/Wizard/screens/AgentSelectionScreen/components.test.tsx
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/utils/sshConfig.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentDetection.ts
  • src/renderer/components/Wizard/screens/AgentSelectionScreen/hooks/useAgentConfigurationPanel.ts
  • src/tests/renderer/components/Wizard/screens/AgentSelectionScreen/hooks.test.tsx

@pedramamini
Copy link
Copy Markdown
Collaborator

Thanks for this, @reachrazamair! This is a clean, well-structured refactor and the directory-module split mirrors the ConversationScreen pattern nicely. The 25 new focused tests plus the passing Wizard regression suite give good confidence.

I verified the extraction against the original 1,349-line AgentSelectionScreen.tsx and it's a faithful carry-over: the screen shell still coordinates useWizard(), refs, view mode, and transitions, while detection, SSH remotes, focus, keyboard, and config-panel logic moved into hooks/utils without changing semantics.

On the bot feedback: the substantive CodeRabbit items (setTimeout transitions without an unmount cleanup, refreshAgentDetection calling bare detect() without SSH context, Shift+Tab landing on the raw last index, remoteId ?? null normalization, and workingDirOverride in the effect deps) all describe behavior that already existed in the original file. Since this PR's contract is "no behavioral change," those are pre-existing and out of scope here, though a couple would be reasonable follow-ups if you want to file them separately.

Two genuinely-new, non-blocking nits from Greptile if you happen to touch these files again (no need to hold the merge for them):

  • useSshRemotes.ts: setSshRemoteConfig is exposed in the hook's return object but has no consumer in the module.
  • AgentTileButton.tsx: the key={tile.id} on the root <button> is a no-op (the key belongs at the AgentGrid call site, which already sets it).

Approving. Nice work, and thanks again for the thorough test coverage and write-up.

@reachrazamair reachrazamair merged commit f7298c4 into rc Jun 5, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants