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
84 changes: 84 additions & 0 deletions src/core/webview/handler/WebviewMessageHandlerRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { WebviewMessage } from "../../../shared/WebviewMessage"
import { registerAutoApprovalHandler } from "./auto-approval"
import { registerNotificationHandler } from "./notification"
import { IWebviewMessageHandler, IWebviewMessageHandlerRegistry } from "./types"

/**
* Singleton registry for managing webview message handlers
* This class maintains a mapping of message types to their respective handlers
*/
export class WebviewMessageHandlerRegistry implements IWebviewMessageHandlerRegistry {
private static instance: WebviewMessageHandlerRegistry
private handlers: Map<WebviewMessage["type"], IWebviewMessageHandler> = new Map()

private constructor() {
this.registerAllHandlers()
}

/**
* Get the singleton instance of the registry
*/
public static getInstance(): WebviewMessageHandlerRegistry {
if (!WebviewMessageHandlerRegistry.instance) {
WebviewMessageHandlerRegistry.instance = new WebviewMessageHandlerRegistry()
}
return WebviewMessageHandlerRegistry.instance
}

/**
* Register a handler for a specific message type
* @param messageType The message type to handle
* @param handler The handler instance
*/
public registerHandler(messageType: WebviewMessage["type"], handler: IWebviewMessageHandler): void {
if (this.handlers.has(messageType)) {
console.warn(`Handler for message type '${messageType}' is already registered. Overwriting.`)
}
this.handlers.set(messageType, handler)
}

/**
* Get a handler for a specific message type
* @param messageType The message type
* @returns The handler instance or undefined if not found
*/
public getHandler(messageType: WebviewMessage["type"]): IWebviewMessageHandler | undefined {
return this.handlers.get(messageType)
}

/**
* Get all registered message types
* @returns Array of registered message types
*/
public getRegisteredTypes(): WebviewMessage["type"][] {
return Array.from(this.handlers.keys())
}

/**
* Check if a message type has a registered handler
* @param messageType The message type to check
* @returns True if handler exists, false otherwise
*/
public hasHandler(messageType: WebviewMessage["type"]): boolean {
return this.handlers.has(messageType)
}

/**
* Register all handlers - this method will be expanded as handlers are created
*/
private registerAllHandlers(): void {
registerAutoApprovalHandler(this)
registerNotificationHandler(this)
}

/**
* Get registry statistics for debugging
* @returns Object containing registry statistics
*/
public getStats(): { totalHandlers: number; registeredTypes: WebviewMessage["type"][] } {
return {
totalHandlers: this.handlers.size,
registeredTypes: this.getRegisteredTypes(),
}
}
}
10 changes: 10 additions & 0 deletions src/core/webview/handler/auto-approval/allowedMaxCostHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AllowedMaxCostHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("allowedMaxCost", message.value)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AllowedMaxRequestsHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("allowedMaxRequests", message.value)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysAllowBrowserHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysAllowBrowser", message.bool ?? undefined)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysAllowExecuteHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysAllowExecute", message.bool ?? undefined)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysAllowFollowupQuestionsHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysAllowFollowupQuestions", message.bool ?? false)
await provider.postStateToWebview()
}
}
10 changes: 10 additions & 0 deletions src/core/webview/handler/auto-approval/alwaysAllowMcpHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysAllowMcpHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysAllowMcp", message.bool)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysAllowModeSwitchHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysAllowModeSwitch", message.bool)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysAllowReadOnlyHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysAllowReadOnly", message.bool ?? undefined)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysAllowReadOnlyOutsideWorkspaceHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysAllowReadOnlyOutsideWorkspace", message.bool ?? undefined)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysAllowSubtasksHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysAllowSubtasks", message.bool)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysAllowUpdateTodoListHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysAllowUpdateTodoList", message.bool)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysAllowWriteHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysAllowWrite", message.bool ?? undefined)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysAllowWriteOutsideWorkspaceHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysAllowWriteOutsideWorkspace", message.bool ?? undefined)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysAllowWriteProtectedHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysAllowWriteProtected", message.bool ?? undefined)
await provider.postStateToWebview()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class AlwaysApproveResubmitHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("alwaysApproveResubmit", message.bool ?? false)
await provider.postStateToWebview()
}
}
34 changes: 34 additions & 0 deletions src/core/webview/handler/auto-approval/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { IWebviewMessageHandlerRegistry } from "../types"
import { AlwaysAllowReadOnlyHandler } from "./alwaysAllowReadOnlyHandler"
import { AlwaysAllowReadOnlyOutsideWorkspaceHandler } from "./alwaysAllowReadOnlyOutsideWorkspaceHandler"
import { AlwaysAllowWriteHandler } from "./alwaysAllowWriteHandler"
import { AlwaysAllowWriteOutsideWorkspaceHandler } from "./alwaysAllowWriteOutsideWorkspaceHandler"
import { AlwaysAllowWriteProtectedHandler } from "./alwaysAllowWriteProtectedHandler"
import { AlwaysAllowExecuteHandler } from "./alwaysAllowExecuteHandler"
import { AlwaysAllowBrowserHandler } from "./alwaysAllowBrowserHandler"
import { AlwaysAllowMcpHandler } from "./alwaysAllowMcpHandler"
import { AlwaysAllowModeSwitchHandler } from "./alwaysAllowModeSwitchHandler"
import { AllowedMaxRequestsHandler } from "./allowedMaxRequestsHandler"
import { AllowedMaxCostHandler } from "./allowedMaxCostHandler"
import { AlwaysAllowSubtasksHandler } from "./alwaysAllowSubtasksHandler"
import { AlwaysAllowUpdateTodoListHandler } from "./alwaysAllowUpdateTodoListHandler"
import { AlwaysApproveResubmitHandler } from "./alwaysApproveResubmitHandler"
import { AlwaysAllowFollowupQuestionsHandler } from "./alwaysAllowFollowupQuestionsHandler"

export function registerAutoApprovalHandler(register: IWebviewMessageHandlerRegistry) {
register.registerHandler("alwaysAllowReadOnly", new AlwaysAllowReadOnlyHandler())
register.registerHandler("alwaysAllowReadOnlyOutsideWorkspace", new AlwaysAllowReadOnlyOutsideWorkspaceHandler())
register.registerHandler("alwaysAllowWrite", new AlwaysAllowWriteHandler())
register.registerHandler("alwaysAllowWriteOutsideWorkspace", new AlwaysAllowWriteOutsideWorkspaceHandler())
register.registerHandler("alwaysAllowWriteProtected", new AlwaysAllowWriteProtectedHandler())
register.registerHandler("alwaysAllowBrowser", new AlwaysAllowBrowserHandler())
register.registerHandler("alwaysAllowExecute", new AlwaysAllowExecuteHandler())
register.registerHandler("alwaysAllowMcp", new AlwaysAllowMcpHandler())
register.registerHandler("alwaysAllowModeSwitch", new AlwaysAllowModeSwitchHandler())
register.registerHandler("allowedMaxRequests", new AllowedMaxRequestsHandler())
register.registerHandler("allowedMaxCost", new AllowedMaxCostHandler())
register.registerHandler("alwaysAllowSubtasks", new AlwaysAllowSubtasksHandler())
register.registerHandler("alwaysAllowUpdateTodoList", new AlwaysAllowUpdateTodoListHandler())
register.registerHandler("alwaysApproveResubmit", new AlwaysApproveResubmitHandler())
register.registerHandler("alwaysAllowFollowupQuestions", new AlwaysAllowFollowupQuestionsHandler())
}
2 changes: 2 additions & 0 deletions src/core/webview/handler/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export type { IWebviewMessageHandler, IWebviewMessageHandlerRegistry } from "./types"
export { WebviewMessageHandlerRegistry } from "./WebviewMessageHandlerRegistry"
16 changes: 16 additions & 0 deletions src/core/webview/handler/notification/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { IWebviewMessageHandlerRegistry } from "../types"
import { SoundEnabledHandler } from "./soundEnabledHandler"
import { SoundVolumeHandler } from "./soundVolumeHandler"
import { TtsEnabledHandler } from "./ttsEnabledHandler"
import { TtsSpeedHandler } from "./ttsSpeedHandler"
import { PlayTtsHandler } from "./playTtsHandler"
import { StopTtsHandler } from "./stopTtsHandler"

export function registerNotificationHandler(register: IWebviewMessageHandlerRegistry) {
register.registerHandler("soundEnabled", new SoundEnabledHandler())
register.registerHandler("soundVolume", new SoundVolumeHandler())
register.registerHandler("ttsEnabled", new TtsEnabledHandler())
register.registerHandler("ttsSpeed", new TtsSpeedHandler())
register.registerHandler("playTts", new PlayTtsHandler())
register.registerHandler("stopTts", new StopTtsHandler())
}
15 changes: 15 additions & 0 deletions src/core/webview/handler/notification/playTtsHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"
import { playTts } from "../../../../utils/tts"

export class PlayTtsHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
if (message.text) {
playTts(message.text, {
onStart: () => provider.postMessageToWebview({ type: "ttsStart", text: message.text }),
onStop: () => provider.postMessageToWebview({ type: "ttsStop", text: message.text }),
})
}
}
}
10 changes: 10 additions & 0 deletions src/core/webview/handler/notification/soundEnabledHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class SoundEnabledHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
await provider.contextProxy.setValue("soundEnabled", message.bool ?? true)
await provider.postStateToWebview()
}
}
11 changes: 11 additions & 0 deletions src/core/webview/handler/notification/soundVolumeHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"

export class SoundVolumeHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
const soundVolume = message.value ?? 0.5
await provider.contextProxy.setValue("soundVolume", soundVolume)
await provider.postStateToWebview()
}
}
10 changes: 10 additions & 0 deletions src/core/webview/handler/notification/stopTtsHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"
import { stopTts } from "../../../../utils/tts"

export class StopTtsHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
stopTts()
}
}
13 changes: 13 additions & 0 deletions src/core/webview/handler/notification/ttsEnabledHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"
import { setTtsEnabled } from "../../../../utils/tts"

export class TtsEnabledHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
const ttsEnabled = message.bool ?? true
await provider.contextProxy.setValue("ttsEnabled", ttsEnabled)
setTtsEnabled(ttsEnabled)
await provider.postStateToWebview()
}
}
13 changes: 13 additions & 0 deletions src/core/webview/handler/notification/ttsSpeedHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { IWebviewMessageHandler } from "../types"
import { ClineProvider } from "../../ClineProvider"
import { WebviewMessage } from "../../../../shared/WebviewMessage"
import { setTtsSpeed } from "../../../../utils/tts"

export class TtsSpeedHandler implements IWebviewMessageHandler {
async handle(provider: ClineProvider, message: WebviewMessage): Promise<void> {
const ttsSpeed = message.value ?? 1.0
await provider.contextProxy.setValue("ttsSpeed", ttsSpeed)
setTtsSpeed(ttsSpeed)
await provider.postStateToWebview()
}
}
Loading
Loading