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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mock/

# Builds
bin/
roo-cline-*.vsix
*.vsix

# Local prompts and rules
/local-prompts
Expand Down
21 changes: 21 additions & 0 deletions e2e/package-lock.json

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

2 changes: 1 addition & 1 deletion e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"build": "rimraf out && tsc -p tsconfig.json",
"vscode-test": "cd .. && npm run vscode-test"
},
"dependencies": {},
"devDependencies": {
"@roo-code/types": "^1.12.0",
"@types/mocha": "^10.0.10",
"@vscode/test-cli": "^0.0.10",
"@vscode/test-electron": "^2.4.0",
Expand Down
47 changes: 35 additions & 12 deletions e2e/src/suite/extension.test.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,47 @@
import * as assert from "assert"
import * as vscode from "vscode"

import { Package } from "@roo-code/types"

suite("Roo Code Extension", () => {
test("Commands should be registered", async () => {
const expectedCommands = [
"roo-cline.plusButtonClicked",
"roo-cline.mcpButtonClicked",
"roo-cline.historyButtonClicked",
"roo-cline.popoutButtonClicked",
"roo-cline.settingsButtonClicked",
"roo-cline.openInNewTab",
"roo-cline.explainCode",
"roo-cline.fixCode",
"roo-cline.improveCode",
"SidebarProvider.open",
"SidebarProvider.focus",
"SidebarProvider.resetViewLocation",
"SidebarProvider.toggleVisibility",
"SidebarProvider.removeView",
"activationCompleted",
"plusButtonClicked",
"mcpButtonClicked",
"promptsButtonClicked",
"popoutButtonClicked",
"openInNewTab",
"settingsButtonClicked",
"historyButtonClicked",
"showHumanRelayDialog",
"registerHumanRelayCallback",
"unregisterHumanRelayCallback",
"handleHumanRelayResponse",
"newTask",
"setCustomStoragePath",
"focusInput",
"acceptInput",
"explainCode",
"fixCode",
"improveCode",
"addToContext",
"terminalAddToContext",
"terminalFixCommand",
"terminalExplainCommand",
]

const commands = await vscode.commands.getCommands(true)
const commands = new Set(
(await vscode.commands.getCommands(true)).filter((cmd) => cmd.startsWith(Package.name)),
)

for (const cmd of expectedCommands) {
assert.ok(commands.includes(cmd), `Command ${cmd} should be registered`)
for (const command of expectedCommands) {
assert.ok(commands.has(`${Package.name}.${command}`), `Command ${command} should be registered`)
}
})
})
6 changes: 3 additions & 3 deletions e2e/src/suite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Mocha from "mocha"
import { glob } from "glob"
import * as vscode from "vscode"

import type { RooCodeAPI } from "../../../src/exports/roo-code"
import { type RooCodeAPI, Package } from "@roo-code/types"

import { waitFor } from "./utils"

Expand All @@ -12,7 +12,7 @@ declare global {
}

export async function run() {
const extension = vscode.extensions.getExtension<RooCodeAPI>("RooVeterinaryInc.roo-cline")
const extension = vscode.extensions.getExtension<RooCodeAPI>(`${Package.publisher}.${Package.name}`)

if (!extension) {
throw new Error("Extension not found")
Expand All @@ -26,7 +26,7 @@ export async function run() {
openRouterModelId: "google/gemini-2.0-flash-001",
})

await vscode.commands.executeCommand("roo-cline.SidebarProvider.focus")
await vscode.commands.executeCommand(`${Package.name}.SidebarProvider.focus`)
await waitFor(() => api.isReady())

// Expose the API to the tests.
Expand Down
2 changes: 1 addition & 1 deletion e2e/src/suite/modes.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as assert from "assert"

import type { ClineMessage } from "../../../src/exports/roo-code"
import type { ClineMessage } from "@roo-code/types"

import { waitUntilCompleted } from "./utils"

Expand Down
2 changes: 1 addition & 1 deletion e2e/src/suite/subtasks.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as assert from "assert"

import type { ClineMessage } from "../../../src/exports/roo-code"
import type { ClineMessage } from "@roo-code/types"

import { sleep, waitFor, waitUntilCompleted } from "./utils"

Expand Down
2 changes: 1 addition & 1 deletion e2e/src/suite/task.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as assert from "assert"

import type { ClineMessage } from "../../../src/exports/roo-code"
import type { ClineMessage } from "@roo-code/types"

import { waitUntilCompleted } from "./utils"

Expand Down
2 changes: 1 addition & 1 deletion e2e/src/suite/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { RooCodeAPI } from "../../../src/exports/roo-code"
import type { RooCodeAPI } from "@roo-code/types"

type WaitForOptions = {
timeout?: number
Expand Down
46 changes: 13 additions & 33 deletions src/activate/CodeActionProvider.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,17 @@
import * as vscode from "vscode"

import { CodeActionName, CodeActionId } from "../schemas"
import { getCodeActionCommand } from "../utils/commands"
import { EditorUtils } from "../integrations/editor/EditorUtils"

export type CodeActionName = "EXPLAIN" | "FIX" | "IMPROVE" | "ADD_TO_CONTEXT" | "NEW_TASK"

export type CodeActionId =
| "roo-cline.explainCode"
| "roo-cline.fixCode"
| "roo-cline.improveCode"
| "roo-cline.addToContext"
| "roo-cline.newTask"

export const ACTION_TITLES: Record<CodeActionName, string> = {
export const TITLES: Record<CodeActionName, string> = {
EXPLAIN: "Explain with Roo Code",
FIX: "Fix with Roo Code",
IMPROVE: "Improve with Roo Code",
ADD_TO_CONTEXT: "Add to Roo Code",
NEW_TASK: "New Roo Code Task",
} as const

export const COMMAND_IDS: Record<CodeActionName, CodeActionId> = {
EXPLAIN: "roo-cline.explainCode",
FIX: "roo-cline.fixCode",
IMPROVE: "roo-cline.improveCode",
ADD_TO_CONTEXT: "roo-cline.addToContext",
NEW_TASK: "roo-cline.newTask",
} as const

export class CodeActionProvider implements vscode.CodeActionProvider {
public static readonly providedCodeActionKinds = [
vscode.CodeActionKind.QuickFix,
Expand All @@ -40,7 +25,7 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
args: any[],
): vscode.CodeAction {
const action = new vscode.CodeAction(title, kind)
action.command = { command, title, arguments: args }
action.command = { command: getCodeActionCommand(command), title, arguments: args }
return action
}

Expand All @@ -60,17 +45,12 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
const actions: vscode.CodeAction[] = []

actions.push(
this.createAction(
ACTION_TITLES.ADD_TO_CONTEXT,
vscode.CodeActionKind.QuickFix,
COMMAND_IDS.ADD_TO_CONTEXT,
[
filePath,
effectiveRange.text,
effectiveRange.range.start.line + 1,
effectiveRange.range.end.line + 1,
],
),
this.createAction(TITLES.ADD_TO_CONTEXT, vscode.CodeActionKind.QuickFix, "addToContext", [
filePath,
effectiveRange.text,
effectiveRange.range.start.line + 1,
effectiveRange.range.end.line + 1,
]),
)

if (context.diagnostics.length > 0) {
Expand All @@ -80,7 +60,7 @@ export class CodeActionProvider implements vscode.CodeActionProvider {

if (relevantDiagnostics.length > 0) {
actions.push(
this.createAction(ACTION_TITLES.FIX, vscode.CodeActionKind.QuickFix, COMMAND_IDS.FIX, [
this.createAction(TITLES.FIX, vscode.CodeActionKind.QuickFix, "fixCode", [
filePath,
effectiveRange.text,
effectiveRange.range.start.line + 1,
Expand All @@ -91,7 +71,7 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
}
} else {
actions.push(
this.createAction(ACTION_TITLES.EXPLAIN, vscode.CodeActionKind.QuickFix, COMMAND_IDS.EXPLAIN, [
this.createAction(TITLES.EXPLAIN, vscode.CodeActionKind.QuickFix, "explainCode", [
filePath,
effectiveRange.text,
effectiveRange.range.start.line + 1,
Expand All @@ -100,7 +80,7 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
)

actions.push(
this.createAction(ACTION_TITLES.IMPROVE, vscode.CodeActionKind.QuickFix, COMMAND_IDS.IMPROVE, [
this.createAction(TITLES.IMPROVE, vscode.CodeActionKind.QuickFix, "improveCode", [
filePath,
effectiveRange.text,
effectiveRange.range.start.line + 1,
Expand Down
12 changes: 6 additions & 6 deletions src/activate/__tests__/CodeActionProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as vscode from "vscode"

import { EditorUtils } from "../../integrations/editor/EditorUtils"

import { CodeActionProvider, ACTION_TITLES } from "../CodeActionProvider"
import { CodeActionProvider, TITLES } from "../CodeActionProvider"

jest.mock("vscode", () => ({
CodeAction: jest.fn().mockImplementation((title, kind) => ({
Expand Down Expand Up @@ -70,9 +70,9 @@ describe("CodeActionProvider", () => {
const actions = provider.provideCodeActions(mockDocument, mockRange, mockContext)

expect(actions).toHaveLength(3)
expect((actions as any)[0].title).toBe(ACTION_TITLES.ADD_TO_CONTEXT)
expect((actions as any)[1].title).toBe(ACTION_TITLES.EXPLAIN)
expect((actions as any)[2].title).toBe(ACTION_TITLES.IMPROVE)
expect((actions as any)[0].title).toBe(TITLES.ADD_TO_CONTEXT)
expect((actions as any)[1].title).toBe(TITLES.EXPLAIN)
expect((actions as any)[2].title).toBe(TITLES.IMPROVE)
})

it("should provide fix action instead of fix logic when diagnostics exist", () => {
Expand All @@ -83,8 +83,8 @@ describe("CodeActionProvider", () => {
const actions = provider.provideCodeActions(mockDocument, mockRange, mockContext)

expect(actions).toHaveLength(2)
expect((actions as any).some((a: any) => a.title === `${ACTION_TITLES.FIX}`)).toBe(true)
expect((actions as any).some((a: any) => a.title === `${ACTION_TITLES.ADD_TO_CONTEXT}`)).toBe(true)
expect((actions as any).some((a: any) => a.title === `${TITLES.FIX}`)).toBe(true)
expect((actions as any).some((a: any) => a.title === `${TITLES.ADD_TO_CONTEXT}`)).toBe(true)
})

it("should return empty array when no effective range", () => {
Expand Down
8 changes: 3 additions & 5 deletions src/activate/handleTask.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import * as vscode from "vscode"

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

import { t } from "../i18n"

import { COMMAND_IDS } from "./CodeActionProvider"

export const handleNewTask = async (params: { prompt?: string } | null | undefined) => {
let prompt = params?.prompt

Expand All @@ -17,9 +15,9 @@ export const handleNewTask = async (params: { prompt?: string } | null | undefin
}

if (!prompt) {
await vscode.commands.executeCommand("roo-cline.SidebarProvider.focus")
await vscode.commands.executeCommand(`${Package.name}.SidebarProvider.focus`)
Copy link
Collaborator Author

@cte cte May 20, 2025

Choose a reason for hiding this comment

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

As a follow-up we might want to add a vscode utility that packages up wraps command execution for better DX.

For example:

export const focusSidebar = () =>
  vscode.commands.executeCommand(`${Package.name}.SidebarProvider.focus`)

return
}

await ClineProvider.handleCodeAction(COMMAND_IDS.NEW_TASK, "NEW_TASK", { userInput: prompt })
await ClineProvider.handleCodeAction("newTask", "NEW_TASK", { userInput: prompt })
}
14 changes: 7 additions & 7 deletions src/activate/registerCodeActions.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import * as vscode from "vscode"

import { CodeActionId, CodeActionName } from "../schemas"
import { getCodeActionCommand } from "../utils/commands"
import { EditorUtils } from "../integrations/editor/EditorUtils"
import { ClineProvider } from "../core/webview/ClineProvider"

import { type CodeActionName, type CodeActionId, COMMAND_IDS } from "./CodeActionProvider"

export const registerCodeActions = (context: vscode.ExtensionContext) => {
registerCodeAction(context, COMMAND_IDS.EXPLAIN, "EXPLAIN")
registerCodeAction(context, COMMAND_IDS.FIX, "FIX")
registerCodeAction(context, COMMAND_IDS.IMPROVE, "IMPROVE")
registerCodeAction(context, COMMAND_IDS.ADD_TO_CONTEXT, "ADD_TO_CONTEXT")
registerCodeAction(context, "explainCode", "EXPLAIN")
registerCodeAction(context, "fixCode", "FIX")
registerCodeAction(context, "improveCode", "IMPROVE")
registerCodeAction(context, "addToContext", "ADD_TO_CONTEXT")
}

const registerCodeAction = (context: vscode.ExtensionContext, command: CodeActionId, promptType: CodeActionName) => {
let userInput: string | undefined

context.subscriptions.push(
vscode.commands.registerCommand(command, async (...args: any[]) => {
vscode.commands.registerCommand(getCodeActionCommand(command), async (...args: any[]) => {
// Handle both code action and direct command cases.
let filePath: string
let selectedText: string
Expand Down
Loading
Loading