From e18ce6fbee30966f7a51efd3ff55442948fb8477 Mon Sep 17 00:00:00 2001 From: Jay <53023+jayair@users.noreply.github.com> Date: Sat, 18 Jul 2026 00:07:20 +0000 Subject: [PATCH 1/3] fix(app): mute comment-only prompt errors --- .../components/prompt-input/submit.test.ts | 75 ++++++++++++++++++- .../app/src/components/prompt-input/submit.ts | 10 +++ .../context/notification-error-sound.test.ts | 22 ++++++ .../src/context/notification-error-sound.ts | 22 ++++++ packages/app/src/context/notification.tsx | 18 ++++- packages/app/src/pages/session.tsx | 2 + 6 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 packages/app/src/context/notification-error-sound.test.ts create mode 100644 packages/app/src/context/notification-error-sound.ts diff --git a/packages/app/src/components/prompt-input/submit.test.ts b/packages/app/src/components/prompt-input/submit.test.ts index f563a509822a..8b32939eee91 100644 --- a/packages/app/src/components/prompt-input/submit.test.ts +++ b/packages/app/src/components/prompt-input/submit.test.ts @@ -23,6 +23,7 @@ const promoted: Array<{ directory: string; sessionID: string }> = [] const sentShell: string[] = [] const syncedDirectories: string[] = [] const promotedDrafts: Array<{ draftID: string; server: string; sessionId: string }> = [] +const mutedErrorSounds: string[] = [] let params: { id?: string } = {} let search: { draftId?: string } = {} @@ -32,6 +33,8 @@ let permissionServer = "server-a" let createSessionGate: Promise | undefined const promptValue: Prompt = [{ type: "text", content: "ls", start: 0, end: 2 }] +let currentPrompt = promptValue +let contextItems: PromptStore["context"]["items"] = [] const [promptStore, setPromptStore] = createStore({ prompt: promptValue, cursor: 0, @@ -40,7 +43,7 @@ const [promptStore, setPromptStore] = createStore({ const prompt = { store: [() => promptStore, setPromptStore] as [() => PromptStore, typeof setPromptStore], ready: Object.assign(() => true, { promise: Promise.resolve(true) }), - current: () => promptValue, + current: () => currentPrompt, cursor: () => 0, dirty: () => true, model: { @@ -55,7 +58,7 @@ const prompt = { removeComment: () => undefined, updateComment: () => undefined, replaceComments: () => undefined, - items: () => [], + items: () => contextItems, }, capture: () => prompt, } @@ -141,6 +144,17 @@ beforeAll(async () => { return { usePermission: () => ({ currentServerState: () => state(permissionServer) }) } }) + mock.module("@/context/notification", () => ({ + useNotification: () => ({ + error: { + muteNextSound(sessionID: string) { + mutedErrorSounds.push(sessionID) + return () => undefined + }, + }, + }), + })) + mock.module("@/context/server", () => ({ useServer: () => ({ key: "server-key" }), })) @@ -256,6 +270,7 @@ beforeEach(() => { optimisticSeeded.length = 0 promoted.length = 0 promotedDrafts.length = 0 + mutedErrorSounds.length = 0 params = {} search = {} sentShell.length = 0 @@ -264,10 +279,66 @@ beforeEach(() => { variant = undefined permissionServer = "server-a" createSessionGate = undefined + currentPrompt = promptValue + contextItems = [] for (const key of Object.keys(storedSessions)) delete storedSessions[key] }) describe("prompt submit worktree selection", () => { + const commentSubmit = (promptLength: number) => + createPromptSubmit({ + prompt, + info: () => ({ id: "session-1" }), + imageAttachments: () => [], + commentCount: () => 1, + autoAccept: () => false, + mode: () => "normal", + working: () => false, + editor: () => undefined, + queueScroll: () => undefined, + promptLength: () => promptLength, + addToHistory: () => undefined, + resetHistoryNavigation: () => undefined, + setMode: () => undefined, + setPopover: () => undefined, + onSubmit: () => undefined, + }) + + test("mutes the error sound for a comment-only prompt", async () => { + params = { id: "session-1" } + currentPrompt = [{ type: "text", content: "", start: 0, end: 0 }] + contextItems = [ + { + key: "comment-1", + type: "file", + path: "src/example.ts", + comment: "Please rename this", + commentID: "comment-1", + commentOrigin: "review", + }, + ] + await commentSubmit(0).handleSubmit({ preventDefault: () => undefined } as unknown as Event) + + expect(mutedErrorSounds).toEqual(["session-1"]) + }) + + test("keeps error sounds enabled when the prompt includes text", async () => { + params = { id: "session-1" } + contextItems = [ + { + key: "comment-1", + type: "file", + path: "src/example.ts", + comment: "Please rename this", + commentID: "comment-1", + commentOrigin: "review", + }, + ] + await commentSubmit(2).handleSubmit({ preventDefault: () => undefined } as unknown as Event) + + expect(mutedErrorSounds).toEqual([]) + }) + test("reads the latest worktree accessor value per submit", async () => { const submit = createPromptSubmit({ prompt, diff --git a/packages/app/src/components/prompt-input/submit.ts b/packages/app/src/components/prompt-input/submit.ts index 203722fc6c74..0122c0c3df72 100644 --- a/packages/app/src/components/prompt-input/submit.ts +++ b/packages/app/src/components/prompt-input/submit.ts @@ -10,6 +10,7 @@ import { useLanguage } from "@/context/language" import { useLayout } from "@/context/layout" import { useLocal, type ModelSelection } from "@/context/local" import { usePermission } from "@/context/permission" +import { useNotification } from "@/context/notification" import { type ContextItem, type ImageAttachmentPart, type Prompt, type usePrompt } from "@/context/prompt" import { useSDK, type DirectorySDK } from "@/context/sdk" import { useSync, type DirectorySync } from "@/context/sync" @@ -46,6 +47,7 @@ type FollowupSendInput = { messageID?: string optimisticBusy?: boolean before?: () => Promise | boolean + muteErrorSound?: (sessionID: string) => VoidFunction } const draftText = (prompt: Prompt) => prompt.map((part) => ("content" in part ? part.content : "")).join("") @@ -104,6 +106,10 @@ export async function sendFollowupDraft(input: FollowupSendInput) { } const messageID = input.messageID ?? Identifier.ascending("message") + const cancelErrorSoundMute = + text.trim().length === 0 && images.length === 0 && input.draft.context.some((item) => !!item.comment?.trim()) + ? input.muteErrorSound?.(input.draft.sessionID) + : undefined const { requestParts, optimisticParts } = buildRequestParts({ prompt: input.draft.prompt, context: input.draft.context, @@ -145,6 +151,7 @@ export async function sendFollowupDraft(input: FollowupSendInput) { try { if (!(await wait())) { + cancelErrorSoundMute?.() batch(() => { setIdle() remove() @@ -162,6 +169,7 @@ export async function sendFollowupDraft(input: FollowupSendInput) { }) return true } catch (err) { + cancelErrorSoundMute?.() batch(() => { setIdle() remove() @@ -201,6 +209,7 @@ export function createPromptSubmit(input: PromptSubmitInput) { const serverSync = useServerSync() const local = useLocal() const permission = usePermission() + const notification = useNotification() const prompt = input.prompt const layout = useLayout() const language = useLanguage() @@ -580,6 +589,7 @@ export function createPromptSubmit(input: PromptSubmitInput) { messageID, optimisticBusy: sessionDirectory === projectDirectory, before: waitForWorktree, + muteErrorSound: notification.error.muteNextSound, }).catch((err) => { pending.delete(pendingKey(session.id)) if (sessionDirectory === projectDirectory) { diff --git a/packages/app/src/context/notification-error-sound.test.ts b/packages/app/src/context/notification-error-sound.test.ts new file mode 100644 index 000000000000..446084f80d44 --- /dev/null +++ b/packages/app/src/context/notification-error-sound.test.ts @@ -0,0 +1,22 @@ +import { describe, expect, test } from "bun:test" +import { createNotificationErrorSound } from "./notification-error-sound" + +describe("notification error sound", () => { + test("mutes one session error and keeps other errors audible", () => { + const sound = createNotificationErrorSound() + sound.muteNext("session-comment-only") + + expect(sound.shouldPlay("session-other")).toBe(true) + expect(sound.shouldPlay()).toBe(true) + expect(sound.shouldPlay("session-comment-only")).toBe(false) + expect(sound.shouldPlay("session-comment-only")).toBe(true) + }) + + test("restores the sound when the session settles without an error", () => { + const sound = createNotificationErrorSound() + sound.muteNext("session-comment-only") + sound.settle("session-comment-only") + + expect(sound.shouldPlay("session-comment-only")).toBe(true) + }) +}) diff --git a/packages/app/src/context/notification-error-sound.ts b/packages/app/src/context/notification-error-sound.ts new file mode 100644 index 000000000000..ce79e751c092 --- /dev/null +++ b/packages/app/src/context/notification-error-sound.ts @@ -0,0 +1,22 @@ +export function createNotificationErrorSound() { + const muted = new Set() + + return { + muteNext(sessionID: string) { + muted.add(sessionID) + return () => { + muted.delete(sessionID) + } + }, + shouldPlay(sessionID?: string) { + if (!sessionID) return true + return !muted.delete(sessionID) + }, + settle(sessionID?: string) { + if (sessionID) muted.delete(sessionID) + }, + dispose() { + muted.clear() + }, + } +} diff --git a/packages/app/src/context/notification.tsx b/packages/app/src/context/notification.tsx index e12f8f1250ea..29cca2d3828b 100644 --- a/packages/app/src/context/notification.tsx +++ b/packages/app/src/context/notification.tsx @@ -12,6 +12,7 @@ import { decode64 } from "@/utils/base64" import { EventSessionError } from "@opencode-ai/sdk/v2" import { Persist, persisted } from "@/utils/persist" import { playSoundById } from "@/utils/sound" +import { createNotificationErrorSound } from "./notification-error-sound" import { useGlobal } from "./global" import { ServerConnection, useServer } from "./server" import { type DraftTab, useTabs } from "./tabs" @@ -181,6 +182,9 @@ export const { use: useNotification, provider: NotificationProvider } = createSi return { ready: () => selected().ready(), ensureServerState: ensure, + error: { + muteNextSound: (session: string) => selected().error.muteNextSound(session), + }, session: { all: (session: string) => selected().session.all(session), unseen: (session: string) => selected().session.unseen(session), @@ -231,6 +235,7 @@ function createServerNotificationState(input: { const [index, setIndex] = createStore(buildNotificationIndex(store.list)) const meta = { pruned: false, disposed: false } + const errorSound = createNotificationErrorSound() const updateUnseen = (scope: "session" | "project", key: string, unseen: Notification[]) => { setIndex(scope, "unseen", key, unseen) @@ -327,6 +332,7 @@ function createServerNotificationState(input: { const handleSessionIdle = (directory: string, event: { properties: { sessionID?: string } }, time: number) => { const sessionID = event.properties.sessionID + errorSound.settle(sessionID) void lookup(directory, sessionID).then((session) => { if (meta.disposed) return if (!session) return @@ -355,13 +361,14 @@ function createServerNotificationState(input: { directory: string, event: { properties: { sessionID?: string; error?: EventSessionError["properties"]["error"] } }, time: number, + sound: boolean, ) => { const sessionID = event.properties.sessionID void lookup(directory, sessionID).then((session) => { if (meta.disposed) return if (session?.parentID) return - if (settings.sounds.errorsEnabled()) { + if (sound && settings.sounds.errorsEnabled()) { void playSoundById(settings.sounds.errors()) } @@ -394,15 +401,22 @@ function createServerNotificationState(input: { handleSessionIdle(directory, event, time) return } - handleSessionError(directory, event, time) + const sessionID = event.properties.sessionID + handleSessionError(directory, event, time, errorSound.shouldPlay(sessionID)) }) onCleanup(() => { meta.disposed = true unsub() + errorSound.dispose() }) return { ready, + error: { + muteNextSound(session: string) { + return errorSound.muteNext(session) + }, + }, session: { all(session: string) { return index.session.all[session] ?? empty diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index 2327cbf735b1..bc06ba96c16c 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -364,6 +364,7 @@ export default function Page() { const platform = usePlatform() const prompt = usePrompt() const comments = useComments() + const notification = useNotification() const command = useCommand() const terminal = useTerminal() const [searchParams, setSearchParams] = useSearchParams<{ prompt?: string }>() @@ -1761,6 +1762,7 @@ export default function Page() { serverSync: serverSync(), draft: item, optimisticBusy: item.sessionDirectory === sdk().directory, + muteErrorSound: notification.error.muteNextSound, }).catch((err) => { setFollowup("failed", input.sessionID, input.id) fail(err) From aeaef6c344cdb2435c9aefb6cb8db9b8f521a631 Mon Sep 17 00:00:00 2001 From: Jay <53023+jayair@users.noreply.github.com> Date: Sat, 18 Jul 2026 00:12:23 +0000 Subject: [PATCH 2/3] test(app): remove comment error coverage --- .../components/prompt-input/submit.test.ts | 75 +------------------ .../context/notification-error-sound.test.ts | 22 ------ 2 files changed, 2 insertions(+), 95 deletions(-) delete mode 100644 packages/app/src/context/notification-error-sound.test.ts diff --git a/packages/app/src/components/prompt-input/submit.test.ts b/packages/app/src/components/prompt-input/submit.test.ts index 8b32939eee91..f563a509822a 100644 --- a/packages/app/src/components/prompt-input/submit.test.ts +++ b/packages/app/src/components/prompt-input/submit.test.ts @@ -23,7 +23,6 @@ const promoted: Array<{ directory: string; sessionID: string }> = [] const sentShell: string[] = [] const syncedDirectories: string[] = [] const promotedDrafts: Array<{ draftID: string; server: string; sessionId: string }> = [] -const mutedErrorSounds: string[] = [] let params: { id?: string } = {} let search: { draftId?: string } = {} @@ -33,8 +32,6 @@ let permissionServer = "server-a" let createSessionGate: Promise | undefined const promptValue: Prompt = [{ type: "text", content: "ls", start: 0, end: 2 }] -let currentPrompt = promptValue -let contextItems: PromptStore["context"]["items"] = [] const [promptStore, setPromptStore] = createStore({ prompt: promptValue, cursor: 0, @@ -43,7 +40,7 @@ const [promptStore, setPromptStore] = createStore({ const prompt = { store: [() => promptStore, setPromptStore] as [() => PromptStore, typeof setPromptStore], ready: Object.assign(() => true, { promise: Promise.resolve(true) }), - current: () => currentPrompt, + current: () => promptValue, cursor: () => 0, dirty: () => true, model: { @@ -58,7 +55,7 @@ const prompt = { removeComment: () => undefined, updateComment: () => undefined, replaceComments: () => undefined, - items: () => contextItems, + items: () => [], }, capture: () => prompt, } @@ -144,17 +141,6 @@ beforeAll(async () => { return { usePermission: () => ({ currentServerState: () => state(permissionServer) }) } }) - mock.module("@/context/notification", () => ({ - useNotification: () => ({ - error: { - muteNextSound(sessionID: string) { - mutedErrorSounds.push(sessionID) - return () => undefined - }, - }, - }), - })) - mock.module("@/context/server", () => ({ useServer: () => ({ key: "server-key" }), })) @@ -270,7 +256,6 @@ beforeEach(() => { optimisticSeeded.length = 0 promoted.length = 0 promotedDrafts.length = 0 - mutedErrorSounds.length = 0 params = {} search = {} sentShell.length = 0 @@ -279,66 +264,10 @@ beforeEach(() => { variant = undefined permissionServer = "server-a" createSessionGate = undefined - currentPrompt = promptValue - contextItems = [] for (const key of Object.keys(storedSessions)) delete storedSessions[key] }) describe("prompt submit worktree selection", () => { - const commentSubmit = (promptLength: number) => - createPromptSubmit({ - prompt, - info: () => ({ id: "session-1" }), - imageAttachments: () => [], - commentCount: () => 1, - autoAccept: () => false, - mode: () => "normal", - working: () => false, - editor: () => undefined, - queueScroll: () => undefined, - promptLength: () => promptLength, - addToHistory: () => undefined, - resetHistoryNavigation: () => undefined, - setMode: () => undefined, - setPopover: () => undefined, - onSubmit: () => undefined, - }) - - test("mutes the error sound for a comment-only prompt", async () => { - params = { id: "session-1" } - currentPrompt = [{ type: "text", content: "", start: 0, end: 0 }] - contextItems = [ - { - key: "comment-1", - type: "file", - path: "src/example.ts", - comment: "Please rename this", - commentID: "comment-1", - commentOrigin: "review", - }, - ] - await commentSubmit(0).handleSubmit({ preventDefault: () => undefined } as unknown as Event) - - expect(mutedErrorSounds).toEqual(["session-1"]) - }) - - test("keeps error sounds enabled when the prompt includes text", async () => { - params = { id: "session-1" } - contextItems = [ - { - key: "comment-1", - type: "file", - path: "src/example.ts", - comment: "Please rename this", - commentID: "comment-1", - commentOrigin: "review", - }, - ] - await commentSubmit(2).handleSubmit({ preventDefault: () => undefined } as unknown as Event) - - expect(mutedErrorSounds).toEqual([]) - }) - test("reads the latest worktree accessor value per submit", async () => { const submit = createPromptSubmit({ prompt, diff --git a/packages/app/src/context/notification-error-sound.test.ts b/packages/app/src/context/notification-error-sound.test.ts deleted file mode 100644 index 446084f80d44..000000000000 --- a/packages/app/src/context/notification-error-sound.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { describe, expect, test } from "bun:test" -import { createNotificationErrorSound } from "./notification-error-sound" - -describe("notification error sound", () => { - test("mutes one session error and keeps other errors audible", () => { - const sound = createNotificationErrorSound() - sound.muteNext("session-comment-only") - - expect(sound.shouldPlay("session-other")).toBe(true) - expect(sound.shouldPlay()).toBe(true) - expect(sound.shouldPlay("session-comment-only")).toBe(false) - expect(sound.shouldPlay("session-comment-only")).toBe(true) - }) - - test("restores the sound when the session settles without an error", () => { - const sound = createNotificationErrorSound() - sound.muteNext("session-comment-only") - sound.settle("session-comment-only") - - expect(sound.shouldPlay("session-comment-only")).toBe(true) - }) -}) From 6c4848315b732aa88bfb333dabe31a59e4d29651 Mon Sep 17 00:00:00 2001 From: Jay <53023+jayair@users.noreply.github.com> Date: Sat, 18 Jul 2026 00:18:15 +0000 Subject: [PATCH 3/3] fix(app): omit empty prompt text parts --- .../prompt-input/build-request-parts.ts | 16 ++++++++------ .../app/src/components/prompt-input/submit.ts | 10 --------- .../src/context/notification-error-sound.ts | 22 ------------------- packages/app/src/context/notification.tsx | 18 ++------------- packages/app/src/pages/session.tsx | 2 -- 5 files changed, 11 insertions(+), 57 deletions(-) delete mode 100644 packages/app/src/context/notification-error-sound.ts diff --git a/packages/app/src/components/prompt-input/build-request-parts.ts b/packages/app/src/components/prompt-input/build-request-parts.ts index c5bdd730c461..7f0fea2bfe79 100644 --- a/packages/app/src/components/prompt-input/build-request-parts.ts +++ b/packages/app/src/components/prompt-input/build-request-parts.ts @@ -89,13 +89,15 @@ const toOptimisticPart = (part: PromptRequestPart, sessionID: string, messageID: } export function buildRequestParts(input: BuildRequestPartsInput) { - const requestParts: PromptRequestPart[] = [ - { - id: Identifier.ascending("part"), - type: "text", - text: input.text, - }, - ] + const requestParts: PromptRequestPart[] = input.text.trim() + ? [ + { + id: Identifier.ascending("part"), + type: "text", + text: input.text, + }, + ] + : [] const files = input.prompt.filter(isFileAttachment).map((attachment) => { const path = absolute(input.sessionDirectory, attachment.path) diff --git a/packages/app/src/components/prompt-input/submit.ts b/packages/app/src/components/prompt-input/submit.ts index 0122c0c3df72..203722fc6c74 100644 --- a/packages/app/src/components/prompt-input/submit.ts +++ b/packages/app/src/components/prompt-input/submit.ts @@ -10,7 +10,6 @@ import { useLanguage } from "@/context/language" import { useLayout } from "@/context/layout" import { useLocal, type ModelSelection } from "@/context/local" import { usePermission } from "@/context/permission" -import { useNotification } from "@/context/notification" import { type ContextItem, type ImageAttachmentPart, type Prompt, type usePrompt } from "@/context/prompt" import { useSDK, type DirectorySDK } from "@/context/sdk" import { useSync, type DirectorySync } from "@/context/sync" @@ -47,7 +46,6 @@ type FollowupSendInput = { messageID?: string optimisticBusy?: boolean before?: () => Promise | boolean - muteErrorSound?: (sessionID: string) => VoidFunction } const draftText = (prompt: Prompt) => prompt.map((part) => ("content" in part ? part.content : "")).join("") @@ -106,10 +104,6 @@ export async function sendFollowupDraft(input: FollowupSendInput) { } const messageID = input.messageID ?? Identifier.ascending("message") - const cancelErrorSoundMute = - text.trim().length === 0 && images.length === 0 && input.draft.context.some((item) => !!item.comment?.trim()) - ? input.muteErrorSound?.(input.draft.sessionID) - : undefined const { requestParts, optimisticParts } = buildRequestParts({ prompt: input.draft.prompt, context: input.draft.context, @@ -151,7 +145,6 @@ export async function sendFollowupDraft(input: FollowupSendInput) { try { if (!(await wait())) { - cancelErrorSoundMute?.() batch(() => { setIdle() remove() @@ -169,7 +162,6 @@ export async function sendFollowupDraft(input: FollowupSendInput) { }) return true } catch (err) { - cancelErrorSoundMute?.() batch(() => { setIdle() remove() @@ -209,7 +201,6 @@ export function createPromptSubmit(input: PromptSubmitInput) { const serverSync = useServerSync() const local = useLocal() const permission = usePermission() - const notification = useNotification() const prompt = input.prompt const layout = useLayout() const language = useLanguage() @@ -589,7 +580,6 @@ export function createPromptSubmit(input: PromptSubmitInput) { messageID, optimisticBusy: sessionDirectory === projectDirectory, before: waitForWorktree, - muteErrorSound: notification.error.muteNextSound, }).catch((err) => { pending.delete(pendingKey(session.id)) if (sessionDirectory === projectDirectory) { diff --git a/packages/app/src/context/notification-error-sound.ts b/packages/app/src/context/notification-error-sound.ts deleted file mode 100644 index ce79e751c092..000000000000 --- a/packages/app/src/context/notification-error-sound.ts +++ /dev/null @@ -1,22 +0,0 @@ -export function createNotificationErrorSound() { - const muted = new Set() - - return { - muteNext(sessionID: string) { - muted.add(sessionID) - return () => { - muted.delete(sessionID) - } - }, - shouldPlay(sessionID?: string) { - if (!sessionID) return true - return !muted.delete(sessionID) - }, - settle(sessionID?: string) { - if (sessionID) muted.delete(sessionID) - }, - dispose() { - muted.clear() - }, - } -} diff --git a/packages/app/src/context/notification.tsx b/packages/app/src/context/notification.tsx index 29cca2d3828b..e12f8f1250ea 100644 --- a/packages/app/src/context/notification.tsx +++ b/packages/app/src/context/notification.tsx @@ -12,7 +12,6 @@ import { decode64 } from "@/utils/base64" import { EventSessionError } from "@opencode-ai/sdk/v2" import { Persist, persisted } from "@/utils/persist" import { playSoundById } from "@/utils/sound" -import { createNotificationErrorSound } from "./notification-error-sound" import { useGlobal } from "./global" import { ServerConnection, useServer } from "./server" import { type DraftTab, useTabs } from "./tabs" @@ -182,9 +181,6 @@ export const { use: useNotification, provider: NotificationProvider } = createSi return { ready: () => selected().ready(), ensureServerState: ensure, - error: { - muteNextSound: (session: string) => selected().error.muteNextSound(session), - }, session: { all: (session: string) => selected().session.all(session), unseen: (session: string) => selected().session.unseen(session), @@ -235,7 +231,6 @@ function createServerNotificationState(input: { const [index, setIndex] = createStore(buildNotificationIndex(store.list)) const meta = { pruned: false, disposed: false } - const errorSound = createNotificationErrorSound() const updateUnseen = (scope: "session" | "project", key: string, unseen: Notification[]) => { setIndex(scope, "unseen", key, unseen) @@ -332,7 +327,6 @@ function createServerNotificationState(input: { const handleSessionIdle = (directory: string, event: { properties: { sessionID?: string } }, time: number) => { const sessionID = event.properties.sessionID - errorSound.settle(sessionID) void lookup(directory, sessionID).then((session) => { if (meta.disposed) return if (!session) return @@ -361,14 +355,13 @@ function createServerNotificationState(input: { directory: string, event: { properties: { sessionID?: string; error?: EventSessionError["properties"]["error"] } }, time: number, - sound: boolean, ) => { const sessionID = event.properties.sessionID void lookup(directory, sessionID).then((session) => { if (meta.disposed) return if (session?.parentID) return - if (sound && settings.sounds.errorsEnabled()) { + if (settings.sounds.errorsEnabled()) { void playSoundById(settings.sounds.errors()) } @@ -401,22 +394,15 @@ function createServerNotificationState(input: { handleSessionIdle(directory, event, time) return } - const sessionID = event.properties.sessionID - handleSessionError(directory, event, time, errorSound.shouldPlay(sessionID)) + handleSessionError(directory, event, time) }) onCleanup(() => { meta.disposed = true unsub() - errorSound.dispose() }) return { ready, - error: { - muteNextSound(session: string) { - return errorSound.muteNext(session) - }, - }, session: { all(session: string) { return index.session.all[session] ?? empty diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index bc06ba96c16c..2327cbf735b1 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -364,7 +364,6 @@ export default function Page() { const platform = usePlatform() const prompt = usePrompt() const comments = useComments() - const notification = useNotification() const command = useCommand() const terminal = useTerminal() const [searchParams, setSearchParams] = useSearchParams<{ prompt?: string }>() @@ -1762,7 +1761,6 @@ export default function Page() { serverSync: serverSync(), draft: item, optimisticBusy: item.sessionDirectory === sdk().directory, - muteErrorSound: notification.error.muteNextSound, }).catch((err) => { setFollowup("failed", input.sessionID, input.id) fail(err)