Skip to content

Commit 75731bc

Browse files
committed
🤖 fix: Cmd+Q now properly quits app on macOS
The menu structure was placing 'close' in the Window menu for all platforms, which may have caused accelerator conflicts with 'quit' on macOS. Following the official Electron documentation pattern: - macOS: 'close' (Cmd+W) now in File menu, 'quit' (Cmd+Q) in App menu - macOS Window menu: minimize, zoom (no close) - Windows/Linux: unchanged (close in Window menu, quit in File menu) This ensures proper accelerator registration and matches standard macOS app behavior. Fixes #1100
1 parent cac3cb0 commit 75731bc

File tree

4 files changed

+55
-11
lines changed

4 files changed

+55
-11
lines changed

src/browser/contexts/ProviderOptionsContext.tsx

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
import React, { createContext, useContext } from "react";
2-
import { usePersistedState } from "@/browser/hooks/usePersistedState";
1+
import React, { createContext, useContext, useLayoutEffect } from "react";
2+
import {
3+
readPersistedState,
4+
updatePersistedState,
5+
usePersistedState,
6+
} from "@/browser/hooks/usePersistedState";
37
import type { MuxProviderOptions } from "@/common/types/providerOptions";
48

59
interface ProviderOptionsContextType {
@@ -11,6 +15,10 @@ interface ProviderOptionsContextType {
1115

1216
const ProviderOptionsContext = createContext<ProviderOptionsContextType | undefined>(undefined);
1317

18+
const OPENAI_OPTIONS_KEY = "provider_options_openai";
19+
// One-time migration key: force disableAutoTruncation to true for existing users
20+
const OPENAI_TRUNCATION_MIGRATION_KEY = "provider_options_openai_truncation_migrated";
21+
1422
export function ProviderOptionsProvider({ children }: { children: React.ReactNode }) {
1523
const [anthropicOptions, setAnthropicOptions] = usePersistedState<
1624
MuxProviderOptions["anthropic"]
@@ -19,12 +27,20 @@ export function ProviderOptionsProvider({ children }: { children: React.ReactNod
1927
});
2028

2129
const [openaiOptions, setOpenAIOptions] = usePersistedState<MuxProviderOptions["openai"]>(
22-
"provider_options_openai",
23-
{
24-
disableAutoTruncation: false,
25-
}
30+
OPENAI_OPTIONS_KEY,
31+
{ disableAutoTruncation: true }
2632
);
2733

34+
// One-time migration: force disableAutoTruncation to true for existing users
35+
useLayoutEffect(() => {
36+
const alreadyMigrated = readPersistedState<boolean>(OPENAI_TRUNCATION_MIGRATION_KEY, false);
37+
if (alreadyMigrated) {
38+
return;
39+
}
40+
updatePersistedState(OPENAI_OPTIONS_KEY, { disableAutoTruncation: true });
41+
updatePersistedState(OPENAI_TRUNCATION_MIGRATION_KEY, true);
42+
}, []);
43+
2844
const [googleOptions, setGoogleOptions] = usePersistedState<MuxProviderOptions["google"]>(
2945
"provider_options_google",
3046
{}

src/browser/utils/messages/sendOptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function getProviderOptions(): MuxProviderOptions {
2626
{ use1MContext: false }
2727
);
2828
const openai = readPersistedState<MuxProviderOptions["openai"]>("provider_options_openai", {
29-
disableAutoTruncation: false,
29+
disableAutoTruncation: true,
3030
});
3131
const google = readPersistedState<MuxProviderOptions["google"]>("provider_options_google", {});
3232

src/desktop/main.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,13 @@ function timestamp(): string {
143143

144144
function createMenu() {
145145
const template: MenuItemConstructorOptions[] = [
146+
{
147+
label: "File",
148+
submenu:
149+
process.platform === "darwin"
150+
? [{ role: "close" }] // macOS: Cmd+W to close window
151+
: [{ role: "quit" }], // Windows/Linux: Quit in File menu
152+
},
146153
{
147154
label: "Edit",
148155
submenu: [
@@ -182,7 +189,14 @@ function createMenu() {
182189
},
183190
{
184191
label: "Window",
185-
submenu: [{ role: "minimize" }, { role: "close" }],
192+
submenu:
193+
process.platform === "darwin"
194+
? [
195+
// macOS Window menu - close is in File menu to avoid Cmd+Q/Cmd+W conflicts
196+
{ role: "minimize" },
197+
{ role: "zoom" },
198+
]
199+
: [{ role: "minimize" }, { role: "close" }],
186200
},
187201
];
188202

tests/ipc/sendMessage.heavy.test.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,21 @@ describeIntegration("sendMessage heavy/load tests", () => {
4141
await withSharedWorkspace(provider, async ({ env, workspaceId, collector }) => {
4242
// Build up large conversation history to exceed context limit
4343
// This approach is model-agnostic - it keeps sending until we've built up enough history
44+
// Use auto-truncation enabled (disableAutoTruncation: false) so history builds up successfully
4445
const largeMessage = "x".repeat(50_000);
4546
for (let i = 0; i < 10; i++) {
4647
await sendMessageWithModel(
4748
env,
4849
workspaceId,
4950
`Message ${i}: ${largeMessage}`,
50-
modelString(provider, model)
51+
modelString(provider, model),
52+
{
53+
providerOptions: {
54+
openai: {
55+
disableAutoTruncation: false,
56+
},
57+
},
58+
}
5159
);
5260
await collector.waitForEvent("stream-end", 30000);
5361
collector.clear();
@@ -93,8 +101,14 @@ describeIntegration("sendMessage heavy/load tests", () => {
93101
env,
94102
workspaceId,
95103
"This should succeed with auto-truncation",
96-
modelString(provider, model)
97-
// disableAutoTruncation defaults to false (auto-truncation enabled)
104+
modelString(provider, model),
105+
{
106+
providerOptions: {
107+
openai: {
108+
disableAutoTruncation: false,
109+
},
110+
},
111+
}
98112
);
99113

100114
expect(successResult.success).toBe(true);

0 commit comments

Comments
 (0)