refactor(chat-ui): one shared composer, with link submenus and matching chat chips

Merged
SU
12d ago
+4119-10116

What & why

The shared composer refactor (#8706), finished against the "Tightening the shared composer" page and rebased on current main. The usage-limit and shell-row work from #8439 is not in this PR any more; it stays in #8439.

Commits

  • #8706's four commits: delete the v1 modal, move TiptapPromptEditor, updateQueuedPrompt, and the composer owning its editor, chips, attachments and submit.
  • fix(composer): close the gaps left from the composer cleanup page: New Workspace mode picker, CLI model aliases resolved for chats, sourcePath + "Show in folder", usedDictation.
  • fix: resolve the rebase onto main: follow-ups for main's composer, WorkDrawer and channels changes.
  • feat(chat-ui): link tasks, issues and pull requests from a submenu: replaces the removed New Workspace link buttons.
  • fix(desktop): a chip in a sent message looks as the composer drew it: the composer/chat chip mismatch raised on #9020.

Link submenu

  • ⊕ and a bare @ lead with a "Link" section: Linear issues (or Tasks), GitHub issues, Pull requests, each with ›.
  • → / Enter opens a submenu in place: search box, results before typing (assigned issues, recent tasks, open items), a "Show closed" switch. ← at the start of the search goes back, Esc closes. Typing after @ still mixes all providers.
  • Generic in chat-ui: a mention provider opts in with browse: { label, placeholder, filters }, and its search receives the filters that are on. Nothing in the composer knows about Linear or GitHub, so a plugin can supply such a provider later.

Sent chips match the composer

  • A linked issue/PR chip keeps its composer data on the message element: a new optional, opaque TextElement.data. The chat rebuilds it with the composer's linkedPrChip / linkedIssueChip, so the label and state icon are identical.
  • A pasted GitHub link in a message renders through linkChip, as in the composer. GithubWorkItemChip is removed; the hover card, link menu and open-on-click are kept (MessageChip, and LinkHoverCard shared with the composer).
  • Messages sent before this carry no data and show a plain chip, as before. The chip shows the state at send time; the hover card fetches the live one.
  • data is additive: TextElement is a loose object, so older hosts and desktops pass it through or ignore it, and the Codex adapter only forwards byteRange to the agent.

Decisions made while rebasing onto main (please check)

  • Composer.tsx and ComposerBody.tsx were rebuilt from main's version with #8706's changes re-applied.
  • Queued-prompt Edit in main's WorkDrawer edits in place and keeps attachments (main removed the prompt and appended its text).
  • Main's canQueue is removed: it only fed submitWhileStreaming, which #8706 deletes.
  • Paste: a link still becomes main's link chip; only text ≥ 5,000 chars becomes an attachment.

How I tested it

  • bunx turbo run typecheck: 42/42 pass. bun run check:i18n: passes (new strings reuse main's translations). Biome on changed files: clean; full bun run lint not run.
  • Tests: chat 102, chat-ui 38, chat-runtime 397, i18n 166, desktop src/renderer 7,293, 0 fail. New: MentionSubmenu, browseRows, WorkDrawer in-place edit, element data, and a sent PR chip drawn as the composer drew it; GithubWorkItemChip's hover, link-menu and click tests ported to MessageChip.
  • Not checked in the running app for the submenu or the chip change: the dev sandbox's local API only accepts the desktop on its default port, which another desktop instance was using. Earlier in-app checks of the composer (before these two commits) are on https://app.superset.sh/page/tightening-the-shared-composer-real-screenshots-7judk6

Checklist

  • PR title follows conventional commits (type(scope): subject)
  • bun run lint and bun run typecheck pass (typecheck passes; lint run with Biome on changed files only)
  • "Allow edits from maintainers" is checked on fork PRs (not a fork)
  • I have signed the CLA