diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 4c4d53d..afbae37 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -205,10 +205,10 @@ export class Cline { const taskMessage = this.clineMessages[0] // first message is always the task say const lastRelevantMessage = this.clineMessages[ - findLastIndex( - this.clineMessages, - (m) => !(m.ask === "resume_task" || m.ask === "resume_completed_task"), - ) + findLastIndex( + this.clineMessages, + (m) => !(m.ask === "resume_task" || m.ask === "resume_completed_task"), + ) ] await this.providerRef.deref()?.updateTaskHistory({ id: this.taskId, @@ -390,7 +390,8 @@ export class Cline { async sayAndCreateMissingParamError(toolName: ToolUseName, paramName: string, relPath?: string) { await this.say( "error", - `Cline tried to use ${toolName}${relPath ? ` for '${relPath.toPosix()}'` : "" + `Cline tried to use ${toolName}${ + relPath ? ` for '${relPath.toPosix()}'` : "" } without value for required parameter '${paramName}'. Retrying...`, ) return formatResponse.toolError(formatResponse.missingToolParameterError(paramName)) @@ -448,7 +449,7 @@ export class Cline { // need to make sure that the api conversation history can be resumed by the api, even if it goes out of sync with cline messages let existingApiConversationHistory: Anthropic.Messages.MessageParam[] = - await this.getSavedApiConversationHistory() + await this.getSavedApiConversationHistory() // Now present the cline messages to the user and ask if they want to resume @@ -559,8 +560,8 @@ export class Cline { : [{ type: "text", text: lastMessage.content }] if (previousAssistantMessage && previousAssistantMessage.role === "assistant") { const assistantContent = Array.isArray(previousAssistantMessage.content) - ? previousAssistantMessage.content - : [{ type: "text", text: previousAssistantMessage.content }] + ? previousAssistantMessage.content + : [{ type: "text", text: previousAssistantMessage.content }] const toolUseBlocks = assistantContent.filter( (block) => block.type === "tool_use", @@ -625,9 +626,10 @@ export class Cline { newUserContent.push({ type: "text", text: - `[TASK RESUMPTION] This task was interrupted ${agoText}. It may or may not be complete, so please reassess the task context. Be aware that the project state may have changed since then. The current working directory is now '${cwd.toPosix()}'. If the task has not been completed, retry the last step before interruption and proceed with completing the task.\n\nNote: If you previously attempted a tool use that the user did not provide a result for, you should assume the tool use was not successful and assess whether you should retry. If the last tool was a browser_action, the browser has been closed and you must launch a new browser if needed.${wasRecent - ? "\n\nIMPORTANT: If the last tool use was a write_to_file that was interrupted, the file was reverted back to its original state before the interrupted edit, and you do NOT need to re-read the file as you already have its up-to-date contents." - : "" + `[TASK RESUMPTION] This task was interrupted ${agoText}. It may or may not be complete, so please reassess the task context. Be aware that the project state may have changed since then. The current working directory is now '${cwd.toPosix()}'. If the task has not been completed, retry the last step before interruption and proceed with completing the task.\n\nNote: If you previously attempted a tool use that the user did not provide a result for, you should assume the tool use was not successful and assess whether you should retry. If the last tool was a browser_action, the browser has been closed and you must launch a new browser if needed.${ + wasRecent + ? "\n\nIMPORTANT: If the last tool use was a write_to_file that was interrupted, the file was reverted back to its original state before the interrupted edit, and you do NOT need to re-read the file as you already have its up-to-date contents." + : "" }` + (responseText ? `\n\nNew instructions for task continuation:\n\n${responseText}\n` @@ -741,7 +743,8 @@ export class Cline { return [ true, formatResponse.toolResult( - `Command is still running in the user's terminal.${result.length > 0 ? `\nHere's the output so far:\n${result}` : "" + `Command is still running in the user's terminal.${ + result.length > 0 ? `\nHere's the output so far:\n${result}` : "" }\n\nThe user provided the following feedback:\n\n${userFeedback.text}\n`, userFeedback.images, ), @@ -753,7 +756,8 @@ export class Cline { } else { return [ false, - `Command is still running in the user's terminal.${result.length > 0 ? `\nHere's the output so far:\n${result}` : "" + `Command is still running in the user's terminal.${ + result.length > 0 ? `\nHere's the output so far:\n${result}` : "" }\n\nYou will be updated on the terminal status and new output in the future.`, ] } @@ -931,8 +935,9 @@ export class Cline { case "apply_diff": return `[${block.name} for '${block.params.path}']` case "search_files": - return `[${block.name} for '${block.params.regex}'${block.params.file_pattern ? ` in '${block.params.file_pattern}'` : "" - }]` + return `[${block.name} for '${block.params.regex}'${ + block.params.file_pattern ? ` in '${block.params.file_pattern}'` : "" + }]` case "list_files": return `[${block.name} for '${block.params.path}']` case "list_code_definition_names": @@ -1118,7 +1123,7 @@ export class Cline { if (block.partial) { // update gui message const partialMessage = JSON.stringify(sharedMessageProps) - await this.ask("tool", partialMessage, block.partial).catch(() => { }) + await this.ask("tool", partialMessage, block.partial).catch(() => {}) // update editor if (!this.diffViewProvider.isEditing) { // open the editor and prepare to stream content in @@ -1154,7 +1159,7 @@ export class Cline { if (!this.diffViewProvider.isEditing) { // show gui message before showing edit animation const partialMessage = JSON.stringify(sharedMessageProps) - await this.ask("tool", partialMessage, true).catch(() => { }) // sending true for partial even though it's not a partial, this shows the edit row before the content is streamed into the editor + await this.ask("tool", partialMessage, true).catch(() => {}) // sending true for partial even though it's not a partial, this shows the edit row before the content is streamed into the editor await this.diffViewProvider.open(relPath) } await this.diffViewProvider.update(everyLineHasLineNumbers(newContent) ? stripLineNumbers(newContent) : newContent, true) @@ -1192,10 +1197,10 @@ export class Cline { content: fileExists ? undefined : newContent, diff: fileExists ? formatResponse.createPrettyPatch( - relPath, - this.diffViewProvider.originalContent, - newContent, - ) + relPath, + this.diffViewProvider.originalContent, + newContent, + ) : undefined, } satisfies ClineSayTool) const didApprove = await askApproval("tool", completeMessage) @@ -1217,13 +1222,13 @@ export class Cline { ) pushToolResult( `The user made the following updates to your content:\n\n${userEdits}\n\n` + - `The updated content, which includes both your original modifications and the user's edits, has been successfully saved to ${relPath.toPosix()}. Here is the full, updated content of the file, including line numbers:\n\n` + - `\n${addLineNumbers(finalContent || '')}\n\n\n` + - `Please note:\n` + - `1. You do not need to re-write the file with these changes, as they have already been applied.\n` + - `2. Proceed with the task using this updated file content as the new baseline.\n` + - `3. If the user's edits have addressed part of the task or changed the requirements, adjust your approach accordingly.` + - `${newProblemsMessage}`, + `The updated content, which includes both your original modifications and the user's edits, has been successfully saved to ${relPath.toPosix()}. Here is the full, updated content of the file, including line numbers:\n\n` + + `\n${addLineNumbers(finalContent || '')}\n\n\n` + + `Please note:\n` + + `1. You do not need to re-write the file with these changes, as they have already been applied.\n` + + `2. Proceed with the task using this updated file content as the new baseline.\n` + + `3. If the user's edits have addressed part of the task or changed the requirements, adjust your approach accordingly.` + + `${newProblemsMessage}`, ) } else { pushToolResult( @@ -1252,7 +1257,7 @@ export class Cline { if (block.partial) { // update gui message const partialMessage = JSON.stringify(sharedMessageProps) - await this.ask("tool", partialMessage, block.partial).catch(() => { }) + await this.ask("tool", partialMessage, block.partial).catch(() => {}) break } else { if (!relPath) { @@ -1281,9 +1286,9 @@ export class Cline { // Apply the diff to the original content const diffResult = this.diffStrategy?.applyDiff( - originalContent, - diffContent, - parseInt(block.params.start_line ?? ''), + originalContent, + diffContent, + parseInt(block.params.start_line ?? ''), parseInt(block.params.end_line ?? '') ) ?? { success: false, @@ -1335,13 +1340,13 @@ export class Cline { ) pushToolResult( `The user made the following updates to your content:\n\n${userEdits}\n\n` + - `The updated content, which includes both your original modifications and the user's edits, has been successfully saved to ${relPath.toPosix()}. Here is the full, updated content of the file, including line numbers:\n\n` + - `\n${addLineNumbers(finalContent || '')}\n\n\n` + - `Please note:\n` + - `1. You do not need to re-write the file with these changes, as they have already been applied.\n` + - `2. Proceed with the task using this updated file content as the new baseline.\n` + - `3. If the user's edits have addressed part of the task or changed the requirements, adjust your approach accordingly.` + - `${newProblemsMessage}`, + `The updated content, which includes both your original modifications and the user's edits, has been successfully saved to ${relPath.toPosix()}. Here is the full, updated content of the file, including line numbers:\n\n` + + `\n${addLineNumbers(finalContent || '')}\n\n\n` + + `Please note:\n` + + `1. You do not need to re-write the file with these changes, as they have already been applied.\n` + + `2. Proceed with the task using this updated file content as the new baseline.\n` + + `3. If the user's edits have addressed part of the task or changed the requirements, adjust your approach accordingly.` + + `${newProblemsMessage}`, ) } else { pushToolResult(`Changes successfully applied to ${relPath.toPosix()}:\n\n${newProblemsMessage}`) @@ -1367,7 +1372,7 @@ export class Cline { ...sharedMessageProps, content: undefined, } satisfies ClineSayTool) - await this.ask("tool", partialMessage, block.partial).catch(() => { }) + await this.ask("tool", partialMessage, block.partial).catch(() => {}) break } else { if (!relPath) { @@ -1409,7 +1414,7 @@ export class Cline { ...sharedMessageProps, content: "", } satisfies ClineSayTool) - await this.ask("tool", partialMessage, block.partial).catch(() => { }) + await this.ask("tool", partialMessage, block.partial).catch(() => {}) break } else { if (!relDirPath) { @@ -1449,7 +1454,7 @@ export class Cline { ...sharedMessageProps, content: "", } satisfies ClineSayTool) - await this.ask("tool", partialMessage, block.partial).catch(() => { }) + await this.ask("tool", partialMessage, block.partial).catch(() => {}) break } else { if (!relDirPath) { @@ -1494,7 +1499,7 @@ export class Cline { ...sharedMessageProps, content: "", } satisfies ClineSayTool) - await this.ask("tool", partialMessage, block.partial).catch(() => { }) + await this.ask("tool", partialMessage, block.partial).catch(() => {}) break } else { if (!relDirPath) { @@ -1549,7 +1554,7 @@ export class Cline { "browser_action_launch", removeClosingTag("url", url), block.partial - ).catch(() => { }) + ).catch(() => {}) } else { await this.say( "browser_action", @@ -1649,7 +1654,8 @@ export class Cline { await this.say("browser_action_result", JSON.stringify(browserActionResult)) pushToolResult( formatResponse.toolResult( - `The browser action has been executed. The console logs and screenshot have been captured for your analysis.\n\nConsole logs:\n${browserActionResult.logs || "(No new logs)" + `The browser action has been executed. The console logs and screenshot have been captured for your analysis.\n\nConsole logs:\n${ + browserActionResult.logs || "(No new logs)" }\n\n(REMEMBER: if you need to proceed to using non-\`browser_action\` tools or launch a new browser, you MUST first close this browser. For example, if after analyzing the logs and screenshot you need to edit a file, you must first close the browser before you can use the write_to_file tool.)`, browserActionResult.screenshot ? [browserActionResult.screenshot] : [], ), @@ -1676,7 +1682,7 @@ export class Cline { try { if (block.partial) { await this.ask("command", removeClosingTag("command", command), block.partial).catch( - () => { } + () => {} ) break } else { @@ -1717,7 +1723,7 @@ export class Cline { toolName: removeClosingTag("tool_name", tool_name), arguments: removeClosingTag("arguments", mcp_arguments), } satisfies ClineAskUseMcpServer) - await this.ask("use_mcp_server", partialMessage, block.partial).catch(() => { }) + await this.ask("use_mcp_server", partialMessage, block.partial).catch(() => {}) break } else { if (!server_name) { @@ -1778,19 +1784,19 @@ export class Cline { // TODO: add progress indicator and ability to parse images and non-text responses const toolResultPretty = (toolResult?.isError ? "Error:\n" : "") + - toolResult?.content - .map((item) => { - if (item.type === "text") { - return item.text - } - if (item.type === "resource") { - const { blob, ...rest } = item.resource - return JSON.stringify(rest, null, 2) - } - return "" - }) - .filter(Boolean) - .join("\n\n") || "(No response)" + toolResult?.content + .map((item) => { + if (item.type === "text") { + return item.text + } + if (item.type === "resource") { + const { blob, ...rest } = item.resource + return JSON.stringify(rest, null, 2) + } + return "" + }) + .filter(Boolean) + .join("\n\n") || "(No response)" await this.say("mcp_server_response", toolResultPretty) pushToolResult(formatResponse.toolResult(toolResultPretty)) break @@ -1810,7 +1816,7 @@ export class Cline { serverName: removeClosingTag("server_name", server_name), uri: removeClosingTag("uri", uri), } satisfies ClineAskUseMcpServer) - await this.ask("use_mcp_server", partialMessage, block.partial).catch(() => { }) + await this.ask("use_mcp_server", partialMessage, block.partial).catch(() => {}) break } else { if (!server_name) { @@ -1866,7 +1872,7 @@ export class Cline { try { if (block.partial) { await this.ask("followup", removeClosingTag("question", question), block.partial).catch( - () => { }, + () => {}, ) break } else { @@ -1925,7 +1931,7 @@ export class Cline { "command", removeClosingTag("command", command), block.partial, - ).catch(() => { }) + ).catch(() => {}) } else { // last message is completion_result // we have command string, which means we have the result as well, so finish it (doesnt have to exist yet) @@ -1939,7 +1945,7 @@ export class Cline { "command", removeClosingTag("command", command), block.partial, - ).catch(() => { }) + ).catch(() => {}) } } else { // no command, still outputting partial result @@ -2165,9 +2171,10 @@ export class Cline { type: "text", text: assistantMessage + - `\n\n[${cancelReason === "streaming_failed" - ? "Response interrupted by API Error" - : "Response interrupted by user" + `\n\n[${ + cancelReason === "streaming_failed" + ? "Response interrupted by API Error" + : "Response interrupted by user" }]`, }, ], @@ -2421,7 +2428,7 @@ export class Cline { await pWaitFor(() => busyTerminals.every((t) => !this.terminalManager.isProcessHot(t.id)), { interval: 100, timeout: 15_000, - }).catch(() => { }) + }).catch(() => {}) } // we want to get diagnostics AFTER terminal cools down for a few reasons: terminal could be scaffolding a project, dev servers (compilers like webpack) will first re-compile and then send diagnostics, etc diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index b70d814..579a12e 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -235,7 +235,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { diffEnabled, fuzzyMatchThreshold } = await this.getState() - + this.cline = new Cline( this, apiConfiguration, @@ -255,7 +255,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { diffEnabled, fuzzyMatchThreshold } = await this.getState() - + this.cline = new Cline( this, apiConfiguration, @@ -321,15 +321,15 @@ export class ClineProvider implements vscode.WebviewViewProvider { // Use a nonce to only allow a specific script to be run. /* - content security policy of your webview to only allow scripts that have a specific nonce - create a content security policy meta tag so that only loading scripts with a nonce is allowed - As your extension grows you will likely want to add custom styles, fonts, and/or images to your webview. If you do, you will need to update the content security policy meta tag to explicity allow for these resources. E.g. - + content security policy of your webview to only allow scripts that have a specific nonce + create a content security policy meta tag so that only loading scripts with a nonce is allowed + As your extension grows you will likely want to add custom styles, fonts, and/or images to your webview. If you do, you will need to update the content security policy meta tag to explicity allow for these resources. E.g. + - 'unsafe-inline' is required for styles due to vscode-webview-toolkit's dynamic style injection - since we pass base64 images to the webview, we need to specify img-src ${webview.cspSource} data:; - in meta tag we add nonce attribute: A cryptographic nonce (only used once) to allow scripts. The server must generate a unique nonce value each time it transmits a policy. It is critical to provide a nonce that cannot be guessed as bypassing a resource's policy is otherwise trivial. - */ + in meta tag we add nonce attribute: A cryptographic nonce (only used once) to allow scripts. The server must generate a unique nonce value each time it transmits a policy. It is critical to provide a nonce that cannot be guessed as bypassing a resource's policy is otherwise trivial. + */ const nonce = getNonce() // Tip: Install the es6-string-html VS Code extension to enable code highlighting below @@ -557,7 +557,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { this.postMessageToWebview({ type: "lmStudioModels", lmStudioModels }) break case "refreshGlamaModels": - await this.refreshGlamaModels() + await this.refreshGlamaModels() break case "refreshOpenRouterModels": await this.refreshOpenRouterModels() @@ -566,7 +566,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { if (message?.values?.baseUrl && message?.values?.apiKey) { const openAiModels = await this.getOpenAiModels(message?.values?.baseUrl, message?.values?.apiKey) this.postMessageToWebview({ type: "openAiModels", openAiModels }) - } + } break case "openImage": openImage(message.text!) @@ -1257,7 +1257,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { alwaysApproveResubmit, requestDelaySeconds, } = await this.getState() - + const allowedCommands = vscode.workspace .getConfiguration('roo-cline') .get('allowedCommands') || [] diff --git a/src/core/webview/__tests__/ClineProvider.test.ts b/src/core/webview/__tests__/ClineProvider.test.ts index c3470fe..0a7ee9a 100644 --- a/src/core/webview/__tests__/ClineProvider.test.ts +++ b/src/core/webview/__tests__/ClineProvider.test.ts @@ -146,8 +146,8 @@ jest.mock('../../../integrations/misc/extract-text', () => ({ // Spy on console.error and console.log to suppress expected messages beforeAll(() => { - jest.spyOn(console, 'error').mockImplementation(() => { }) - jest.spyOn(console, 'log').mockImplementation(() => { }) + jest.spyOn(console, 'error').mockImplementation(() => {}) + jest.spyOn(console, 'log').mockImplementation(() => {}) }) afterAll(() => { @@ -230,7 +230,7 @@ describe('ClineProvider', () => { test('resolveWebviewView sets up webview correctly', () => { provider.resolveWebviewView(mockWebviewView) - + expect(mockWebviewView.webview.options).toEqual({ enableScripts: true, localResourceRoots: [mockContext.extensionUri] @@ -240,7 +240,7 @@ describe('ClineProvider', () => { test('postMessageToWebview sends message to webview', async () => { provider.resolveWebviewView(mockWebviewView) - + const mockState: ExtensionState = { version: '1.0.0', preferredLanguage: 'English', @@ -263,16 +263,15 @@ describe('ClineProvider', () => { browserViewportSize: "900x600", fuzzyMatchThreshold: 1.0, mcpEnabled: true, - alwaysApproveResubmit: false, - requestDelaySeconds: 5, + requestDelaySeconds: 5 } - - const message: ExtensionMessage = { - type: 'state', + + const message: ExtensionMessage = { + type: 'state', state: mockState } await provider.postMessageToWebview(message) - + expect(mockPostMessage).toHaveBeenCalledWith(message) }) @@ -303,7 +302,7 @@ describe('ClineProvider', () => { test('getState returns correct initial state', async () => { const state = await provider.getState() - + expect(state).toHaveProperty('apiConfiguration') expect(state.apiConfiguration).toHaveProperty('apiProvider') expect(state).toHaveProperty('customInstructions') @@ -320,7 +319,7 @@ describe('ClineProvider', () => { test('preferredLanguage defaults to VSCode language when not set', async () => { // Mock VSCode language as Spanish (vscode.env as any).language = 'es-ES'; - + const state = await provider.getState(); expect(state.preferredLanguage).toBe('Spanish'); }) @@ -328,7 +327,7 @@ describe('ClineProvider', () => { test('preferredLanguage defaults to English for unsupported VSCode language', async () => { // Mock VSCode language as an unsupported language (vscode.env as any).language = 'unsupported-LANG'; - + const state = await provider.getState(); expect(state.preferredLanguage).toBe('English'); }) @@ -336,9 +335,9 @@ describe('ClineProvider', () => { test('diffEnabled defaults to true when not set', async () => { // Mock globalState.get to return undefined for diffEnabled (mockContext.globalState.get as jest.Mock).mockReturnValue(undefined) - + const state = await provider.getState() - + expect(state.diffEnabled).toBe(true) }) @@ -350,7 +349,7 @@ describe('ClineProvider', () => { } return null }) - + const state = await provider.getState() expect(state.writeDelayMs).toBe(1000) }) @@ -358,9 +357,9 @@ describe('ClineProvider', () => { test('handles writeDelayMs message', async () => { provider.resolveWebviewView(mockWebviewView) const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0] - + await messageHandler({ type: 'writeDelayMs', value: 2000 }) - + expect(mockContext.globalState.update).toHaveBeenCalledWith('writeDelayMs', 2000) expect(mockPostMessage).toHaveBeenCalled() }) diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index f9e5c61..6b877a0 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -8,28 +8,28 @@ import { GitCommit } from "../utils/git" // webview will hold state export interface ExtensionMessage { type: - | "action" - | "state" - | "selectedImages" - | "ollamaModels" - | "lmStudioModels" - | "theme" - | "workspaceUpdated" - | "invoke" - | "partialMessage" - | "glamaModels" - | "openRouterModels" - | "openAiModels" - | "mcpServers" - | "enhancedPrompt" - | "commitSearchResults" + | "action" + | "state" + | "selectedImages" + | "ollamaModels" + | "lmStudioModels" + | "theme" + | "workspaceUpdated" + | "invoke" + | "partialMessage" + | "glamaModels" + | "openRouterModels" + | "openAiModels" + | "mcpServers" + | "enhancedPrompt" + | "commitSearchResults" text?: string action?: - | "chatButtonClicked" - | "mcpButtonClicked" - | "settingsButtonClicked" - | "historyButtonClicked" - | "didBecomeVisible" + | "chatButtonClicked" + | "mcpButtonClicked" + | "settingsButtonClicked" + | "historyButtonClicked" + | "didBecomeVisible" invoke?: "sendMessage" | "primaryButtonClick" | "secondaryButtonClick" state?: ExtensionState images?: string[] @@ -117,14 +117,14 @@ export type ClineSay = export interface ClineSayTool { tool: - | "editedExistingFile" - | "appliedDiff" - | "newFileCreated" - | "readFile" - | "listFilesTopLevel" - | "listFilesRecursive" - | "listCodeDefinitionNames" - | "searchFiles" + | "editedExistingFile" + | "appliedDiff" + | "newFileCreated" + | "readFile" + | "listFilesTopLevel" + | "listFilesRecursive" + | "listCodeDefinitionNames" + | "searchFiles" path?: string diff?: string content?: string diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index e5c9b64..0ca7cb3 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -1,59 +1,59 @@ -import { ApiConfiguration } from "./api" +import { ApiConfiguration, ApiProvider } from "./api" export type AudioType = "notification" | "celebration" | "progress_loop" export interface WebviewMessage { type: - | "apiConfiguration" - | "customInstructions" - | "allowedCommands" - | "alwaysAllowReadOnly" - | "alwaysAllowWrite" - | "alwaysAllowExecute" - | "webviewDidLaunch" - | "newTask" - | "askResponse" - | "clearTask" - | "didShowAnnouncement" - | "selectImages" - | "exportCurrentTask" - | "showTaskWithId" - | "deleteTaskWithId" - | "exportTaskWithId" - | "resetState" - | "requestOllamaModels" - | "requestLmStudioModels" - | "openImage" - | "openFile" - | "openMention" - | "cancelTask" - | "refreshGlamaModels" - | "refreshOpenRouterModels" - | "refreshOpenAiModels" - | "alwaysAllowBrowser" - | "alwaysAllowMcp" - | "playSound" - | "soundEnabled" - | "soundVolume" - | "diffEnabled" - | "browserViewportSize" - | "screenshotQuality" - | "openMcpSettings" - | "restartMcpServer" - | "toggleToolAlwaysAllow" - | "toggleMcpServer" - | "fuzzyMatchThreshold" - | "preferredLanguage" - | "writeDelayMs" - | "enhancePrompt" - | "enhancedPrompt" - | "draggedImages" - | "deleteMessage" - | "terminalOutputLineLimit" - | "mcpEnabled" - | "searchCommits" - | "alwaysApproveResubmit" - | "requestDelaySeconds" + | "apiConfiguration" + | "customInstructions" + | "allowedCommands" + | "alwaysAllowReadOnly" + | "alwaysAllowWrite" + | "alwaysAllowExecute" + | "webviewDidLaunch" + | "newTask" + | "askResponse" + | "clearTask" + | "didShowAnnouncement" + | "selectImages" + | "exportCurrentTask" + | "showTaskWithId" + | "deleteTaskWithId" + | "exportTaskWithId" + | "resetState" + | "requestOllamaModels" + | "requestLmStudioModels" + | "openImage" + | "openFile" + | "openMention" + | "cancelTask" + | "refreshGlamaModels" + | "refreshOpenRouterModels" + | "refreshOpenAiModels" + | "alwaysAllowBrowser" + | "alwaysAllowMcp" + | "playSound" + | "soundEnabled" + | "soundVolume" + | "diffEnabled" + | "browserViewportSize" + | "screenshotQuality" + | "openMcpSettings" + | "restartMcpServer" + | "toggleToolAlwaysAllow" + | "toggleMcpServer" + | "fuzzyMatchThreshold" + | "preferredLanguage" + | "writeDelayMs" + | "enhancePrompt" + | "enhancedPrompt" + | "draggedImages" + | "deleteMessage" + | "terminalOutputLineLimit" + | "mcpEnabled" + | "searchCommits" + | "alwaysApproveResubmit" + | "requestDelaySeconds" text?: string disabled?: boolean askResponse?: ClineAskResponse diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index b6a922d..131364b 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -96,18 +96,18 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode const config = message.state?.apiConfiguration const hasKey = config ? [ - config.apiKey, - config.glamaApiKey, - config.openRouterApiKey, - config.awsRegion, - config.vertexProjectId, - config.openAiApiKey, - config.ollamaModelId, - config.lmStudioModelId, - config.geminiApiKey, - config.openAiNativeApiKey, - config.deepSeekApiKey, - ].some((key) => key !== undefined) + config.apiKey, + config.glamaApiKey, + config.openRouterApiKey, + config.awsRegion, + config.vertexProjectId, + config.openAiApiKey, + config.ollamaModelId, + config.lmStudioModelId, + config.geminiApiKey, + config.openAiNativeApiKey, + config.deepSeekApiKey, + ].some((key) => key !== undefined) : false setShowWelcome(!hasKey) setDidHydrateState(true)