* Add keyboard shortcut for workspace deletion
Default Mod+Shift+Backspace (⌘⇧⌫ on Mac) lets users delete the hovered
worktree or folder workspace immediately. The shortcut targets the
sidebar hover state rather than requiring focus, and avoids terminal
pane D-based split shortcuts on all platforms.
Co-authored-by: Brennan Benson <brennankbenson@gmail.com>
* Omit delete shortcut from disabled Delete Worktree for primary checkout
- Remove shortcut badge from the disabled "Delete Worktree" action when it cannot be executed
- Only show shortcut in multi-context delete actions where the command is available
- Extract host identity parsing into reusable helper function to prevent inline string manipulation
- Fix folder workspace deletion to use correct host-qualified identity comparison
* Document host extraction safety for destructive worktree ops
Unqualified identities must stay undefined rather than defaulting to
'local'. Destructive operations depend on correct host identification.
Added tests and JSDoc to clarify this safety-critical behavior.
* fix test
---------
Co-authored-by: Brennan Benson <brennankbenson@gmail.com>
Adds a configurable, unbound-by-default `dashboard.toggle` action that toggles the Agent Dashboard (in-window drawer or pop-out, per the existing mode setting).
- Wired through window-shortcut-policy, main-window dispatch, browser-guest dispatch, preload, and the renderer IPC handler.
- Opening the in-window drawer reveals the sidebar first; closing leaves it alone.
- Gated on the `experimentalAgentDashboardPopout` experiment, and the Settings shortcut row is hidden while that experiment is off.
#14397 split `shared/types.ts` into 46 per-domain modules but kept the path as
a re-export barrel so the import sites did not have to change. This removes
the barrel: every consumer now imports from the module that actually declares
the type, and `src/shared/types.ts` is deleted.
Barrels hide where a type lives, make every consumer look like it depends on
the whole domain, and let an unrelated edit invalidate a module that ~2,000
files transitively import.
2,323 import declarations across 2,321 files. Rewritten mechanically: each
specifier was resolved to an absolute path via the TypeScript AST and
recomputed, rather than string-substituted, so alias forms (`@/../../shared/
types`) and per-specifier `type` modifiers survive.
Four cases the mechanical pass had to handle, each found by a gate rather than
by reading the diff:
- Modules inside `src/shared` import the barrel as `./types`, not
`shared/types`. A pre-filter on the latter string skipped 176 of them and
left imports dangling at a deleted file, which surfaced as confusing
`Property 'x' is optional in type 'Repo' but required in Pick<Repo, ...>`
errors rather than "module not found".
- The barrel RENAMED one type on the way through
(`WorkspaceSource as WorkspaceCreateTelemetrySource`), so the original name
in the owning module has to be re-aliased at each consumer.
- Three test files put `;(globalThis as ...)` on the line after the import.
TypeScript parses that `;` as the import statement's terminator, so
replacing through `statement.getEnd()` deletes it and breaks ASI. The
rewrite now stops at the module specifier.
- A file that already imported directly from a module got a SECOND import
from it, because the barrel re-exported those same names — which trips
`import/no-duplicates` under `--deny-warnings`. A post-pass merges
declarations sharing a specifier and type-only-ness; the `import type` plus
`import` pair from one module is left alone, since that form is allowed.
Splitting one barrel import into several genuinely adds lines, which pushed
`terminal-layout-pty-ownership.ts` to 301 counted lines: its 107-character
import must wrap, and neither local type collapses onto one line (101 and 116
characters). Rather than contort a type declaration to fit a line budget,
`collectLeafIds` and `pruneLeaves` move to `terminal-pane-layout-tree.ts` —
they are pure structural operations on the layout tree and independent of PTY
ownership. `visible-worktrees.ts` similarly loses its own mini-barrel
re-export of `isDefaultBranchWorkspace`, with the four real consumers
repointed at the declaring module. No `max-lines` bypass added.
Verified: cold `tsc --noEmit` green on node, cli, and web (buildinfo deleted
first — these projects are `composite: true` and reuse stale caches); the full
`pnpm lint` green, not just bare oxlint — the narrower local check is what let
the duplicate imports reach CI; max-lines ratchet OK at 344.
* feat(workspaces): make workspace board shortcut a toggle
The workspace.openBoard command only opened the board; pressing the
bound shortcut again was a no-op, so closing required Escape, the
toolbar button, or collapsing the sidebar. Bind the shortcut bridge
event to the existing toggleWorkspaceBoard so one shortcut both opens
and closes.
Rename the bridge event to TOGGLE_WORKSPACE_BOARD_EVENT and retitle the
command "Toggle Workspace Board". The action id stays workspace.openBoard
to preserve users' stored keybinding overrides.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(keybindings): assert new toggle/open/close search keywords
Cover the search-keyword additions from the toggle rename, per CodeRabbit review on #14240.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* style(keybindings): wrap workspace board search keywords for oxfmt
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* feat(plugins): Orca plugin system — kernel, content packs, panels, workers, marketplace v0 (experimental)
Adds Orca's experimental plugin system behind a settings flag: a
supervised kernel, declarative content packs (VM recipes, commands and
keybindings, language packs), sandboxed iframe panels, forked worker
hosts, and a Git-backed marketplace v0 with consent, provenance and
kill-list enforcement.
Theme, icon-theme and terminal-theme contributions are deferred to a
follow-up pass.
* fix(plugins): make unsupported marketplace listings unreachable by key
findPlugin() backs preview/install/previewInstalledUpdate via
requireListing(), so filtering only listPlugins() hid the catalog card
while leaving the dead install path reachable one click later.
* fix(plugins): fan Pi session-only status out to plugin subscribers
The providerSessionOnly early-return in applyNormalizedStatus emitted to
onAgentStatus (main-window fanout) but skipped enrichedStatusListeners, so
plugins subscribed to agent.status.changed silently missed every Pi
session_start event. Route both emit sites through one helper so a future
early return cannot drop the plugin tap again.
Co-authored-by: Orca <help@stably.ai>
* plugins: drop dead code and hoist duplicated trust-boundary patterns
Cleanup pass over the P1 diff, no behavior change:
- Delete `readPluginTreeSnapshot`/`readSnapshotFile` and their types, plus
the now-vestigial `directories`/`signal` plumbing in `collectFiles`.
- Delete `resolveContainedPluginDirectory` (no callers).
- Delete `plugin-content-load-pool.ts`; it reimplemented the existing
`mapWithConcurrency`, whose index arg also removes the pairing wrapper
in `buildPluginList`.
- Hoist `PLUGIN_CONTENT_HASH_PATTERN` and `PLUGIN_COMMIT_PATTERN` into
the install-lockfile module; 11 sites hand-rolled these identically.
- Point the new reliability gate at the PR instead of gitignored docs
paths, matching every other gate's link form.
* fix(plugins): retry plugin state renames on Windows AV/EPERM locks
Six plugin write paths (lockfile, provenance, current pointer, kill
list, marketplace cache, staged install dir) did a plain rename, so an
antivirus or indexer holding the target open surfaced as a failed
install. The repo already retries this hazard for issue #1507, but only
through a sync helper; these paths are all async.
Adds one bounded async retry + atomic write used by all six, and trims a
consent-provenance header that restated its own JSX.
* test(plugins): cover the Windows rename retry path
The retry loop shipped untested: both existing cases hit the non-retry path,
and the temp-cleanup test passed identically with the `finally` removed.
Mock `rename` to queue errno codes so CI can exercise locks it cannot provoke.
Co-authored-by: Orca <help@stably.ai>
* fix(plugins): pin bundled plugin resources to LF
Windows CI checks out with autocrlf, so the byte-hashed launch tree arrived
as CRLF and verify-packaged-plugin-resources rejected it — the packaged build
could never pass on Windows. Reproduced locally: CRLF yields the exact CI
error, LF verifies clean. Files are already LF, so nothing renormalizes.
Co-authored-by: Orca <help@stably.ai>
* test: guard the bundled-plugin LF pin against a CRLF checkout
The byte-hash mismatch only surfaced in Windows packaging CI. Assert the
.gitattributes pin and that a CRLF tree is rejected, so a regression fails
on any platform instead of waiting for a packaged Windows build.
Co-authored-by: Orca <help@stably.ai>
* ci: trigger packaged-build check on bundled plugin resource changes
The launch tree is byte-hashed during packaging, but no trigger path covered
it — so the CRLF fix for that check would not have re-run the check. Add the
resources, verifier and .gitattributes paths that can break packaging.
Co-authored-by: Orca <help@stably.ai>
* perf(plugins): rebuild the panel frame only when its baked theme values change
The revision keys the panel iframe, so every bump destroys the sandboxed
frame and its in-panel state. It counted root attribute mutations, but
--workspace-sidebar-live-width is written every rAF of a sidebar drag, so
dragging with a panel open blanked it ~60x/sec. Compare the two values the
shell actually bakes in instead.
Co-authored-by: Orca <help@stably.ai>
* test: stop pinning a plugin name in the CRLF guard
The CRLF case rewrites every launch file, so the reported mismatch is
whichever plugin sorts first. P2 adds theme plugins that sort ahead of
orca-navigation-shortcuts, which broke the assertion there.
Co-authored-by: Orca <help@stably.ai>
* style: drop stray blank lines left by the rebase resolutions
Both sides of the agent-hooks and orca-runtime conflicts contributed a
trailing blank, which oxfmt rejects. Whitespace only.
Co-authored-by: Orca <help@stably.ai>
* test(plugins): stop the startup budget failing on machine load
P95 runs 16-34ms idle but exceeds the 50ms bound under full-suite
parallelism, so the gate flaked. Widen it to catch an order-of-magnitude
regression instead; the no-worker/no-plugin-code assertions are the real
guarantee. Verified a 400ms regression still fails.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* feat(editor): toggle Word Wrap from file tab actions and Alt+Z
Long single-line and structured files wrap by default and misalign.
Surface Word Wrap on the editor more-actions menu for normal file tabs
(diff already had it) and add editor.toggleWordWrap (Alt+Z) so users can
unwrap without opening Settings.
Closes#9974
* fix(editor): toggle diffWordWrap for diff surfaces on Alt+Z
CodeRabbit: Alt+Z previously always flipped editorWordWrap, leaving
diff panes out of sync with the markdown actions menu.
* test(editor): verify word wrap shortcut routing
Cover editor/diff setting callbacks and the cross-platform Alt+Z binding.
---------
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Adds a keyboard command that opens the "Send notes to an agent" picker for
the active worktree's AI diff-review notes, enabling a fully keyboard-driven
review flow. Unbound by default; users assign it in Settings → Keyboard
Shortcuts.
- New `sourceControl.sendReviewNotes` command (scope global, unbound). Set
`conflictGroup: 'editor'` so Settings warns on collisions with editor chords
(e.g. Add Review Note), not just global ones.
- Dispatched from App.tsx's existing global capture handler so it respects the
terminal-shortcut policy, the shortcut-recorder guard, and defaultPrevented.
- Store thunk `openDiffNotesSendMenuForActiveWorktree` reveals Source Control
and requests the notes send menu open; no-op when there are no unsent notes.
- Menu opens via a nonce-based store request consumed on mount, TTL-bounded so
a request the menu never consumed can't reopen it on a later remount.
Co-authored-by: Orca <help@stably.ai>
Collapse multi-line explanatory comment blocks into single-line "why" statements
per AGENTS.md ("Document the Why, Briefly"): drop restatements of the code and
mechanism narration; keep the non-obvious reason, external refs, and directives.
Comments-only — verified no code changed via a Babel/esbuild comment-strip
token-equality gate against origin/main; typecheck and oxlint clean.
Area: shared, cli, relay, preload. 26 files changed, 1039 insertions(+), 3300 deletions(-).
Co-authored-by: Orca <help@stably.ai>
* fix(keybindings): use AltGr-safe default for Add Review Note
The editor.addReviewNote default was Mod+Alt+N, which resolves to
Ctrl+Alt+N (AltGr) on Windows/Linux. On diacritic layouts AltGr+N
types a real character (e.g. Polish n-acute), so the editor-scope
chord hijacked normal typing. Switch the default to Mod+Shift+A,
which is AltGr-safe and keeps a mnemonic (A for annotate).
* test(keybindings): cover Add Review Note chord end to end
* feat(keybindings): swap tab-switch chords to the common convention for new users
New installs now get the widespread mapping — Mod+Shift+[ / ] cycles across
all tabs, Mod+Alt+[ / ] cycles within the active tab type. Pre-existing installs
keep today's mapping: a one-time cohort seed (frozen on first launch via the
fileExistedOnLoad signal, mirroring the telemetry migration) pins the legacy
chords into keybindings.json, skipping any action the user already customized.
- shared registry: swap the four tab.*SameType / tab.*AllTypes defaults; export
LEGACY_TAB_SWITCH_BINDINGS for the seed
- persistence: migrateTabSwitchKeybindings freezes the existing-vs-fresh cohort
(tabSwitchKeybindingSeed = pending | done)
- keybinding-file: seedLegacyTabSwitchBindings writes the legacy pins into the
active-platform section so Settings reset still works
- refresh stale default-chord comments
- tests for the swapped defaults, the seed (fresh/existing/customized/idempotent),
and the cohort migration
* test(keybindings): prove existing-user parity + make the seed strictly per-action
seedLegacyTabSwitchBindings now pins each un-customized action individually
instead of skipping all four when any one is customized. A partially-customized
existing user keeps their rebound action AND the pre-swap default on the rest;
no existing user's behavior changes. The skip check keys on this platform's
effective overrides so a foreign-platform-only override can't leave the active
platform on a new default.
Adds keybinding-service.test.ts: constructs a real KeybindingService and asserts
effective bindings + real keystroke matching for both cohorts across darwin/
linux/win32, plus partial-customization, idempotency, and seed-failure retry.
* fix(keybindings): preserve legacy files during tab shortcut seed
* fix(keybindings): preserve valid pre-swap overrides
* feat(editor): bindable shortcut to add a markdown review note
Adds editor.addReviewNote (default Mod+Alt+N) to the shared keybinding
registry and wires it into all three markdown surfaces: the rich editor
key handler invokes the annotation popover opener, the Monaco editor
installs a keydown listener that opens the composer for the tracked
selection target, and the preview maps the DOM selection to its
annotation block. openAnnotationPopover now prefers the live selection
target over synced state so the shortcut works even before the sync
render lands.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYtipbTz8N4woN1sxTK1ia
* fix(editor): cover list items and Monaco path for add-review-note shortcut
Tag the preview's list-item annotation blocks with data-annotation-block-key
so the shortcut resolves selections inside li blocks (review feedback), and
extend the e2e spec to drive the Monaco source-editor wiring.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYtipbTz8N4woN1sxTK1ia
* docs(e2e): explain store-driven view-mode switch in add-review-note spec
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYtipbTz8N4woN1sxTK1ia
* refactor(editor): extract add-review-note + selection-flush modules to satisfy max-lines after rebase
* refactor(editor): spread key-handler params and extract TOC hook to satisfy max-lines
* test(editor): move add-review-note installer test into its own describe
* fix(editor): pass add-review-note chord through when Monaco cannot act; cover preview surface e2e
* fix(editor): unify add-review-note chord consumption — consume only when a composer opens
* fix(editor): gate list-item annotation block key on composer availability
* fix(editor): require live selection for keyboard add-review-note
* chore: retrigger CI against current main (merge ref built during transient main breakage at 6e91ca6c0)
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
sidebar.focusWorktreeList shared Mod+0 with zoom.reset, so main-process
zoom always won. Keep browser-standard Mod+0 for reset and bind focus
worktree list to Mod+Shift+0.
* feat(diff): add F7/Shift+F7 keyboard navigation for diff changes
Stacks on the Previous/Next change buttons (#6668) to add keyboard
navigation for single-file diffs, matching VS Code / JetBrains diff review.
- Register editor.nextChange (F7) / editor.previousChange (Shift+F7) in the
keybinding registry (Editors group) so they show in Settings and stay
rebindable.
- Teach the keybinding normalizer function keys (F1-F24) and make them
first-class in the bare-key safety model (safe standalone or with Shift,
opt-in per action) - F7 was previously unbindable.
- Install a capture-phase listener from DiffNavigationProvider so keyboard
and the existing header buttons share one goToDiff path; works on
read-only and editable single-file diffs.
- Translate the Previous/Next change strings for es/ja/ko/zh.
Refs #6215
* test(diff): cover change navigation shortcuts
* fix(diff): use shortcut chips in navigation tooltips
---------
Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
* Add keyboard shortcut to toggle the Quick Commands menu
- New `tab.openQuickCommandsMenu` keybinding action (no default binding)
- TabBarQuickCommandsMenu listens for the binding and toggles open/closed
- Scoped to the active tab group naturally since the component only mounts when its group is focused
* Show keyboard shortcut in Quick Commands menu trigger tooltip
* Add tests
* expand tests
* Expand keyboard toggle to call handleOpenChange and skip repeated keys
- Replace `setMenuOpen` toggle with `handleOpenChange(!menuOpen)` so closing
via keyboard runs the same reset logic (query, focus frame, value override)
- Guard against key-repeat events to prevent rapid toggling on held key
- Wrap `handleOpenChange` in `useCallback` so it's stable enough to include
in the `useEffect` dependency array without causing spurious re-registrations
- Update tests to reflect that re-running the effect between presses is
required for the close path, and add a repeat-event test
* Add docstring to withShortcutHint func
* review: harden quick commands menu shortcut
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Adds replace, replace all, match case, whole word, and the editor replace shortcut to the rich markdown editor. Includes review hardening for live replace matching and Unicode-safe whole-word boundaries.
Fixes#6274.
Non-Latin layouts (Cyrillic, Greek, ABNT2, …) report a non-Latin logical `event.key` for physical letter keys (physical `KeyC` → `с`) while `event.code` stays `KeyC`. The shortcut matcher only fell back to the physical code when `event.key` was empty/Dead/Unidentified, so Mod+letter/digit chords never matched on those layouts — Ctrl+C copy in Monaco Source mode appeared to do nothing and the chord could not even be rebound in Settings.
Adds a tightly-gated non-Latin physical-code fallback (non-macOS, real Ctrl/Meta modifier held, excludes AltGr/Ctrl+Alt composition, only when no logical Latin token exists). Verified: full keybindings suite (55 tests) + targeted Cyrillic/Greek/AltGr/wrong-key cases pass; web + node typecheck clean.
Adds an unbound sidebar.sleepingWorkspaces.toggle keybinding action, wires it to the global shortcut dispatcher, and shows assigned shortcut labels in the workspace-board filter menu.
Also resolves the PR against current main and removes an unnecessary exhaustive-switch fallback that blocked current lint.
* feat: add floating workspace shortcuts
* test: shim localStorage in happy-dom tests
* refactor: tighten floating shortcut tests and docs
- Drop unrelated localStorage test shim (local Node 25 only; CI runs Node 24)
- Add why-comments for minify/minimize macOS-only and unbound defaults
- Assert minify bounds via getMinifiedFloatingTerminalBounds() not magic numbers
- Cover out-of-range tab index and no-active-tab rename edge cases
* test: cover custom floating shortcut bindings on Linux/Windows
Proves user-assigned overrides for floatingWorkspace.maximize/minify fire
on platforms where the default bindings are intentionally empty.
* feat: show keybinding hints in floating panel control tooltips
Maximize/restore and minimize tooltips now surface their live shortcut as
"Label (shortcut)", matching the repo convention (e.g. ReviewPRViewAnimatedVisual).
Degrades to a bare label when the action is unbound (Win/Linux defaults,
and minimize on every platform).
* feat: rework floating panel resize shortcut to Cmd+Opt+Shift+A
- Move maximize/restore default from Cmd+Opt+Up to Cmd+Opt+Shift+A so it
shares the Cmd+Opt+A toggle anchor and stays one-handed.
- Open-into-maximized: pressing the chord while the panel is closed opens
it straight into the maximized state (one-shot intent bridges the
closed->mounted gap), regardless of last saved size. While open it
remains a maximize<->restore toggle returning to saved dimensions.
- Drop the minify action and its Cmd+Opt+Down default entirely; it was
introduced earlier in this PR and is not in main, so this trims unshipped
surface rather than removing an existing feature.
Maximize tooltip now surfaces the new chord. Adds panel tests for the
open-maximized intent and updates keybinding default tests.
* feat: surface tab shortcut affordances
* refactor: address 5.5 Pro review on tab shortcut affordances
- Add Darwin Option-composed (Cmd+Opt+Shift+A) maximize capture/round-trip regression
- Replace 'Unassigned' string-sentinel checks with useOptionalShortcutLabel (string | null)
- Add TTL guard + unit tests so a stale open-maximized intent cannot leak into a later open
* feat: show default agent shortcut in new tab menu
* fix: address PR review on tab tooltip a11y, i18n, and test guards
* Fix floating workspace shortcut edge cases
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Wolfgang Schoenberger <221313372+wolfiesch@users.noreply.github.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* feat(shortcuts): make Select Tab/Workspace 1-9 remappable (#5741)
Expose Select Tab 1-9 and Select Workspace 1-9 as single remappable rows in
Settings -> Shortcuts. Previously both chords were hardcoded in
window-shortcut-policy.ts and absent from the Shortcuts UI.
Each is modeled as one ranged action whose stored chord is a representative
(digit canonicalized to 1) that fires for any of 1-9, mirroring the cmux
single-row UX. Defaults reproduce existing behavior (mac: tab Ctrl+1-9,
workspace Cmd+1-9; win/linux: tab Alt+1-9, workspace Ctrl+1-9). Swapping the
two modifiers - the headline use case - works without a false conflict.
Co-authored-by: Orca <help@stably.ai>
* refactor(shortcuts): tighten digit-index review nits
- Canonicalize digit-index overrides in getEffectiveKeybindingsForAction so
display/conflict detection stay consistent regardless of stored digit.
- Use a shared DIGIT_INDEX_KEY_PATTERN regex instead of string comparison.
- Document that extra modifiers (e.g. Shift) are allowed on digit-index chords
and that the matcher honors terminal-context gating.
- Clarify the workspace-first precedence comment.
- Add tests: Shift modifier, physical-code fallback matching, both ranges disabled.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* Add keyboard shortcuts to launch agent tabs
Cmd+T opens a plain terminal tab, but launching an agent in a new tab was
mouse-only (tab bar + menu). This adds:
- tab.newAgent ("New agent tab"): launches the default agent in a new tab
in the active workspace. Default chord Cmd+Alt+T on macOS; unassigned on
Windows/Linux (AltGr / desktop-terminal chord conflicts), bindable in
Settings. Resolves the agent via the configured default when detected
and enabled, otherwise the shared auto-pick order; a 'blank' default
falls through to auto-pick since an explicit agent chord wants an agent.
- tab.newAgent.<id>: one bindable action per TUI agent so each enabled
agent can sit on its own chord. All ship unassigned. Settings →
Shortcuts shows them in a new "Agents" group, hiding disabled agents;
a per-agent chord launches its agent even when detection hasn't
confirmed the binary (explicit request fails visibly in the tab).
Launches go through launchAgentInNewTab (same path as the tab-bar quick
launch) with launch_source 'shortcut'. Agent display names move to a
shared module so the keybinding registry can title the generated actions
without importing renderer code. groupDefinitions moves out of
ShortcutsPane.tsx to keep it under the max-lines lint cap.
* Fix recording Option-composed shortcuts on macOS
On macOS, Option changes the produced character (Cmd+Alt+C reports
key 'ç'), so the shortcut recorder rejected Alt combos with 'Press a
key, not only a modifier'. Capture now falls back to the physical key
code when Alt is held, matching the existing matcher behavior.
* fix: ignore disabled agent shortcuts in conflict checks
Co-authored-by: Orca <help@stably.ai>
* fix: align mac option shortcut capture with matching
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Adds configurable macOS shortcuts for renaming the active terminal tab and active workspace, with review follow-up fixes for conflict detection, sidebar reveal, lineage child rename surfaces, and floating workspace focus scoping.
Fix shortcut dispatch so app commands follow the produced logical key for the active keyboard layout, while preserving intentional physical-code fallbacks for terminal byte paths and unavailable logical keys.\n\nCloses #2858
Fix JIS bracket/backslash shortcut intent matching across tab and terminal-pane shortcuts.\n\nReview follow-up:\n- centralize semantic punctuation matching for bracket/backslash keys\n- preserve physical-code fallback when key text is inconclusive\n- avoid stealing AltGr bracket input on Windows/Linux\n- add regression coverage for JIS, AltGr, and fallback behavior