feat(web): add terminal.focus and chat.focusComposer keybindings - #5961

Open
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions
Open

feat(web): add terminal.focus and chat.focusComposer keybindings#5961
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions

Conversation

@achtan

@achtanachtan commented Aug 10, 2026

Copy link
Copy Markdown

Part of #4641 (items 4 and 5).

Problem

Focus is coupled to panel visibility. Opening the terminal drawer requests terminal focus and closing it returns focus to the composer, but there is no keyboard route between the two while the drawer stays open: type-to-focus bails when focus sits in any input or textarea, and the terminal renders a textarea, so typing in the terminal can never bring you back. The workaround today is toggling the drawer twice with mod+j.

What changed

  • packages/contractsterminal.focus and chat.focusComposer join STATIC_KEYBINDING_COMMANDS. Older clients drop unknown commands through the existing ForwardCompatibleArray decoding, so no compatibility work was needed.

  • packages/shared — both ship as one default key with mutually exclusive when clauses, so a single key hops focus in either direction without touching drawer visibility:

    { "key": "ctrl+`", "command": "terminal.focus", "when": "!terminalFocus" },
    { "key": "ctrl+`", "command": "chat.focusComposer", "when": "terminalFocus" }

    ctrl+` follows VS Code's focus-terminal binding and is unclaimed by the existing defaults on every platform. Each command is still independently rebindable; the startup default sync backfills both rules into existing configs.

  • apps/web (ChatView) — dispatch in the existing global shortcut handler.

    • terminal.focus picks one target via a pure resolveTerminalFocusTarget decision (unit-tested): the right-panel terminal when it is the only terminal showing (drawer closed, or right panel maximized), otherwise the drawer — opening it when closed, where the closed→open transition already requests focus and creates the first session. The right-panel terminal now consumes its own panelTerminalFocusRequestId — bumped by the panel's own lifecycle actions (add, split, activate, close, surface activation) and by terminal.focus when the panel is the target — so a focus request lands on exactly one surface instead of broadcasting to both terminal hosts.
    • chat.focusComposer calls the existing focusComposer() and leaves the terminal open.
    • Both commands first un-maximize the right panel when their target lives in the chat column, which a maximized panel collapses to zero width — without this, focus would land on an invisible element.
  • Settings → Keybindings — no changes needed: labels derive from the command IDs ("Terminal: Focus", "Chat: Focus Composer") and both commands appear in the add-binding dropdown because they ship as defaults.

  • docs/user/keybindings.md — short note on the pair and how it differs from terminal.toggle.

Verification

  • vp test run on the touched suites: web keybindings 46 passed (4 new: the ctrl+` pair resolves per terminalFocus context on macOS and Windows, against the real shipped defaults so the rules are proven to parse), ChatView logic 43 passed (5 new covering every resolveTerminalFocusTarget branch), keybindings settings logic 9 passed (label + dropdown coverage), server keybindings 22 passed (default backfill is generic over DEFAULT_KEYBINDINGS).

  • tsgo --noEmit clean for contracts, shared, and web; vp lint clean on touched files.

  • Demo video (25s):ctrl-backtick-focus-demo.webm — recorded in a real browser against a dev build of this branch. It shows: typing in the composer → ctrl+` opens the drawer and focuses the terminal (an echo typed immediately after the keypress lands at the shell prompt) → ctrl+` hops back to the composer with the drawer still open → a third press hops into the already-open terminal (pwd) → a final press returns to the composer. No mouse after the first click.

    Final state:

    final state: composer text typed across two hops, terminal transcript with echo and pwd

Built with Claude Fable 5 (claude-fable-5) via Claude Code.


Note

Low Risk
UI focus and keybinding routing only; no auth, data, or API changes. Logic is isolated and covered by new unit tests.

Overview
Adds terminal.focus and chat.focusComposer so users can hop between the message composer and terminal without toggling the drawer (addresses the gap where typing cannot return focus from the terminal textarea).

Defaults: Both bind to ctrl+` with opposite when: terminalFocus clauses in shared keybindings; contracts register the new static commands.

Behavior:ChatView handles the commands in the global shortcut handler. resolveTerminalFocusTarget (pure, unit-tested) chooses the right-panel terminal vs drawer vs open-drawer, including when the right panel is maximized. Right-panel terminal actions bump a separate panelTerminalFocusRequestId so focus requests hit one surface instead of drawer + panel together. Either command un-maximizes the right panel when focus must land in the chat column.

Docs and settings tests cover labels and the new commands in the keybindings UI.

Reviewed by Cursor Bugbot for commit 488b424. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add terminal.focus and chat.focusComposer keybindings mapped to Ctrl+`

  • Pressing Ctrl+` outside the terminal focuses the terminal: targeting the panel terminal if active, or opening/focusing the drawer otherwise.
  • Pressing Ctrl+` while inside the terminal focuses the message composer and collapses a maximized right panel if needed.
  • Adds resolveTerminalFocusTarget in ChatView.logic.ts to determine which terminal surface (panel, drawer, or open-drawer) to target.
  • Introduces a dedicated panelTerminalFocusRequestId state separate from terminalFocusRequestId so panel terminal actions no longer interfere with drawer focus requests.
  • Behavioral Change: panel terminal actions (addTerminalSurface, splitPanelTerminal, etc.) now increment panelTerminalFocusRequestId instead of terminalFocusRequestId.

Macroscope summarized 488b424.

@coderabbitai

coderabbitaiBot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 788c1747-a060-4715-b0b6-9df2041b6711

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 10, 2026
Comment threadapps/web/src/components/ChatView.tsx
Comment threadapps/web/src/components/ChatView.tsx
@macroscopeapp

macroscopeappBot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds new user-facing keybindings (terminal.focus and chat.focusComposer) that modify focus management behavior. While well-structured and tested, new capabilities from a first-time contributor warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@cursorcursorBot left a comment

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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e3adb5b. Configure here.

Comment threadapps/web/src/components/ChatView.tsx
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@achtan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(web): add terminal.focus and chat.focusComposer keybindings - #5961

Open
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions
Open

feat(web): add terminal.focus and chat.focusComposer keybindings#5961
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions

Conversation

@achtan

@achtanachtan commented Aug 10, 2026

Copy link
Copy Markdown

Part of #4641 (items 4 and 5).

Problem

Focus is coupled to panel visibility. Opening the terminal drawer requests terminal focus and closing it returns focus to the composer, but there is no keyboard route between the two while the drawer stays open: type-to-focus bails when focus sits in any input or textarea, and the terminal renders a textarea, so typing in the terminal can never bring you back. The workaround today is toggling the drawer twice with mod+j.

What changed

  • packages/contractsterminal.focus and chat.focusComposer join STATIC_KEYBINDING_COMMANDS. Older clients drop unknown commands through the existing ForwardCompatibleArray decoding, so no compatibility work was needed.

  • packages/shared — both ship as one default key with mutually exclusive when clauses, so a single key hops focus in either direction without touching drawer visibility:

    { "key": "ctrl+`", "command": "terminal.focus", "when": "!terminalFocus" },
    { "key": "ctrl+`", "command": "chat.focusComposer", "when": "terminalFocus" }

    ctrl+` follows VS Code's focus-terminal binding and is unclaimed by the existing defaults on every platform. Each command is still independently rebindable; the startup default sync backfills both rules into existing configs.

  • apps/web (ChatView) — dispatch in the existing global shortcut handler.

    • terminal.focus picks one target via a pure resolveTerminalFocusTarget decision (unit-tested): the right-panel terminal when it is the only terminal showing (drawer closed, or right panel maximized), otherwise the drawer — opening it when closed, where the closed→open transition already requests focus and creates the first session. The right-panel terminal now consumes its own panelTerminalFocusRequestId — bumped by the panel's own lifecycle actions (add, split, activate, close, surface activation) and by terminal.focus when the panel is the target — so a focus request lands on exactly one surface instead of broadcasting to both terminal hosts.
    • chat.focusComposer calls the existing focusComposer() and leaves the terminal open.
    • Both commands first un-maximize the right panel when their target lives in the chat column, which a maximized panel collapses to zero width — without this, focus would land on an invisible element.
  • Settings → Keybindings — no changes needed: labels derive from the command IDs ("Terminal: Focus", "Chat: Focus Composer") and both commands appear in the add-binding dropdown because they ship as defaults.

  • docs/user/keybindings.md — short note on the pair and how it differs from terminal.toggle.

Verification

  • vp test run on the touched suites: web keybindings 46 passed (4 new: the ctrl+` pair resolves per terminalFocus context on macOS and Windows, against the real shipped defaults so the rules are proven to parse), ChatView logic 43 passed (5 new covering every resolveTerminalFocusTarget branch), keybindings settings logic 9 passed (label + dropdown coverage), server keybindings 22 passed (default backfill is generic over DEFAULT_KEYBINDINGS).

  • tsgo --noEmit clean for contracts, shared, and web; vp lint clean on touched files.

  • Demo video (25s):ctrl-backtick-focus-demo.webm — recorded in a real browser against a dev build of this branch. It shows: typing in the composer → ctrl+` opens the drawer and focuses the terminal (an echo typed immediately after the keypress lands at the shell prompt) → ctrl+` hops back to the composer with the drawer still open → a third press hops into the already-open terminal (pwd) → a final press returns to the composer. No mouse after the first click.

    Final state:

    final state: composer text typed across two hops, terminal transcript with echo and pwd

Built with Claude Fable 5 (claude-fable-5) via Claude Code.


Note

Low Risk
UI focus and keybinding routing only; no auth, data, or API changes. Logic is isolated and covered by new unit tests.

Overview
Adds terminal.focus and chat.focusComposer so users can hop between the message composer and terminal without toggling the drawer (addresses the gap where typing cannot return focus from the terminal textarea).

Defaults: Both bind to ctrl+` with opposite when: terminalFocus clauses in shared keybindings; contracts register the new static commands.

Behavior:ChatView handles the commands in the global shortcut handler. resolveTerminalFocusTarget (pure, unit-tested) chooses the right-panel terminal vs drawer vs open-drawer, including when the right panel is maximized. Right-panel terminal actions bump a separate panelTerminalFocusRequestId so focus requests hit one surface instead of drawer + panel together. Either command un-maximizes the right panel when focus must land in the chat column.

Docs and settings tests cover labels and the new commands in the keybindings UI.

Reviewed by Cursor Bugbot for commit 488b424. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add terminal.focus and chat.focusComposer keybindings mapped to Ctrl+`

  • Pressing Ctrl+` outside the terminal focuses the terminal: targeting the panel terminal if active, or opening/focusing the drawer otherwise.
  • Pressing Ctrl+` while inside the terminal focuses the message composer and collapses a maximized right panel if needed.
  • Adds resolveTerminalFocusTarget in ChatView.logic.ts to determine which terminal surface (panel, drawer, or open-drawer) to target.
  • Introduces a dedicated panelTerminalFocusRequestId state separate from terminalFocusRequestId so panel terminal actions no longer interfere with drawer focus requests.
  • Behavioral Change: panel terminal actions (addTerminalSurface, splitPanelTerminal, etc.) now increment panelTerminalFocusRequestId instead of terminalFocusRequestId.

Macroscope summarized 488b424.

@coderabbitai

coderabbitaiBot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 788c1747-a060-4715-b0b6-9df2041b6711

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 10, 2026
Comment threadapps/web/src/components/ChatView.tsx
Comment threadapps/web/src/components/ChatView.tsx
@macroscopeapp

macroscopeappBot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds new user-facing keybindings (terminal.focus and chat.focusComposer) that modify focus management behavior. While well-structured and tested, new capabilities from a first-time contributor warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@cursorcursorBot left a comment

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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e3adb5b. Configure here.

Comment threadapps/web/src/components/ChatView.tsx
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@achtan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(web): add terminal.focus and chat.focusComposer keybindings - #5961

Open
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions
Open

feat(web): add terminal.focus and chat.focusComposer keybindings#5961
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions

Conversation

@achtan

@achtanachtan commented Aug 10, 2026

Copy link
Copy Markdown

Part of #4641 (items 4 and 5).

Problem

Focus is coupled to panel visibility. Opening the terminal drawer requests terminal focus and closing it returns focus to the composer, but there is no keyboard route between the two while the drawer stays open: type-to-focus bails when focus sits in any input or textarea, and the terminal renders a textarea, so typing in the terminal can never bring you back. The workaround today is toggling the drawer twice with mod+j.

What changed

  • packages/contractsterminal.focus and chat.focusComposer join STATIC_KEYBINDING_COMMANDS. Older clients drop unknown commands through the existing ForwardCompatibleArray decoding, so no compatibility work was needed.

  • packages/shared — both ship as one default key with mutually exclusive when clauses, so a single key hops focus in either direction without touching drawer visibility:

    { "key": "ctrl+`", "command": "terminal.focus", "when": "!terminalFocus" },
    { "key": "ctrl+`", "command": "chat.focusComposer", "when": "terminalFocus" }

    ctrl+` follows VS Code's focus-terminal binding and is unclaimed by the existing defaults on every platform. Each command is still independently rebindable; the startup default sync backfills both rules into existing configs.

  • apps/web (ChatView) — dispatch in the existing global shortcut handler.

    • terminal.focus picks one target via a pure resolveTerminalFocusTarget decision (unit-tested): the right-panel terminal when it is the only terminal showing (drawer closed, or right panel maximized), otherwise the drawer — opening it when closed, where the closed→open transition already requests focus and creates the first session. The right-panel terminal now consumes its own panelTerminalFocusRequestId — bumped by the panel's own lifecycle actions (add, split, activate, close, surface activation) and by terminal.focus when the panel is the target — so a focus request lands on exactly one surface instead of broadcasting to both terminal hosts.
    • chat.focusComposer calls the existing focusComposer() and leaves the terminal open.
    • Both commands first un-maximize the right panel when their target lives in the chat column, which a maximized panel collapses to zero width — without this, focus would land on an invisible element.
  • Settings → Keybindings — no changes needed: labels derive from the command IDs ("Terminal: Focus", "Chat: Focus Composer") and both commands appear in the add-binding dropdown because they ship as defaults.

  • docs/user/keybindings.md — short note on the pair and how it differs from terminal.toggle.

Verification

  • vp test run on the touched suites: web keybindings 46 passed (4 new: the ctrl+` pair resolves per terminalFocus context on macOS and Windows, against the real shipped defaults so the rules are proven to parse), ChatView logic 43 passed (5 new covering every resolveTerminalFocusTarget branch), keybindings settings logic 9 passed (label + dropdown coverage), server keybindings 22 passed (default backfill is generic over DEFAULT_KEYBINDINGS).

  • tsgo --noEmit clean for contracts, shared, and web; vp lint clean on touched files.

  • Demo video (25s):ctrl-backtick-focus-demo.webm — recorded in a real browser against a dev build of this branch. It shows: typing in the composer → ctrl+` opens the drawer and focuses the terminal (an echo typed immediately after the keypress lands at the shell prompt) → ctrl+` hops back to the composer with the drawer still open → a third press hops into the already-open terminal (pwd) → a final press returns to the composer. No mouse after the first click.

    Final state:

    final state: composer text typed across two hops, terminal transcript with echo and pwd

Built with Claude Fable 5 (claude-fable-5) via Claude Code.


Note

Low Risk
UI focus and keybinding routing only; no auth, data, or API changes. Logic is isolated and covered by new unit tests.

Overview
Adds terminal.focus and chat.focusComposer so users can hop between the message composer and terminal without toggling the drawer (addresses the gap where typing cannot return focus from the terminal textarea).

Defaults: Both bind to ctrl+` with opposite when: terminalFocus clauses in shared keybindings; contracts register the new static commands.

Behavior:ChatView handles the commands in the global shortcut handler. resolveTerminalFocusTarget (pure, unit-tested) chooses the right-panel terminal vs drawer vs open-drawer, including when the right panel is maximized. Right-panel terminal actions bump a separate panelTerminalFocusRequestId so focus requests hit one surface instead of drawer + panel together. Either command un-maximizes the right panel when focus must land in the chat column.

Docs and settings tests cover labels and the new commands in the keybindings UI.

Reviewed by Cursor Bugbot for commit 488b424. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add terminal.focus and chat.focusComposer keybindings mapped to Ctrl+`

  • Pressing Ctrl+` outside the terminal focuses the terminal: targeting the panel terminal if active, or opening/focusing the drawer otherwise.
  • Pressing Ctrl+` while inside the terminal focuses the message composer and collapses a maximized right panel if needed.
  • Adds resolveTerminalFocusTarget in ChatView.logic.ts to determine which terminal surface (panel, drawer, or open-drawer) to target.
  • Introduces a dedicated panelTerminalFocusRequestId state separate from terminalFocusRequestId so panel terminal actions no longer interfere with drawer focus requests.
  • Behavioral Change: panel terminal actions (addTerminalSurface, splitPanelTerminal, etc.) now increment panelTerminalFocusRequestId instead of terminalFocusRequestId.

Macroscope summarized 488b424.

@coderabbitai

coderabbitaiBot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 788c1747-a060-4715-b0b6-9df2041b6711

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 10, 2026
Comment threadapps/web/src/components/ChatView.tsx
Comment threadapps/web/src/components/ChatView.tsx
@macroscopeapp

macroscopeappBot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds new user-facing keybindings (terminal.focus and chat.focusComposer) that modify focus management behavior. While well-structured and tested, new capabilities from a first-time contributor warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@cursorcursorBot left a comment

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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e3adb5b. Configure here.

Comment threadapps/web/src/components/ChatView.tsx
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@achtan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(web): add terminal.focus and chat.focusComposer keybindings - #5961

Open
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions
Open

feat(web): add terminal.focus and chat.focusComposer keybindings#5961
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions

Conversation

@achtan

@achtanachtan commented Aug 10, 2026

Copy link
Copy Markdown

Part of #4641 (items 4 and 5).

Problem

Focus is coupled to panel visibility. Opening the terminal drawer requests terminal focus and closing it returns focus to the composer, but there is no keyboard route between the two while the drawer stays open: type-to-focus bails when focus sits in any input or textarea, and the terminal renders a textarea, so typing in the terminal can never bring you back. The workaround today is toggling the drawer twice with mod+j.

What changed

  • packages/contractsterminal.focus and chat.focusComposer join STATIC_KEYBINDING_COMMANDS. Older clients drop unknown commands through the existing ForwardCompatibleArray decoding, so no compatibility work was needed.

  • packages/shared — both ship as one default key with mutually exclusive when clauses, so a single key hops focus in either direction without touching drawer visibility:

    { "key": "ctrl+`", "command": "terminal.focus", "when": "!terminalFocus" },
    { "key": "ctrl+`", "command": "chat.focusComposer", "when": "terminalFocus" }

    ctrl+` follows VS Code's focus-terminal binding and is unclaimed by the existing defaults on every platform. Each command is still independently rebindable; the startup default sync backfills both rules into existing configs.

  • apps/web (ChatView) — dispatch in the existing global shortcut handler.

    • terminal.focus picks one target via a pure resolveTerminalFocusTarget decision (unit-tested): the right-panel terminal when it is the only terminal showing (drawer closed, or right panel maximized), otherwise the drawer — opening it when closed, where the closed→open transition already requests focus and creates the first session. The right-panel terminal now consumes its own panelTerminalFocusRequestId — bumped by the panel's own lifecycle actions (add, split, activate, close, surface activation) and by terminal.focus when the panel is the target — so a focus request lands on exactly one surface instead of broadcasting to both terminal hosts.
    • chat.focusComposer calls the existing focusComposer() and leaves the terminal open.
    • Both commands first un-maximize the right panel when their target lives in the chat column, which a maximized panel collapses to zero width — without this, focus would land on an invisible element.
  • Settings → Keybindings — no changes needed: labels derive from the command IDs ("Terminal: Focus", "Chat: Focus Composer") and both commands appear in the add-binding dropdown because they ship as defaults.

  • docs/user/keybindings.md — short note on the pair and how it differs from terminal.toggle.

Verification

  • vp test run on the touched suites: web keybindings 46 passed (4 new: the ctrl+` pair resolves per terminalFocus context on macOS and Windows, against the real shipped defaults so the rules are proven to parse), ChatView logic 43 passed (5 new covering every resolveTerminalFocusTarget branch), keybindings settings logic 9 passed (label + dropdown coverage), server keybindings 22 passed (default backfill is generic over DEFAULT_KEYBINDINGS).

  • tsgo --noEmit clean for contracts, shared, and web; vp lint clean on touched files.

  • Demo video (25s):ctrl-backtick-focus-demo.webm — recorded in a real browser against a dev build of this branch. It shows: typing in the composer → ctrl+` opens the drawer and focuses the terminal (an echo typed immediately after the keypress lands at the shell prompt) → ctrl+` hops back to the composer with the drawer still open → a third press hops into the already-open terminal (pwd) → a final press returns to the composer. No mouse after the first click.

    Final state:

    final state: composer text typed across two hops, terminal transcript with echo and pwd

Built with Claude Fable 5 (claude-fable-5) via Claude Code.


Note

Low Risk
UI focus and keybinding routing only; no auth, data, or API changes. Logic is isolated and covered by new unit tests.

Overview
Adds terminal.focus and chat.focusComposer so users can hop between the message composer and terminal without toggling the drawer (addresses the gap where typing cannot return focus from the terminal textarea).

Defaults: Both bind to ctrl+` with opposite when: terminalFocus clauses in shared keybindings; contracts register the new static commands.

Behavior:ChatView handles the commands in the global shortcut handler. resolveTerminalFocusTarget (pure, unit-tested) chooses the right-panel terminal vs drawer vs open-drawer, including when the right panel is maximized. Right-panel terminal actions bump a separate panelTerminalFocusRequestId so focus requests hit one surface instead of drawer + panel together. Either command un-maximizes the right panel when focus must land in the chat column.

Docs and settings tests cover labels and the new commands in the keybindings UI.

Reviewed by Cursor Bugbot for commit 488b424. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add terminal.focus and chat.focusComposer keybindings mapped to Ctrl+`

  • Pressing Ctrl+` outside the terminal focuses the terminal: targeting the panel terminal if active, or opening/focusing the drawer otherwise.
  • Pressing Ctrl+` while inside the terminal focuses the message composer and collapses a maximized right panel if needed.
  • Adds resolveTerminalFocusTarget in ChatView.logic.ts to determine which terminal surface (panel, drawer, or open-drawer) to target.
  • Introduces a dedicated panelTerminalFocusRequestId state separate from terminalFocusRequestId so panel terminal actions no longer interfere with drawer focus requests.
  • Behavioral Change: panel terminal actions (addTerminalSurface, splitPanelTerminal, etc.) now increment panelTerminalFocusRequestId instead of terminalFocusRequestId.

Macroscope summarized 488b424.

@coderabbitai

coderabbitaiBot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 788c1747-a060-4715-b0b6-9df2041b6711

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 10, 2026
Comment threadapps/web/src/components/ChatView.tsx
Comment threadapps/web/src/components/ChatView.tsx
@macroscopeapp

macroscopeappBot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds new user-facing keybindings (terminal.focus and chat.focusComposer) that modify focus management behavior. While well-structured and tested, new capabilities from a first-time contributor warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@cursorcursorBot left a comment

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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e3adb5b. Configure here.

Comment threadapps/web/src/components/ChatView.tsx
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@achtan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(web): add terminal.focus and chat.focusComposer keybindings - #5961

Open
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions
Open

feat(web): add terminal.focus and chat.focusComposer keybindings#5961
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions

Conversation

@achtan

@achtanachtan commented Aug 10, 2026

Copy link
Copy Markdown

Part of #4641 (items 4 and 5).

Problem

Focus is coupled to panel visibility. Opening the terminal drawer requests terminal focus and closing it returns focus to the composer, but there is no keyboard route between the two while the drawer stays open: type-to-focus bails when focus sits in any input or textarea, and the terminal renders a textarea, so typing in the terminal can never bring you back. The workaround today is toggling the drawer twice with mod+j.

What changed

  • packages/contractsterminal.focus and chat.focusComposer join STATIC_KEYBINDING_COMMANDS. Older clients drop unknown commands through the existing ForwardCompatibleArray decoding, so no compatibility work was needed.

  • packages/shared — both ship as one default key with mutually exclusive when clauses, so a single key hops focus in either direction without touching drawer visibility:

    { "key": "ctrl+`", "command": "terminal.focus", "when": "!terminalFocus" },
    { "key": "ctrl+`", "command": "chat.focusComposer", "when": "terminalFocus" }

    ctrl+` follows VS Code's focus-terminal binding and is unclaimed by the existing defaults on every platform. Each command is still independently rebindable; the startup default sync backfills both rules into existing configs.

  • apps/web (ChatView) — dispatch in the existing global shortcut handler.

    • terminal.focus picks one target via a pure resolveTerminalFocusTarget decision (unit-tested): the right-panel terminal when it is the only terminal showing (drawer closed, or right panel maximized), otherwise the drawer — opening it when closed, where the closed→open transition already requests focus and creates the first session. The right-panel terminal now consumes its own panelTerminalFocusRequestId — bumped by the panel's own lifecycle actions (add, split, activate, close, surface activation) and by terminal.focus when the panel is the target — so a focus request lands on exactly one surface instead of broadcasting to both terminal hosts.
    • chat.focusComposer calls the existing focusComposer() and leaves the terminal open.
    • Both commands first un-maximize the right panel when their target lives in the chat column, which a maximized panel collapses to zero width — without this, focus would land on an invisible element.
  • Settings → Keybindings — no changes needed: labels derive from the command IDs ("Terminal: Focus", "Chat: Focus Composer") and both commands appear in the add-binding dropdown because they ship as defaults.

  • docs/user/keybindings.md — short note on the pair and how it differs from terminal.toggle.

Verification

  • vp test run on the touched suites: web keybindings 46 passed (4 new: the ctrl+` pair resolves per terminalFocus context on macOS and Windows, against the real shipped defaults so the rules are proven to parse), ChatView logic 43 passed (5 new covering every resolveTerminalFocusTarget branch), keybindings settings logic 9 passed (label + dropdown coverage), server keybindings 22 passed (default backfill is generic over DEFAULT_KEYBINDINGS).

  • tsgo --noEmit clean for contracts, shared, and web; vp lint clean on touched files.

  • Demo video (25s):ctrl-backtick-focus-demo.webm — recorded in a real browser against a dev build of this branch. It shows: typing in the composer → ctrl+` opens the drawer and focuses the terminal (an echo typed immediately after the keypress lands at the shell prompt) → ctrl+` hops back to the composer with the drawer still open → a third press hops into the already-open terminal (pwd) → a final press returns to the composer. No mouse after the first click.

    Final state:

    final state: composer text typed across two hops, terminal transcript with echo and pwd

Built with Claude Fable 5 (claude-fable-5) via Claude Code.


Note

Low Risk
UI focus and keybinding routing only; no auth, data, or API changes. Logic is isolated and covered by new unit tests.

Overview
Adds terminal.focus and chat.focusComposer so users can hop between the message composer and terminal without toggling the drawer (addresses the gap where typing cannot return focus from the terminal textarea).

Defaults: Both bind to ctrl+` with opposite when: terminalFocus clauses in shared keybindings; contracts register the new static commands.

Behavior:ChatView handles the commands in the global shortcut handler. resolveTerminalFocusTarget (pure, unit-tested) chooses the right-panel terminal vs drawer vs open-drawer, including when the right panel is maximized. Right-panel terminal actions bump a separate panelTerminalFocusRequestId so focus requests hit one surface instead of drawer + panel together. Either command un-maximizes the right panel when focus must land in the chat column.

Docs and settings tests cover labels and the new commands in the keybindings UI.

Reviewed by Cursor Bugbot for commit 488b424. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add terminal.focus and chat.focusComposer keybindings mapped to Ctrl+`

  • Pressing Ctrl+` outside the terminal focuses the terminal: targeting the panel terminal if active, or opening/focusing the drawer otherwise.
  • Pressing Ctrl+` while inside the terminal focuses the message composer and collapses a maximized right panel if needed.
  • Adds resolveTerminalFocusTarget in ChatView.logic.ts to determine which terminal surface (panel, drawer, or open-drawer) to target.
  • Introduces a dedicated panelTerminalFocusRequestId state separate from terminalFocusRequestId so panel terminal actions no longer interfere with drawer focus requests.
  • Behavioral Change: panel terminal actions (addTerminalSurface, splitPanelTerminal, etc.) now increment panelTerminalFocusRequestId instead of terminalFocusRequestId.

Macroscope summarized 488b424.

@coderabbitai

coderabbitaiBot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 788c1747-a060-4715-b0b6-9df2041b6711

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 10, 2026
Comment threadapps/web/src/components/ChatView.tsx
Comment threadapps/web/src/components/ChatView.tsx
@macroscopeapp

macroscopeappBot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds new user-facing keybindings (terminal.focus and chat.focusComposer) that modify focus management behavior. While well-structured and tested, new capabilities from a first-time contributor warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@cursorcursorBot left a comment

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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e3adb5b. Configure here.

Comment threadapps/web/src/components/ChatView.tsx
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@achtan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(web): add terminal.focus and chat.focusComposer keybindings - #5961

Open
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions
Open

feat(web): add terminal.focus and chat.focusComposer keybindings#5961
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions

Conversation

@achtan

@achtanachtan commented Aug 10, 2026

Copy link
Copy Markdown

Part of #4641 (items 4 and 5).

Problem

Focus is coupled to panel visibility. Opening the terminal drawer requests terminal focus and closing it returns focus to the composer, but there is no keyboard route between the two while the drawer stays open: type-to-focus bails when focus sits in any input or textarea, and the terminal renders a textarea, so typing in the terminal can never bring you back. The workaround today is toggling the drawer twice with mod+j.

What changed

  • packages/contractsterminal.focus and chat.focusComposer join STATIC_KEYBINDING_COMMANDS. Older clients drop unknown commands through the existing ForwardCompatibleArray decoding, so no compatibility work was needed.

  • packages/shared — both ship as one default key with mutually exclusive when clauses, so a single key hops focus in either direction without touching drawer visibility:

    { "key": "ctrl+`", "command": "terminal.focus", "when": "!terminalFocus" },
    { "key": "ctrl+`", "command": "chat.focusComposer", "when": "terminalFocus" }

    ctrl+` follows VS Code's focus-terminal binding and is unclaimed by the existing defaults on every platform. Each command is still independently rebindable; the startup default sync backfills both rules into existing configs.

  • apps/web (ChatView) — dispatch in the existing global shortcut handler.

    • terminal.focus picks one target via a pure resolveTerminalFocusTarget decision (unit-tested): the right-panel terminal when it is the only terminal showing (drawer closed, or right panel maximized), otherwise the drawer — opening it when closed, where the closed→open transition already requests focus and creates the first session. The right-panel terminal now consumes its own panelTerminalFocusRequestId — bumped by the panel's own lifecycle actions (add, split, activate, close, surface activation) and by terminal.focus when the panel is the target — so a focus request lands on exactly one surface instead of broadcasting to both terminal hosts.
    • chat.focusComposer calls the existing focusComposer() and leaves the terminal open.
    • Both commands first un-maximize the right panel when their target lives in the chat column, which a maximized panel collapses to zero width — without this, focus would land on an invisible element.
  • Settings → Keybindings — no changes needed: labels derive from the command IDs ("Terminal: Focus", "Chat: Focus Composer") and both commands appear in the add-binding dropdown because they ship as defaults.

  • docs/user/keybindings.md — short note on the pair and how it differs from terminal.toggle.

Verification

  • vp test run on the touched suites: web keybindings 46 passed (4 new: the ctrl+` pair resolves per terminalFocus context on macOS and Windows, against the real shipped defaults so the rules are proven to parse), ChatView logic 43 passed (5 new covering every resolveTerminalFocusTarget branch), keybindings settings logic 9 passed (label + dropdown coverage), server keybindings 22 passed (default backfill is generic over DEFAULT_KEYBINDINGS).

  • tsgo --noEmit clean for contracts, shared, and web; vp lint clean on touched files.

  • Demo video (25s):ctrl-backtick-focus-demo.webm — recorded in a real browser against a dev build of this branch. It shows: typing in the composer → ctrl+` opens the drawer and focuses the terminal (an echo typed immediately after the keypress lands at the shell prompt) → ctrl+` hops back to the composer with the drawer still open → a third press hops into the already-open terminal (pwd) → a final press returns to the composer. No mouse after the first click.

    Final state:

    final state: composer text typed across two hops, terminal transcript with echo and pwd

Built with Claude Fable 5 (claude-fable-5) via Claude Code.


Note

Low Risk
UI focus and keybinding routing only; no auth, data, or API changes. Logic is isolated and covered by new unit tests.

Overview
Adds terminal.focus and chat.focusComposer so users can hop between the message composer and terminal without toggling the drawer (addresses the gap where typing cannot return focus from the terminal textarea).

Defaults: Both bind to ctrl+` with opposite when: terminalFocus clauses in shared keybindings; contracts register the new static commands.

Behavior:ChatView handles the commands in the global shortcut handler. resolveTerminalFocusTarget (pure, unit-tested) chooses the right-panel terminal vs drawer vs open-drawer, including when the right panel is maximized. Right-panel terminal actions bump a separate panelTerminalFocusRequestId so focus requests hit one surface instead of drawer + panel together. Either command un-maximizes the right panel when focus must land in the chat column.

Docs and settings tests cover labels and the new commands in the keybindings UI.

Reviewed by Cursor Bugbot for commit 488b424. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add terminal.focus and chat.focusComposer keybindings mapped to Ctrl+`

  • Pressing Ctrl+` outside the terminal focuses the terminal: targeting the panel terminal if active, or opening/focusing the drawer otherwise.
  • Pressing Ctrl+` while inside the terminal focuses the message composer and collapses a maximized right panel if needed.
  • Adds resolveTerminalFocusTarget in ChatView.logic.ts to determine which terminal surface (panel, drawer, or open-drawer) to target.
  • Introduces a dedicated panelTerminalFocusRequestId state separate from terminalFocusRequestId so panel terminal actions no longer interfere with drawer focus requests.
  • Behavioral Change: panel terminal actions (addTerminalSurface, splitPanelTerminal, etc.) now increment panelTerminalFocusRequestId instead of terminalFocusRequestId.

Macroscope summarized 488b424.

@coderabbitai

coderabbitaiBot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 788c1747-a060-4715-b0b6-9df2041b6711

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 10, 2026
Comment threadapps/web/src/components/ChatView.tsx
Comment threadapps/web/src/components/ChatView.tsx
@macroscopeapp

macroscopeappBot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds new user-facing keybindings (terminal.focus and chat.focusComposer) that modify focus management behavior. While well-structured and tested, new capabilities from a first-time contributor warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@cursorcursorBot left a comment

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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e3adb5b. Configure here.

Comment threadapps/web/src/components/ChatView.tsx
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@achtan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(web): add terminal.focus and chat.focusComposer keybindings - #5961

Open
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions
Open

feat(web): add terminal.focus and chat.focusComposer keybindings#5961
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions

Conversation

@achtan

@achtanachtan commented Aug 10, 2026

Copy link
Copy Markdown

Part of #4641 (items 4 and 5).

Problem

Focus is coupled to panel visibility. Opening the terminal drawer requests terminal focus and closing it returns focus to the composer, but there is no keyboard route between the two while the drawer stays open: type-to-focus bails when focus sits in any input or textarea, and the terminal renders a textarea, so typing in the terminal can never bring you back. The workaround today is toggling the drawer twice with mod+j.

What changed

  • packages/contractsterminal.focus and chat.focusComposer join STATIC_KEYBINDING_COMMANDS. Older clients drop unknown commands through the existing ForwardCompatibleArray decoding, so no compatibility work was needed.

  • packages/shared — both ship as one default key with mutually exclusive when clauses, so a single key hops focus in either direction without touching drawer visibility:

    { "key": "ctrl+`", "command": "terminal.focus", "when": "!terminalFocus" },
    { "key": "ctrl+`", "command": "chat.focusComposer", "when": "terminalFocus" }

    ctrl+` follows VS Code's focus-terminal binding and is unclaimed by the existing defaults on every platform. Each command is still independently rebindable; the startup default sync backfills both rules into existing configs.

  • apps/web (ChatView) — dispatch in the existing global shortcut handler.

    • terminal.focus picks one target via a pure resolveTerminalFocusTarget decision (unit-tested): the right-panel terminal when it is the only terminal showing (drawer closed, or right panel maximized), otherwise the drawer — opening it when closed, where the closed→open transition already requests focus and creates the first session. The right-panel terminal now consumes its own panelTerminalFocusRequestId — bumped by the panel's own lifecycle actions (add, split, activate, close, surface activation) and by terminal.focus when the panel is the target — so a focus request lands on exactly one surface instead of broadcasting to both terminal hosts.
    • chat.focusComposer calls the existing focusComposer() and leaves the terminal open.
    • Both commands first un-maximize the right panel when their target lives in the chat column, which a maximized panel collapses to zero width — without this, focus would land on an invisible element.
  • Settings → Keybindings — no changes needed: labels derive from the command IDs ("Terminal: Focus", "Chat: Focus Composer") and both commands appear in the add-binding dropdown because they ship as defaults.

  • docs/user/keybindings.md — short note on the pair and how it differs from terminal.toggle.

Verification

  • vp test run on the touched suites: web keybindings 46 passed (4 new: the ctrl+` pair resolves per terminalFocus context on macOS and Windows, against the real shipped defaults so the rules are proven to parse), ChatView logic 43 passed (5 new covering every resolveTerminalFocusTarget branch), keybindings settings logic 9 passed (label + dropdown coverage), server keybindings 22 passed (default backfill is generic over DEFAULT_KEYBINDINGS).

  • tsgo --noEmit clean for contracts, shared, and web; vp lint clean on touched files.

  • Demo video (25s):ctrl-backtick-focus-demo.webm — recorded in a real browser against a dev build of this branch. It shows: typing in the composer → ctrl+` opens the drawer and focuses the terminal (an echo typed immediately after the keypress lands at the shell prompt) → ctrl+` hops back to the composer with the drawer still open → a third press hops into the already-open terminal (pwd) → a final press returns to the composer. No mouse after the first click.

    Final state:

    final state: composer text typed across two hops, terminal transcript with echo and pwd

Built with Claude Fable 5 (claude-fable-5) via Claude Code.


Note

Low Risk
UI focus and keybinding routing only; no auth, data, or API changes. Logic is isolated and covered by new unit tests.

Overview
Adds terminal.focus and chat.focusComposer so users can hop between the message composer and terminal without toggling the drawer (addresses the gap where typing cannot return focus from the terminal textarea).

Defaults: Both bind to ctrl+` with opposite when: terminalFocus clauses in shared keybindings; contracts register the new static commands.

Behavior:ChatView handles the commands in the global shortcut handler. resolveTerminalFocusTarget (pure, unit-tested) chooses the right-panel terminal vs drawer vs open-drawer, including when the right panel is maximized. Right-panel terminal actions bump a separate panelTerminalFocusRequestId so focus requests hit one surface instead of drawer + panel together. Either command un-maximizes the right panel when focus must land in the chat column.

Docs and settings tests cover labels and the new commands in the keybindings UI.

Reviewed by Cursor Bugbot for commit 488b424. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add terminal.focus and chat.focusComposer keybindings mapped to Ctrl+`

  • Pressing Ctrl+` outside the terminal focuses the terminal: targeting the panel terminal if active, or opening/focusing the drawer otherwise.
  • Pressing Ctrl+` while inside the terminal focuses the message composer and collapses a maximized right panel if needed.
  • Adds resolveTerminalFocusTarget in ChatView.logic.ts to determine which terminal surface (panel, drawer, or open-drawer) to target.
  • Introduces a dedicated panelTerminalFocusRequestId state separate from terminalFocusRequestId so panel terminal actions no longer interfere with drawer focus requests.
  • Behavioral Change: panel terminal actions (addTerminalSurface, splitPanelTerminal, etc.) now increment panelTerminalFocusRequestId instead of terminalFocusRequestId.

Macroscope summarized 488b424.

@coderabbitai

coderabbitaiBot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 788c1747-a060-4715-b0b6-9df2041b6711

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 10, 2026
Comment threadapps/web/src/components/ChatView.tsx
Comment threadapps/web/src/components/ChatView.tsx
@macroscopeapp

macroscopeappBot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds new user-facing keybindings (terminal.focus and chat.focusComposer) that modify focus management behavior. While well-structured and tested, new capabilities from a first-time contributor warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@cursorcursorBot left a comment

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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e3adb5b. Configure here.

Comment threadapps/web/src/components/ChatView.tsx
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@achtan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(web): add terminal.focus and chat.focusComposer keybindings - #5961

Open
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions
Open

feat(web): add terminal.focus and chat.focusComposer keybindings#5961
achtan wants to merge 3 commits into
pingdotgg:mainfrom
achtan:t3code/terminal-focus-and-chat-composer-focus-actions

Conversation

@achtan

@achtanachtan commented Aug 10, 2026

Copy link
Copy Markdown

Part of #4641 (items 4 and 5).

Problem

Focus is coupled to panel visibility. Opening the terminal drawer requests terminal focus and closing it returns focus to the composer, but there is no keyboard route between the two while the drawer stays open: type-to-focus bails when focus sits in any input or textarea, and the terminal renders a textarea, so typing in the terminal can never bring you back. The workaround today is toggling the drawer twice with mod+j.

What changed

  • packages/contractsterminal.focus and chat.focusComposer join STATIC_KEYBINDING_COMMANDS. Older clients drop unknown commands through the existing ForwardCompatibleArray decoding, so no compatibility work was needed.

  • packages/shared — both ship as one default key with mutually exclusive when clauses, so a single key hops focus in either direction without touching drawer visibility:

    { "key": "ctrl+`", "command": "terminal.focus", "when": "!terminalFocus" },
    { "key": "ctrl+`", "command": "chat.focusComposer", "when": "terminalFocus" }

    ctrl+` follows VS Code's focus-terminal binding and is unclaimed by the existing defaults on every platform. Each command is still independently rebindable; the startup default sync backfills both rules into existing configs.

  • apps/web (ChatView) — dispatch in the existing global shortcut handler.

    • terminal.focus picks one target via a pure resolveTerminalFocusTarget decision (unit-tested): the right-panel terminal when it is the only terminal showing (drawer closed, or right panel maximized), otherwise the drawer — opening it when closed, where the closed→open transition already requests focus and creates the first session. The right-panel terminal now consumes its own panelTerminalFocusRequestId — bumped by the panel's own lifecycle actions (add, split, activate, close, surface activation) and by terminal.focus when the panel is the target — so a focus request lands on exactly one surface instead of broadcasting to both terminal hosts.
    • chat.focusComposer calls the existing focusComposer() and leaves the terminal open.
    • Both commands first un-maximize the right panel when their target lives in the chat column, which a maximized panel collapses to zero width — without this, focus would land on an invisible element.
  • Settings → Keybindings — no changes needed: labels derive from the command IDs ("Terminal: Focus", "Chat: Focus Composer") and both commands appear in the add-binding dropdown because they ship as defaults.

  • docs/user/keybindings.md — short note on the pair and how it differs from terminal.toggle.

Verification

  • vp test run on the touched suites: web keybindings 46 passed (4 new: the ctrl+` pair resolves per terminalFocus context on macOS and Windows, against the real shipped defaults so the rules are proven to parse), ChatView logic 43 passed (5 new covering every resolveTerminalFocusTarget branch), keybindings settings logic 9 passed (label + dropdown coverage), server keybindings 22 passed (default backfill is generic over DEFAULT_KEYBINDINGS).

  • tsgo --noEmit clean for contracts, shared, and web; vp lint clean on touched files.

  • Demo video (25s):ctrl-backtick-focus-demo.webm — recorded in a real browser against a dev build of this branch. It shows: typing in the composer → ctrl+` opens the drawer and focuses the terminal (an echo typed immediately after the keypress lands at the shell prompt) → ctrl+` hops back to the composer with the drawer still open → a third press hops into the already-open terminal (pwd) → a final press returns to the composer. No mouse after the first click.

    Final state:

    final state: composer text typed across two hops, terminal transcript with echo and pwd

Built with Claude Fable 5 (claude-fable-5) via Claude Code.


Note

Low Risk
UI focus and keybinding routing only; no auth, data, or API changes. Logic is isolated and covered by new unit tests.

Overview
Adds terminal.focus and chat.focusComposer so users can hop between the message composer and terminal without toggling the drawer (addresses the gap where typing cannot return focus from the terminal textarea).

Defaults: Both bind to ctrl+` with opposite when: terminalFocus clauses in shared keybindings; contracts register the new static commands.

Behavior:ChatView handles the commands in the global shortcut handler. resolveTerminalFocusTarget (pure, unit-tested) chooses the right-panel terminal vs drawer vs open-drawer, including when the right panel is maximized. Right-panel terminal actions bump a separate panelTerminalFocusRequestId so focus requests hit one surface instead of drawer + panel together. Either command un-maximizes the right panel when focus must land in the chat column.

Docs and settings tests cover labels and the new commands in the keybindings UI.

Reviewed by Cursor Bugbot for commit 488b424. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add terminal.focus and chat.focusComposer keybindings mapped to Ctrl+`

  • Pressing Ctrl+` outside the terminal focuses the terminal: targeting the panel terminal if active, or opening/focusing the drawer otherwise.
  • Pressing Ctrl+` while inside the terminal focuses the message composer and collapses a maximized right panel if needed.
  • Adds resolveTerminalFocusTarget in ChatView.logic.ts to determine which terminal surface (panel, drawer, or open-drawer) to target.
  • Introduces a dedicated panelTerminalFocusRequestId state separate from terminalFocusRequestId so panel terminal actions no longer interfere with drawer focus requests.
  • Behavioral Change: panel terminal actions (addTerminalSurface, splitPanelTerminal, etc.) now increment panelTerminalFocusRequestId instead of terminalFocusRequestId.

Macroscope summarized 488b424.

@coderabbitai

coderabbitaiBot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 788c1747-a060-4715-b0b6-9df2041b6711

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 10, 2026
Comment threadapps/web/src/components/ChatView.tsx
Comment threadapps/web/src/components/ChatView.tsx
@macroscopeapp

macroscopeappBot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds new user-facing keybindings (terminal.focus and chat.focusComposer) that modify focus management behavior. While well-structured and tested, new capabilities from a first-time contributor warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@cursorcursorBot left a comment

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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e3adb5b. Configure here.

Comment threadapps/web/src/components/ChatView.tsx
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@achtan