Skip to content

feat(web): move branch selector into the toolbar breadcrumb - #4556

Closed
guitavano wants to merge 2 commits into
mainfrom
guitavano/abuja-v1
Closed

feat(web): move branch selector into the toolbar breadcrumb#4556
guitavano wants to merge 2 commits into
mainfrom
guitavano/abuja-v1

Conversation

@guitavano

@guitavano guitavano commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Moves the GitHub branch selector out of the chat composer and into the shell breadcrumb, so the toolbar reads deco › org › agent › branch.

  • New BranchCrumb in shell-breadcrumb.tsx, rendered after the agent crumb. Shows only inside a thread whose agent is a sandbox agent (GitHub repo with an attached connection). Non-sandbox agents (e.g. Decopilot) get no branch crumb.
  • The breadcrumb lives above ChatContextProvider, so it can't read the chat task context — BranchCrumb resolves the active thread's branch + lock state from the ThreadManager store instead (harness_id != null ⇒ runtime pinned ⇒ branch locked, matching ChatTaskContextValue.isThreadLocked).
  • Reuses the existing BranchPill with placement="header", restyled ghost (no border/bg, hover:bg-accent/60) to match the agent crumb.
  • Drops the ChatModeRow wrapper: the chat composer (input.tsx) and agent home (agent-home.tsx) now render ModePicker directly. BranchPill tests moved to their own branch-pill.test.tsx.

Testing

  • bun run check
  • bun run lint ✅ (0 errors)
  • bun test apps/mesh/src/web/components/chat/ ✅ (366 pass)

Notes / follow-up

  • Lock timing: in the chat the branch locked as soon as messages existed; in the breadcrumb it locks when harness_id is pinned (first send). There's a brief window where the branch stays editable until the runtime is actually pinned — which is arguably the more correct semantic.
  • Worth a visual check on mobile, where the breadcrumb row is tight; the chip truncates at max-w-[200px].

🤖 Generated with Claude Code


Summary by cubic

Moved the GitHub branch selector from the chat composer into the toolbar breadcrumb so it reads “org › agent › branch”. It shows only in sandbox-agent threads and avoids rendering for off-list/archived threads.

  • New Features

    • Added BranchCrumb in shell-breadcrumb.tsx that renders BranchPill. Lock state comes from the ThreadManager store (harness_id != null), and updates use useThreadActions.setBranch.
    • BranchCrumb gates on the active thread being present in the panel store; off-list/archived threads render nothing to avoid an unlocked, branch-less picker and phantom “New chat” rows.
  • Refactors

    • Removed placement from BranchPill/BranchPicker; always render a ghost, header-styled chip with a visible label. Simplified styles and removed responsive label collapse.
    • ChatModeRow now only renders the RuntimeSwitcher or the locked-runtime chip; removed branch pill composition and ChatModeRowPure. Callers in input.tsx and agent-home.tsx updated.

Written for commit 8416e38. Summary will update on new commits.

Review in cubic

@guitavano
guitavano force-pushed the guitavano/abuja-v1 branch from a8d786f to b93c5d0 Compare July 14, 2026 20:50
guitavano and others added 2 commits July 14, 2026 18:26
Relocate the GitHub branch picker from the chat composer's ChatModeRow to
the shell breadcrumb, rendering it as `org › agent › branch`. It shows only
inside a thread whose agent is a sandbox agent (GitHub repo with an attached
connection); non-sandbox agents have no branch crumb.

The breadcrumb lives above ChatContextProvider, so BranchCrumb resolves the
active thread's branch + lock state from the ThreadManager store
(`harness_id != null` => locked). Reuses BranchPill with placement="header",
now styled ghost to match the agent crumb.

ChatModeRow keeps only the RuntimeSwitcher / locked-runtime chip; its BranchPill
composition and the ChatModeRowPure layout helper are gone. BranchPill tests
moved to their own file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nt path)

- BranchCrumb: gate on the active thread being resolved in the panel store.
  It read the paginated (page-0) store while the chat sourced its branch from
  the useEnsureTask-resolved task, so older/archived threads rendered an
  unlocked, branch-less picker — and picking a branch prepended a phantom
  "New chat" row via applyPatch. Off-list threads are always locked; render
  nothing until resolved (fresh unlocked threads are always in page 0).
- Remove the now-dead placement="chat" path from BranchPill/BranchPicker
  (the only caller is the breadcrumb, always header) and its stale doc comment.
- Update the stale ChatModeRow reference in the locked-thread e2e comment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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