diff --git a/src/extension.ts b/src/extension.ts index 6cb6ea4b07..eef3e51d0a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -22,6 +22,7 @@ import { Package } from "./shared/package" import { formatLanguage } from "./shared/language" import { ContextProxy } from "./core/config/ContextProxy" import { ClineProvider } from "./core/webview/ClineProvider" +import { getAllModesInfo } from "./shared/modes" import { DIFF_VIEW_URI_SCHEME } from "./integrations/editor/DiffViewProvider" import { TerminalRegistry } from "./integrations/terminal/TerminalRegistry" import { McpServerManager } from "./services/mcp/McpServerManager" @@ -147,6 +148,16 @@ export async function activate(context: vscode.ExtensionContext) { { ...bridgeConfig, provider, sessionId: vscode.env.sessionId }, (message: string) => outputChannel.appendLine(message), ) + + // Send available modes to the bridge + const bridgeInstance = ExtensionBridgeService.getInstance() + if (bridgeInstance && provider) { + const customModes = await provider.customModesManager.getCustomModes() + const modesInfo = getAllModesInfo(customModes) + + await bridgeInstance.setAvailableModes(modesInfo) + outputChannel.appendLine(`[CloudService] Sent ${modesInfo.length} modes to bridge`) + } }) // Add to subscriptions for proper cleanup on deactivate. diff --git a/src/shared/__tests__/modes.test.ts b/src/shared/__tests__/modes.test.ts new file mode 100644 index 0000000000..fb3d353d4b --- /dev/null +++ b/src/shared/__tests__/modes.test.ts @@ -0,0 +1,68 @@ +import { describe, it, expect } from "vitest" +import { getAllModesInfo } from "../modes" +import { ModeConfig } from "@roo-code/types" + +describe("getAllModesInfo", () => { + it("should return slug and name for all built-in modes", () => { + const modesInfo = getAllModesInfo() + + // Should have multiple modes + expect(modesInfo.length).toBeGreaterThan(0) + + // Each mode should have slug and name + modesInfo.forEach((mode) => { + expect(mode).toHaveProperty("slug") + expect(mode).toHaveProperty("name") + expect(typeof mode.slug).toBe("string") + expect(typeof mode.name).toBe("string") + expect(mode.slug).toBeTruthy() + expect(mode.name).toBeTruthy() + }) + + // Check that we have some expected built-in modes + const slugs = modesInfo.map((m) => m.slug) + expect(slugs).toContain("code") + expect(slugs).toContain("architect") + expect(slugs).toContain("ask") + }) + + it("should include custom modes when provided", () => { + const customModes: ModeConfig[] = [ + { + slug: "custom-test", + name: "Custom Test Mode", + roleDefinition: "Test role", + groups: ["read"], + }, + ] + + const modesInfo = getAllModesInfo(customModes) + + // Should include the custom mode + const customMode = modesInfo.find((m) => m.slug === "custom-test") + expect(customMode).toBeDefined() + expect(customMode?.name).toBe("Custom Test Mode") + }) + + it("should override built-in modes with custom modes of the same slug", () => { + const customModes: ModeConfig[] = [ + { + slug: "code", + name: "Custom Code Mode", + roleDefinition: "Custom role", + groups: ["read"], + }, + ] + + const modesInfo = getAllModesInfo(customModes) + + // Should have the custom mode name for the code slug + const codeMode = modesInfo.find((m) => m.slug === "code") + expect(codeMode).toBeDefined() + expect(codeMode?.name).toBe("Custom Code Mode") + + // Should not have duplicate entries + const codeModes = modesInfo.filter((m) => m.slug === "code") + expect(codeModes.length).toBe(1) + }) +}) diff --git a/src/shared/modes.ts b/src/shared/modes.ts index f68d25c682..299475819c 100644 --- a/src/shared/modes.ts +++ b/src/shared/modes.ts @@ -109,6 +109,12 @@ export function getAllModes(customModes?: ModeConfig[]): ModeConfig[] { return allModes } +// Get all mode slugs and display names (in the same precedence order as getAllModes). +// Custom modes override built-in modes when slugs collide. +export function getAllModesInfo(customModes?: ModeConfig[]): Array<{ slug: string; name: string }> { + return getAllModes(customModes).map((m) => ({ slug: m.slug, name: m.name })) +} + // Check if a mode is custom or an override export function isCustomMode(slug: string, customModes?: ModeConfig[]): boolean { return !!customModes?.some((mode) => mode.slug === slug)