feat(desktop): paginated branch picker with checkout + open actions#3397
feat(desktop): paginated branch picker with checkout + open actions#3397
Conversation
…actions Rework the v2 new-workspace modal's branch picker to handle thousands of branches and surface existing workspaces directly. - Host-service searchBranches: cursor pagination, refresh flag gated by 30s TTL, server-side filter (branch/worktree), reflog-based recency, git-worktree-derived worktreePath, isCheckedOut flag. - New checkout procedure: git worktree add <path> <existing-branch> (no -b, no dedup). Auto-resolves local vs origin/<branch>. - Renderer: useInfiniteQuery + IntersectionObserver for infinite scroll; tabs for Branch vs Worktree filters; hover-reveal action buttons — Check out on Branch tab (disabled when isCheckedOut), Open on Worktree tab (navigates to existing workspace). Click row body still sets base branch for the prompt-driven fork flow.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds server-side paginated branch discovery with richer per-branch metadata and branch/worktree filtering; client infinite-query integration with Branch/Worktree tabs and per-row checkout/open/adopt actions; new host-service checkout/adopt TRPC mutations; and React hooks and UI wiring. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client / UI
participant HostService as Host Service
participant Git as Git Repository
participant DB as Local DB
Client->>HostService: searchBranches(projectId, hostUrl, query, filter, cursor?, refresh)
activate HostService
alt refresh=true & TTL elapsed
HostService->>Git: git fetch --prune --quiet --no-tags
Git-->>HostService: fetch complete
end
HostService->>Git: git for-each-ref (refs/heads + refs/remotes/origin)
Git-->>HostService: refs
HostService->>Git: git worktree list --porcelain
Git-->>HostService: worktree list & checked-out branches
HostService->>Git: git log -g --grep-reflog=checkout:
Git-->>HostService: reflog entries
HostService->>DB: query local workspace rows
DB-->>HostService: workspace rows
HostService->>HostService: merge refs, apply filter/query, sort, slice -> {items, defaultBranch, nextCursor}
HostService-->>Client: { items, defaultBranch, nextCursor }
deactivate HostService
Client->>Client: render items
Client->>Client: user scroll -> IntersectionObserver triggers load
Client->>HostService: searchBranches(..., cursor=nextCursor)
sequenceDiagram
participant Client as Client / UI
participant HostService as Host Service
participant Git as Git Repository
participant Cloud as Cloud Backend
participant DB as Local DB
Client->>Client: User clicks "Checkout" (generate pendingId)
Client->>HostService: checkout({ pendingId, projectId, workspaceName, branch, composer?, linkedContext? })
activate HostService
HostService->>Git: ensure repo present (clone/pull)
Git-->>HostService: repo ready
HostService->>Git: resolve ref (refs/heads/<branch> or refs/remotes/origin/<branch>)
Git-->>HostService: ref resolved/missing
alt need origin fetch
HostService->>Git: git fetch origin <branch>
Git-->>HostService: fetched
end
HostService->>Git: git worktree add <path> <ref>
Git-->>HostService: worktree created
HostService->>Cloud: register cloud workspace
Cloud-->>HostService: cloud workspace id
HostService->>DB: insert local workspaces row
DB-->>HostService: local row created
alt setup requested
HostService->>HostService: start setup terminal
end
HostService-->>Client: { workspace, terminals?, warnings? }
deactivate HostService
Client->>Client: close modal, navigate to workspace route
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
Greptile SummaryThis PR reworks the v2 new-workspace modal's branch picker from a flat single-query list into a paginated, server-filtered two-tab UI with per-row actions (Check out / Open). The host-service Key changes and findings:
Confidence Score: 4/5Safe to merge — checkout/rollback paths are solid with no data-loss risk; the P1 performance issue (un-debounced search) is a notable UX concern but not a correctness blocker. The host-service changes are well-structured with correct TTL guard, rollback on failure, and careful ref resolution. The renderer migration to useInfiniteQuery is clean. The un-debounced search causes excessive IPC traffic per keystroke, the IntersectionObserver can cascade page loads in small viewports, and the duplicated BranchRow interface is a maintainability concern. None of these block primary user paths or introduce data loss, and known limitations are clearly documented. PromptGroup.tsx (missing search debounce) and CompareBaseBranchPicker.tsx (duplicate BranchRow type, IntersectionObserver cascade) Important Files Changed
Sequence DiagramsequenceDiagram
participant U as User
participant P as PromptGroup
participant H as useBranchContext
participant HS as host-service
participant G as git
U->>P: opens modal / types search
P->>H: query=branchSearch, filter, page=undefined
H->>HS: searchBranches(refresh:true, cursor:undefined)
HS->>G: git fetch --prune (TTL-gated 30s)
HS->>G: git worktree list --porcelain
HS->>G: git log -g (reflog recency)
HS->>G: git for-each-ref refs/heads + refs/remotes/origin
G-->>HS: raw output
HS-->>H: defaultBranch, items[0..49], nextCursor
H-->>P: branches[], hasNextPage=true
U->>P: scrolls near bottom
P->>H: fetchNextPage()
H->>HS: searchBranches(refresh:false, cursor:encoded)
HS->>G: worktree list + log -g + for-each-ref
HS-->>H: items[50..99], nextCursor
H-->>P: branches[] grows
U->>P: clicks Check out
P->>HS: checkout(pendingId, branch, workspaceName)
HS->>G: git show-ref refs/heads/branch
alt local ref exists
G-->>HS: ok, ref=branch
else remote-only
HS->>G: git show-ref refs/remotes/origin/branch
HS->>G: git fetch origin branch
G-->>HS: ok, ref=origin/branch
end
HS->>G: git worktree add worktreePath ref
HS->>HS: ensureV2Host + v2Workspace.create (cloud)
HS->>HS: local DB insert workspaces
HS-->>P: workspace.id
P->>P: navigate /v2-workspace/$workspaceId
U->>P: clicks Open (Worktree tab)
P->>P: lookup workspaceId via workspaceByBranch
P->>P: closeModal + navigate
|
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/BRANCH_DISCOVERY_DESIGN.md`:
- Around line 171-180: The fenced mockup blocks containing lines like "⎇
feature-foo [remote] 3d ago [✓ when selected]" and the
hover/focus mockup with "⎇ feature-foo [remote] 3d ago [Check
out]" should be given a language tag to satisfy markdownlint MD040; update each
triple-backtick fence in BRANCH_DISCOVERY_DESIGN.md to start with ```text so
both mockup blocks are labeled as plain text.
In
`@apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/hooks/useBranchContext/useBranchContext.ts`:
- Around line 50-62: The queryFn in useBranchContext currently only destructures
{ pageParam } and doesn't forward TanStack Query's AbortSignal, so update the
queryFn to destructure the signal (e.g., async ({ pageParam, signal })) and pass
that signal into the tRPC call to cancel in-flight requests; specifically,
modify the call to client.workspaceCreation.searchBranches.query to include the
signal from the queryFn parameters so searches are aborted when the query key
changes.
In
`@apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/components/CompareBaseBranchPicker/CompareBaseBranchPicker.tsx`:
- Around line 183-215: The row action buttons in CompareBaseBranchPicker are
only exposed via the "group-hover" class, making them unreachable to keyboard
users; update the JSX for the Open and Check out controls (the elements that
call onOpenExisting and onCheckoutBranch) to be focusable when the row is
focused by adding focus-visible/focus-within visibility classes instead of
relying solely on group-hover (e.g., replace "hidden group-hover:inline-flex"
with classes that show on hover or focus), and replace the non-focusable span
used as a TooltipTrigger for the disabled state with a focusable element (a
button or a TooltipTrigger with asChild wrapping a button) that includes
aria-disabled when branch.isCheckedOut so the tooltip is reachable via keyboard
and screen readers while preserving the disabled styling.
In
`@apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/PromptGroup.tsx`:
- Around line 152-176: The handler handleOpenExisting currently looks up a
workspace by branch using workspaceByBranch, which is unstable when duplicate
branch names exist; change the API to accept a stable identifier (workspace id
or worktreePath) from the picker rows and stop resolving by branch name. Update
handleOpenExisting to receive workspaceId (or worktreePath) directly, remove
workspaceByBranch.get usage and toast branch-missing logic, and use that id when
calling navigate({ to: "/v2-workspace/$workspaceId", params: { workspaceId } });
also update the component prop onOpenExisting and any call sites that call
handleOpenExisting to pass the row's workspace id/worktreePath instead of
branchName. Ensure workspaceByBranch can be removed or adjusted if no longer
needed.
In
`@packages/host-service/src/trpc/router/workspace-creation/workspace-creation.ts`:
- Around line 776-816: The code resolving refs treats an origin-only branch as
if `git worktree add <path> origin/<branch>` will auto-create a local tracking
branch; instead, when ref startsWith("origin/") (the resolved ref variable) call
git.worktree add with explicit tracking flags so a local branch is created (use
`--track -b <branch> <worktreePath> origin/<branch>` semantics) and update the
preceding comment to remove the incorrect claim about auto-tracking for
origin/<branch>; modify the block that currently does git.raw(["worktree",
"add", worktreePath, ref]) to detect origin/* and invoke git.raw with the
`--track` and `-b` flags using the plain branch name, keeping existing
fetch/error handling (refer to variables ref, branch, and worktreePath).
🪄 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: 0b7c8e74-8f69-42aa-9e7e-dc993a317c65
📒 Files selected for processing (8)
apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/BRANCH_DISCOVERY_DESIGN.mdapps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/PromptGroup.tsxapps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/components/CompareBaseBranchPicker/CompareBaseBranchPicker.tsxapps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/hooks/useBranchContext/index.tsapps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/hooks/useBranchContext/useBranchContext.tsapps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/hooks/useCheckoutDashboardWorkspace/index.tsapps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/hooks/useCheckoutDashboardWorkspace/useCheckoutDashboardWorkspace.tspackages/host-service/src/trpc/router/workspace-creation/workspace-creation.ts
There was a problem hiding this comment.
3 issues found across 8 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/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/PromptGroup.tsx">
<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/PromptGroup.tsx:156">
P2: Open-by-branch lookup ignores host, so it can open the wrong workspace when the same branch exists on multiple hosts.</violation>
</file>
<file name="packages/host-service/src/trpc/router/workspace-creation/workspace-creation.ts">
<violation number="1" location="packages/host-service/src/trpc/router/workspace-creation/workspace-creation.ts:123">
P2: Silent `catch` swallows `git worktree list` errors without logging. If this fails, every branch's `isCheckedOut` will be `false`, enabling the Checkout button for already-checked-out branches. Add a `console.warn` with context so the failure is observable.
(Based on your team's feedback about handling async errors explicitly and not silently swallowing failures.) [FEEDBACK_USED]</violation>
</file>
<file name="apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/components/CompareBaseBranchPicker/CompareBaseBranchPicker.tsx">
<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/components/CompareBaseBranchPicker/CompareBaseBranchPicker.tsx:22">
P2: This local `BranchRow` interface manually duplicates the shape already derived from the host-service zod schema in `useBranchContext.ts` (via `inferRouterOutputs`). If the server type changes, this copy silently diverges.
Import the canonical type instead and add `BranchRow` to the barrel export in `hooks/useBranchContext/index.ts`:
```ts
// index.ts
export { type BranchFilter, type BranchRow, useBranchContext } from "./useBranchContext";
// CompareBaseBranchPicker.tsx
import type { BranchFilter, BranchRow } from "../../../hooks/useBranchContext";
```</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
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/components/DashboardNewWorkspaceModal/BRANCH_DISCOVERY_DESIGN.md">
<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/BRANCH_DISCOVERY_DESIGN.md:77">
P1: The claim that `git worktree add <path> origin/<branch>` auto-creates a local tracking branch is incorrect. Per git documentation, the auto-create convenience only triggers when the **short** branch name is passed (e.g., `branch`, not `origin/branch`) and no `-b`/`-B`/`--detach` flag is given. Passing the fully-qualified `origin/<branch>` treats it as a commit-ish, which may result in a detached HEAD rather than a proper local tracking branch.
The `checkout` procedure should use `--track -b <branch> <path> origin/<branch>` for remote-only branches to ensure a local tracking branch is created, and this doc should be updated accordingly.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
- Remote-only Check out: use `git worktree add --track -b <branch>` so the worktree lands on a proper local tracking branch instead of detached HEAD. Auto-track only fires for the short name; passing `origin/<branch>` is treated as a commit-ish. - Open existing: scope the branch→workspace map by host id so the Worktree tab doesn't navigate to a workspace on the wrong host when the same branch exists on multiple hosts. - Picker a11y: reveal row action buttons on focus-within, not just hover. Swap the disabled span for a focusable button with aria-disabled so keyboard users can reach the "already checked out" tooltip.
|
You're iterating quickly on this pull request. To help protect your rate limits, cubic has paused automatic reviews on new pushes for now—when you're ready for another review, comment |
Captures the design for full-resource workspace deletion — worktree on disk, optional branch, cloud row, local host-DB row. Host-service orchestrates in that order (hard-to-reverse side first). Covers failure modes, UX decisions (delete-branch opt-in, confirm only when dirty), and what replaces the current cloud-only v2Workspace.delete. Not implemented here — separate PR picks this up.
The old short-circuit returned `existingLocal.id` whenever a local `workspaces` row matched the (project, branch) pair, without calling cloud. After a prior workspace was hard-deleted in the cloud, the host sqlite row leaked — so re-adopting the worktree echoed a phantom id whose cloud row no longer existed. Renderer navigated to it, Electric never synced anything back, sidebar/target page showed "not found" indefinitely. Fix: drop the local-idempotency shortcut. Always call `v2Workspace.create`; the new cloudRow.id is authoritative. If a stale local row exists for this (project, branch), replace it with the fresh mapping. Also: pending page now waits for the newly-created cloud row to sync into the Electric-backed `v2Workspaces` collection before navigating, with a 3s fallback. Fast intents (adopt) were beating the sync to the punch and landing on /v2-workspace/<id> before the row was visible. Docs: replaced the draft delete design with the canonical version — v2 delete unifies through `workspaceCleanup.destroy`; implementation owned by a follow-up PR.
…hrows, harden lint script Three PR-review follow-ups: - Pending page: reset `firedRef` / `navigatedRef` when `pendingId` changes under a mounted component. Previously, navigating from one pending page to another kept the flags stuck at true → the second page never fired its mutation and sat in "creating" forever. - Checkout procedure: `clearProgress(pendingId)` on the empty-branch and `safeResolveWorktreePath` error paths. Without this, a stale pending row lingered until the 5-minute sweeper removed it. - check-git-ref-strings.sh: distinguish ripgrep exit codes. Exit 1 (no matches) still passes; exit 2+ (unreadable file, bad regex) now fails loudly. `2>/dev/null` previously masked real scan failures as clean passes.
…payload builders
Addresses two code-smell findings from the PR review:
- pendingWorkspaceSchema had `hostTarget`, `linkedIssues`, `linkedPR` as
`z.unknown()`, forcing `as`-casts at every read site and hiding
malformed rows until a consumer crashed. Replaced with structured zod
shapes (discriminatedUnion for hostTarget, typed object schemas for
linkedIssues/linkedPR). Drops the casts in the pending page and the
submit hook, and any malformed row now fails zod parsing instead of
reaching the dispatch.
- Intent dispatch logic in useFireIntent (the switch that translates
pending-row state into mutation inputs per intent) was untested and
tangled up with IO. Extracted the payload-building into pure helpers
in buildIntentPayload.ts and added a contract suite (11 tests, all
passing) covering:
- mapLinkedContextFromPending: internal filtering, github filtering,
skip-missing-fields, linkedPR passthrough, empty-input
- buildForkPayload: full fork shape, empty-prompt → undefined,
attachments plumbing, host-tracking hostTarget survives
- buildCheckoutPayload: branch + runSetupScript only
- buildAdoptPayload: minimal shape
Pending page's useFireIntent becomes a thin wrapper: build payload,
call mutation, update collection. Bonus cleanup: the `hostUrl`
derivation block collapses from a nested ternary with 3 string casts
to a plain discriminant switch now that the type is known.
Merges three separate design docs in the modal directory into one `DESIGN.md` covering the full v2 workspace-creation architecture: - Branch discovery (data shape, server flow, client flow) — was BRANCH_DISCOVERY_DESIGN.md - Actions per row (Fork / Check out / Open / Create, authority for hasWorkspace) - Workspace creation flow (three intents, pending-row schema, pending-page dispatch, baseBranchSource plumbing, per-mutation details) — was PENDING_FLOW.md - Workspace delete (follow-up PR spec with host-service ownership principle) — was WORKSPACE_DELETE_DESIGN.md - Invariants + enforcement (authority decisions, tests, lint, type guarantees) Cross-links to `packages/host-service/GIT_REFS.md` which stays separate — it's a cross-cutting pattern doc, not modal-specific. Code-comment pointers updated from the old filenames to the new consolidated DESIGN.md with section references.
…op root The doc covers a multi-module subsystem (modal + pending page + host-service procedures) — it doesn't belong nested deep inside the modal directory where 'DESIGN.md' is also too generic to be findable. Moved to apps/desktop/V2_WORKSPACE_CREATION.md, parallel to AGENTS.md and CLAUDE.md, where system-level architecture docs live in this repo. Name says what it covers. Code-comment pointers updated to use the new path. Internal cross-link to GIT_REFS.md fixed for the new depth.
…ATION The fallback doc was the original design proposal for resolveStartPoint + --no-track + targeted single-ref fetch. All shipped in this PR. The spec/diff sections are now stale — implementation lives in code. Kept the prior-art comparison (VS Code, T3Code, GitHub Desktop, v1) as an appendix in V2_WORKSPACE_CREATION.md — that's the part future contributors might re-derive without reference. Updated the comparison table to reflect what we actually shipped (local-first instead of remote-first; targeted single-ref fetch). Added the rationale for each rejection (why not VS Code's upstream lookup, why not T3Code's gh-merge-base, etc.). Removed packages/host-service/WORKSPACE_CREATION_FALLBACK.md.
…rom PromptGroup PromptGroup was 592 lines mixing form state, agent prefs, branch picker state + handlers, link handlers, hotkey wiring, and JSX. Split the picker controller and link handlers into co-located hooks; PromptGroup is now 360 lines focused on form composition. - useBranchPickerController: owns picker state (search, filter), the branch-context query, host-id resolution + workspace lookup, and the three per-row action handlers (Open / Check out / Adopt). Returns a `pickerProps` bag the caller spreads into <CompareBaseBranchPicker>. Hides ~70 lines of plumbing behind one hook call. - useLinkedContext: bundles addLinkedIssue / addLinkedGitHubIssue / removeLinkedIssue / setLinkedPR / removeLinkedPR. Pure delegation over updateDraft. - Collapse the PromptGroup / PromptGroupInner indirection. There was no error boundary, provider, or conditional in the wrapper — just a pass-through. Removed. Behavior unchanged. Typecheck + lint clean; 11 pending-page tests pass.
Summary
Reworks the v2 new-workspace modal's branch picker so it scales to thousands of branches and exposes direct actions for existing workspaces. Adds a pure-checkout path alongside the existing prompt-driven fork flow.
What changed
Host-service (
workspace-creation.ts)searchBranches: cursor pagination,refreshflag gated by a 30s TTL per project (avoids thrashinggit fetchon every keystroke), server-side filter (branch/worktree), reflog-based recency ordering.isLocal/isRemote/worktreePath/recency/isCheckedOut.worktreePathis limited to Superset-managed worktrees under<repoPath>/.worktrees/so the primary clone's branch doesn't get treated as "has workspace".isCheckedOutis derived from the fullgit worktree list(including primary) — used by the UI to disable Checkout when a branch is already checked out elsewhere.checkoutprocedure:git worktree add <path> <branch>(no-b, no branch-name dedup). Resolves local vsorigin/<branch>automatically; fetches the latest when only the remote ref exists. Same cloud-workspace registration + setup-script + rollback path ascreate.Renderer
useBranchContextis now auseInfiniteQuery. Types (BranchFilter,BranchRow) are derived from the host-service zod schema viainferRouterInputs/inferRouterOutputs— single source of truth, no duplicate enums.CompareBaseBranchPickergets a 2-tab strip (Branch / Worktree) and anIntersectionObserversentinel for infinite scroll. Client no longer filters — the server does.isCheckedOut), Open on Worktree (navigates to the existing workspace). Clicking the row body still sets the base branch, preserving today's prompt-driven fork flow.useCheckoutDashboardWorkspacehook — sibling ofuseCreateDashboardWorkspace.Design doc
apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/BRANCH_DISCOVERY_DESIGN.mdcovers the data model, pagination strategy, and the action-intent design.Known limitations (punted to follow-ups)
searchBranchesis called for a project that has no localprojectsrow in the host-service DB, it still returns empty. Discussed; left for a separate PR that either auto-sets-up the project on modal open or falls back to GitHub API.initialLaunchConfig); deferred per review.Test plan
main), confirm the Check out button is disabled with the tooltip.Summary by cubic
Reworked the v2 new‑workspace branch picker to handle large repos and added per‑row actions, with fork/checkout/adopt unified under a pending flow and safer git‑ref handling. Also extracted a picker controller and linked‑context hooks to simplify
PromptGroupand reduce plumbing.New Features
searchBrancheswith pagination and 30srefreshTTL, serverfilter(branch/worktree), and richer metadata (isLocal,isRemote,recency,worktreePath,hasWorkspace,isCheckedOut). Returnsitems+nextCursor.intent, retry,warnings), and navigation waits for the new workspace to sync.--track -b). Adopt registers a fresh cloud row for an existing.worktrees/<branch>and replaces any stale local mapping; idempotent.apps/desktop/V2_WORKSPACE_CREATION.md(folded previous fallback doc); removedpackages/host-service/WORKSPACE_CREATION_FALLBACK.md.Bug Fixes
ResolvedRefusing full refnames;resolveRefacceptsorigin/<branch>; added tests andpackages/host-service/GIT_REFS.md. Lint script forbids short‑name prefix checks.baseBranchSourcehint so the server uses the exact start point the user selected.aria-disabled; infinite scroll guarded; actions respect a typed workspace name; typed pending‑row schema and pure intent‑payload builders with tests; reset pending‑page refs onpendingIdchange; clear progress on early errors; lint distinguishes realripgreperrors.Written for commit 1b8d8f1. Summary will update on new commits.
Summary by CodeRabbit
New Features
Documentation