diff --git a/.gitignore b/.gitignore index 6e90445e1bd..4085bb84863 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,7 @@ mock/ # Builds bin/ -roo-cline-*.vsix +*.vsix # Local prompts and rules /local-prompts diff --git a/e2e/package-lock.json b/e2e/package-lock.json index e7f75013fdc..bb6a34c0825 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -8,6 +8,7 @@ "name": "e2e", "version": "0.1.0", "devDependencies": { + "@roo-code/types": "^1.12.0", "@types/mocha": "^10.0.10", "@vscode/test-cli": "^0.0.10", "@vscode/test-electron": "^2.4.0", @@ -89,6 +90,16 @@ "node": ">=14" } }, + "node_modules/@roo-code/types": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@roo-code/types/-/types-1.12.0.tgz", + "integrity": "sha512-djdZ4lzsiOc+umX357JvcSwRlAMm05P+8DU58IFyZERmEh8wkm4TglDuaaRVGtQSHw9YGFikqfruLtZSEb7zJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^3.24.4" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -2344,6 +2355,16 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.25.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.8.tgz", + "integrity": "sha512-iJPWX8HoZ2VE21VrhHGU9jVo/kVDUQyqM9vF0MxDhW/fp2sAl1eVwGJgiYZdHGiMwQJImXIW80lKk0MnfDxqiQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/e2e/package.json b/e2e/package.json index 604c96a56c2..22d76db6b5d 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -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", diff --git a/e2e/src/suite/extension.test.ts b/e2e/src/suite/extension.test.ts index 1f448246102..54544a26273 100644 --- a/e2e/src/suite/extension.test.ts +++ b/e2e/src/suite/extension.test.ts @@ -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`) } }) }) diff --git a/e2e/src/suite/index.ts b/e2e/src/suite/index.ts index 1a3e2656623..5331ef37c3e 100644 --- a/e2e/src/suite/index.ts +++ b/e2e/src/suite/index.ts @@ -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" @@ -12,7 +12,7 @@ declare global { } export async function run() { - const extension = vscode.extensions.getExtension("RooVeterinaryInc.roo-cline") + const extension = vscode.extensions.getExtension(`${Package.publisher}.${Package.name}`) if (!extension) { throw new Error("Extension not found") @@ -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. diff --git a/e2e/src/suite/modes.test.ts b/e2e/src/suite/modes.test.ts index f5cd2141f3c..286ab2ce8cc 100644 --- a/e2e/src/suite/modes.test.ts +++ b/e2e/src/suite/modes.test.ts @@ -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" diff --git a/e2e/src/suite/subtasks.test.ts b/e2e/src/suite/subtasks.test.ts index c73e2c4ce98..b5ff033d129 100644 --- a/e2e/src/suite/subtasks.test.ts +++ b/e2e/src/suite/subtasks.test.ts @@ -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" diff --git a/e2e/src/suite/task.test.ts b/e2e/src/suite/task.test.ts index 434d1fcc4f9..e97c3b4f1ea 100644 --- a/e2e/src/suite/task.test.ts +++ b/e2e/src/suite/task.test.ts @@ -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" diff --git a/e2e/src/suite/utils.ts b/e2e/src/suite/utils.ts index 784d299820c..d41fa9e8ed5 100644 --- a/e2e/src/suite/utils.ts +++ b/e2e/src/suite/utils.ts @@ -1,4 +1,4 @@ -import type { RooCodeAPI } from "../../../src/exports/roo-code" +import type { RooCodeAPI } from "@roo-code/types" type WaitForOptions = { timeout?: number diff --git a/src/activate/CodeActionProvider.ts b/src/activate/CodeActionProvider.ts index 1cf3f666f5b..37b1a827129 100644 --- a/src/activate/CodeActionProvider.ts +++ b/src/activate/CodeActionProvider.ts @@ -1,17 +1,10 @@ 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 = { +export const TITLES: Record = { EXPLAIN: "Explain with Roo Code", FIX: "Fix with Roo Code", IMPROVE: "Improve with Roo Code", @@ -19,14 +12,6 @@ export const ACTION_TITLES: Record = { NEW_TASK: "New Roo Code Task", } as const -export const COMMAND_IDS: Record = { - 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, @@ -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 } @@ -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) { @@ -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, @@ -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, @@ -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, diff --git a/src/activate/__tests__/CodeActionProvider.test.ts b/src/activate/__tests__/CodeActionProvider.test.ts index 1a56ad899f3..4bb2966bcf9 100644 --- a/src/activate/__tests__/CodeActionProvider.test.ts +++ b/src/activate/__tests__/CodeActionProvider.test.ts @@ -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) => ({ @@ -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", () => { @@ -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", () => { diff --git a/src/activate/handleTask.ts b/src/activate/handleTask.ts index 6f9d35c26f2..208b7bf427e 100644 --- a/src/activate/handleTask.ts +++ b/src/activate/handleTask.ts @@ -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 @@ -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`) return } - await ClineProvider.handleCodeAction(COMMAND_IDS.NEW_TASK, "NEW_TASK", { userInput: prompt }) + await ClineProvider.handleCodeAction("newTask", "NEW_TASK", { userInput: prompt }) } diff --git a/src/activate/registerCodeActions.ts b/src/activate/registerCodeActions.ts index 7af28076a78..ba8be1a4714 100644 --- a/src/activate/registerCodeActions.ts +++ b/src/activate/registerCodeActions.ts @@ -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 diff --git a/src/activate/registerCommands.ts b/src/activate/registerCommands.ts index f90fc1e1d62..b6c7b547796 100644 --- a/src/activate/registerCommands.ts +++ b/src/activate/registerCommands.ts @@ -1,6 +1,8 @@ import * as vscode from "vscode" import delay from "delay" +import { CommandId, Package } from "../schemas" +import { getCommand } from "../utils/commands" import { ClineProvider } from "../core/webview/ClineProvider" import { ContextProxy } from "../core/config/ContextProxy" import { telemetryService } from "../services/telemetry/TelemetryService" @@ -57,125 +59,124 @@ export type RegisterCommandOptions = { export const registerCommands = (options: RegisterCommandOptions) => { const { context } = options - for (const [command, callback] of Object.entries(getCommandsMap(options))) { + for (const [id, callback] of Object.entries(getCommandsMap(options))) { + const command = getCommand(id as CommandId) context.subscriptions.push(vscode.commands.registerCommand(command, callback)) } } -const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOptions) => { - return { - "roo-cline.activationCompleted": () => {}, - "roo-cline.plusButtonClicked": async () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) - - if (!visibleProvider) { - return - } - - telemetryService.captureTitleButtonClicked("plus") - - await visibleProvider.removeClineFromStack() - await visibleProvider.postStateToWebview() - await visibleProvider.postMessageToWebview({ type: "action", action: "chatButtonClicked" }) - }, - "roo-cline.mcpButtonClicked": () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) - - if (!visibleProvider) { - return - } - - telemetryService.captureTitleButtonClicked("mcp") - - visibleProvider.postMessageToWebview({ type: "action", action: "mcpButtonClicked" }) - }, - "roo-cline.promptsButtonClicked": () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) - - if (!visibleProvider) { - return - } - - telemetryService.captureTitleButtonClicked("prompts") - - visibleProvider.postMessageToWebview({ type: "action", action: "promptsButtonClicked" }) - }, - "roo-cline.popoutButtonClicked": () => { - telemetryService.captureTitleButtonClicked("popout") - - return openClineInNewTab({ context, outputChannel }) - }, - "roo-cline.openInNewTab": () => openClineInNewTab({ context, outputChannel }), - "roo-cline.settingsButtonClicked": () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) - - if (!visibleProvider) { - return - } - - telemetryService.captureTitleButtonClicked("settings") - - visibleProvider.postMessageToWebview({ type: "action", action: "settingsButtonClicked" }) - // Also explicitly post the visibility message to trigger scroll reliably - visibleProvider.postMessageToWebview({ type: "action", action: "didBecomeVisible" }) - }, - "roo-cline.historyButtonClicked": () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) - - if (!visibleProvider) { - return - } - - telemetryService.captureTitleButtonClicked("history") - - visibleProvider.postMessageToWebview({ type: "action", action: "historyButtonClicked" }) - }, - "roo-cline.showHumanRelayDialog": (params: { requestId: string; promptText: string }) => { +const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOptions): Record => ({ + activationCompleted: () => {}, + plusButtonClicked: async () => { + const visibleProvider = getVisibleProviderOrLog(outputChannel) + + if (!visibleProvider) { + return + } + + telemetryService.captureTitleButtonClicked("plus") + + await visibleProvider.removeClineFromStack() + await visibleProvider.postStateToWebview() + await visibleProvider.postMessageToWebview({ type: "action", action: "chatButtonClicked" }) + }, + mcpButtonClicked: () => { + const visibleProvider = getVisibleProviderOrLog(outputChannel) + + if (!visibleProvider) { + return + } + + telemetryService.captureTitleButtonClicked("mcp") + + visibleProvider.postMessageToWebview({ type: "action", action: "mcpButtonClicked" }) + }, + promptsButtonClicked: () => { + const visibleProvider = getVisibleProviderOrLog(outputChannel) + + if (!visibleProvider) { + return + } + + telemetryService.captureTitleButtonClicked("prompts") + + visibleProvider.postMessageToWebview({ type: "action", action: "promptsButtonClicked" }) + }, + popoutButtonClicked: () => { + telemetryService.captureTitleButtonClicked("popout") + + return openClineInNewTab({ context, outputChannel }) + }, + openInNewTab: () => openClineInNewTab({ context, outputChannel }), + settingsButtonClicked: () => { + const visibleProvider = getVisibleProviderOrLog(outputChannel) + + if (!visibleProvider) { + return + } + + telemetryService.captureTitleButtonClicked("settings") + + visibleProvider.postMessageToWebview({ type: "action", action: "settingsButtonClicked" }) + // Also explicitly post the visibility message to trigger scroll reliably + visibleProvider.postMessageToWebview({ type: "action", action: "didBecomeVisible" }) + }, + historyButtonClicked: () => { + const visibleProvider = getVisibleProviderOrLog(outputChannel) + + if (!visibleProvider) { + return + } + + telemetryService.captureTitleButtonClicked("history") + + visibleProvider.postMessageToWebview({ type: "action", action: "historyButtonClicked" }) + }, + showHumanRelayDialog: (params: { requestId: string; promptText: string }) => { + const panel = getPanel() + + if (panel) { + panel?.webview.postMessage({ + type: "showHumanRelayDialog", + requestId: params.requestId, + promptText: params.promptText, + }) + } + }, + registerHumanRelayCallback: registerHumanRelayCallback, + unregisterHumanRelayCallback: unregisterHumanRelayCallback, + handleHumanRelayResponse: handleHumanRelayResponse, + newTask: handleNewTask, + setCustomStoragePath: async () => { + const { promptForCustomStoragePath } = await import("../utils/storage") + await promptForCustomStoragePath() + }, + focusInput: async () => { + try { const panel = getPanel() - if (panel) { - panel?.webview.postMessage({ - type: "showHumanRelayDialog", - requestId: params.requestId, - promptText: params.promptText, - }) - } - }, - "roo-cline.registerHumanRelayCallback": registerHumanRelayCallback, - "roo-cline.unregisterHumanRelayCallback": unregisterHumanRelayCallback, - "roo-cline.handleHumanRelayResponse": handleHumanRelayResponse, - "roo-cline.newTask": handleNewTask, - "roo-cline.setCustomStoragePath": async () => { - const { promptForCustomStoragePath } = await import("../shared/storagePathManager") - await promptForCustomStoragePath() - }, - "roo-cline.focusInput": async () => { - try { - const panel = getPanel() - - if (!panel) { - await vscode.commands.executeCommand("workbench.view.extension.roo-cline-ActivityBar") - } else if (panel === tabPanel) { - panel.reveal(vscode.ViewColumn.Active, false) - } else if (panel === sidebarPanel) { - await vscode.commands.executeCommand(`${ClineProvider.sideBarId}.focus`) - provider.postMessageToWebview({ type: "action", action: "focusInput" }) - } - } catch (error) { - outputChannel.appendLine(`Error focusing input: ${error}`) - } - }, - "roo.acceptInput": () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) - - if (!visibleProvider) { - return + if (!panel) { + await vscode.commands.executeCommand(`workbench.view.extension.${Package.name}-ActivityBar`) + } else if (panel === tabPanel) { + panel.reveal(vscode.ViewColumn.Active, false) + } else if (panel === sidebarPanel) { + await vscode.commands.executeCommand(`${ClineProvider.sideBarId}.focus`) + provider.postMessageToWebview({ type: "action", action: "focusInput" }) } - - visibleProvider.postMessageToWebview({ type: "acceptInput" }) - }, - } -} + } catch (error) { + outputChannel.appendLine(`Error focusing input: ${error}`) + } + }, + acceptInput: () => { + const visibleProvider = getVisibleProviderOrLog(outputChannel) + + if (!visibleProvider) { + return + } + + visibleProvider.postMessageToWebview({ type: "acceptInput" }) + }, +}) export const openClineInNewTab = async ({ context, outputChannel }: Omit) => { // (This example uses webviewProvider activation event which is necessary to diff --git a/src/activate/registerTerminalActions.ts b/src/activate/registerTerminalActions.ts index 40d30afc61f..f2dc8b47094 100644 --- a/src/activate/registerTerminalActions.ts +++ b/src/activate/registerTerminalActions.ts @@ -1,27 +1,24 @@ import * as vscode from "vscode" + +import { TerminalActionId, TerminalActionPromptType } from "../schemas" +import { getTerminalCommand } from "../utils/commands" import { ClineProvider } from "../core/webview/ClineProvider" import { Terminal } from "../integrations/terminal/Terminal" import { t } from "../i18n" -const TERMINAL_COMMAND_IDS = { - ADD_TO_CONTEXT: "roo-cline.terminalAddToContext", - FIX: "roo-cline.terminalFixCommand", - EXPLAIN: "roo-cline.terminalExplainCommand", -} as const - export const registerTerminalActions = (context: vscode.ExtensionContext) => { - registerTerminalAction(context, TERMINAL_COMMAND_IDS.ADD_TO_CONTEXT, "TERMINAL_ADD_TO_CONTEXT") - registerTerminalAction(context, TERMINAL_COMMAND_IDS.FIX, "TERMINAL_FIX") - registerTerminalAction(context, TERMINAL_COMMAND_IDS.EXPLAIN, "TERMINAL_EXPLAIN") + registerTerminalAction(context, "terminalAddToContext", "TERMINAL_ADD_TO_CONTEXT") + registerTerminalAction(context, "terminalFixCommand", "TERMINAL_FIX") + registerTerminalAction(context, "terminalExplainCommand", "TERMINAL_EXPLAIN") } const registerTerminalAction = ( context: vscode.ExtensionContext, - command: string, - promptType: "TERMINAL_ADD_TO_CONTEXT" | "TERMINAL_FIX" | "TERMINAL_EXPLAIN", + command: TerminalActionId, + promptType: TerminalActionPromptType, ) => { context.subscriptions.push( - vscode.commands.registerCommand(command, async (args: any) => { + vscode.commands.registerCommand(getTerminalCommand(command), async (args: any) => { let content = args.selection if (!content || content === "") { diff --git a/src/api/providers/fetchers/modelCache.ts b/src/api/providers/fetchers/modelCache.ts index c3c662415b0..9517bda8ae1 100644 --- a/src/api/providers/fetchers/modelCache.ts +++ b/src/api/providers/fetchers/modelCache.ts @@ -4,7 +4,7 @@ import fs from "fs/promises" import NodeCache from "node-cache" import { ContextProxy } from "../../../core/config/ContextProxy" -import { getCacheDirectoryPath } from "../../../shared/storagePathManager" +import { getCacheDirectoryPath } from "../../../utils/storage" import { RouterName, ModelRecord } from "../../../shared/api" import { fileExistsAtPath } from "../../../utils/fs" diff --git a/src/api/providers/fetchers/modelEndpointCache.ts b/src/api/providers/fetchers/modelEndpointCache.ts index 23c486e4204..c69e7c82a3d 100644 --- a/src/api/providers/fetchers/modelEndpointCache.ts +++ b/src/api/providers/fetchers/modelEndpointCache.ts @@ -5,7 +5,7 @@ import NodeCache from "node-cache" import sanitize from "sanitize-filename" import { ContextProxy } from "../../../core/config/ContextProxy" -import { getCacheDirectoryPath } from "../../../shared/storagePathManager" +import { getCacheDirectoryPath } from "../../../utils/storage" import { RouterName, ModelRecord } from "../../../shared/api" import { fileExistsAtPath } from "../../../utils/fs" diff --git a/src/api/providers/glama.ts b/src/api/providers/glama.ts index b0132580d47..6010c85d41d 100644 --- a/src/api/providers/glama.ts +++ b/src/api/providers/glama.ts @@ -2,6 +2,7 @@ import { Anthropic } from "@anthropic-ai/sdk" import axios from "axios" import OpenAI from "openai" +import { Package } from "../../schemas" import { ApiHandlerOptions, glamaDefaultModelId, glamaDefaultModelInfo } from "../../shared/api" import { ApiStream } from "../transform/stream" @@ -14,7 +15,9 @@ import { RouterProvider } from "./router-provider" const GLAMA_DEFAULT_TEMPERATURE = 0 const DEFAULT_HEADERS = { - "X-Glama-Metadata": JSON.stringify({ labels: [{ key: "app", value: "vscode.rooveterinaryinc.roo-cline" }] }), + "X-Glama-Metadata": JSON.stringify({ + labels: [{ key: "app", value: `vscode.${Package.publisher}.${Package.name}` }], + }), } export class GlamaHandler extends RouterProvider implements SingleCompletionHandler { diff --git a/src/api/providers/human-relay.ts b/src/api/providers/human-relay.ts index ecc29c8e7d3..7a7f3c10a18 100644 --- a/src/api/providers/human-relay.ts +++ b/src/api/providers/human-relay.ts @@ -2,9 +2,9 @@ import { Anthropic } from "@anthropic-ai/sdk" import * as vscode from "vscode" import { ModelInfo } from "../../shared/api" -import { ApiHandler, SingleCompletionHandler } from "../index" +import { getCommand } from "../../utils/commands" import { ApiStream } from "../transform/stream" - +import { ApiHandler, SingleCompletionHandler } from "../index" /** * Human Relay API processor * This processor does not directly call the API, but interacts with the model through human operations copy and paste. @@ -111,17 +111,17 @@ function getMessageContent(message: Anthropic.Messages.MessageParam): string { */ async function showHumanRelayDialog(promptText: string): Promise { return new Promise((resolve) => { - // Create a unique request ID + // Create a unique request ID. const requestId = Date.now().toString() - // Register a global callback function + // Register a global callback function. vscode.commands.executeCommand( - "roo-cline.registerHumanRelayCallback", + getCommand("registerHumanRelayCallback"), requestId, (response: string | undefined) => resolve(response), ) - // Open the dialog box directly using the current panel - vscode.commands.executeCommand("roo-cline.showHumanRelayDialog", { requestId, promptText }) + // Open the dialog box directly using the current panel. + vscode.commands.executeCommand(getCommand("showHumanRelayDialog"), { requestId, promptText }) }) } diff --git a/src/core/context-tracking/FileContextTracker.ts b/src/core/context-tracking/FileContextTracker.ts index 18eee943267..4e96ede6544 100644 --- a/src/core/context-tracking/FileContextTracker.ts +++ b/src/core/context-tracking/FileContextTracker.ts @@ -1,6 +1,6 @@ import * as path from "path" import * as vscode from "vscode" -import { getTaskDirectoryPath } from "../../shared/storagePathManager" +import { getTaskDirectoryPath } from "../../utils/storage" import { GlobalFileNames } from "../../shared/globalFileNames" import { fileExistsAtPath } from "../../utils/fs" import fs from "fs/promises" diff --git a/src/core/task-persistence/apiMessages.ts b/src/core/task-persistence/apiMessages.ts index 6ac36ed08fa..0ba9628a5d8 100644 --- a/src/core/task-persistence/apiMessages.ts +++ b/src/core/task-persistence/apiMessages.ts @@ -6,7 +6,7 @@ import { Anthropic } from "@anthropic-ai/sdk" import { fileExistsAtPath } from "../../utils/fs" import { GlobalFileNames } from "../../shared/globalFileNames" -import { getTaskDirectoryPath } from "../../shared/storagePathManager" +import { getTaskDirectoryPath } from "../../utils/storage" export type ApiMessage = Anthropic.MessageParam & { ts?: number; isSummary?: boolean } diff --git a/src/core/task-persistence/taskMessages.ts b/src/core/task-persistence/taskMessages.ts index 96129e62855..54d33b1a51b 100644 --- a/src/core/task-persistence/taskMessages.ts +++ b/src/core/task-persistence/taskMessages.ts @@ -5,7 +5,7 @@ import { fileExistsAtPath } from "../../utils/fs" import { GlobalFileNames } from "../../shared/globalFileNames" import { ClineMessage } from "../../shared/ExtensionMessage" -import { getTaskDirectoryPath } from "../../shared/storagePathManager" +import { getTaskDirectoryPath } from "../../utils/storage" export type ReadTaskMessagesOptions = { taskId: string diff --git a/src/core/task-persistence/taskMetadata.ts b/src/core/task-persistence/taskMetadata.ts index 9784e622958..0a028e5ba82 100644 --- a/src/core/task-persistence/taskMetadata.ts +++ b/src/core/task-persistence/taskMetadata.ts @@ -7,7 +7,7 @@ import { combineCommandSequences } from "../../shared/combineCommandSequences" import { getApiMetrics } from "../../shared/getApiMetrics" import { findLastIndex } from "../../shared/array" import { HistoryItem } from "../../shared/HistoryItem" -import { getTaskDirectoryPath } from "../../shared/storagePathManager" +import { getTaskDirectoryPath } from "../../utils/storage" const taskSizeCache = new NodeCache({ stdTTL: 30, checkperiod: 5 * 60 }) diff --git a/src/core/task/__tests__/Task.test.ts b/src/core/task/__tests__/Task.test.ts index 84756b8a2de..f21499bda0c 100644 --- a/src/core/task/__tests__/Task.test.ts +++ b/src/core/task/__tests__/Task.test.ts @@ -130,7 +130,7 @@ jest.mock("../../environment/getEnvironmentDetails", () => ({ jest.mock("../../ignore/RooIgnoreController") // Mock storagePathManager to prevent dynamic import issues -jest.mock("../../../shared/storagePathManager", () => ({ +jest.mock("../../../utils/storage", () => ({ getTaskDirectoryPath: jest .fn() .mockImplementation((globalStoragePath, taskId) => Promise.resolve(`${globalStoragePath}/tasks/${taskId}`)), diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 0ddd071393a..27b7fa8217f 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -9,7 +9,18 @@ import axios from "axios" import pWaitFor from "p-wait-for" import * as vscode from "vscode" -import type { GlobalState, ProviderName, ProviderSettings, RooCodeSettings, ProviderSettingsEntry } from "../../schemas" +import { + GlobalState, + ProviderName, + ProviderSettings, + RooCodeSettings, + ProviderSettingsEntry, + Package, + CodeActionId, + CodeActionName, + TerminalActionId, + TerminalActionPromptType, +} from "../../schemas" import { t } from "../../i18n" import { setPanel } from "../../activate/registerCommands" import { requestyDefaultModelId, openRouterDefaultModelId, glamaDefaultModelId } from "../../shared/api" @@ -34,7 +45,6 @@ import { ContextProxy } from "../config/ContextProxy" import { ProviderSettingsManager } from "../config/ProviderSettingsManager" import { CustomModesManager } from "../config/CustomModesManager" import { buildApiHandler } from "../../api" -import { CodeActionName } from "../../activate/CodeActionProvider" import { Task, TaskOptions } from "../task/Task" import { getNonce } from "./getNonce" import { getUri } from "./getUri" @@ -54,8 +64,11 @@ export type ClineProviderEvents = { } export class ClineProvider extends EventEmitter implements vscode.WebviewViewProvider { - public static readonly sideBarId = "roo-cline.SidebarProvider" // used in package.json as the view's id. This value cannot be changed due to how vscode caches views based on their id, and updating the id would break existing instances of the extension. - public static readonly tabPanelId = "roo-cline.TabPanelProvider" + // Used in package.json as the view's id. This value cannot be changed due + // to how VSCode caches views based on their id, and updating the id would + // break existing instances of the extension. + public static readonly sideBarId = `${Package.name}.SidebarProvider` + public static readonly tabPanelId = `${Package.name}.TabPanelProvider` private static activeInstances: Set = new Set() private disposables: vscode.Disposable[] = [] private view?: vscode.WebviewView | vscode.WebviewPanel @@ -225,7 +238,7 @@ export class ClineProvider extends EventEmitter implements // If no visible provider, try to show the sidebar view if (!visibleProvider) { - await vscode.commands.executeCommand("roo-cline.SidebarProvider.focus") + await vscode.commands.executeCommand(`${Package.name}.SidebarProvider.focus`) // Wait briefly for the view to become visible await delay(100) visibleProvider = ClineProvider.getVisibleInstance() @@ -254,7 +267,7 @@ export class ClineProvider extends EventEmitter implements } public static async handleCodeAction( - command: string, + command: CodeActionId, promptType: CodeActionName, params: Record, ): Promise { @@ -272,7 +285,7 @@ export class ClineProvider extends EventEmitter implements // TODO: Improve type safety for promptType. const prompt = supportPrompt.create(promptType, params, customSupportPrompts) - if (command.endsWith("addToContext")) { + if (command === "addToContext") { await visibleProvider.postMessageToWebview({ type: "invoke", invoke: "setChatBoxMessage", text: prompt }) return } @@ -281,12 +294,12 @@ export class ClineProvider extends EventEmitter implements } public static async handleTerminalAction( - command: string, - promptType: "TERMINAL_ADD_TO_CONTEXT" | "TERMINAL_FIX" | "TERMINAL_EXPLAIN", + command: TerminalActionId, + promptType: TerminalActionPromptType, params: Record, ): Promise { - // Capture telemetry for terminal action usage telemetryService.captureCodeActionUsed(promptType) + const visibleProvider = await ClineProvider.getInstance() if (!visibleProvider) { @@ -294,10 +307,9 @@ export class ClineProvider extends EventEmitter implements } const { customSupportPrompts } = await visibleProvider.getState() - const prompt = supportPrompt.create(promptType, params, customSupportPrompts) - if (command.endsWith("AddToContext")) { + if (command === "terminalAddToContext") { await visibleProvider.postMessageToWebview({ type: "invoke", invoke: "setChatBoxMessage", text: prompt }) return } @@ -974,7 +986,7 @@ export class ClineProvider extends EventEmitter implements } async ensureSettingsDirectoryExists(): Promise { - const { getSettingsDirectoryPath } = await import("../../shared/storagePathManager") + const { getSettingsDirectoryPath } = await import("../../utils/storage") const globalStoragePath = this.contextProxy.globalStorageUri.fsPath return getSettingsDirectoryPath(globalStoragePath) } @@ -1070,7 +1082,7 @@ export class ClineProvider extends EventEmitter implements const historyItem = history.find((item) => item.id === id) if (historyItem) { - const { getTaskDirectoryPath } = await import("../../shared/storagePathManager") + const { getTaskDirectoryPath } = await import("../../utils/storage") const globalStoragePath = this.contextProxy.globalStorageUri.fsPath const taskDirPath = await getTaskDirectoryPath(globalStoragePath, id) const apiConversationHistoryFilePath = path.join(taskDirPath, GlobalFileNames.apiConversationHistory) @@ -1260,7 +1272,7 @@ export class ClineProvider extends EventEmitter implements const telemetryKey = process.env.POSTHOG_API_KEY const machineId = vscode.env.machineId - const allowedCommands = vscode.workspace.getConfiguration("roo-cline").get("allowedCommands") || [] + const allowedCommands = vscode.workspace.getConfiguration(Package.name).get("allowedCommands") || [] const cwd = this.cwd // Check if there's a system prompt override for the current mode diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index c96615edd19..3cb33561ea0 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -4,11 +4,10 @@ import pWaitFor from "p-wait-for" import * as vscode from "vscode" import { ClineProvider } from "./ClineProvider" -import { Language, ProviderSettings, GlobalState } from "../../schemas" +import { Language, ProviderSettings, GlobalState, Package } from "../../schemas" import { changeLanguage, t } from "../../i18n" import { RouterName, toRouterName } from "../../shared/api" import { supportPrompt } from "../../shared/support-prompt" - import { checkoutDiffPayloadSchema, checkoutRestorePayloadSchema, WebviewMessage } from "../../shared/WebviewMessage" import { checkExistKey } from "../../shared/checkExistApiConfig" import { experimentDefault } from "../../shared/experiments" @@ -34,6 +33,7 @@ import { getWorkspacePath } from "../../utils/path" import { Mode, defaultModeSlug } from "../../shared/modes" import { getModels, flushModels } from "../../api/providers/fetchers/modelCache" import { generateSystemPrompt } from "./generateSystemPrompt" +import { getCommand } from "../../utils/commands" const ALLOWED_VSCODE_SETTINGS = new Set(["terminal.integrated.inheritEnv"]) @@ -376,7 +376,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We // Also update workspace settings. await vscode.workspace - .getConfiguration("roo-cline") + .getConfiguration(Package.name) .update("allowedCommands", message.commands, vscode.ConfigurationTarget.Global) break @@ -1230,7 +1230,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We break case "humanRelayResponse": if (message.requestId && message.text) { - vscode.commands.executeCommand("roo-cline.handleHumanRelayResponse", { + vscode.commands.executeCommand(getCommand("handleHumanRelayResponse"), { requestId: message.requestId, text: message.text, cancelled: false, @@ -1240,7 +1240,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We case "humanRelayCancel": if (message.requestId) { - vscode.commands.executeCommand("roo-cline.handleHumanRelayResponse", { + vscode.commands.executeCommand(getCommand("handleHumanRelayResponse"), { requestId: message.requestId, cancelled: true, }) diff --git a/src/exports/README.md b/src/exports/README.md index 36b7c23d555..ee79b160bb7 100644 --- a/src/exports/README.md +++ b/src/exports/README.md @@ -7,7 +7,9 @@ The Roo Code extension exposes an API that can be used by other extensions. To u 3. Get access to the API with the following code: ```typescript -const extension = vscode.extensions.getExtension("rooveterinaryinc.roo-cline") +import { RooCodeAPI, Package } from "path/to/roo-code" + +const extension = vscode.extensions.getExtension(`${Package.publisher}.${Package.name}`) if (!extension?.isActive) { throw new Error("Extension is not activated") @@ -35,10 +37,10 @@ await api.pressPrimaryButton() await api.pressSecondaryButton() ``` -**NOTE:** To ensure that the `rooveterinaryinc.roo-cline` extension is activated before your extension, add it to the `extensionDependencies` in your `package.json`: +**NOTE:** To ensure that the `RooVeterinaryInc.roo-cline` extension is activated before your extension, add it to the `extensionDependencies` in your `package.json`: ```json -"extensionDependencies": ["rooveterinaryinc.roo-cline"] +"extensionDependencies": ["RooVeterinaryInc.roo-cline"] ``` For detailed information on the available methods and their usage, refer to the `roo-code.d.ts` file. diff --git a/src/exports/api.ts b/src/exports/api.ts index 05080cb89f0..17728f3019f 100644 --- a/src/exports/api.ts +++ b/src/exports/api.ts @@ -3,6 +3,7 @@ import * as vscode from "vscode" import fs from "fs/promises" import * as path from "path" +import { Package } from "../schemas" import { getWorkspacePath } from "../utils/path" import { ClineProvider } from "../core/webview/ClineProvider" import { openClineInNewTab } from "../activate/registerCommands" @@ -112,7 +113,7 @@ export class API extends EventEmitter implements RooCodeAPI { provider = await openClineInNewTab({ context: this.context, outputChannel: this.outputChannel }) this.registerListeners(provider) } else { - await vscode.commands.executeCommand("roo-cline.SidebarProvider.focus") + await vscode.commands.executeCommand(`${Package.name}.SidebarProvider.focus`) provider = this.sidebarProvider } @@ -122,7 +123,7 @@ export class API extends EventEmitter implements RooCodeAPI { if (configuration.allowedCommands) { await vscode.workspace - .getConfiguration("roo-cline") + .getConfiguration(Package.name) .update("allowedCommands", configuration.allowedCommands, vscode.ConfigurationTarget.Global) } } diff --git a/src/exports/interface.ts b/src/exports/interface.ts index 6642bd84914..d8423511da9 100644 --- a/src/exports/interface.ts +++ b/src/exports/interface.ts @@ -43,9 +43,9 @@ export { RooCodeEventName, IpcOrigin, IpcMessageType } * Constants */ -import { providerNames } from "../schemas" +import { providerNames, Package } from "../schemas" -export { providerNames } +export { providerNames, Package } /** * RooCodeAPI diff --git a/src/exports/roo-code.d.ts b/src/exports/roo-code.d.ts index f68889f5308..2715d259819 100644 --- a/src/exports/roo-code.d.ts +++ b/src/exports/roo-code.d.ts @@ -1540,6 +1540,11 @@ type TaskEvent = ] } +declare const Package: { + readonly publisher: string + readonly name: string + readonly version: string +} /** * ProviderName */ @@ -1752,6 +1757,7 @@ export { IpcMessageType, IpcOrigin, type IpcServerEvents, + Package, type ProviderName, type ProviderSettings, type ProviderSettingsEntry, diff --git a/src/extension.ts b/src/extension.ts index 34248619d62..8fd30532ea4 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -14,6 +14,7 @@ try { import "./utils/path" // Necessary to have access to String.prototype.toPosix. +import { Package } from "./schemas" import { ContextProxy } from "./core/config/ContextProxy" import { ClineProvider } from "./core/webview/ClineProvider" import { DIFF_VIEW_URI_SCHEME } from "./integrations/editor/DiffViewProvider" @@ -65,7 +66,7 @@ export async function activate(context: vscode.ExtensionContext) { TerminalRegistry.initialize() // Get default commands from configuration. - const defaultCommands = vscode.workspace.getConfiguration("roo-cline").get("allowedCommands") || [] + const defaultCommands = vscode.workspace.getConfiguration(Package.name).get("allowedCommands") || [] // Initialize global state if not already set. if (!context.globalState.get("allowedCommands")) { @@ -123,7 +124,7 @@ export async function activate(context: vscode.ExtensionContext) { registerTerminalActions(context) // Allows other extensions to activate once Roo is ready. - vscode.commands.executeCommand("roo-cline.activationCompleted") + vscode.commands.executeCommand(`${Package.name}.activationCompleted`) // Implements the `RooCodeAPI` interface. const socketPath = process.env.ROO_CODE_IPC_SOCKET_PATH diff --git a/src/integrations/theme/getTheme.ts b/src/integrations/theme/getTheme.ts index dbc7a0f0b25..1ff9b0fbc40 100644 --- a/src/integrations/theme/getTheme.ts +++ b/src/integrations/theme/getTheme.ts @@ -3,6 +3,8 @@ import * as path from "path" import * as fs from "fs/promises" import { convertTheme } from "monaco-vscode-textmate-theme-converter/lib/cjs" +import { Package } from "../../schemas" + const defaultThemes: Record = { "Default Dark Modern": "dark_modern", "Dark+": "dark_plus", @@ -141,5 +143,5 @@ export function mergeJson( } function getExtensionUri(): vscode.Uri { - return vscode.extensions.getExtension("rooveterinaryinc.roo-cline")!.extensionUri + return vscode.extensions.getExtension(`${Package.publisher}.${Package.name}`)!.extensionUri } diff --git a/src/schemas/index.ts b/src/schemas/index.ts index 64671be91ae..9e47050ac1e 100644 --- a/src/schemas/index.ts +++ b/src/schemas/index.ts @@ -6,6 +6,61 @@ import { z } from "zod" import { Equals, Keys, AssertEqual } from "../utils/type-fu" +/** + * Extension + */ + +import { publisher, name, version } from "../../package.json" + +export const Package = { + publisher, + name, + version, +} as const + +/** + * CodeAction + */ + +export type CodeActionName = "EXPLAIN" | "FIX" | "IMPROVE" | "ADD_TO_CONTEXT" | "NEW_TASK" + +export type CodeActionId = "explainCode" | "fixCode" | "improveCode" | "addToContext" | "newTask" + +/** + * TerminalAction + */ + +export type TerminalActionName = "ADD_TO_CONTEXT" | "FIX" | "EXPLAIN" + +export type TerminalActionPromptType = `TERMINAL_${TerminalActionName}` + +export type TerminalActionId = "terminalAddToContext" | "terminalFixCommand" | "terminalExplainCommand" + +/** + * Command + */ + +const commandIds = [ + "activationCompleted", + "plusButtonClicked", + "mcpButtonClicked", + "promptsButtonClicked", + "popoutButtonClicked", + "openInNewTab", + "settingsButtonClicked", + "historyButtonClicked", + "showHumanRelayDialog", + "registerHumanRelayCallback", + "unregisterHumanRelayCallback", + "handleHumanRelayResponse", + "newTask", + "setCustomStoragePath", + "focusInput", + "acceptInput", +] as const + +export type CommandId = (typeof commandIds)[number] + /** * ProviderName */ diff --git a/src/shared/support-prompt.ts b/src/shared/support-prompt.ts index 2dfa478e152..4f9751e7a88 100644 --- a/src/shared/support-prompt.ts +++ b/src/shared/support-prompt.ts @@ -32,7 +32,18 @@ interface SupportPromptConfig { template: string } -const supportPromptConfigs: Record = { +type SupportPromptType = + | "ENHANCE" + | "EXPLAIN" + | "FIX" + | "IMPROVE" + | "ADD_TO_CONTEXT" + | "TERMINAL_ADD_TO_CONTEXT" + | "TERMINAL_FIX" + | "TERMINAL_EXPLAIN" + | "NEW_TASK" + +const supportPromptConfigs: Record = { ENHANCE: { template: `Generate an enhanced version of this prompt (reply with only the enhanced prompt - no conversation, explanations, lead-in, bullet points, placeholders, or surrounding quotes): @@ -124,8 +135,6 @@ Please provide: }, } as const -type SupportPromptType = keyof typeof supportPromptConfigs - export const supportPrompt = { default: Object.fromEntries(Object.entries(supportPromptConfigs).map(([key, config]) => [key, config.template])), get: (customSupportPrompts: Record | undefined, type: SupportPromptType): string => { diff --git a/src/utils/commands.ts b/src/utils/commands.ts new file mode 100644 index 00000000000..cb7d5487255 --- /dev/null +++ b/src/utils/commands.ts @@ -0,0 +1,7 @@ +import { Package, CommandId, CodeActionId, TerminalActionId } from "../schemas" + +export const getCommand = (id: CommandId) => `${Package.name}.${id}` + +export const getCodeActionCommand = (id: CodeActionId) => `${Package.name}.${id}` + +export const getTerminalCommand = (id: TerminalActionId) => `${Package.name}.${id}` diff --git a/src/shared/storagePathManager.ts b/src/utils/storage.ts similarity index 94% rename from src/shared/storagePathManager.ts rename to src/utils/storage.ts index 1dde82623a6..b4e47c98881 100644 --- a/src/shared/storagePathManager.ts +++ b/src/utils/storage.ts @@ -1,6 +1,8 @@ import * as vscode from "vscode" import * as path from "path" import * as fs from "fs/promises" + +import { Package } from "../schemas" import { t } from "../i18n" /** @@ -14,7 +16,7 @@ export async function getStorageBasePath(defaultPath: string): Promise { try { // This is the line causing the error in tests - const config = vscode.workspace.getConfiguration("roo-cline") + const config = vscode.workspace.getConfiguration(Package.name) customStoragePath = config.get("customStoragePath", "") } catch (error) { console.warn("Could not access VSCode configuration - using default path") @@ -88,7 +90,7 @@ export async function promptForCustomStoragePath(): Promise { let currentPath = "" try { - const currentConfig = vscode.workspace.getConfiguration("roo-cline") + const currentConfig = vscode.workspace.getConfiguration(Package.name) currentPath = currentConfig.get("customStoragePath", "") } catch (error) { console.error("Could not access configuration") @@ -123,7 +125,7 @@ export async function promptForCustomStoragePath(): Promise { // If user canceled the operation, result will be undefined if (result !== undefined) { try { - const currentConfig = vscode.workspace.getConfiguration("roo-cline") + const currentConfig = vscode.workspace.getConfiguration(Package.name) await currentConfig.update("customStoragePath", result, vscode.ConfigurationTarget.Global) if (result) { diff --git a/webview-ui/src/components/chat/Announcement.tsx b/webview-ui/src/components/chat/Announcement.tsx index 058c8ab6561..5bce25b786d 100644 --- a/webview-ui/src/components/chat/Announcement.tsx +++ b/webview-ui/src/components/chat/Announcement.tsx @@ -2,9 +2,10 @@ import { useState, memo } from "react" import { Trans } from "react-i18next" import { VSCodeLink } from "@vscode/webview-ui-toolkit/react" +import { Package } from "@roo/schemas" + import { useAppTranslation } from "@src/i18n/TranslationContext" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@src/components/ui" -import { version } from "../../../../package.json" interface AnnouncementProps { hideAnnouncement: () => void @@ -35,8 +36,10 @@ const Announcement = ({ hideAnnouncement }: AnnouncementProps) => { }}> - {t("chat:announcement.title", { version })} - {t("chat:announcement.description", { version })} + {t("chat:announcement.title", { version: Package.version })} + + {t("chat:announcement.description", { version: Package.version })} +

{t("chat:announcement.whatsNew")}

diff --git a/webview-ui/src/components/chat/__tests__/Announcement.test.tsx b/webview-ui/src/components/chat/__tests__/Announcement.test.tsx index d06a25906a3..70cc8ac506a 100644 --- a/webview-ui/src/components/chat/__tests__/Announcement.test.tsx +++ b/webview-ui/src/components/chat/__tests__/Announcement.test.tsx @@ -1,6 +1,7 @@ import { render, screen } from "@testing-library/react" import { jest } from "@jest/globals" // Or 'jest' if using Jest -import { version } from "../../../../../package.json" + +import { Package } from "@roo/schemas" import Announcement from "../Announcement" @@ -31,7 +32,7 @@ jest.mock("@src/i18n/TranslationContext", () => ({ describe("Announcement", () => { const mockHideAnnouncement = jest.fn() - const expectedVersion = version + const expectedVersion = Package.version it("renders the announcement with the version number from package.json", () => { render() diff --git a/webview-ui/src/oauth/urls.ts b/webview-ui/src/oauth/urls.ts index 205c19cf53e..17e205ae3e1 100644 --- a/webview-ui/src/oauth/urls.ts +++ b/webview-ui/src/oauth/urls.ts @@ -1,5 +1,7 @@ +import { Package } from "@roo/schemas" + export function getCallbackUrl(provider: string, uriScheme?: string) { - return encodeURIComponent(`${uriScheme || "vscode"}://rooveterinaryinc.roo-cline/${provider}`) + return encodeURIComponent(`${uriScheme || "vscode"}://${Package.publisher}.${Package.name}/${provider}`) } export function getGlamaAuthUrl(uriScheme?: string) {