Skip to content
Merged
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
37 changes: 37 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,43 @@
"group": "navigation@7",
"when": "view == roo-cline.SidebarProvider"
}
],
"editor/title": [
{
"command": "roo-cline.plusButtonClicked",
"group": "navigation@1",
"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
},
{
"command": "roo-cline.promptsButtonClicked",
"group": "navigation@2",
"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
},
{
"command": "roo-cline.mcpButtonClicked",
"group": "navigation@3",
"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
},
{
"command": "roo-cline.historyButtonClicked",
"group": "navigation@4",
"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
},
{
"command": "roo-cline.popoutButtonClicked",
"group": "navigation@5",
"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
},
{
"command": "roo-cline.settingsButtonClicked",
"group": "navigation@6",
"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
},
{
"command": "roo-cline.helpButtonClicked",
"group": "navigation@7",
"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
}
]
},
"configuration": {
Expand Down
54 changes: 54 additions & 0 deletions src/activate/__tests__/registerCommands.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
jest.mock("vscode", () => ({
CodeActionKind: {
QuickFix: { value: "quickfix" },
RefactorRewrite: { value: "refactor.rewrite" },
},
window: {
createTextEditorDecorationType: jest.fn().mockReturnValue({ dispose: jest.fn() }),
},
}))

import * as vscode from "vscode"
import { ClineProvider } from "../../core/webview/ClineProvider"

// Import the helper function from the actual file
import { getVisibleProviderOrLog } from "../registerCommands"

jest.mock("../../core/webview/ClineProvider")

describe("getVisibleProviderOrLog", () => {
let mockOutputChannel: vscode.OutputChannel

beforeEach(() => {
mockOutputChannel = {
appendLine: jest.fn(),
append: jest.fn(),
clear: jest.fn(),
hide: jest.fn(),
name: "mock",
replace: jest.fn(),
show: jest.fn(),
dispose: jest.fn(),
}
jest.clearAllMocks()
})

it("returns the visible provider if found", () => {
const mockProvider = {} as ClineProvider
;(ClineProvider.getVisibleInstance as jest.Mock).mockReturnValue(mockProvider)

const result = getVisibleProviderOrLog(mockOutputChannel)

expect(result).toBe(mockProvider)
expect(mockOutputChannel.appendLine).not.toHaveBeenCalled()
})

it("logs and returns undefined if no provider found", () => {
;(ClineProvider.getVisibleInstance as jest.Mock).mockReturnValue(undefined)

const result = getVisibleProviderOrLog(mockOutputChannel)

expect(result).toBeUndefined()
expect(mockOutputChannel.appendLine).toHaveBeenCalledWith("Cannot find any visible Cline instances.")
})
})
36 changes: 29 additions & 7 deletions src/activate/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ import delay from "delay"

import { ClineProvider } from "../core/webview/ClineProvider"

/**
* Helper to get the visible ClineProvider instance or log if not found.
*/
export function getVisibleProviderOrLog(outputChannel: vscode.OutputChannel): ClineProvider | undefined {
const visibleProvider = ClineProvider.getVisibleInstance()
if (!visibleProvider) {
outputChannel.appendLine("Cannot find any visible Cline instances.")
return undefined
}
return visibleProvider
}

import { registerHumanRelayCallback, unregisterHumanRelayCallback, handleHumanRelayResponse } from "./humanRelay"
import { handleNewTask } from "./handleTask"

Expand Down Expand Up @@ -52,23 +64,33 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt
return {
"roo-cline.activationCompleted": () => {},
"roo-cline.plusButtonClicked": async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding try/catch blocks in these asynchronous command callbacks (e.g., in roo-cline.plusButtonClicked) to gracefully handle errors arising from provider methods. This will prevent unhandled promise rejections and improve overall extension stability.

await provider.removeClineFromStack()
await provider.postStateToWebview()
await provider.postMessageToWebview({ type: "action", action: "chatButtonClicked" })
const visibleProvider = getVisibleProviderOrLog(outputChannel)
if (!visibleProvider) return
await visibleProvider.removeClineFromStack()
await visibleProvider.postStateToWebview()
await visibleProvider.postMessageToWebview({ type: "action", action: "chatButtonClicked" })
},
"roo-cline.mcpButtonClicked": () => {
provider.postMessageToWebview({ type: "action", action: "mcpButtonClicked" })
const visibleProvider = getVisibleProviderOrLog(outputChannel)
if (!visibleProvider) return
visibleProvider.postMessageToWebview({ type: "action", action: "mcpButtonClicked" })
},
"roo-cline.promptsButtonClicked": () => {
provider.postMessageToWebview({ type: "action", action: "promptsButtonClicked" })
const visibleProvider = getVisibleProviderOrLog(outputChannel)
if (!visibleProvider) return
visibleProvider.postMessageToWebview({ type: "action", action: "promptsButtonClicked" })
},
"roo-cline.popoutButtonClicked": () => openClineInNewTab({ context, outputChannel }),
"roo-cline.openInNewTab": () => openClineInNewTab({ context, outputChannel }),
"roo-cline.settingsButtonClicked": () => {
provider.postMessageToWebview({ type: "action", action: "settingsButtonClicked" })
const visibleProvider = getVisibleProviderOrLog(outputChannel)
if (!visibleProvider) return
visibleProvider.postMessageToWebview({ type: "action", action: "settingsButtonClicked" })
},
"roo-cline.historyButtonClicked": () => {
provider.postMessageToWebview({ type: "action", action: "historyButtonClicked" })
const visibleProvider = getVisibleProviderOrLog(outputChannel)
if (!visibleProvider) return
visibleProvider.postMessageToWebview({ type: "action", action: "historyButtonClicked" })
},
"roo-cline.helpButtonClicked": () => {
vscode.env.openExternal(vscode.Uri.parse("https://docs.roocode.com"))
Expand Down