diff --git a/apps/twig/src/main/services/notification/service.ts b/apps/twig/src/main/services/notification/service.ts
index bf58068ab..4f2bb6ab0 100644
--- a/apps/twig/src/main/services/notification/service.ts
+++ b/apps/twig/src/main/services/notification/service.ts
@@ -35,6 +35,13 @@ export class NotificationService {
log.info("Dock badge shown");
}
+ bounceDock(): void {
+ if (process.platform === "darwin") {
+ app.dock?.bounce("informational");
+ log.info("Dock bounce triggered");
+ }
+ }
+
private clearDockBadge(): void {
if (!this.hasBadge) return;
diff --git a/apps/twig/src/main/trpc/routers/notification.ts b/apps/twig/src/main/trpc/routers/notification.ts
index abb279525..bc8292570 100644
--- a/apps/twig/src/main/trpc/routers/notification.ts
+++ b/apps/twig/src/main/trpc/routers/notification.ts
@@ -20,4 +20,5 @@ export const notificationRouter = router({
getService().send(input.title, input.body, input.silent),
),
showDockBadge: publicProcedure.mutation(() => getService().showDockBadge()),
+ bounceDock: publicProcedure.mutation(() => getService().bounceDock()),
});
diff --git a/apps/twig/src/renderer/features/settings/components/sections/ChatSettings.tsx b/apps/twig/src/renderer/features/settings/components/sections/ChatSettings.tsx
index 19e072c32..3e3506e11 100644
--- a/apps/twig/src/renderer/features/settings/components/sections/ChatSettings.tsx
+++ b/apps/twig/src/renderer/features/settings/components/sections/ChatSettings.tsx
@@ -14,12 +14,14 @@ export function ChatSettings() {
const {
desktopNotifications,
dockBadgeNotifications,
+ dockBounceNotifications,
completionSound,
completionVolume,
autoConvertLongText,
sendMessagesWith,
setDesktopNotifications,
setDockBadgeNotifications,
+ setDockBounceNotifications,
setCompletionSound,
setCompletionVolume,
setAutoConvertLongText,
@@ -90,6 +92,17 @@ export function ChatSettings() {
/>
+
+
+
+
void;
setDesktopNotifications: (enabled: boolean) => void;
setDockBadgeNotifications: (enabled: boolean) => void;
+ setDockBounceNotifications: (enabled: boolean) => void;
setCursorGlow: (enabled: boolean) => void;
setAutoConvertLongText: (enabled: boolean) => void;
setSendMessagesWith: (mode: SendMessagesWith) => void;
@@ -54,6 +56,7 @@ export const useSettingsStore = create()(
lastUsedModel: null,
desktopNotifications: true,
dockBadgeNotifications: true,
+ dockBounceNotifications: false,
completionSound: "none",
completionVolume: 80,
cursorGlow: false,
@@ -75,6 +78,8 @@ export const useSettingsStore = create()(
set({ desktopNotifications: enabled }),
setDockBadgeNotifications: (enabled) =>
set({ dockBadgeNotifications: enabled }),
+ setDockBounceNotifications: (enabled) =>
+ set({ dockBounceNotifications: enabled }),
setCursorGlow: (enabled) => set({ cursorGlow: enabled }),
setAutoConvertLongText: (enabled) =>
set({ autoConvertLongText: enabled }),
@@ -96,6 +101,7 @@ export const useSettingsStore = create()(
lastUsedModel: state.lastUsedModel,
desktopNotifications: state.desktopNotifications,
dockBadgeNotifications: state.dockBadgeNotifications,
+ dockBounceNotifications: state.dockBounceNotifications,
cursorGlow: state.cursorGlow,
autoConvertLongText: state.autoConvertLongText,
completionSound: state.completionSound,
diff --git a/apps/twig/src/renderer/lib/notifications.ts b/apps/twig/src/renderer/lib/notifications.ts
index 9458223a9..12497250e 100644
--- a/apps/twig/src/renderer/lib/notifications.ts
+++ b/apps/twig/src/renderer/lib/notifications.ts
@@ -28,6 +28,12 @@ function showDockBadge(): void {
});
}
+function bounceDock(): void {
+ trpcVanilla.notification.bounceDock.mutate().catch((err) => {
+ log.error("Failed to bounce dock", err);
+ });
+}
+
export function notifyPromptComplete(
taskTitle: string,
stopReason: string,
@@ -39,6 +45,7 @@ export function notifyPromptComplete(
completionVolume,
desktopNotifications,
dockBadgeNotifications,
+ dockBounceNotifications,
} = useSettingsStore.getState();
const isWindowFocused = document.hasFocus();
@@ -57,6 +64,9 @@ export function notifyPromptComplete(
if (dockBadgeNotifications) {
showDockBadge();
}
+ if (dockBounceNotifications) {
+ bounceDock();
+ }
}
export function notifyPermissionRequest(taskTitle: string): void {
@@ -65,6 +75,7 @@ export function notifyPermissionRequest(taskTitle: string): void {
completionVolume,
desktopNotifications,
dockBadgeNotifications,
+ dockBounceNotifications,
} = useSettingsStore.getState();
const isWindowFocused = document.hasFocus();
@@ -82,5 +93,8 @@ export function notifyPermissionRequest(taskTitle: string): void {
if (dockBadgeNotifications) {
showDockBadge();
}
+ if (dockBounceNotifications) {
+ bounceDock();
+ }
}
}