Skip to content

feat(desktop): agent picker for v2 PR action button#4979

Open
Kitenite wants to merge 3 commits into
mainfrom
pr-button-agent-select
Open

feat(desktop): agent picker for v2 PR action button#4979
Kitenite wants to merge 3 commits into
mainfrom
pr-button-agent-select

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented May 28, 2026

Summary

Turns the top-right v2 Create / Update PR control into a split button with a working agent picker. The primary region runs the last-picked agent; the chevron dropdown lets you switch where PR authoring is handed off — a running terminal session or a freshly launched preset — without losing the one-click default. This mirrors the agent-pick affordance shipped on the DiffPane comment composer (#4966).

Two phases land here:

  • Phase 1 (29a20e127) — bordered split-button shell with all-states routing (create / update / busy / spinner), replacing the icon-only button.
  • Phase 2 (a7c69ef29) — the real agent picker dropdown and dispatch routing.

What changed (phase 2)

  • Shared useAgentTarget hook (renderer/hooks/agents/useAgentTarget) — selection state + localStorage persistence + validation/fallbacks, extracted from the comment composer. useDiffCommentTarget and the new usePRActionAgentTarget are now thin wrappers with surface-scoped storage keys, so PR picks and comment picks don't trample each other.
  • Shared useCreateNewAgentSession hook — pulled out of usePaneRegistry so both the DiffPane composer and the PR action header launch new preset sessions through one code path.
  • PRAgentPickerMenuDropdownMenu rendition of the picker, grouped "Active sessions" + "Start new" with preset icons, matching AgentPickerSelect. One-click = pick + submit.
  • usePRActionDispatch — routes a submit by target kind:
    • no pick → legacy chat-tab flow (/pr/* slash command + pr-context.md)
    • existing terminal → sendToTerminalAgent with the slash command + pr-context inlined (xterm can't carry separate attachments)
    • new preset → useCreateNewAgentSession seeded with the same inlined prompt
  • Dropped the createPREnabled kill-switch — the split button is the default now.

Test plan

  • bun run lint — clean
  • bun run typecheck --filter=@superset/desktop — passes
  • bun test for hooks/agents + PRActionHeader — 32 pass
  • Manual: pick an existing session / new preset from the dropdown and confirm the PR-flow payload lands in the right pane

Plan: apps/desktop/plans/20260528-1500-pr-button-agent-select.md (phase 3 — per-project custom prompt — still pending).


Open in Stage

Summary by cubic

Adds a split “Create/Update PR” button with an agent picker to the v2 workspace header. One click runs the last-picked agent; the dropdown lets you send the PR flow to an existing terminal session or start a new preset, with a chat-tab fallback if no agent is picked.

  • New Features

    • Split button UI for Create PR and Update PR with busy states; pairs with the PR status pill when a PR exists.
    • Agent picker dropdown: Active sessions and Start new presets; one click = pick and submit; remembers the last pick per surface.
    • Transport routing: no pick → legacy chat tab with slash command + pr-context.md; existing session → send inlined prompt to terminal; new preset → launch session seeded with the same prompt.
    • Update PR supported (/pr/update-pr); pr-context.md now includes existing PR details and branch sync info.
    • Removed the Create PR kill-switch; the split button is always enabled.
  • Refactors

    • Shared useAgentTarget hook; useDiffCommentTarget and usePRActionAgentTarget wrap it with surface-scoped storage keys.
    • Shared useCreateNewAgentSession hook extracted from usePaneRegistry for launching terminal agents.
    • New usePRActionDispatch to route submits by target; adds PRAgentPickerMenu for the dropdown.
    • State machine updated: selectActionButton returns update-pr-dropdown; tests updated accordingly.

Written for commit a7c69ef. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

Release Notes

  • New Features
    • Redesigned PR action interface with split-button control and dropdown agent picker
    • Users can now select which agent or terminal session to use for PR operations
    • Added support for updating existing pull requests
    • Option to create new agent sessions directly from PR workflows
    • Agent picker displays active sessions and available presets for quick selection

Review Change Stack

Kitenite added 3 commits May 28, 2026 11:02
Replace the top-right icon-only Create PR button with a labeled, bordered
split-button that mirrors the v1 PRButton / v2 PRStatusGroup pill style.
Primary click runs the existing slash-command flow through the default
agent (new chat tab today); chevron exposes an agent picker, stubbed
with "Coming soon" rows pending the phase-2 data wiring.

Surfaces all PR states cleanly:
- no-pr     → "Create PR" pill
- pr-exists → "Update PR" pill alongside the existing #N status pill
- busy      → same pill, primary disabled, spinner + "Creating…/Updating…"
- loading / unavailable / error paths unchanged

planDispatch + buildPRContext learn the pr-exists case so Update PR
opens a chat with /pr/update-pr and a pr-context.md attachment
(the matching slash command is a follow-up). Flip the
CREATE_PR_BUTTON_ENABLED gate on now that the flow ships.

Phase 1 of plans/20260528-1500-pr-button-agent-select.md.
Phase 2 of the PR action button. The chevron dropdown now renders a
real agent picker (active terminal sessions + "Start new" presets)
instead of placeholder items, and the primary button routes to the
last-picked agent.

- Extract the comment composer's selection/persistence into a shared
  `useAgentTarget` hook (renderer/hooks/agents); `useDiffCommentTarget`
  and the new `usePRActionAgentTarget` are now thin wrappers with
  surface-scoped storage keys so picks don't trample each other.
- Extract `createNewAgentSession` out of usePaneRegistry into a shared
  `useCreateNewAgentSession` hook, consumed by both the DiffPane
  composer and the PR action header.
- Add `usePRActionDispatch` to route a submit by target kind: chat-tab
  fallback (no pick) via the legacy flow, existing terminal via
  `sendToTerminalAgent` with pr-context inlined, or a new preset launch.
- Drop the `createPREnabled` kill-switch; the split button is the
  default now.
@capy-ai
Copy link
Copy Markdown

capy-ai Bot commented May 28, 2026

Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

📝 Walkthrough

Walkthrough

This PR implements a phased redesign of the PR action button in the desktop app, replacing legacy icon-driven UI with an agent-session-aware split-button. It introduces shared agent-target selection abstractions for persistence and validation, routes PR submissions to legacy chat tabs, existing terminal agents, or new agent sessions, supports updating existing PRs, and refactors the diff-comment composer to reuse the shared logic.

Changes

PR Action Split-Button with Agent Selection

Layer / File(s) Summary
Design and specification document
apps/desktop/plans/20260528-1500-pr-button-agent-select.md
Spec document defining the split-button UI structure, agent picker dropdown behavior, placement persistence, dispatch routing by target kind, custom project-prompt file integration, component architecture, and phasing plan.
Shared agent-target abstraction
apps/desktop/src/renderer/hooks/agents/useAgentTarget/...
useAgentTarget hook with encoded selection model (existing:<id>, new:<id>), localStorage persistence for terminalId/configId/placement, default computation from current sessions/configs, validation, and resolution to AgentTarget type. Barrel exports types, constants, and decoder.
PR action split-button component and agent picker
apps/desktop/src/renderer/routes/.../PRActionHeader/components/PRActionSplitButton/..., components/PRAgentPickerMenu/...
PRActionSplitButton renders bordered button with chevron dropdown, busy spinner, and tooltip. PRAgentPickerMenu groups active terminal sessions and "start new" presets with encoded active-item marking. usePRActionAgentTarget wraps shared hook with PR-action-scoped storage keys.
PR action dispatch routing and new session creation
apps/desktop/src/renderer/routes/.../PRActionSplitButton/hooks/usePRActionDispatch/..., useCreateNewAgentSession/...
usePRActionDispatch routes submission to legacy chat (null), existing terminal with inlined pr-context.md, or new session. useCreateNewAgentSession creates terminal-agent sessions via TRPC, seats pane into active tab or new tab based on placement, and handles errors via toast.
PR flow state selection and context rendering
apps/desktop/src/renderer/routes/.../PRActionHeader/utils/getPRFlowState/..., buildPRContext/...
getPRFlowState adds update-pr-dropdown action variant for existing PRs. buildPRContext renders pr-exists state with PR metadata, optional branch/sync details, required-preconditions, and update instructions. Test updates validate both.
PR flow dispatch for pr-exists state
apps/desktop/src/renderer/routes/.../hooks/usePRFlowDispatch/usePRFlowDispatch.ts
planDispatch now handles pr-exists state: builds /pr/update-pr prompt with base64-encoded pr-context.md attachment. Test fixtures and assertions validate prompt and attachment content.
PRActionHeader refactor: split-button integration
apps/desktop/src/renderer/routes/.../components/PRActionHeader/PRActionHeader.tsx
Refactors PRActionHeader to assemble agent picker state via hooks, replaces legacy icon-based UI with PRActionSplitButton for create/update, removes createPREnabled flag, adds optional onCreateNewAgentSession prop, and simplifies unavailable-state tooltip handling.
WorkspaceSidebar and workspace-page wiring
apps/desktop/src/renderer/routes/.../components/WorkspaceSidebar/..., usePaneRegistry.tsx, page.tsx
WorkspaceSidebar accepts and forwards onCreateNewAgentSession prop, removes hardcoded gating constant. usePaneRegistry delegates session creation to useCreateNewAgentSession hook. page.tsx initializes the hook and passes callback through sidebar props.
Refactor useDiffCommentTarget to use shared agent-target logic
apps/desktop/src/renderer/routes/.../usePaneRegistry/components/DiffPane/components/AgentCommentComposer/hooks/useDiffCommentTarget/...
Converts useDiffCommentTarget from self-contained logic to thin wrapper around useAgentTarget with comment-scoped storage keys, removes local type/constant/decoder definitions, and updates return type to shared UseAgentTargetResult.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • superset-sh/superset#4966: Introduces the original useDiffCommentTarget hook for agent-session selection in the diff-comment composer; this PR refactors that code to use the new shared useAgentTarget abstraction.

Poem

🐰 A split-button grows from the design,
With agents to pick and targets to send,
From chat to terminal in a blink,
Diff composer and PR action now sync,
Hop forth with shared abstractions! 🚀

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.63% 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
Title check ✅ Passed The title accurately summarizes the main change: adding an agent picker to the v2 PR action button, making it a split button with selection capability.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering summary, phases, changes, and test plan. It follows the general spirit of the template with clear sections explaining the implementation.
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 pr-button-agent-select

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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.

@stage-review
Copy link
Copy Markdown

stage-review Bot commented May 28, 2026

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 28, 2026

Greptile Summary

Upgrades the v2 top-right PR action control from an icon-only button to a split button with a working agent picker, mirroring the affordance from the DiffPane comment composer. Shared infrastructure (useAgentTarget, useCreateNewAgentSession) is extracted to avoid duplication, and the pr-exists state now has its own "Update PR" button and context builder.

  • Shared hooks: useAgentTarget and useCreateNewAgentSession are lifted out of their original DiffPane/paneRegistry homes; useDiffCommentTarget and usePRActionAgentTarget become thin wrappers with surface-scoped localStorage keys.
  • New components: PRActionSplitButton + PRAgentPickerMenu add the split-button shell and grouped dropdown (active sessions / start new), routing submission through usePRActionDispatch to terminal, new-preset, or legacy chat-tab transports.
  • buildPRContext + planDispatch extended for pr-exists, with tests covering the new dispatch path and attachment content.

Confidence Score: 4/5

Safe to merge; all three transports route correctly and the shared hook extraction preserves existing behaviour for the DiffPane composer.

The dispatch hook computes buildPRContext twice for every non-chat-tab submit, and useCreateNewAgentSession is instantiated twice in V2WorkspaceContent creating two independent tRPC mutation objects for the same endpoint. Neither causes wrong behaviour today, but both are unnecessary overhead.

page.tsx and usePRActionDispatch.ts have the redundancy findings; the rest of the files are clean.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/hooks/agents/useAgentTarget/useAgentTarget.ts New shared hook extracting selection state, localStorage persistence, and fallback logic from useDiffCommentTarget — clean abstraction with parameterised storage keys; logic is correct.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useCreateNewAgentSession/useCreateNewAgentSession.ts Extracted useCreateNewAgentSession hook from usePaneRegistry; logic is identical to the removed inline callback, instantiated in two places (page.tsx + usePaneRegistry) creating two separate mutation objects.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/hooks/usePRActionDispatch/usePRActionDispatch.ts Routes PR submit to terminal, new-session, or legacy chat-tab transport; calls planDispatch (which builds the attachment) then buildPRContext again via formatInlinedPrompt, producing the context string twice for non-chat-tab paths.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/PRActionHeader.tsx Wires agent picker data, selection state, and dispatch into the ActionSlot; uses inline import() type annotations for AgentTarget in two places instead of a top-level import.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsx Instantiates useCreateNewAgentSession directly and passes it to WorkspaceSidebar; usePaneRegistry (called on the same line) also instantiates the hook internally, creating two mutation objects for the same endpoint.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/usePaneRegistry.tsx createNewAgentSession correctly replaced by the extracted hook; callback is functionally equivalent to the removed inline implementation.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/DiffPane/components/AgentCommentComposer/hooks/useDiffCommentTarget/useDiffCommentTarget.ts Thinned to a wrapper re-exporting from the shared useAgentTarget; backward-compatible re-exports preserve existing consumers.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/PRActionSplitButton.tsx New split-button component; handlePick correctly passes the direct target to onSubmit (not stale resolvedTarget), so the one-click-pick-and-submit flow is correct.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/components/PRAgentPickerMenu/PRAgentPickerMenu.tsx DropdownMenu picker grouping Active sessions + Start new; hardcodes placement split-pane on new items, consistent with plan — no toggle is surfaced here.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/utils/buildPRContext/buildPRContext.ts Adds renderPrExists for the pr-exists state, generating a well-structured markdown context block with PR metadata, branch/sync status, and preconditions.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    SB["PRActionSplitButton\n(primary click or dropdown pick)"]
    PAD["usePRActionDispatch\n(routes by target.kind)"]
    T_NULL["target = null\n(no agent picked)"]
    T_EXIST["target.kind = 'existing'"]
    T_NEW["target.kind = 'new'"]
    FD["flowDispatch\n(legacy chat tab +\nattachment)"]
    TA["sendToTerminalAgent\n(inlined slash cmd +\npr-context)"]
    NA["onCreateNewAgentSession\n(useCreateNewAgentSession)\n(inlined seed prompt)"]

    SB -->|"onSubmit(target)"| PAD
    PAD --> T_NULL --> FD
    PAD --> T_EXIST --> TA
    PAD --> T_NEW -->|"onCreateNewAgentSession?"| NA
    PAD --> T_NEW -->|"no handler"| ERR["toast.error"]

    subgraph "Storage (per-surface keys)"
        LS1["lastSelectedPRActionTerminalId"]
        LS2["lastSelectedPRActionNewAgentConfigId"]
        LS3["lastSelectedPRActionPlacement"]
    end
    SB -.->|"usePRActionAgentTarget"| LS1
    SB -.->|"usePRActionAgentTarget"| LS2
    SB -.->|"usePRActionAgentTarget"| LS3
Loading

Comments Outside Diff (1)

  1. apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsx, line 1865 (link)

    P2 Duplicate useCreateNewAgentSession instance

    V2WorkspaceContent calls useCreateNewAgentSession({ store }) directly here and again implicitly via usePaneRegistry (which now calls the same hook with the same store). Both produce independent workspaceTrpc.agents.run.useMutation() instances with separate loading state. Functionally correct but wasteful — consider passing createNewAgentSession from usePaneRegistry out to the page (or vice-versa) so the same instance serves both consumers.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsx
    Line: 1865
    
    Comment:
    **Duplicate `useCreateNewAgentSession` instance**
    
    `V2WorkspaceContent` calls `useCreateNewAgentSession({ store })` directly here and again implicitly via `usePaneRegistry` (which now calls the same hook with the same `store`). Both produce independent `workspaceTrpc.agents.run.useMutation()` instances with separate loading state. Functionally correct but wasteful — consider passing `createNewAgentSession` from `usePaneRegistry` out to the page (or vice-versa) so the same instance serves both consumers.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/hooks/usePRActionDispatch/usePRActionDispatch.ts:89-92
`buildPRContext` is computed twice for every terminal/new-agent dispatch: first inside `planDispatch` (which base64-encodes it into an attachment that is then discarded), and again inside `formatInlinedPrompt`. For those two transport paths only `plan.prompt` (the slash command string) is needed from `planDispatch`. Having `formatInlinedPrompt` accept the already-built context string would eliminate the redundant computation.

```suggestion
function formatInlinedPrompt(prompt: string, context: string): string {
	return `${prompt}\n\n--- pr-context.md ---\n${context}`;
}
```

### Issue 2 of 3
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsx:1865
**Duplicate `useCreateNewAgentSession` instance**

`V2WorkspaceContent` calls `useCreateNewAgentSession({ store })` directly here and again implicitly via `usePaneRegistry` (which now calls the same hook with the same `store`). Both produce independent `workspaceTrpc.agents.run.useMutation()` instances with separate loading state. Functionally correct but wasteful — consider passing `createNewAgentSession` from `usePaneRegistry` out to the page (or vice-versa) so the same instance serves both consumers.

### Issue 3 of 3
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/PRActionHeader.tsx:66-85
Two inline `import()` type annotations are used for `AgentTarget` in this file. Since `AgentTarget` is already re-exported from the `PRActionSplitButton` barrel (which is already imported just above), a single top-level import is cleaner and avoids the repeated inline syntax.

```suggestion
	const onPickTarget = (
		target: AgentTarget,
	) => {
		onValueChange(
			target.kind === "existing"
				? `existing:${target.terminalId}`
				: `new:${target.configId}`,
		);
	};

	const splitButtonProps = {
		sessions,
		configs,
		selectedValue,
		resolvedTarget,
		onPickTarget,
		onSubmit: (target: AgentTarget | null) => submit({ state, target }),
	};
```

Reviews (1): Last reviewed commit: "feat(desktop): wire agent picker into v2..." | Re-trigger Greptile

Comment on lines +89 to +92
function formatInlinedPrompt(prompt: string, state: PRFlowState): string {
const context = buildPRContext(state);
return `${prompt}\n\n--- pr-context.md ---\n${context}`;
}
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.

P2 buildPRContext is computed twice for every terminal/new-agent dispatch: first inside planDispatch (which base64-encodes it into an attachment that is then discarded), and again inside formatInlinedPrompt. For those two transport paths only plan.prompt (the slash command string) is needed from planDispatch. Having formatInlinedPrompt accept the already-built context string would eliminate the redundant computation.

Suggested change
function formatInlinedPrompt(prompt: string, state: PRFlowState): string {
const context = buildPRContext(state);
return `${prompt}\n\n--- pr-context.md ---\n${context}`;
}
function formatInlinedPrompt(prompt: string, context: string): string {
return `${prompt}\n\n--- pr-context.md ---\n${context}`;
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/hooks/usePRActionDispatch/usePRActionDispatch.ts
Line: 89-92

Comment:
`buildPRContext` is computed twice for every terminal/new-agent dispatch: first inside `planDispatch` (which base64-encodes it into an attachment that is then discarded), and again inside `formatInlinedPrompt`. For those two transport paths only `plan.prompt` (the slash command string) is needed from `planDispatch`. Having `formatInlinedPrompt` accept the already-built context string would eliminate the redundant computation.

```suggestion
function formatInlinedPrompt(prompt: string, context: string): string {
	return `${prompt}\n\n--- pr-context.md ---\n${context}`;
}
```

How can I resolve this? If you propose a fix, please make it concise.

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 +66 to +85
const onPickTarget = (
target: import("renderer/hooks/agents/useAgentTarget").AgentTarget,
) => {
onValueChange(
target.kind === "existing"
? `existing:${target.terminalId}`
: `new:${target.configId}`,
);
};

const splitButtonProps = {
sessions,
configs,
selectedValue,
resolvedTarget,
onPickTarget,
onSubmit: (
target: import("renderer/hooks/agents/useAgentTarget").AgentTarget | null,
) => submit({ state, target }),
};
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.

P2 Two inline import() type annotations are used for AgentTarget in this file. Since AgentTarget is already re-exported from the PRActionSplitButton barrel (which is already imported just above), a single top-level import is cleaner and avoids the repeated inline syntax.

Suggested change
const onPickTarget = (
target: import("renderer/hooks/agents/useAgentTarget").AgentTarget,
) => {
onValueChange(
target.kind === "existing"
? `existing:${target.terminalId}`
: `new:${target.configId}`,
);
};
const splitButtonProps = {
sessions,
configs,
selectedValue,
resolvedTarget,
onPickTarget,
onSubmit: (
target: import("renderer/hooks/agents/useAgentTarget").AgentTarget | null,
) => submit({ state, target }),
};
const onPickTarget = (
target: AgentTarget,
) => {
onValueChange(
target.kind === "existing"
? `existing:${target.terminalId}`
: `new:${target.configId}`,
);
};
const splitButtonProps = {
sessions,
configs,
selectedValue,
resolvedTarget,
onPickTarget,
onSubmit: (target: AgentTarget | null) => submit({ state, target }),
};
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/PRActionHeader.tsx
Line: 66-85

Comment:
Two inline `import()` type annotations are used for `AgentTarget` in this file. Since `AgentTarget` is already re-exported from the `PRActionSplitButton` barrel (which is already imported just above), a single top-level import is cleaner and avoids the repeated inline syntax.

```suggestion
	const onPickTarget = (
		target: AgentTarget,
	) => {
		onValueChange(
			target.kind === "existing"
				? `existing:${target.terminalId}`
				: `new:${target.configId}`,
		);
	};

	const splitButtonProps = {
		sessions,
		configs,
		selectedValue,
		resolvedTarget,
		onPickTarget,
		onSubmit: (target: AgentTarget | null) => submit({ state, target }),
	};
```

How can I resolve this? If you propose a fix, please make it concise.

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
Contributor

@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: 4

🤖 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 `@apps/desktop/plans/20260528-1500-pr-button-agent-select.md`:
- Line 28: Line 28 begins with the token "`#4966`" which is being parsed as a
Markdown heading; update that token to avoid a heading by prefixing it with text
(for example change "`#4966`) gives us the pattern we want to reuse:" to "PR
`#4966`) gives us the pattern we want to reuse:" or equivalent) so the line is
treated as normal text rather than a heading.
- Around line 42-46: Update the Markdown fenced code blocks that render ASCII UI
(e.g., the block containing "┌──────────────────┬───┐ │ 📥  Create PR    │ ▾ │
└──────────────────┴───┘") to include an explicit language identifier (use
"text") after the opening backticks so they become ```text; do the same for the
other fenced blocks mentioned in the review (the blocks around the other
ASCII/UI sections) to satisfy MD040.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/components/PRAgentPickerMenu/PRAgentPickerMenu.tsx:
- Around line 91-101: The menu is hardcoding placement:"split-pane" when calling
onPickTarget in the DropdownMenuItem callback (for config.id), which overrides
the persisted default; change the call in PRAgentPickerMenu so it forwards the
current placement from the parent (or omits placement to let
usePRActionAgentTarget resolve it) instead of the literal "split-pane" — update
the onSelect handler that calls onPickTarget({ kind: "new", configId: config.id,
placement: ... }) to use the placement prop or resolvedTarget passed into
PRAgentPickerMenu rather than the hardcoded string.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/PRActionHeader.tsx:
- Around line 198-200: In PRActionHeader, the unavailable/error tooltip text
rendered via TooltipContent (and produced by unavailableTooltip(reason)) must be
selectable; update the TooltipContent usage in PRActionHeader.tsx to include
explicit select-text and cursor-text classes (e.g., via the component's
className prop) so the tooltip text becomes copyable when renderer-level
selection is disabled—if TooltipContent does not accept className, wrap
unavailableTooltip(reason) in a span/div with className="select-text
cursor-text" inside TooltipContent.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 60946a07-b2a8-4b25-9dc1-9139e04afc9e

📥 Commits

Reviewing files that changed from the base of the PR and between dbf96b5 and a7c69ef.

📒 Files selected for processing (23)
  • apps/desktop/plans/20260528-1500-pr-button-agent-select.md
  • apps/desktop/src/renderer/hooks/agents/useAgentTarget/index.ts
  • apps/desktop/src/renderer/hooks/agents/useAgentTarget/useAgentTarget.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/PRActionHeader.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/PRActionSplitButton.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/components/PRAgentPickerMenu/PRAgentPickerMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/components/PRAgentPickerMenu/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/hooks/usePRActionAgentTarget/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/hooks/usePRActionAgentTarget/usePRActionAgentTarget.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/hooks/usePRActionDispatch/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/hooks/usePRActionDispatch/usePRActionDispatch.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/utils/buildPRContext/buildPRContext.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/utils/getPRFlowState/getPRFlowState.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/utils/getPRFlowState/getPRFlowState.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/usePRFlowDispatch/usePRFlowDispatch.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/usePRFlowDispatch/usePRFlowDispatch.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useCreateNewAgentSession/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useCreateNewAgentSession/useCreateNewAgentSession.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/DiffPane/components/AgentCommentComposer/hooks/useDiffCommentTarget/useDiffCommentTarget.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/usePaneRegistry.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsx

no agent handoff.

The DiffPane comment composer (`AgentCommentComposer`, shipped in
#4966) gives us the pattern we want to reuse:
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix unintended heading token at Line 28.

#4966 at line start is parsed as a heading marker. Prefix it with text (for example, PR #4966``) to avoid malformed markdown structure.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 28-28: No space after hash on atx style heading

(MD018, no-missing-space-atx)

🤖 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 `@apps/desktop/plans/20260528-1500-pr-button-agent-select.md` at line 28, Line
28 begins with the token "`#4966`" which is being parsed as a Markdown heading;
update that token to avoid a heading by prefixing it with text (for example
change "`#4966`) gives us the pattern we want to reuse:" to "PR `#4966`) gives us
the pattern we want to reuse:" or equivalent) so the line is treated as normal
text rather than a heading.

Comment on lines +42 to +46
```
┌──────────────────┬───┐
│ 📥 Create PR │ ▾ │
└──────────────────┴───┘
```
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add languages to fenced code blocks.

The fenced blocks are missing language identifiers, which triggers markdown lint (MD040). Add explicit languages (for example, text) to each fence.

Also applies to: 80-91, 198-220

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 42-42: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 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 `@apps/desktop/plans/20260528-1500-pr-button-agent-select.md` around lines 42 -
46, Update the Markdown fenced code blocks that render ASCII UI (e.g., the block
containing "┌──────────────────┬───┐ │ 📥  Create PR    │ ▾ │
└──────────────────┴───┘") to include an explicit language identifier (use
"text") after the opening backticks so they become ```text; do the same for the
other fenced blocks mentioned in the review (the blocks around the other
ASCII/UI sections) to satisfy MD040.

Comment on lines +91 to +101
<DropdownMenuItem
key={config.id}
onSelect={() =>
onPickTarget({
kind: "new",
configId: config.id,
// Placement is the persisted default — picked up by
// the parent's usePRActionAgentTarget. The menu
// itself doesn't surface a toggle (one-click flow).
placement: "split-pane",
})
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Don’t hardcode new-session placement in menu picks.

This always submits "split-pane" and can ignore a persisted placement default (new-tab). It also conflicts with the comment at Lines 97–99. Pass the current placement from parent (or submit using resolved target after selection) instead of hardcoding here.

Suggested direction
 interface PRAgentPickerMenuProps {
   sessions: TerminalAgentBinding[];
   configs: HostAgentConfig[];
   value: string | null;
+  placement: AgentSessionPlacement;
   onPickTarget: (target: AgentTarget) => void;
 }
@@
-                onPickTarget({
+                onPickTarget({
                   kind: "new",
                   configId: config.id,
-                  placement: "split-pane",
+                  placement,
                 })
🤖 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
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/components/PRAgentPickerMenu/PRAgentPickerMenu.tsx
around lines 91 - 101, The menu is hardcoding placement:"split-pane" when
calling onPickTarget in the DropdownMenuItem callback (for config.id), which
overrides the persisted default; change the call in PRAgentPickerMenu so it
forwards the current placement from the parent (or omits placement to let
usePRActionAgentTarget resolve it) instead of the literal "split-pane" — update
the onSelect handler that calls onPickTarget({ kind: "new", configId: config.id,
placement: ... }) to use the placement prop or resolvedTarget passed into
PRAgentPickerMenu rather than the hardcoded string.

Comment on lines +198 to +200
<TooltipContent side="bottom">
{unavailableTooltip(reason)}
</TooltipContent>
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make unavailable tooltip text selectable.

Line 198 renders unavailable/error text without select-text cursor-text, so users can’t select/copy it when renderer-level selection is disabled.

Proposed fix
-			<TooltipContent side="bottom">
+			<TooltipContent side="bottom" className="select-text cursor-text">
 				{unavailableTooltip(reason)}
 			</TooltipContent>

As per coding guidelines: apps/desktop/**/*.{tsx,jsx}: Error text must be selectable by users with explicit select-text cursor-text classes; renderer sets user-select: none on body.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<TooltipContent side="bottom">
{unavailableTooltip(reason)}
</TooltipContent>
<TooltipContent side="bottom" className="select-text cursor-text">
{unavailableTooltip(reason)}
</TooltipContent>
🤖 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
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/PRActionHeader.tsx
around lines 198 - 200, In PRActionHeader, the unavailable/error tooltip text
rendered via TooltipContent (and produced by unavailableTooltip(reason)) must be
selectable; update the TooltipContent usage in PRActionHeader.tsx to include
explicit select-text and cursor-text classes (e.g., via the component's
className prop) so the tooltip text becomes copyable when renderer-level
selection is disabled—if TooltipContent does not accept className, wrap
unavailableTooltip(reason) in a span/div with className="select-text
cursor-text" inside TooltipContent.

Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

3 issues found across 23 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/utils/buildPRContext/buildPRContext.ts">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/utils/buildPRContext/buildPRContext.ts:128">
P2: `pr-exists` preconditions miss the no-upstream publish case, so the agent may omit publishing the branch before PR update steps.</violation>
</file>

<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/components/PRAgentPickerMenu/PRAgentPickerMenu.tsx">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/components/PRAgentPickerMenu/PRAgentPickerMenu.tsx:100">
P2: New-session picks force `placement: "split-pane"`, which can bypass persisted placement and make dropdown submits behave differently from the resolved default target.</violation>
</file>

<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/PRActionSplitButton.tsx">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/PRActionSplitButton.tsx:59">
P1: Handle rejected `onSubmit` promises in click handlers to avoid unhandled promise rejections.

(Based on your team's feedback about handling async calls and errors explicitly.) [FEEDBACK_USED]</violation>
</file>
Architecture diagram
sequenceDiagram
    participant User as User
    participant UI as PRActionSplitButton
    participant Dropdown as PRAgentPickerMenu
    participant PickHook as usePRActionAgentTarget
    participant Dispatch as usePRActionDispatch
    participant CreateSession as useCreateNewAgentSession
    participant TerminalBindings as Terminal Bindings
    participant AgentConfigs as Agent Configs
    participant FlowDispatch as PRFlowDispatch (Legacy)
    participant TerminalAgent as Existing Terminal Agent
    participant HostService as Host Service

    Note over User,HostService: PR Action Button Agent Picker Flow

    User->>UI: Click primary button (last picked agent)
    UI->>PickHook: Get resolvedAgentTarget
    alt resolvedTarget is null
        UI->>Dispatch: submit(null)
        Dispatch->>FlowDispatch: Legacy chat tab flow
        FlowDispatch->>FlowDispatch: /pr/create-pr or /pr/update-pr
    else resolvedTarget.kind is "existing"
        UI->>Dispatch: submit(existingTarget)
        Dispatch->>TerminalAgent: sendToTerminalAgent(inlined prompt)
        TerminalAgent-->>Dispatch: Success
    else resolvedTarget.kind is "new"
        UI->>Dispatch: submit(newTarget)
        Dispatch->>CreateSession: createNewAgentSession(configId, placement, prompt)
        CreateSession->>HostService: workspaceTrpc.agents.run(configId, prompt)
        HostService-->>CreateSession: terminal session result
        alt placement is "split-pane" and active tab exists
            CreateSession->>CreateSession: addPane to active tab
        else
            CreateSession->>CreateSession: addTab with new pane
        end
        CreateSession-->>Dispatch: { terminalId }
    end

    Note over User,HostService: Agent Picker Dropdown Flow

    User->>UI: Click chevron dropdown
    UI->>Dropdown: Open PRAgentPickerMenu
    Dropdown->>TerminalBindings: Get active sessions (sorted by lastEventAt)
    TerminalBindings-->>Dropdown: Active sessions list
    Dropdown->>AgentConfigs: Get available HostAgentConfigs
    AgentConfigs-->>Dropdown: Configs list
    alt has sessions
        Dropdown-->>User: Show "Active sessions" group
        User->>Dropdown: Pick existing session
    else has configs
        Dropdown-->>User: Show "Start new" group
        User->>Dropdown: Pick new config
    else no sessions and no configs
        Dropdown-->>User: Show "No agents configured" disabled item
    end
    Dropdown->>PickHook: onPickTarget(target)
    PickHook->>PickHook: Persist to localStorage
    Dropdown->>UI: Submit with picked target

    Note over PickHook,FlowDispatch: Target Resolution Logic
    Note over PickHook: Priority: last picked terminal > most recent active > last picked config > first config
    alt last picked session is alive
        PickHook->>PickHook: Use existing session
    else no sessions, last picked config exists
        PickHook->>PickHook: Use config (new session)
    else no data
        PickHook->>PickHook: Return null (fallback to legacy chat)
    end

    Note over Dispatch,FlowDispatch: Dispatch Routing Logic
    alt target is null
        Dispatch->>FlowDispatch: Legacy chat tab with slah command + pr-context.md
    else target.kind is "existing"
        Dispatch->>TerminalAgent: Send inlined slah command + context via xterm
    else target.kind is "new"
        alt onClickNewAgentSession exists
            Dispatch->>CreateSession: Launch new preset with seed prompt
        else
            Dispatch->>Dispatch: toast.error("Couldn't start agent session")
        end
    end
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

busy = false,
}: PRActionSplitButtonProps) {
const copy = labels(kind, busy);
const primaryHandler = () => void onSubmit(resolvedTarget);
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.

P1: Handle rejected onSubmit promises in click handlers to avoid unhandled promise rejections.

(Based on your team's feedback about handling async calls and errors explicitly.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/PRActionSplitButton.tsx, line 59:

<comment>Handle rejected `onSubmit` promises in click handlers to avoid unhandled promise rejections.

(Based on your team's feedback about handling async calls and errors explicitly.) </comment>

<file context>
@@ -0,0 +1,133 @@
+	busy = false,
+}: PRActionSplitButtonProps) {
+	const copy = labels(kind, busy);
+	const primaryHandler = () => void onSubmit(resolvedTarget);
+	const handlePick = (target: AgentTarget) => {
+		onPickTarget(target);
</file context>

Comment on lines +128 to +130
if (sync.hasUpstream && sync.pushCount > 0) {
preconditions.push("- Push unpushed commits.");
}
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.

P2: pr-exists preconditions miss the no-upstream publish case, so the agent may omit publishing the branch before PR update steps.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/utils/buildPRContext/buildPRContext.ts, line 128:

<comment>`pr-exists` preconditions miss the no-upstream publish case, so the agent may omit publishing the branch before PR update steps.</comment>

<file context>
@@ -77,6 +83,75 @@ function renderNoPR(sync: BranchSyncStatus): string {
+		if (sync.hasUncommitted) {
+			preconditions.push("- Commit or stash uncommitted changes.");
+		}
+		if (sync.hasUpstream && sync.pushCount > 0) {
+			preconditions.push("- Push unpushed commits.");
+		}
</file context>
Suggested change
if (sync.hasUpstream && sync.pushCount > 0) {
preconditions.push("- Push unpushed commits.");
}
if (!sync.hasUpstream) {
preconditions.push("- Publish the branch (`git push -u origin <branch>`).");
} else if (sync.pushCount > 0) {
preconditions.push("- Push unpushed commits.");
}

// Placement is the persisted default — picked up by
// the parent's usePRActionAgentTarget. The menu
// itself doesn't surface a toggle (one-click flow).
placement: "split-pane",
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.

P2: New-session picks force placement: "split-pane", which can bypass persisted placement and make dropdown submits behave differently from the resolved default target.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/PRActionHeader/components/PRActionSplitButton/components/PRAgentPickerMenu/PRAgentPickerMenu.tsx, line 100:

<comment>New-session picks force `placement: "split-pane"`, which can bypass persisted placement and make dropdown submits behave differently from the resolved default target.</comment>

<file context>
@@ -0,0 +1,162 @@
+										// Placement is the persisted default — picked up by
+										// the parent's usePRActionAgentTarget. The menu
+										// itself doesn't surface a toggle (one-click flow).
+										placement: "split-pane",
+									})
+								}
</file context>

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