Skip to content

feat(tasks): Cmd+Option+Left/Right to cycle task tabs#99

Draft
wise-toddler wants to merge 9 commits into
debuglebowski:mainfrom
wise-toddler:fix/task-tab-shortcuts
Draft

feat(tasks): Cmd+Option+Left/Right to cycle task tabs#99
wise-toddler wants to merge 9 commits into
debuglebowski:mainfrom
wise-toddler:fix/task-tab-shortcuts

Conversation

@wise-toddler

@wise-toddler wise-toddler commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add Cmd+Option+Left / Cmd+Option+Right to cycle through open task tabs in the top tab bar (wrap-around at edges, skips the home tab).
  • Suppress the new cycle shortcuts inside text inputs (INPUT, TEXTAREA, SELECT, contentEditable, role="textbox", CodeMirror, xterm, Milkdown, ProseMirror) so they don't hijack the macOS "move by word" cursor behavior.

Closes

Closes #98

Notes on the diff

This branch also includes two small unrelated fixes that the typecheck on main currently fails without:

  • fix(transport): add missing resolve-task route stub — registers a 501 stub for the missing module imported by rest-api/index.ts.
  • fix(app): add missing ws and @trpc/server deps for host-capability-server — adds runtime deps already used by packages/apps/app/src/main/host-capability-server.ts.

Happy to split these out into a separate PR if preferred.

Test plan

  • pnpm typecheck passes
  • pnpm --filter @slayzone/app test:e2e e2e/core/16-tab-management.spec.ts — 11/11 pass, including 4 new cases for the shortcuts above.
  • Manual: with multiple task tabs open, Cmd+Option+Left and Cmd+Option+Right cycle through them and wrap at the edges.
  • Manual: shortcuts do NOT fire while typing in an input, textarea, contentEditable field, CodeMirror editor, xterm terminal, Milkdown/ProseMirror editor, or native <select>.
  • Manual: with only the home tab open, the cycle shortcuts are a no-op.

Comment on lines 244 to 254
useGuardedHotkeys(
getKeys('last-task-tab'),
(e) => {
e.preventDefault()
if (visibleTabs.length > 1) {
useTabStore.getState().setActiveView('tabs')
setActiveTabIndex(toFullIndex(visibleTabs.length - 1))
}
},
{ enableOnFormTags: true, enabled: !isRecording }
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Last-Tab Shortcut Hijacks Editors

When focus is inside an input, textarea, contentEditable editor, CodeMirror, xterm, Milkdown, ProseMirror, or select, Cmd+9 still runs because this handler is enabled on form tags and has no editing guard. It calls preventDefault() and can switch tabs instead of letting the focused editor handle the key.

Suggested change
useGuardedHotkeys(
getKeys('last-task-tab'),
(e) => {
e.preventDefault()
if (visibleTabs.length > 1) {
useTabStore.getState().setActiveView('tabs')
setActiveTabIndex(toFullIndex(visibleTabs.length - 1))
}
},
{ enableOnFormTags: true, enabled: !isRecording }
)
useGuardedHotkeys(
getKeys('last-task-tab'),
(e) => {
const el = e.target as HTMLElement
if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.tagName === 'SELECT') return
if (el.isContentEditable || el.getAttribute('role') === 'textbox') return
if (el.closest?.('.cm-editor') || el.closest?.('.xterm')) return
if (el.closest?.('.milkdown') || el.closest?.('.ProseMirror')) return
e.preventDefault()
if (visibleTabs.length > 1) {
useTabStore.getState().setActiveView('tabs')
setActiveTabIndex(toFullIndex(visibleTabs.length - 1))
}
},
{ enableOnFormTags: true, enabled: !isRecording }
)

Context Used: CLAUDE.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/apps/app/src/renderer/src/app-shell/useAppShortcuts.ts
Line: 244-254

Comment:
**Last-Tab Shortcut Hijacks Editors**

When focus is inside an input, textarea, contentEditable editor, CodeMirror, xterm, Milkdown, ProseMirror, or select, `Cmd+9` still runs because this handler is enabled on form tags and has no editing guard. It calls `preventDefault()` and can switch tabs instead of letting the focused editor handle the key.

```suggestion
  useGuardedHotkeys(
    getKeys('last-task-tab'),
    (e) => {
      const el = e.target as HTMLElement
      if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.tagName === 'SELECT') return
      if (el.isContentEditable || el.getAttribute('role') === 'textbox') return
      if (el.closest?.('.cm-editor') || el.closest?.('.xterm')) return
      if (el.closest?.('.milkdown') || el.closest?.('.ProseMirror')) return
      e.preventDefault()
      if (visibleTabs.length > 1) {
        useTabStore.getState().setActiveView('tabs')
        setActiveTabIndex(toFullIndex(visibleTabs.length - 1))
      }
    },
    { enableOnFormTags: true, enabled: !isRecording }
  )
```

**Context Used:** CLAUDE.md ([source](https://app.greptile.com/slayzone/github/debuglebowski/slayzone/-/custom-context?memory=4d0a5da1-ee49-442f-ba49-d4a3dc97238d))

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

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +172 to +178
id: 'last-task-tab',
label: 'Last Task Tab',
group: 'Tabs',
defaultKeys: 'mod+9',
scope: 'global',
customizable: true
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Rebinding Leaves Cmd+9 Unbound

last-task-tab is customizable, but the numbered tab handler now only binds Cmd+1 through Cmd+8. If a user rebinds this shortcut, Cmd+9 no longer has any handler even though the existing switch-tab-1-9 shortcut definition still presents mod+1-9 as the numbered tab range.

Context Used: CLAUDE.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/shared/shortcuts/src/definitions.ts
Line: 172-178

Comment:
**Rebinding Leaves Cmd+9 Unbound**

`last-task-tab` is customizable, but the numbered tab handler now only binds `Cmd+1` through `Cmd+8`. If a user rebinds this shortcut, `Cmd+9` no longer has any handler even though the existing `switch-tab-1-9` shortcut definition still presents `mod+1-9` as the numbered tab range.

**Context Used:** CLAUDE.md ([source](https://app.greptile.com/slayzone/github/debuglebowski/slayzone/-/custom-context?memory=4d0a5da1-ee49-442f-ba49-d4a3dc97238d))

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

…wski#98)

Original issue debuglebowski#98 asked for Cmd+1..9 as indexed jumps to the Nth task
tab. The Chrome-style "Cmd+9 = last tab" branch was an over-interpretation
of the spec. Restore Cmd+9 to indexed behavior: jump to the 9th task tab
if it exists, otherwise no-op.

- Delete the `last-task-tab` shortcut definition.
- Drop the dedicated `last-task-tab` handler; extend the indexed handler
  from `mod+1..8` to `mod+1..9`.
- Replace the "Cmd+9 = last" e2e test with an indexed-jump test
  (Cmd+3 with 3 tabs, Cmd+9 is a no-op).
@wise-toddler wise-toddler marked this pull request as draft June 26, 2026 19:13
…wski#98)

Original issue debuglebowski#98 listed numeric jumps as a 'bonus'. User confirmed only Cmd+Option+Left/Right is wanted. Restored main's switch-tab-1-9 behavior verbatim.
@wise-toddler wise-toddler changed the title feat(tasks): Cmd+Option+Left/Right and Cmd+1..9 to switch task tabs feat(tasks): Cmd+Option+Left/Right to cycle task tabs Jun 26, 2026
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.

feat: Cmd+Option+Left/Right to switch between open task tabs (top bar)

1 participant