Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 30 additions & 28 deletions locales/ca/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/de/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/es/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/fr/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/hi/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/it/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/ja/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/ko/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/nl/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/pl/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/pt-BR/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/ru/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/tr/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/vi/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/zh-CN/README.md

Large diffs are not rendered by default.

58 changes: 30 additions & 28 deletions locales/zh-TW/README.md

Large diffs are not rendered by default.

6 changes: 0 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,6 @@
"say": "^0.16.0",
"serialize-error": "^11.0.3",
"simple-git": "^3.27.0",
"sound-play": "^1.1.0",
"string-similarity": "^4.0.4",
"strip-ansi": "^7.1.0",
"strip-bom": "^5.0.0",
Expand Down
10 changes: 6 additions & 4 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import { McpHub } from "../../services/mcp/McpHub"
import { McpServerManager } from "../../services/mcp/McpServerManager"
import { ShadowCheckpointService } from "../../services/checkpoints/ShadowCheckpointService"
import { fileExistsAtPath } from "../../utils/fs"
import { setSoundEnabled } from "../../utils/sound"
import { setTtsEnabled, setTtsSpeed } from "../../utils/tts"
import { ContextProxy } from "../config/ContextProxy"
import { ProviderSettingsManager } from "../config/ProviderSettingsManager"
Expand Down Expand Up @@ -327,7 +326,6 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
// Initialize out-of-scope variables that need to recieve persistent global state values
this.getState().then(
({
soundEnabled = false,
terminalShellIntegrationTimeout = Terminal.defaultShellIntegrationTimeout,
terminalShellIntegrationDisabled = false,
terminalCommandDelay = 0,
Expand All @@ -337,7 +335,6 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
terminalPowershellCounter = false,
terminalZdotdir = false,
}) => {
setSoundEnabled(soundEnabled)
Terminal.setShellIntegrationTimeout(terminalShellIntegrationTimeout)
Terminal.setShellIntegrationDisabled(terminalShellIntegrationDisabled)
Terminal.setCommandDelay(terminalCommandDelay)
Expand Down Expand Up @@ -598,6 +595,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
])

const imagesUri = getUri(webview, this.contextProxy.extensionUri, ["assets", "images"])
const audioUri = getUri(webview, this.contextProxy.extensionUri, ["webview-ui", "audio"])

const file = "src/index.tsx"
const scriptUri = `http://${localServerUrl}/${file}`
Expand All @@ -617,6 +615,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
`font-src ${webview.cspSource}`,
`style-src ${webview.cspSource} 'unsafe-inline' https://* http://${localServerUrl} http://0.0.0.0:${localPort}`,
`img-src ${webview.cspSource} data:`,
`media-src ${webview.cspSource}`,
`script-src 'unsafe-eval' ${webview.cspSource} https://* https://*.posthog.com http://${localServerUrl} http://0.0.0.0:${localPort} 'nonce-${nonce}'`,
`connect-src https://* https://*.posthog.com ws://${localServerUrl} ws://0.0.0.0:${localPort} http://${localServerUrl} http://0.0.0.0:${localPort}`,
]
Expand All @@ -632,6 +631,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
<link href="${codiconsUri}" rel="stylesheet" />
<script nonce="${nonce}">
window.IMAGES_BASE_URI = "${imagesUri}"
window.AUDIO_BASE_URI = "${audioUri}"
window.MATERIAL_ICONS_BASE_URI = "${materialIconsUri}"
</script>
<title>Roo Code</title>
Expand Down Expand Up @@ -691,6 +691,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
])

const imagesUri = getUri(webview, this.contextProxy.extensionUri, ["assets", "images"])
const audioUri = getUri(webview, this.contextProxy.extensionUri, ["webview-ui", "audio"])

// const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, "assets", "main.js"))

Expand Down Expand Up @@ -721,11 +722,12 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; font-src ${webview.cspSource}; style-src ${webview.cspSource} 'unsafe-inline'; img-src ${webview.cspSource} data:; script-src ${webview.cspSource} 'wasm-unsafe-eval' 'nonce-${nonce}' https://us-assets.i.posthog.com 'strict-dynamic'; connect-src https://openrouter.ai https://api.requesty.ai https://us.i.posthog.com https://us-assets.i.posthog.com;">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; font-src ${webview.cspSource}; style-src ${webview.cspSource} 'unsafe-inline'; img-src ${webview.cspSource} data:; media-src ${webview.cspSource}; script-src ${webview.cspSource} 'wasm-unsafe-eval' 'nonce-${nonce}' https://us-assets.i.posthog.com 'strict-dynamic'; connect-src https://openrouter.ai https://api.requesty.ai https://us.i.posthog.com https://us-assets.i.posthog.com https://file+.vscode-resource.vscode-cdn.net;">
<link rel="stylesheet" type="text/css" href="${stylesUri}">
<link href="${codiconsUri}" rel="stylesheet" />
<script nonce="${nonce}">
window.IMAGES_BASE_URI = "${imagesUri}"
window.AUDIO_BASE_URI = "${audioUri}"
window.MATERIAL_ICONS_BASE_URI = "${materialIconsUri}"
</script>
<title>Roo Code</title>
Expand Down
9 changes: 1 addition & 8 deletions src/core/webview/__tests__/ClineProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import axios from "axios"

import { ClineProvider } from "../ClineProvider"
import { ProviderSettingsEntry, ClineMessage, ExtensionMessage, ExtensionState } from "../../../shared/ExtensionMessage"
import { setSoundEnabled } from "../../../utils/sound"
import { setTtsEnabled } from "../../../utils/tts"
import { defaultModeSlug } from "../../../shared/modes"
import { experimentDefault } from "../../../shared/experiments"
Expand Down Expand Up @@ -173,10 +172,6 @@ jest.mock("vscode", () => ({
},
}))

jest.mock("../../../utils/sound", () => ({
setSoundEnabled: jest.fn(),
}))

jest.mock("../../../utils/tts", () => ({
setTtsEnabled: jest.fn(),
setTtsSpeed: jest.fn(),
Expand Down Expand Up @@ -365,7 +360,7 @@ describe("ClineProvider", () => {

// Verify Content Security Policy contains the necessary PostHog domains
expect(mockWebviewView.webview.html).toContain(
"connect-src https://openrouter.ai https://api.requesty.ai https://us.i.posthog.com https://us-assets.i.posthog.com;",
"connect-src https://openrouter.ai https://api.requesty.ai https://us.i.posthog.com https://us-assets.i.posthog.com https://file+.vscode-resource.vscode-cdn.net;",
)

// Extract the script-src directive section and verify required security elements
Expand Down Expand Up @@ -545,14 +540,12 @@ describe("ClineProvider", () => {

// Simulate setting sound to enabled
await messageHandler({ type: "soundEnabled", bool: true })
expect(setSoundEnabled).toHaveBeenCalledWith(true)
expect(updateGlobalStateSpy).toHaveBeenCalledWith("soundEnabled", true)
expect(mockContext.globalState.update).toHaveBeenCalledWith("soundEnabled", true)
expect(mockPostMessage).toHaveBeenCalled()

// Simulate setting sound to disabled
await messageHandler({ type: "soundEnabled", bool: false })
expect(setSoundEnabled).toHaveBeenCalledWith(false)
expect(mockContext.globalState.update).toHaveBeenCalledWith("soundEnabled", false)
expect(mockPostMessage).toHaveBeenCalled()

Expand Down
10 changes: 1 addition & 9 deletions src/core/webview/webviewMessageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { getTheme } from "../../integrations/theme/getTheme"
import { discoverChromeHostUrl, tryChromeHostUrl } from "../../services/browser/browserDiscovery"
import { searchWorkspaceFiles } from "../../services/search/file-search"
import { fileExistsAtPath } from "../../utils/fs"
import { playSound, setSoundEnabled, setSoundVolume } from "../../utils/sound"
import { playTts, setTtsEnabled, setTtsSpeed, stopTts } from "../../utils/tts"
import { singleCompletionHandler } from "../../utils/single-completion-handler"
import { searchCommits } from "../../utils/git"
Expand Down Expand Up @@ -483,22 +482,15 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
await updateGlobalState("enableMcpServerCreation", message.bool ?? true)
await provider.postStateToWebview()
break
case "playSound":
if (message.audioType) {
const soundPath = path.join(provider.context.extensionPath, "audio", `${message.audioType}.wav`)
playSound(soundPath)
}
break
// playSound handler removed - now handled directly in the webview
case "soundEnabled":
const soundEnabled = message.bool ?? true
await updateGlobalState("soundEnabled", soundEnabled)
setSoundEnabled(soundEnabled) // Add this line to update the sound utility
await provider.postStateToWebview()
break
case "soundVolume":
const soundVolume = message.value ?? 0.5
await updateGlobalState("soundVolume", soundVolume)
setSoundVolume(soundVolume)
await provider.postStateToWebview()
break
case "ttsEnabled":
Expand Down
75 changes: 0 additions & 75 deletions src/utils/sound.ts

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes.
19 changes: 19 additions & 0 deletions webview-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions webview-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"tailwind-merge": "^2.6.0",
"tailwindcss": "^4.0.0",
"tailwindcss-animate": "^1.0.7",
"use-sound": "^5.0.0",
"vscrui": "^0.2.2",
"zod": "^3.24.2"
},
Expand Down
39 changes: 38 additions & 1 deletion webview-ui/src/components/chat/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Virtuoso, type VirtuosoHandle } from "react-virtuoso"
import removeMd from "remove-markdown"
import { Trans } from "react-i18next"
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
import useSound from "use-sound"

import {
ClineAsk,
Expand Down Expand Up @@ -84,6 +85,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
telemetrySetting,
hasSystemPromptOverride,
historyPreviewCollapsed, // Added historyPreviewCollapsed
soundEnabled,
soundVolume,
} = useExtensionState()

const { tasks } = useTaskSearch()
Expand Down Expand Up @@ -136,8 +139,42 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
const lastMessage = useMemo(() => messages.at(-1), [messages])
const secondLastMessage = useMemo(() => messages.at(-2), [messages])

// Setup sound hooks with use-sound
const volume = typeof soundVolume === "number" ? soundVolume : 0.5
const soundConfig = {
volume,
// useSound expects 'disabled' property, not 'soundEnabled'
soundEnabled,
}

// Helper function to get audio URLs that works in both development and Jest environments
const getAudioUrl = (path: string) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return `${window.AUDIO_BASE_URI}/${path}`
}

// Use the getAudioUrl helper function
const [playNotification] = useSound(getAudioUrl("notification.wav"), soundConfig)
const [playCelebration] = useSound(getAudioUrl("celebration.wav"), soundConfig)
const [playProgressLoop] = useSound(getAudioUrl("progress_loop.wav"), soundConfig)

function playSound(audioType: AudioType) {
vscode.postMessage({ type: "playSound", audioType })
// Play the appropriate sound based on type
// The disabled state is handled by the useSound hook configuration
switch (audioType) {
case "notification":
playNotification()
break
case "celebration":
playCelebration()
break
case "progress_loop":
playProgressLoop()
break
default:
console.warn(`Unknown audio type: ${audioType}`)
}
}

function playTts(text: string) {
Expand Down
Loading