From f274a150c4fdec94f2a96d1de3a2451aa50fb10e Mon Sep 17 00:00:00 2001 From: Chris Estreich Date: Tue, 20 May 2025 16:41:03 -0700 Subject: [PATCH] Get package publisher and name from package.json + command type safety (#3766) --- .gitignore | 2 +- e2e/package-lock.json | 21 ++ e2e/package.json | 2 +- e2e/src/suite/extension.test.ts | 47 +++-- e2e/src/suite/index.ts | 6 +- e2e/src/suite/modes.test.ts | 2 +- e2e/src/suite/subtasks.test.ts | 2 +- e2e/src/suite/task.test.ts | 2 +- e2e/src/suite/utils.ts | 2 +- src/activate/CodeActionProvider.ts | 46 ++--- .../__tests__/CodeActionProvider.test.ts | 12 +- src/activate/handleTask.ts | 8 +- src/activate/registerCodeActions.ts | 14 +- src/activate/registerCommands.ts | 189 +++++++++--------- src/activate/registerTerminalActions.ts | 21 +- src/api/providers/fetchers/modelCache.ts | 2 +- .../providers/fetchers/modelEndpointCache.ts | 2 +- src/api/providers/glama.ts | 5 +- src/api/providers/human-relay.ts | 14 +- .../context-tracking/FileContextTracker.ts | 2 +- src/core/task-persistence/apiMessages.ts | 2 +- src/core/task-persistence/taskMessages.ts | 2 +- src/core/task-persistence/taskMetadata.ts | 2 +- src/core/task/__tests__/Task.test.ts | 2 +- src/core/webview/ClineProvider.ts | 42 ++-- src/core/webview/webviewMessageHandler.ts | 10 +- src/exports/README.md | 8 +- src/exports/api.ts | 5 +- src/exports/interface.ts | 4 +- src/exports/roo-code.d.ts | 6 + src/extension.ts | 5 +- src/integrations/theme/getTheme.ts | 4 +- src/schemas/index.ts | 55 +++++ src/shared/support-prompt.ts | 15 +- src/utils/commands.ts | 7 + .../storage.ts} | 8 +- .../src/components/chat/Announcement.tsx | 9 +- .../chat/__tests__/Announcement.test.tsx | 5 +- webview-ui/src/oauth/urls.ts | 4 +- 39 files changed, 361 insertions(+), 235 deletions(-) create mode 100644 src/utils/commands.ts rename src/{shared/storagePathManager.ts => utils/storage.ts} (94%) diff --git a/.gitignore b/.gitignore index 6e90445e1b..4085bb8486 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 e7f75013fd..bb6a34c082 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 604c96a56c..22d76db6b5 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 1f44824610..54544a2627 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 1a3e265662..5331ef37c3 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 f5cd2141f3..286ab2ce8c 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 c73e2c4ce9..b5ff033d12 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 434d1fcc4f..e97c3b4f1e 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 784d299820..d41fa9e8ed 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 1cf3f666f5..37b1a82712 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 1a56ad899f..4bb2966bcf 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 6f9d35c26f..208b7bf427 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 7af28076a7..ba8be1a471 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 f90fc1e1d6..b6c7b54779 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) +const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOptions): Record => ({ + activationCompleted: () => {}, + plusButtonClicked: async () => { + const visibleProvider = getVisibleProviderOrLog(outputChannel) - if (!visibleProvider) { - return - } + if (!visibleProvider) { + return + } - telemetryService.captureTitleButtonClicked("plus") + telemetryService.captureTitleButtonClicked("plus") - await visibleProvider.removeClineFromStack() - await visibleProvider.postStateToWebview() - await visibleProvider.postMessageToWebview({ type: "action", action: "chatButtonClicked" }) - }, - "roo-cline.mcpButtonClicked": () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) + await visibleProvider.removeClineFromStack() + await visibleProvider.postStateToWebview() + await visibleProvider.postMessageToWebview({ type: "action", action: "chatButtonClicked" }) + }, + mcpButtonClicked: () => { + const visibleProvider = getVisibleProviderOrLog(outputChannel) - if (!visibleProvider) { - return - } + if (!visibleProvider) { + return + } - telemetryService.captureTitleButtonClicked("mcp") + telemetryService.captureTitleButtonClicked("mcp") - visibleProvider.postMessageToWebview({ type: "action", action: "mcpButtonClicked" }) - }, - "roo-cline.promptsButtonClicked": () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) + visibleProvider.postMessageToWebview({ type: "action", action: "mcpButtonClicked" }) + }, + promptsButtonClicked: () => { + const visibleProvider = getVisibleProviderOrLog(outputChannel) - if (!visibleProvider) { - return - } + if (!visibleProvider) { + return + } - telemetryService.captureTitleButtonClicked("prompts") + telemetryService.captureTitleButtonClicked("prompts") - visibleProvider.postMessageToWebview({ type: "action", action: "promptsButtonClicked" }) - }, - "roo-cline.popoutButtonClicked": () => { - telemetryService.captureTitleButtonClicked("popout") + visibleProvider.postMessageToWebview({ type: "action", action: "promptsButtonClicked" }) + }, + popoutButtonClicked: () => { + telemetryService.captureTitleButtonClicked("popout") - return openClineInNewTab({ context, outputChannel }) - }, - "roo-cline.openInNewTab": () => openClineInNewTab({ context, outputChannel }), - "roo-cline.settingsButtonClicked": () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) + return openClineInNewTab({ context, outputChannel }) + }, + openInNewTab: () => openClineInNewTab({ context, outputChannel }), + settingsButtonClicked: () => { + const visibleProvider = getVisibleProviderOrLog(outputChannel) - if (!visibleProvider) { - return - } + if (!visibleProvider) { + return + } - telemetryService.captureTitleButtonClicked("settings") + 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) + 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 - } + if (!visibleProvider) { + return + } - telemetryService.captureTitleButtonClicked("history") + telemetryService.captureTitleButtonClicked("history") - visibleProvider.postMessageToWebview({ type: "action", action: "historyButtonClicked" }) - }, - "roo-cline.showHumanRelayDialog": (params: { requestId: string; promptText: string }) => { + 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, - }) + 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" }) } - }, - "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() + } catch (error) { + outputChannel.appendLine(`Error focusing input: ${error}`) + } + }, + acceptInput: () => { + const visibleProvider = getVisibleProviderOrLog(outputChannel) - 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 (!visibleProvider) { - return - } - - visibleProvider.postMessageToWebview({ type: "acceptInput" }) - }, - } -} + 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 40d30afc61..f2dc8b4709 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 c3c662415b..9517bda8ae 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 23c486e420..c69e7c82a3 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 b0132580d4..6010c85d41 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 ecc29c8e7d..7a7f3c10a1 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 18eee94326..4e96ede654 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 6ac36ed08f..0ba9628a5d 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 96129e6285..54d33b1a51 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 9784e62295..0a028e5ba8 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 84756b8a2d..f21499bda0 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 0ddd071393..27b7fa8217 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 c96615edd1..3cb33561ea 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 36b7c23d55..ee79b160bb 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 05080cb89f..17728f3019 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 6642bd8491..d8423511da 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 f68889f530..2715d25981 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 34248619d6..8fd30532ea 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 dbc7a0f0b2..1ff9b0fbc4 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 64671be91a..9e47050ac1 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 2dfa478e15..4f9751e7a8 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 0000000000..cb7d548725 --- /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 1dde82623a..b4e47c9888 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 058c8ab656..5bce25b786 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 d06a25906a..70cc8ac506 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 205c19cf53..17e205ae3e 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) {