Title: Add a keyboard shortcut (⌘⇧E) to open the composer's thinking menu by DragonnZhang · Pull Request #55 · modelstudioai/openwork · GitHub
Open Graph Title: Add a keyboard shortcut (⌘⇧E) to open the composer's thinking menu by DragonnZhang · Pull Request #55 · modelstudioai/openwork
X Title: Add a keyboard shortcut (⌘⇧E) to open the composer's thinking menu by DragonnZhang · Pull Request #55 · modelstudioai/openwork
Description: Closes #54 What & why OpenWork's composer toolbar has a model picker, a thinking-level (reasoning effort) picker (#45), and a permission-mode selector. Two of those already have keyboard access — permission mode cycles with Shift+Tab — but the thinking-level menu could only be opened with the mouse. Claude Code Desktop documents a dedicated effort-menu shortcut (⌘⇧E) in its composer. When the thinking picker landed here, #44 explicitly flagged the shortcut as a natural follow-up ("A keyboard-only shortcut (à la ⌘⇧E) could open a menu … can be layered on later"). This layers it on. Press ⌘⇧E (macOS) / Ctrl+Shift+E (Windows/Linux) to open the composer's thinking-effort menu from anywhere — matching Claude Code Desktop's effort-menu shortcut exactly. Changes actions/definitions.ts — new chat.openThinkingMenu action (hotkey mod+shift+e, category Chat). actions/action-i18n.ts — maps it to shortcuts.action.openThinkingMenu. components/app-shell/input/composer-menu-events.ts (new) — a small, scoped craft:open-composer-menu event, modeled on focus-input-events.ts. AppShell.tsx — registers the action; it dispatches the scoped event to the focused composer. components/app-shell/input/FreeFormInput.tsx — listens for the event (guarded by shouldHandleScopedInputEvent, the same multi-panel routing used by craft:focus-input) and opens its already-controlled thinkingDropdownOpen dropdown. No-ops in compact mode / when the picker is unavailable. packages/shared/src/i18n/locales/*.json — one new key (shortcuts.action.openThinkingMenu) in all 7 locales, in sorted position. e2e/assertions/thinking-menu-shortcut.assert.ts (new) — CDP assertion (below). Because it registers in the action registry, the shortcut automatically appears in the Command Palette (#42) and the Keyboard Shortcuts reference — no extra wiring. Frontend-only: no backend / qwen-code change. Why ⌘⇧E and not also ⌘⇧I / ⌘⇧M Claude binds all three composer menus, but in OpenWork ⌘⇧I / Ctrl+Shift+I is already Developer Tools, and permission mode already has Shift+Tab. The thinking menu is the one composer picker with no keyboard access and no binding conflict, so this PR scopes to the clean ⌘⇧E gap. Verification (DoD) bun run typecheck:all — zero new errors. The only errors are the 11 pre-existing ones in apps/electron (auto-update.ts owner/repo, a settings-default-thinking test tuple, two test files importing vitest) — none in the files this PR touches. packages/{core,shared,server-core,server,session-tools-core,ui} all pass clean. bun test — the failing set is byte-for-byte identical to main, verified by diffing the sorted unique failure lists from a clean-main run and this branch in the same environment: 56 pre-existing failures on both, zero new failures. The touched-area suites (renderer/actions, app-shell/input) pass 23/23. bun run lint:i18n:parity — OK (6 locales, 1543 keys each). Renderer build (bun run electron:build:renderer, where this change lives) — ✅ builds cleanly. CDP assertion transpiles (bun build e2e/assertions/thinking-menu-shortcut.assert.ts) — ✅. CDP e2e assertion (thinking-menu-shortcut.assert.ts) Drives the real built app over CDP entirely in the draft (no-session) state — no seeded conversation and no backend: The composer renders the thinking-level trigger with its menu closed (zero visible menu items). Dispatch the Cmd/Ctrl+Shift+E keydown at the window level (where the action registry's capture-phase listener lives). The thinking menu opens and lists all six levels. Asserting the menu is closed before the keypress and open after it proves the shortcut actually opens the menu, not merely that the menu can render. ⚠️ Local CDP run was blocked by this sandbox's egress policy, not by the feature. electron:build:main cannot resolve the libsignal GitHub dependency (pulled in transitively by the WhatsApp/Baileys worker), and the Electron binary download 403s from the egress proxy, so the app can't be built or launched here (xvfb is present; only those network fetches fail) — the same limitation noted on the other open loop-bot PRs. The assertion transpiles and is included so CI / a reviewer can run bun run e2e in an environment with normal network access. Everything that doesn't require launching Electron (typecheck, unit tests, i18n parity, renderer build) passes with zero delta vs main. Part of the autonomous desktop-feature loop (loop-bot). 🤖 Generated with Claude Code Generated by Claude Code
Open Graph Description: Closes #54 What & why OpenWork's composer toolbar has a model picker, a thinking-level (reasoning effort) picker (#45), and a permission-mode selector. Two of those already have keyboard ac...
X Description: Closes #54 What & why OpenWork's composer toolbar has a model picker, a thinking-level (reasoning effort) picker (#45), and a permission-mode selector. Two of those already have key...
Opengraph URL: https://github.com/modelstudioai/openwork/pull/55
X: @github
Domain: github.com
| route-pattern | /:user_id/:repository/pull/:id/files(.:format) |
| route-controller | pull_requests |
| route-action | files |
| fetch-nonce | v2:1efdc20c-1c83-1814-3a8b-0dc0a1d4ac6f |
| current-catalog-service-hash | ae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b |
| request-id | D112:166AAB:2E9E2C:3E6148:6A52EB8C |
| html-safe-nonce | 360f266d3e73f48436c3448dfcc8f088fc4806a54fa1fcbf6930d2cacb76376e |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJEMTEyOjE2NkFBQjoyRTlFMkM6M0U2MTQ4OjZBNTJFQjhDIiwidmlzaXRvcl9pZCI6IjY0NjkxMjI3NjE0MTE0NTU4ODUiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 783955418ac8a0240e25f4f2f8bcf81643a283c3d80242082da187f5d086aa19 |
| hovercard-subject-tag | pull_request:3990724285 |
| github-keyboard-shortcuts | repository,pull-request-list,pull-request-conversation,pull-request-files-changed,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/modelstudioai/openwork/pull/55/files |
| twitter:image | https://avatars.githubusercontent.com/u/52599892?s=400&v=4 |
| twitter:card | summary_large_image |
| og:image | https://avatars.githubusercontent.com/u/52599892?s=400&v=4 |
| og:image:alt | Closes #54 What & why OpenWork's composer toolbar has a model picker, a thinking-level (reasoning effort) picker (#45), and a permission-mode selector. Two of those already have keyboard ac... |
| og:site_name | GitHub |
| og:type | object |
| hostname | github.com |
| expected-hostname | github.com |
| None | b9a586c06a05a7a86fc7e3f4dbd03e42f6869085879aa184aa6369456dbd50fb |
| turbo-cache-control | no-preview |
| diff-view | unified |
| go-import | github.com/modelstudioai/openwork git https://github.com/modelstudioai/openwork.git |
| octolytics-dimension-user_id | 283556804 |
| octolytics-dimension-user_login | modelstudioai |
| octolytics-dimension-repository_id | 1256697754 |
| octolytics-dimension-repository_nwo | modelstudioai/openwork |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1256697754 |
| octolytics-dimension-repository_network_root_nwo | modelstudioai/openwork |
| turbo-body-classes | logged-out env-production page-responsive full-width |
| disable-turbo | true |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 07a982c1d40157c619b364352b704c3ce66bb332 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width