Просмотр исходного кода

Modes selector improvements (#4902)

Co-authored-by: Bruno Bergher <[email protected]>
Co-authored-by: Matt Rubens <[email protected]>
Co-authored-by: Daniel Riccio <[email protected]>
Bruno Bergher 6 месяцев назад
Родитель
Сommit
21dc57365e
78 измененных файлов с 875 добавлено и 116 удалено
  1. 25 0
      packages/telemetry/src/TelemetryService.ts
  2. 1 0
      packages/types/src/global-settings.ts
  3. 2 0
      packages/types/src/mode.ts
  4. 7 0
      packages/types/src/telemetry.ts
  5. 1 0
      src/core/webview/ClineProvider.ts
  6. 1 0
      src/core/webview/__tests__/ClineProvider.spec.ts
  7. 59 2
      src/core/webview/webviewMessageHandler.ts
  8. 11 26
      src/package.json
  9. 1 0
      src/shared/ExtensionMessage.ts
  10. 1 0
      src/shared/WebviewMessage.ts
  11. 5 0
      src/shared/modes.ts
  12. 10 1
      webview-ui/src/App.tsx
  13. 14 30
      webview-ui/src/components/chat/ChatTextArea.tsx
  14. 171 0
      webview-ui/src/components/chat/ModeSelector.tsx
  15. 58 0
      webview-ui/src/components/chat/__tests__/ModeSelector.spec.tsx
  16. 8 1
      webview-ui/src/components/marketplace/MarketplaceView.tsx
  17. 12 0
      webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts
  18. 19 2
      webview-ui/src/components/marketplace/components/MarketplaceInstallModal.tsx
  19. 104 11
      webview-ui/src/components/modes/ModesView.tsx
  20. 44 1
      webview-ui/src/components/modes/__tests__/ModesView.spec.tsx
  21. 25 21
      webview-ui/src/components/ui/select-dropdown.tsx
  22. 4 0
      webview-ui/src/context/ExtensionStateContext.tsx
  23. 1 0
      webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx
  24. 6 0
      webview-ui/src/i18n/locales/ca/chat.json
  25. 1 1
      webview-ui/src/i18n/locales/ca/marketplace.json
  26. 9 0
      webview-ui/src/i18n/locales/ca/prompts.json
  27. 6 0
      webview-ui/src/i18n/locales/de/chat.json
  28. 1 1
      webview-ui/src/i18n/locales/de/marketplace.json
  29. 9 0
      webview-ui/src/i18n/locales/de/prompts.json
  30. 6 0
      webview-ui/src/i18n/locales/en/chat.json
  31. 1 1
      webview-ui/src/i18n/locales/en/marketplace.json
  32. 11 2
      webview-ui/src/i18n/locales/en/prompts.json
  33. 6 0
      webview-ui/src/i18n/locales/es/chat.json
  34. 1 1
      webview-ui/src/i18n/locales/es/marketplace.json
  35. 9 0
      webview-ui/src/i18n/locales/es/prompts.json
  36. 6 0
      webview-ui/src/i18n/locales/fr/chat.json
  37. 1 1
      webview-ui/src/i18n/locales/fr/marketplace.json
  38. 9 0
      webview-ui/src/i18n/locales/fr/prompts.json
  39. 6 0
      webview-ui/src/i18n/locales/hi/chat.json
  40. 1 1
      webview-ui/src/i18n/locales/hi/marketplace.json
  41. 9 0
      webview-ui/src/i18n/locales/hi/prompts.json
  42. 6 0
      webview-ui/src/i18n/locales/id/chat.json
  43. 1 1
      webview-ui/src/i18n/locales/id/marketplace.json
  44. 9 0
      webview-ui/src/i18n/locales/id/prompts.json
  45. 6 0
      webview-ui/src/i18n/locales/it/chat.json
  46. 1 1
      webview-ui/src/i18n/locales/it/marketplace.json
  47. 9 0
      webview-ui/src/i18n/locales/it/prompts.json
  48. 6 0
      webview-ui/src/i18n/locales/ja/chat.json
  49. 1 1
      webview-ui/src/i18n/locales/ja/marketplace.json
  50. 9 0
      webview-ui/src/i18n/locales/ja/prompts.json
  51. 6 0
      webview-ui/src/i18n/locales/ko/chat.json
  52. 1 1
      webview-ui/src/i18n/locales/ko/marketplace.json
  53. 9 0
      webview-ui/src/i18n/locales/ko/prompts.json
  54. 6 0
      webview-ui/src/i18n/locales/nl/chat.json
  55. 1 1
      webview-ui/src/i18n/locales/nl/marketplace.json
  56. 9 0
      webview-ui/src/i18n/locales/nl/prompts.json
  57. 6 0
      webview-ui/src/i18n/locales/pl/chat.json
  58. 1 1
      webview-ui/src/i18n/locales/pl/marketplace.json
  59. 9 0
      webview-ui/src/i18n/locales/pl/prompts.json
  60. 6 0
      webview-ui/src/i18n/locales/pt-BR/chat.json
  61. 1 1
      webview-ui/src/i18n/locales/pt-BR/marketplace.json
  62. 9 0
      webview-ui/src/i18n/locales/pt-BR/prompts.json
  63. 6 0
      webview-ui/src/i18n/locales/ru/chat.json
  64. 1 1
      webview-ui/src/i18n/locales/ru/marketplace.json
  65. 9 0
      webview-ui/src/i18n/locales/ru/prompts.json
  66. 6 0
      webview-ui/src/i18n/locales/tr/chat.json
  67. 1 1
      webview-ui/src/i18n/locales/tr/marketplace.json
  68. 9 0
      webview-ui/src/i18n/locales/tr/prompts.json
  69. 6 0
      webview-ui/src/i18n/locales/vi/chat.json
  70. 1 1
      webview-ui/src/i18n/locales/vi/marketplace.json
  71. 9 0
      webview-ui/src/i18n/locales/vi/prompts.json
  72. 6 0
      webview-ui/src/i18n/locales/zh-CN/chat.json
  73. 1 1
      webview-ui/src/i18n/locales/zh-CN/marketplace.json
  74. 9 0
      webview-ui/src/i18n/locales/zh-CN/prompts.json
  75. 6 0
      webview-ui/src/i18n/locales/zh-TW/chat.json
  76. 1 1
      webview-ui/src/i18n/locales/zh-TW/marketplace.json
  77. 9 0
      webview-ui/src/i18n/locales/zh-TW/prompts.json
  78. 1 1
      webview-ui/src/utils/context-mentions.ts

+ 25 - 0
packages/telemetry/src/TelemetryService.ts

@@ -152,6 +152,31 @@ export class TelemetryService {
 		this.captureEvent(TelemetryEventName.CONSECUTIVE_MISTAKE_ERROR, { taskId })
 	}
 
+	/**
+	 * Captures when a tab is shown due to user action
+	 * @param tab The tab that was shown
+	 */
+	public captureTabShown(tab: string): void {
+		this.captureEvent(TelemetryEventName.TAB_SHOWN, { tab })
+	}
+
+	/**
+	 * Captures when a setting is changed in ModesView
+	 * @param settingName The name of the setting that was changed
+	 */
+	public captureModeSettingChanged(settingName: string): void {
+		this.captureEvent(TelemetryEventName.MODE_SETTINGS_CHANGED, { settingName })
+	}
+
+	/**
+	 * Captures when a user creates a new custom mode
+	 * @param modeSlug The slug of the custom mode
+	 * @param modeName The name of the custom mode
+	 */
+	public captureCustomModeCreated(modeSlug: string, modeName: string): void {
+		this.captureEvent(TelemetryEventName.CUSTOM_MODE_CREATED, { modeSlug, modeName })
+	}
+
 	/**
 	 * Captures a marketplace item installation event
 	 * @param itemId The unique identifier of the marketplace item

+ 1 - 0
packages/types/src/global-settings.ts

@@ -104,6 +104,7 @@ export const globalSettingsSchema = z.object({
 	enhancementApiConfigId: z.string().optional(),
 	historyPreviewCollapsed: z.boolean().optional(),
 	profileThresholds: z.record(z.string(), z.number()).optional(),
+	hasOpenedModeSelector: z.boolean().optional(),
 })
 
 export type GlobalSettings = z.infer<typeof globalSettingsSchema>

+ 2 - 0
packages/types/src/mode.ts

@@ -66,6 +66,7 @@ export const modeConfigSchema = z.object({
 	name: z.string().min(1, "Name is required"),
 	roleDefinition: z.string().min(1, "Role definition is required"),
 	whenToUse: z.string().optional(),
+	description: z.string().optional(),
 	customInstructions: z.string().optional(),
 	groups: groupEntryArraySchema,
 	source: z.enum(["global", "project"]).optional(),
@@ -106,6 +107,7 @@ export type CustomModesSettings = z.infer<typeof customModesSettingsSchema>
 export const promptComponentSchema = z.object({
 	roleDefinition: z.string().optional(),
 	whenToUse: z.string().optional(),
+	description: z.string().optional(),
 	customInstructions: z.string().optional(),
 })
 

+ 7 - 0
packages/types/src/telemetry.ts

@@ -31,6 +31,10 @@ export enum TelemetryEventName {
 	CHECKPOINT_RESTORED = "Checkpoint Restored",
 	CHECKPOINT_DIFFED = "Checkpoint Diffed",
 
+	TAB_SHOWN = "Tab Shown",
+	MODE_SETTINGS_CHANGED = "Mode Setting Changed",
+	CUSTOM_MODE_CREATED = "Custom Mode Created",
+
 	CONTEXT_CONDENSED = "Context Condensed",
 	SLIDING_WINDOW_TRUNCATION = "Sliding Window Truncation",
 
@@ -119,6 +123,9 @@ export const rooCodeTelemetryEventSchema = z.discriminatedUnion("type", [
 			TelemetryEventName.CONSECUTIVE_MISTAKE_ERROR,
 			TelemetryEventName.CONTEXT_CONDENSED,
 			TelemetryEventName.SLIDING_WINDOW_TRUNCATION,
+			TelemetryEventName.TAB_SHOWN,
+			TelemetryEventName.MODE_SETTINGS_CHANGED,
+			TelemetryEventName.CUSTOM_MODE_CREATED,
 		]),
 		properties: telemetryPropertiesSchema,
 	}),

+ 1 - 0
src/core/webview/ClineProvider.ts

@@ -1485,6 +1485,7 @@ export class ClineProvider
 			},
 			mdmCompliant: this.checkMdmCompliance(),
 			profileThresholds: profileThresholds ?? {},
+			hasOpenedModeSelector: this.getGlobalState("hasOpenedModeSelector") ?? false,
 		}
 	}
 

+ 1 - 0
src/core/webview/__tests__/ClineProvider.spec.ts

@@ -523,6 +523,7 @@ describe("ClineProvider", () => {
 			cloudIsAuthenticated: false,
 			sharingEnabled: false,
 			profileThresholds: {},
+			hasOpenedModeSelector: false,
 		}
 
 		const message: ExtensionMessage = {

+ 59 - 2
src/core/webview/webviewMessageHandler.ts

@@ -948,8 +948,27 @@ export const webviewMessageHandler = async (
 				const updatedPrompts = { ...existingPrompts, [message.promptMode]: message.customPrompt }
 				await updateGlobalState("customModePrompts", updatedPrompts)
 				const currentState = await provider.getStateToPostToWebview()
-				const stateWithPrompts = { ...currentState, customModePrompts: updatedPrompts }
+				const stateWithPrompts = {
+					...currentState,
+					customModePrompts: updatedPrompts,
+					hasOpenedModeSelector: currentState.hasOpenedModeSelector ?? false,
+				}
 				provider.postMessageToWebview({ type: "state", state: stateWithPrompts })
+
+				if (TelemetryService.hasInstance()) {
+					// Determine which setting was changed by comparing objects
+					const oldPrompt = existingPrompts[message.promptMode] || {}
+					const newPrompt = message.customPrompt
+					const changedSettings = Object.keys(newPrompt).filter(
+						(key) =>
+							JSON.stringify((oldPrompt as Record<string, unknown>)[key]) !==
+							JSON.stringify((newPrompt as Record<string, unknown>)[key]),
+					)
+
+					if (changedSettings.length > 0) {
+						TelemetryService.instance.captureModeSettingChanged(changedSettings[0])
+					}
+				}
 			}
 			break
 		case "deleteMessage": {
@@ -1085,6 +1104,10 @@ export const webviewMessageHandler = async (
 			await updateGlobalState("showRooIgnoredFiles", message.bool ?? true)
 			await provider.postStateToWebview()
 			break
+		case "hasOpenedModeSelector":
+			await updateGlobalState("hasOpenedModeSelector", message.bool ?? true)
+			await provider.postStateToWebview()
+			break
 		case "maxReadFileLine":
 			await updateGlobalState("maxReadFileLine", message.value)
 			await provider.postStateToWebview()
@@ -1414,12 +1437,41 @@ export const webviewMessageHandler = async (
 			break
 		case "updateCustomMode":
 			if (message.modeConfig) {
+				// Check if this is a new mode or an update to an existing mode
+				const existingModes = await provider.customModesManager.getCustomModes()
+				const isNewMode = !existingModes.some((mode) => mode.slug === message.modeConfig?.slug)
+
 				await provider.customModesManager.updateCustomMode(message.modeConfig.slug, message.modeConfig)
 				// Update state after saving the mode
 				const customModes = await provider.customModesManager.getCustomModes()
 				await updateGlobalState("customModes", customModes)
 				await updateGlobalState("mode", message.modeConfig.slug)
 				await provider.postStateToWebview()
+
+				// Track telemetry for custom mode creation or update
+				if (TelemetryService.hasInstance()) {
+					if (isNewMode) {
+						// This is a new custom mode
+						TelemetryService.instance.captureCustomModeCreated(
+							message.modeConfig.slug,
+							message.modeConfig.name,
+						)
+					} else {
+						// Determine which setting was changed by comparing objects
+						const existingMode = existingModes.find((mode) => mode.slug === message.modeConfig?.slug)
+						const changedSettings = existingMode
+							? Object.keys(message.modeConfig).filter(
+									(key) =>
+										JSON.stringify((existingMode as Record<string, unknown>)[key]) !==
+										JSON.stringify((message.modeConfig as Record<string, unknown>)[key]),
+								)
+							: []
+
+						if (changedSettings.length > 0) {
+							TelemetryService.instance.captureModeSettingChanged(changedSettings[0])
+						}
+					}
+				}
 			}
 			break
 		case "deleteCustomMode":
@@ -1604,6 +1656,7 @@ export const webviewMessageHandler = async (
 					)
 					await provider.postStateToWebview()
 					console.log(`Marketplace item installed and config file opened: ${configFilePath}`)
+
 					// Send success message to webview
 					provider.postMessageToWebview({
 						type: "marketplaceInstallResult",
@@ -1656,7 +1709,11 @@ export const webviewMessageHandler = async (
 
 		case "switchTab": {
 			if (message.tab) {
-				// Send a message to the webview to switch to the specified tab
+				// Capture tab shown event for all switchTab messages (which are user-initiated)
+				if (TelemetryService.hasInstance()) {
+					TelemetryService.instance.captureTabShown(message.tab)
+				}
+
 				await provider.postMessageToWebview({ type: "action", action: "switchTab", tab: message.tab })
 			}
 			break

+ 11 - 26
src/package.json

@@ -80,11 +80,6 @@
 				"title": "%command.mcpServers.title%",
 				"icon": "$(server)"
 			},
-			{
-				"command": "roo-cline.promptsButtonClicked",
-				"title": "%command.prompts.title%",
-				"icon": "$(organization)"
-			},
 			{
 				"command": "roo-cline.historyButtonClicked",
 				"title": "%command.history.title%",
@@ -219,39 +214,34 @@
 					"group": "navigation@1",
 					"when": "view == roo-cline.SidebarProvider"
 				},
-				{
-					"command": "roo-cline.promptsButtonClicked",
-					"group": "navigation@2",
-					"when": "view == roo-cline.SidebarProvider"
-				},
 				{
 					"command": "roo-cline.mcpButtonClicked",
-					"group": "navigation@3",
+					"group": "navigation@2",
 					"when": "view == roo-cline.SidebarProvider"
 				},
 				{
 					"command": "roo-cline.marketplaceButtonClicked",
-					"group": "navigation@4",
+					"group": "navigation@3",
 					"when": "view == roo-cline.SidebarProvider"
 				},
 				{
 					"command": "roo-cline.historyButtonClicked",
-					"group": "navigation@5",
+					"group": "navigation@4",
 					"when": "view == roo-cline.SidebarProvider"
 				},
 				{
 					"command": "roo-cline.popoutButtonClicked",
-					"group": "navigation@6",
+					"group": "navigation@5",
 					"when": "view == roo-cline.SidebarProvider"
 				},
 				{
 					"command": "roo-cline.accountButtonClicked",
-					"group": "navigation@7",
+					"group": "navigation@6",
 					"when": "view == roo-cline.SidebarProvider && config.roo-cline.rooCodeCloudEnabled"
 				},
 				{
 					"command": "roo-cline.settingsButtonClicked",
-					"group": "navigation@8",
+					"group": "navigation@7",
 					"when": "view == roo-cline.SidebarProvider"
 				}
 			],
@@ -261,34 +251,29 @@
 					"group": "navigation@1",
 					"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
 				},
-				{
-					"command": "roo-cline.promptsButtonClicked",
-					"group": "navigation@2",
-					"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
-				},
 				{
 					"command": "roo-cline.mcpButtonClicked",
-					"group": "navigation@3",
+					"group": "navigation@2",
 					"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
 				},
 				{
 					"command": "roo-cline.marketplaceButtonClicked",
-					"group": "navigation@4",
+					"group": "navigation@3",
 					"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
 				},
 				{
 					"command": "roo-cline.historyButtonClicked",
-					"group": "navigation@5",
+					"group": "navigation@4",
 					"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
 				},
 				{
 					"command": "roo-cline.accountButtonClicked",
-					"group": "navigation@6",
+					"group": "navigation@5",
 					"when": "activeWebviewPanelId == roo-cline.TabPanelProvider && config.roo-cline.rooCodeCloudEnabled"
 				},
 				{
 					"command": "roo-cline.settingsButtonClicked",
-					"group": "navigation@7",
+					"group": "navigation@6",
 					"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
 				}
 			]

+ 1 - 0
src/shared/ExtensionMessage.ts

@@ -261,6 +261,7 @@ export type ExtensionState = Pick<
 	marketplaceItems?: MarketplaceItem[]
 	marketplaceInstalledMetadata?: { project: Record<string, any>; global: Record<string, any> }
 	profileThresholds: Record<string, number>
+	hasOpenedModeSelector: boolean
 }
 
 export interface ClineSayTool {

+ 1 - 0
src/shared/WebviewMessage.ts

@@ -148,6 +148,7 @@ export interface WebviewMessage {
 		| "searchFiles"
 		| "toggleApiConfigPin"
 		| "setHistoryPreviewCollapsed"
+		| "hasOpenedModeSelector"
 		| "accountButtonClicked"
 		| "rooCloudSignIn"
 		| "rooCloudSignOut"

Разница между файлами не показана из-за своего большого размера
+ 5 - 0
src/shared/modes.ts


+ 10 - 1
webview-ui/src/App.tsx

@@ -74,6 +74,7 @@ const App = () => {
 			}
 
 			setCurrentSection(undefined)
+			setCurrentMarketplaceTab(undefined)
 
 			if (settingsRef.current?.checkUnsaveChanges) {
 				settingsRef.current.checkUnsaveChanges(() => setTab(newTab))
@@ -85,6 +86,7 @@ const App = () => {
 	)
 
 	const [currentSection, setCurrentSection] = useState<string | undefined>(undefined)
+	const [currentMarketplaceTab, setCurrentMarketplaceTab] = useState<string | undefined>(undefined)
 
 	const onMessage = useCallback(
 		(e: MessageEvent) => {
@@ -96,14 +98,17 @@ const App = () => {
 					const targetTab = message.tab as Tab
 					switchTab(targetTab)
 					setCurrentSection(undefined)
+					setCurrentMarketplaceTab(undefined)
 				} else {
 					// Handle other actions using the mapping
 					const newTab = tabsByMessageAction[message.action]
 					const section = message.values?.section as string | undefined
+					const marketplaceTab = message.values?.marketplaceTab as string | undefined
 
 					if (newTab) {
 						switchTab(newTab)
 						setCurrentSection(section)
+						setCurrentMarketplaceTab(marketplaceTab)
 					}
 				}
 			}
@@ -171,7 +176,11 @@ const App = () => {
 				<SettingsView ref={settingsRef} onDone={() => setTab("chat")} targetSection={currentSection} />
 			)}
 			{tab === "marketplace" && (
-				<MarketplaceView stateManager={marketplaceStateManager} onDone={() => switchTab("chat")} />
+				<MarketplaceView
+					stateManager={marketplaceStateManager}
+					onDone={() => switchTab("chat")}
+					targetTab={currentMarketplaceTab as "mcp" | "mode" | undefined}
+				/>
 			)}
 			{tab === "account" && (
 				<AccountView

+ 14 - 30
webview-ui/src/components/chat/ChatTextArea.tsx

@@ -22,6 +22,7 @@ import { convertToMentionPath } from "@/utils/path-mentions"
 import { SelectDropdown, DropdownOptionType, Button } from "@/components/ui"
 
 import Thumbnails from "../common/Thumbnails"
+import ModeSelector from "./ModeSelector"
 import { MAX_IMAGES_PER_MESSAGE } from "./ChatView"
 import ContextMenu from "./ContextMenu"
 import { VolumeX, Pin, Check } from "lucide-react"
@@ -74,6 +75,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 			currentApiConfigName,
 			listApiConfigMeta,
 			customModes,
+			customModePrompts,
 			cwd,
 			pinnedApiConfigs,
 			togglePinnedApiConfig,
@@ -193,6 +195,8 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 			}
 		}, [inputValue, sendingDisabled, setInputValue, t])
 
+		const allModes = useMemo(() => getAllModes(customModes), [customModes])
+
 		const queryItems = useMemo(() => {
 			return [
 				{ type: ContextMenuOptionType.Problems, value: "problems" },
@@ -322,7 +326,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 								selectedType,
 								queryItems,
 								fileSearchResults,
-								getAllModes(customModes),
+								allModes,
 							)
 							const optionsLength = options.length
 
@@ -359,7 +363,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 							selectedType,
 							queryItems,
 							fileSearchResults,
-							getAllModes(customModes),
+							allModes,
 						)[selectedMenuIndex]
 						if (
 							selectedOption &&
@@ -446,7 +450,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 				setInputValue,
 				justDeletedSpaceAfterMention,
 				queryItems,
-				customModes,
+				allModes,
 				fileSearchResults,
 				handleHistoryNavigation,
 				resetHistoryNavigation,
@@ -845,7 +849,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 									setSelectedIndex={setSelectedMenuIndex}
 									selectedType={selectedType}
 									queryItems={queryItems}
-									modes={getAllModes(customModes)}
+									modes={allModes}
 									loading={searchLoading}
 									dynamicSearchResults={fileSearchResults}
 								/>
@@ -997,38 +1001,17 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 				<div className={cn("flex", "justify-between", "items-center", "mt-auto", "pt-0.5")}>
 					<div className={cn("flex", "items-center", "gap-1", "min-w-0")}>
 						<div className="shrink-0">
-							<SelectDropdown
+							<ModeSelector
 								value={mode}
 								title={t("chat:selectMode")}
-								options={[
-									{
-										value: "shortcut",
-										label: modeShortcutText,
-										disabled: true,
-										type: DropdownOptionType.SHORTCUT,
-									},
-									...getAllModes(customModes).map((mode) => ({
-										value: mode.slug,
-										label: mode.name,
-										type: DropdownOptionType.ITEM,
-									})),
-									{
-										value: "sep-1",
-										label: t("chat:separator"),
-										type: DropdownOptionType.SEPARATOR,
-									},
-									{
-										value: "promptsButtonClicked",
-										label: t("chat:edit"),
-										type: DropdownOptionType.ACTION,
-									},
-								]}
 								onChange={(value) => {
-									setMode(value as Mode)
+									setMode(value)
 									vscode.postMessage({ type: "mode", text: value })
 								}}
-								shortcutText={modeShortcutText}
 								triggerClassName="w-full"
+								modeShortcutText={modeShortcutText}
+								customModes={customModes}
+								customModePrompts={customModePrompts}
 							/>
 						</div>
 
@@ -1037,6 +1020,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 								value={currentConfigId}
 								disabled={selectApiConfigDisabled}
 								title={t("chat:selectApiConfig")}
+								disableSearch={false}
 								placeholder={displayName}
 								options={[
 									// Pinned items first.

+ 171 - 0
webview-ui/src/components/chat/ModeSelector.tsx

@@ -0,0 +1,171 @@
+import React from "react"
+import { ChevronUp, Check } from "lucide-react"
+import { cn } from "@/lib/utils"
+import { useRooPortal } from "@/components/ui/hooks/useRooPortal"
+import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui"
+import { IconButton } from "./IconButton"
+import { vscode } from "@/utils/vscode"
+import { useExtensionState } from "@/context/ExtensionStateContext"
+import { useAppTranslation } from "@/i18n/TranslationContext"
+import { Mode, getAllModes } from "@roo/modes"
+import { ModeConfig, CustomModePrompts } from "@roo-code/types"
+
+interface ModeSelectorProps {
+	value: Mode
+	onChange: (value: Mode) => void
+	disabled?: boolean
+	title?: string
+	triggerClassName?: string
+	modeShortcutText: string
+	customModes?: ModeConfig[]
+	customModePrompts?: CustomModePrompts
+}
+
+export const ModeSelector = ({
+	value,
+	onChange,
+	disabled = false,
+	title = "",
+	triggerClassName = "",
+	modeShortcutText,
+	customModes,
+	customModePrompts,
+}: ModeSelectorProps) => {
+	const [open, setOpen] = React.useState(false)
+	const portalContainer = useRooPortal("roo-portal")
+	const { hasOpenedModeSelector, setHasOpenedModeSelector } = useExtensionState()
+	const { t } = useAppTranslation()
+
+	const trackModeSelectorOpened = () => {
+		if (!hasOpenedModeSelector) {
+			setHasOpenedModeSelector(true)
+			vscode.postMessage({ type: "hasOpenedModeSelector", bool: true })
+		}
+	}
+
+	// Get all modes including custom modes and merge custom prompt descriptions
+	const modes = React.useMemo(() => {
+		const allModes = getAllModes(customModes)
+		return allModes.map((mode) => ({
+			...mode,
+			description: customModePrompts?.[mode.slug]?.description ?? mode.description,
+		}))
+	}, [customModes, customModePrompts])
+
+	// Find the selected mode
+	const selectedMode = React.useMemo(() => modes.find((mode) => mode.slug === value), [modes, value])
+
+	return (
+		<Popover
+			open={open}
+			onOpenChange={(isOpen) => {
+				if (isOpen) trackModeSelectorOpened()
+				setOpen(isOpen)
+			}}
+			data-testid="mode-selector-root">
+			<PopoverTrigger
+				disabled={disabled}
+				title={title}
+				data-testid="mode-selector-trigger"
+				className={cn(
+					"inline-flex items-center gap-1.5 relative whitespace-nowrap px-1.5 py-1 text-xs",
+					"bg-transparent border border-[rgba(255,255,255,0.08)] rounded-md text-vscode-foreground",
+					"transition-all duration-150 focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder focus-visible:ring-inset",
+					disabled
+						? "opacity-50 cursor-not-allowed"
+						: "opacity-90 hover:opacity-100 hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)] cursor-pointer",
+					triggerClassName,
+					!disabled && !hasOpenedModeSelector
+						? "bg-primary opacity-90 hover:bg-primary-hover text-vscode-button-foreground"
+						: null,
+				)}>
+				<ChevronUp className="pointer-events-none opacity-80 flex-shrink-0 size-3" />
+				<span className="truncate">{selectedMode?.name || ""}</span>
+			</PopoverTrigger>
+
+			<PopoverContent
+				align="start"
+				sideOffset={4}
+				container={portalContainer}
+				className="p-0 overflow-hidden min-w-80 max-w-9/10">
+				<div className="flex flex-col w-full">
+					<div className="p-3 border-b border-vscode-dropdown-border cursor-default">
+						<div className="flex flex-row items-center gap-1 p-0 mt-0 mb-1 w-full">
+							<h4 className="m-0 pb-2 flex-1">{t("chat:modeSelector.title")}</h4>
+							<div className="flex flex-row gap-1 ml-auto mb-1">
+								<IconButton
+									iconClass="codicon-extensions"
+									title={t("chat:modeSelector.marketplace")}
+									onClick={() => {
+										window.postMessage(
+											{
+												type: "action",
+												action: "marketplaceButtonClicked",
+												values: { marketplaceTab: "mode" },
+											},
+											"*",
+										)
+
+										setOpen(false)
+									}}
+								/>
+								<IconButton
+									iconClass="codicon-settings-gear"
+									title={t("chat:modeSelector.settings")}
+									onClick={() => {
+										vscode.postMessage({
+											type: "switchTab",
+											tab: "modes",
+										})
+										setOpen(false)
+									}}
+								/>
+							</div>
+						</div>
+						<p className="my-0 pr-4 text-sm w-full">
+							{t("chat:modeSelector.description")}
+							<br />
+							{modeShortcutText}
+						</p>
+					</div>
+
+					{/* Mode List */}
+					<div className="max-h-[400px] overflow-y-auto py-0">
+						{modes.map((mode) => (
+							<div
+								className={cn(
+									"p-2 text-sm cursor-pointer flex flex-row gap-4 items-center",
+									"hover:bg-vscode-list-hoverBackground",
+									mode.slug === value
+										? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground"
+										: "",
+								)}
+								key={mode.slug}
+								onClick={() => {
+									onChange(mode.slug as Mode)
+									setOpen(false)
+								}}
+								data-testid="mode-selector-item">
+								<div className="flex-grow">
+									<p className="m-0 mb-0 font-bold">{mode.name}</p>
+									{mode.description && (
+										<p className="m-0 py-0 pl-4 h-4 flex-1 text-xs overflow-hidden">
+											{mode.description}
+										</p>
+									)}
+								</div>
+								{mode.slug === value ? (
+									<Check className="m-0 size-4 p-0.5" />
+								) : (
+									<div className="size-4" />
+								)}
+							</div>
+						))}
+					</div>
+				</div>
+			</PopoverContent>
+		</Popover>
+	)
+}
+
+export default ModeSelector

+ 58 - 0
webview-ui/src/components/chat/__tests__/ModeSelector.spec.tsx

@@ -0,0 +1,58 @@
+import React from "react"
+import { render, screen } from "@testing-library/react"
+import { describe, test, expect, vi } from "vitest"
+import ModeSelector from "../ModeSelector"
+import { Mode } from "@roo/modes"
+
+// Mock the dependencies
+vi.mock("@/utils/vscode", () => ({
+	vscode: {
+		postMessage: vi.fn(),
+	},
+}))
+
+vi.mock("@/context/ExtensionStateContext", () => ({
+	useExtensionState: () => ({
+		hasOpenedModeSelector: false,
+		setHasOpenedModeSelector: vi.fn(),
+	}),
+}))
+
+vi.mock("@/i18n/TranslationContext", () => ({
+	useAppTranslation: () => ({
+		t: (key: string) => key,
+	}),
+}))
+
+vi.mock("@/components/ui/hooks/useRooPortal", () => ({
+	useRooPortal: () => document.body,
+}))
+
+describe("ModeSelector", () => {
+	test("shows custom description from customModePrompts", () => {
+		const customModePrompts = {
+			code: {
+				description: "Custom code mode description",
+			},
+		}
+
+		render(
+			<ModeSelector
+				value={"code" as Mode}
+				onChange={vi.fn()}
+				modeShortcutText="Ctrl+M"
+				customModePrompts={customModePrompts}
+			/>,
+		)
+
+		// The component should be rendered
+		expect(screen.getByTestId("mode-selector-trigger")).toBeInTheDocument()
+	})
+
+	test("falls back to default description when no custom prompt", () => {
+		render(<ModeSelector value={"code" as Mode} onChange={vi.fn()} modeShortcutText="Ctrl+M" />)
+
+		// The component should be rendered
+		expect(screen.getByTestId("mode-selector-trigger")).toBeInTheDocument()
+	})
+})

+ 8 - 1
webview-ui/src/components/marketplace/MarketplaceView.tsx

@@ -12,8 +12,9 @@ import { TooltipProvider } from "@/components/ui/tooltip"
 interface MarketplaceViewProps {
 	onDone?: () => void
 	stateManager: MarketplaceViewStateManager
+	targetTab?: "mcp" | "mode"
 }
-export function MarketplaceView({ stateManager, onDone }: MarketplaceViewProps) {
+export function MarketplaceView({ stateManager, onDone, targetTab }: MarketplaceViewProps) {
 	const { t } = useAppTranslation()
 	const [state, manager] = useStateManager(stateManager)
 	const [hasReceivedInitialState, setHasReceivedInitialState] = useState(false)
@@ -26,6 +27,12 @@ export function MarketplaceView({ stateManager, onDone }: MarketplaceViewProps)
 		}
 	}, [state.allItems, hasReceivedInitialState])
 
+	useEffect(() => {
+		if (targetTab && (targetTab === "mcp" || targetTab === "mode")) {
+			manager.transition({ type: "SET_ACTIVE_TAB", payload: { tab: targetTab } })
+		}
+	}, [targetTab, manager])
+
 	// Ensure marketplace state manager processes messages when component mounts
 	useEffect(() => {
 		// When the marketplace view first mounts, we need to trigger a state update

+ 12 - 0
webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts

@@ -370,6 +370,18 @@ export class MarketplaceViewStateManager {
 				// Error case
 				void this.transition({ type: "FETCH_ERROR" })
 			} else {
+				// Check if a specific tab is requested
+				if (
+					message.values?.marketplaceTab &&
+					(message.values.marketplaceTab === "mcp" || message.values.marketplaceTab === "mode")
+				) {
+					// Set the active tab
+					void this.transition({
+						type: "SET_ACTIVE_TAB",
+						payload: { tab: message.values.marketplaceTab },
+					})
+				}
+
 				// Refresh request
 				void this.transition({ type: "FETCH_ITEMS" })
 			}

+ 19 - 2
webview-ui/src/components/marketplace/components/MarketplaceInstallModal.tsx

@@ -195,8 +195,25 @@ export const MarketplaceInstallModal: React.FC<MarketplaceInstallModalProps> = (
 	}
 
 	const handlePostInstallAction = (tab: "mcp" | "modes") => {
-		// Send message to switch to the appropriate tab
-		vscode.postMessage({ type: "switchTab", tab })
+		if (tab === "mcp") {
+			// Navigate to MCP tab
+			window.postMessage(
+				{
+					type: "action",
+					action: "mcpButtonClicked",
+				},
+				"*",
+			)
+		} else {
+			// Navigate to Modes tab
+			window.postMessage(
+				{
+					type: "action",
+					action: "promptsButtonClicked",
+				},
+				"*",
+			)
+		}
 		// Close the modal
 		onClose()
 	}

+ 104 - 11
webview-ui/src/components/modes/ModesView.tsx

@@ -5,9 +5,10 @@ import {
 	VSCodeRadio,
 	VSCodeTextArea,
 	VSCodeLink,
+	VSCodeTextField,
 } from "@vscode/webview-ui-toolkit/react"
 import { Trans } from "react-i18next"
-import { ChevronsUpDown, X } from "lucide-react"
+import { ChevronDown, X } from "lucide-react"
 
 import { ModeConfig, GroupEntry, PromptComponent, ToolGroup, modeConfigSchema } from "@roo-code/types"
 
@@ -15,6 +16,7 @@ import {
 	Mode,
 	getRoleDefinition,
 	getWhenToUse,
+	getDescription,
 	getCustomInstructions,
 	getAllModes,
 	findModeBySlug as findCustomModeBySlug,
@@ -105,6 +107,9 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 			if (updatedPrompt.roleDefinition === getRoleDefinition(mode)) {
 				delete updatedPrompt.roleDefinition
 			}
+			if (updatedPrompt.description === getDescription(mode)) {
+				delete updatedPrompt.description
+			}
 			if (updatedPrompt.whenToUse === getWhenToUse(mode)) {
 				delete updatedPrompt.whenToUse
 			}
@@ -120,6 +125,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 
 	const updateCustomMode = useCallback((slug: string, modeConfig: ModeConfig) => {
 		const source = modeConfig.source || "global"
+
 		vscode.postMessage({
 			type: "updateCustomMode",
 			slug,
@@ -194,6 +200,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 	// State for create mode dialog
 	const [newModeName, setNewModeName] = useState("")
 	const [newModeSlug, setNewModeSlug] = useState("")
+	const [newModeDescription, setNewModeDescription] = useState("")
 	const [newModeRoleDefinition, setNewModeRoleDefinition] = useState("")
 	const [newModeWhenToUse, setNewModeWhenToUse] = useState("")
 	const [newModeCustomInstructions, setNewModeCustomInstructions] = useState("")
@@ -203,6 +210,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 	// Field-specific error states
 	const [nameError, setNameError] = useState<string>("")
 	const [slugError, setSlugError] = useState<string>("")
+	const [descriptionError, setDescriptionError] = useState<string>("")
 	const [roleDefinitionError, setRoleDefinitionError] = useState<string>("")
 	const [groupsError, setGroupsError] = useState<string>("")
 
@@ -211,6 +219,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 		// Reset form fields
 		setNewModeName("")
 		setNewModeSlug("")
+		setNewModeDescription("")
 		setNewModeGroups(availableGroups)
 		setNewModeRoleDefinition("")
 		setNewModeWhenToUse("")
@@ -219,6 +228,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 		// Reset error states
 		setNameError("")
 		setSlugError("")
+		setDescriptionError("")
 		setRoleDefinitionError("")
 		setGroupsError("")
 	}, [])
@@ -252,6 +262,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 		// Clear previous errors
 		setNameError("")
 		setSlugError("")
+		setDescriptionError("")
 		setRoleDefinitionError("")
 		setGroupsError("")
 
@@ -259,6 +270,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 		const newMode: ModeConfig = {
 			slug: newModeSlug,
 			name: newModeName,
+			description: newModeDescription.trim() || undefined,
 			roleDefinition: newModeRoleDefinition.trim(),
 			whenToUse: newModeWhenToUse.trim() || undefined,
 			customInstructions: newModeCustomInstructions.trim() || undefined,
@@ -282,6 +294,9 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 					case "slug":
 						setSlugError(message)
 						break
+					case "description":
+						setDescriptionError(message)
+						break
 					case "roleDefinition":
 						setRoleDefinitionError(message)
 						break
@@ -301,6 +316,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 	}, [
 		newModeName,
 		newModeSlug,
+		newModeDescription,
 		newModeRoleDefinition,
 		newModeWhenToUse, // Add whenToUse dependency
 		newModeCustomInstructions,
@@ -348,6 +364,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 				}
 				if (customMode) {
 					const source = customMode.source || "global"
+
 					updateCustomMode(customMode.slug, {
 						...customMode,
 						groups: newGroups,
@@ -386,7 +403,10 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 		return () => window.removeEventListener("message", handler)
 	}, [])
 
-	const handleAgentReset = (modeSlug: string, type: "roleDefinition" | "whenToUse" | "customInstructions") => {
+	const handleAgentReset = (
+		modeSlug: string,
+		type: "roleDefinition" | "description" | "whenToUse" | "customInstructions",
+	) => {
 		// Only reset for built-in modes
 		const existingPrompt = customModePrompts?.[modeSlug] as PromptComponent
 		const updatedPrompt = { ...existingPrompt }
@@ -493,10 +513,10 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 									variant="combobox"
 									role="combobox"
 									aria-expanded={open}
-									className="grow justify-between"
+									className="justify-between w-60"
 									data-testid="mode-select-trigger">
 									<div>{getCurrentMode()?.name || t("prompts:modes.selectMode")}</div>
-									<ChevronsUpDown className="opacity-50" />
+									<ChevronDown className="opacity-50" />
 								</Button>
 							</PopoverTrigger>
 							<PopoverContent className="p-0 w-[var(--radix-popover-trigger-width)]">
@@ -582,6 +602,9 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 					{/* API Configuration - Moved Here */}
 					<div className="mb-3">
 						<div className="font-bold mb-1">{t("prompts:apiConfiguration.title")}</div>
+						<div className="text-sm text-vscode-descriptionForeground mb-2">
+							{t("prompts:apiConfiguration.select")}
+						</div>
 						<div className="mb-2">
 							<Select
 								value={currentApiConfigName}
@@ -591,7 +614,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 										text: value,
 									})
 								}}>
-								<SelectTrigger className="w-full">
+								<SelectTrigger className="w-60">
 									<SelectValue placeholder={t("settings:common.select")} />
 								</SelectTrigger>
 								<SelectContent>
@@ -602,13 +625,11 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 									))}
 								</SelectContent>
 							</Select>
-							<div className="text-xs mt-1.5 text-vscode-descriptionForeground">
-								{t("prompts:apiConfiguration.select")}
-							</div>
 						</div>
 					</div>
 				</div>
 
+				{/* Name section */}
 				<div className="mb-5">
 					{/* Only show name and delete for custom modes */}
 					{visualMode && findModeBySlug(visualMode, customModes) && (
@@ -647,6 +668,8 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 							</div>
 						</div>
 					)}
+
+					{/* Role Definition section */}
 					<div className="mb-4">
 						<div className="flex justify-between items-center mb-1">
 							<div className="font-bold">{t("prompts:roleDefinition.title")}</div>
@@ -700,11 +723,64 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 								}
 							}}
 							className="w-full"
-							rows={4}
+							rows={5}
 							data-testid={`${getCurrentMode()?.slug || "code"}-prompt-textarea`}
 						/>
 					</div>
 
+					{/* Description section */}
+					<div className="mb-4">
+						<div className="flex justify-between items-center mb-1">
+							<div className="font-bold">{t("prompts:description.title")}</div>
+							{!findModeBySlug(visualMode, customModes) && (
+								<Button
+									variant="ghost"
+									size="icon"
+									onClick={() => {
+										const currentMode = getCurrentMode()
+										if (currentMode?.slug) {
+											handleAgentReset(currentMode.slug, "description")
+										}
+									}}
+									title={t("prompts:description.resetToDefault")}
+									data-testid="description-reset">
+									<span className="codicon codicon-discard"></span>
+								</Button>
+							)}
+						</div>
+						<div className="text-sm text-vscode-descriptionForeground mb-2">
+							{t("prompts:description.description")}
+						</div>
+						<VSCodeTextField
+							value={(() => {
+								const customMode = findModeBySlug(visualMode, customModes)
+								const prompt = customModePrompts?.[visualMode] as PromptComponent
+								return customMode?.description ?? prompt?.description ?? getDescription(visualMode)
+							})()}
+							onChange={(e) => {
+								const value =
+									(e as unknown as CustomEvent)?.detail?.target?.value ||
+									((e as any).target as HTMLTextAreaElement).value
+								const customMode = findModeBySlug(visualMode, customModes)
+								if (customMode) {
+									// For custom modes, update the JSON file
+									updateCustomMode(visualMode, {
+										...customMode,
+										description: value.trim() || undefined,
+										source: customMode.source || "global",
+									})
+								} else {
+									// For built-in modes, update the prompts
+									updateAgentPrompt(visualMode, {
+										description: value.trim() || undefined,
+									})
+								}
+							}}
+							className="w-full"
+							data-testid={`${getCurrentMode()?.slug || "code"}-description-textfield`}
+						/>
+					</div>
+
 					{/* When to Use section */}
 					<div className="mb-4">
 						<div className="flex justify-between items-center mb-1">
@@ -755,7 +831,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 								}
 							}}
 							className="w-full"
-							rows={3}
+							rows={4}
 							data-testid={`${getCurrentMode()?.slug || "code"}-when-to-use-textarea`}
 						/>
 					</div>
@@ -912,7 +988,7 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 									})
 								}
 							}}
-							rows={4}
+							rows={10}
 							className="w-full"
 							data-testid={`${getCurrentMode()?.slug || "code"}-custom-instructions-textarea`}
 						/>
@@ -1189,6 +1265,23 @@ const ModesView = ({ onDone }: ModesViewProps) => {
 								)}
 							</div>
 
+							<div className="mb-4">
+								<div className="font-bold mb-1">{t("prompts:createModeDialog.description.label")}</div>
+								<div className="text-[13px] text-vscode-descriptionForeground mb-2">
+									{t("prompts:createModeDialog.description.description")}
+								</div>
+								<VSCodeTextField
+									value={newModeDescription}
+									onChange={(e) => {
+										setNewModeDescription((e.target as HTMLInputElement).value)
+									}}
+									className="w-full"
+								/>
+								{descriptionError && (
+									<div className="text-xs text-vscode-errorForeground mt-1">{descriptionError}</div>
+								)}
+							</div>
+
 							<div className="mb-4">
 								<div className="font-bold mb-1">{t("prompts:createModeDialog.whenToUse.label")}</div>
 								<div className="text-[13px] text-vscode-descriptionForeground mb-2">

+ 44 - 1
webview-ui/src/components/modes/__tests__/ModesView.spec.tsx

@@ -138,10 +138,13 @@ describe("PromptsView", () => {
 		await fireEvent.click(resetButton)
 
 		// Verify it only resets role definition
+		// When resetting a built-in mode's role definition, the field should be removed entirely
+		// from the customPrompt object, not set to undefined.
+		// This allows the default role definition from the built-in mode to be used instead.
 		expect(vscode.postMessage).toHaveBeenCalledWith({
 			type: "updatePrompt",
 			promptMode: "code",
-			customPrompt: { roleDefinition: undefined },
+			customPrompt: {}, // Empty object because the role definition field is removed entirely
 		})
 
 		// Cleanup before testing custom mode
@@ -159,6 +162,46 @@ describe("PromptsView", () => {
 		expect(screen.queryByTestId("role-definition-reset")).not.toBeInTheDocument()
 	})
 
+	it("description section behavior for different mode types", async () => {
+		const customMode = {
+			slug: "custom-mode",
+			name: "Custom Mode",
+			roleDefinition: "Custom role",
+			description: "Custom description",
+			groups: [],
+		}
+
+		// Test with built-in mode (code) - description section should be shown with reset button
+		const { unmount } = render(
+			<ExtensionStateContext.Provider
+				value={{ ...mockExtensionState, mode: "code", customModes: [customMode] } as any}>
+				<ModesView onDone={vitest.fn()} />
+			</ExtensionStateContext.Provider>,
+		)
+
+		// Verify description reset button IS present for built-in modes
+		// because built-in modes can have their descriptions customized and reset
+		expect(screen.queryByTestId("description-reset")).toBeInTheDocument()
+
+		// Cleanup before testing custom mode
+		unmount()
+
+		// Test with custom mode - description section should be shown
+		render(
+			<ExtensionStateContext.Provider
+				value={{ ...mockExtensionState, mode: "custom-mode", customModes: [customMode] } as any}>
+				<ModesView onDone={vitest.fn()} />
+			</ExtensionStateContext.Provider>,
+		)
+
+		// Verify description section is present for custom modes
+		// but reset button is NOT present (since custom modes manage their own descriptions)
+		expect(screen.queryByTestId("description-reset")).not.toBeInTheDocument()
+
+		// Verify the description text field is present for custom modes
+		expect(screen.getByTestId("custom-mode-description-textfield")).toBeInTheDocument()
+	})
+
 	it("handles clearing custom instructions correctly", async () => {
 		const setCustomInstructions = vitest.fn()
 		renderPromptsView({

+ 25 - 21
webview-ui/src/components/ui/select-dropdown.tsx

@@ -37,6 +37,7 @@ export interface SelectDropdownProps {
 	placeholder?: string
 	shortcutText?: string
 	renderItem?: (option: DropdownOption) => React.ReactNode
+	disableSearch?: boolean
 }
 
 export const SelectDropdown = React.memo(
@@ -56,6 +57,7 @@ export const SelectDropdown = React.memo(
 				placeholder = "",
 				shortcutText = "",
 				renderItem,
+				disableSearch = false,
 			},
 			ref,
 		) => {
@@ -117,8 +119,8 @@ export const SelectDropdown = React.memo(
 
 			// Filter options based on search value using memoized Fzf instance
 			const filteredOptions = React.useMemo(() => {
-				// If no search value, return all options without filtering
-				if (!searchValue) return options
+				// If search is disabled or no search value, return all options without filtering
+				if (disableSearch || !searchValue) return options
 
 				// Get fuzzy matching items - only perform search if we have a search value
 				const matchingItems = fzfInstance.find(searchValue).map((result) => result.item.original)
@@ -132,7 +134,7 @@ export const SelectDropdown = React.memo(
 					// Include if it's in the matching items
 					return matchingItems.some((item) => item.value === option.value)
 				})
-			}, [options, searchValue, fzfInstance])
+			}, [options, searchValue, fzfInstance, disableSearch])
 
 			// Group options by type and handle separators
 			const groupedOptions = React.useMemo(() => {
@@ -209,24 +211,26 @@ export const SelectDropdown = React.memo(
 						className={cn("p-0 overflow-hidden", contentClassName)}>
 						<div className="flex flex-col w-full">
 							{/* Search input */}
-							<div className="relative p-2 border-b border-vscode-dropdown-border">
-								<input
-									aria-label="Search"
-									ref={searchInputRef}
-									value={searchValue}
-									onChange={(e) => setSearchValue(e.target.value)}
-									placeholder={t("common:ui.search_placeholder")}
-									className="w-full h-8 px-2 py-1 text-xs bg-vscode-input-background text-vscode-input-foreground border border-vscode-input-border rounded focus:outline-0"
-								/>
-								{searchValue.length > 0 && (
-									<div className="absolute right-4 top-0 bottom-0 flex items-center justify-center">
-										<X
-											className="text-vscode-input-foreground opacity-50 hover:opacity-100 size-4 p-0.5 cursor-pointer"
-											onClick={onClearSearch}
-										/>
-									</div>
-								)}
-							</div>
+							{!disableSearch && (
+								<div className="relative p-2 border-b border-vscode-dropdown-border">
+									<input
+										aria-label="Search"
+										ref={searchInputRef}
+										value={searchValue}
+										onChange={(e) => setSearchValue(e.target.value)}
+										placeholder={t("common:ui.search_placeholder")}
+										className="w-full h-8 px-2 py-1 text-xs bg-vscode-input-background text-vscode-input-foreground border border-vscode-input-border rounded focus:outline-0"
+									/>
+									{searchValue.length > 0 && (
+										<div className="absolute right-4 top-0 bottom-0 flex items-center justify-center">
+											<X
+												className="text-vscode-input-foreground opacity-50 hover:opacity-100 size-4 p-0.5 cursor-pointer"
+												onClick={onClearSearch}
+											/>
+										</div>
+									)}
+								</div>
+							)}
 
 							{/* Dropdown items - Use windowing for large lists */}
 							<div className="max-h-[300px] overflow-y-auto">

+ 4 - 0
webview-ui/src/context/ExtensionStateContext.tsx

@@ -38,6 +38,8 @@ export interface ExtensionStateContextType extends ExtensionState {
 	sharingEnabled: boolean
 	maxConcurrentFileReads?: number
 	mdmCompliant?: boolean
+	hasOpenedModeSelector: boolean // New property to track if user has opened mode selector
+	setHasOpenedModeSelector: (value: boolean) => void // Setter for the new property
 	condensingApiConfigId?: string
 	setCondensingApiConfigId: (value: string) => void
 	customCondensingPrompt?: string
@@ -180,6 +182,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
 		enhancementApiConfigId: "",
 		condensingApiConfigId: "", // Default empty string for condensing API config ID
 		customCondensingPrompt: "", // Default empty string for custom condensing prompt
+		hasOpenedModeSelector: false, // Default to false (not opened yet)
 		autoApprovalEnabled: false,
 		customModes: [],
 		maxOpenTabsContext: 20,
@@ -427,6 +430,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
 			}),
 		setHistoryPreviewCollapsed: (value) =>
 			setState((prevState) => ({ ...prevState, historyPreviewCollapsed: value })),
+		setHasOpenedModeSelector: (value) => setState((prevState) => ({ ...prevState, hasOpenedModeSelector: value })),
 		setAutoCondenseContext: (value) => setState((prevState) => ({ ...prevState, autoCondenseContext: value })),
 		setAutoCondenseContextPercent: (value) =>
 			setState((prevState) => ({ ...prevState, autoCondenseContextPercent: value })),

+ 1 - 0
webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx

@@ -208,6 +208,7 @@ describe("mergeExtensionState", () => {
 			cloudIsAuthenticated: false,
 			sharingEnabled: false,
 			profileThresholds: {},
+			hasOpenedModeSelector: false, // Add the new required property
 		}
 
 		const prevState: ExtensionState = {

+ 6 - 0
webview-ui/src/i18n/locales/ca/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "manté premut shift per arrossegar fitxers",
 	"dragFilesImages": "manté premut shift per arrossegar fitxers/imatges",
 	"enhancePromptDescription": "El botó 'Millora la sol·licitud' ajuda a millorar la teva sol·licitud proporcionant context addicional, aclariments o reformulacions. Prova d'escriure una sol·licitud aquí i fes clic al botó de nou per veure com funciona.",
+	"modeSelector": {
+		"title": "Modes",
+		"marketplace": "Marketplace de Modes",
+		"settings": "Configuració de Modes",
+		"description": "Personalitats especialitzades que adapten el comportament de Roo."
+	},
 	"errorReadingFile": "Error en llegir el fitxer:",
 	"noValidImages": "No s'ha processat cap imatge vàlida",
 	"separator": "Separador",

+ 1 - 1
webview-ui/src/i18n/locales/ca/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "Ara pots utilitzar aquest mode. Feu clic a la icona Modes de la barra lateral per canviar de pestanya.",
 		"done": "Fet",
 		"goToMcp": "Anar a la pestanya MCP",
-		"goToModes": "Anar a la pestanya Modes",
+		"goToModes": "Anar a la configuració de Modes",
 		"moreInfoMcp": "Veure documentació MCP de {{name}}",
 		"validationRequired": "Si us plau, proporciona un valor per a {{paramName}}",
 		"prerequisites": "Prerequisits"

+ 9 - 0
webview-ui/src/i18n/locales/ca/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "Restablir a valors predeterminats",
 		"description": "Definiu l'experiència i personalitat de Roo per a aquest mode. Aquesta descripció determina com Roo es presenta i aborda les tasques."
 	},
+	"description": {
+		"title": "Descripció curta (per a humans)",
+		"resetToDefault": "Restablir a la descripció predeterminada",
+		"description": "Una breu descripció que es mostra al desplegable del selector de mode."
+	},
 	"whenToUse": {
 		"title": "Quan utilitzar (opcional)",
 		"description": "Descriviu quan s'hauria d'utilitzar aquest mode. Això ajuda l'Orchestrator a escollir el mode correcte per a una tasca.",
@@ -145,6 +150,10 @@
 			"label": "Eines disponibles",
 			"description": "Seleccioneu quines eines pot utilitzar aquest mode."
 		},
+		"description": {
+			"label": "Descripció curta (per a humans)",
+			"description": "Una breu descripció que es mostra al desplegable del selector de mode."
+		},
 		"customInstructions": {
 			"label": "Instruccions personalitzades (opcional)",
 			"description": "Afegiu directrius de comportament específiques per a aquest mode."

+ 6 - 0
webview-ui/src/i18n/locales/de/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "Shift halten, um Dateien einzufügen",
 	"dragFilesImages": "Shift halten, um Dateien/Bilder einzufügen",
 	"enhancePromptDescription": "Die Schaltfläche 'Prompt verbessern' hilft, deine Anfrage durch zusätzlichen Kontext, Klarstellungen oder Umformulierungen zu verbessern. Versuche, hier eine Anfrage einzugeben und klicke erneut auf die Schaltfläche, um zu sehen, wie es funktioniert.",
+	"modeSelector": {
+		"title": "Modi",
+		"marketplace": "Modus-Marketplace",
+		"settings": "Modus-Einstellungen",
+		"description": "Spezialisierte Personas, die Roos Verhalten anpassen."
+	},
 	"errorReadingFile": "Fehler beim Lesen der Datei:",
 	"noValidImages": "Keine gültigen Bilder wurden verarbeitet",
 	"separator": "Trennlinie",

+ 1 - 1
webview-ui/src/i18n/locales/de/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "Du kannst diesen Modus jetzt verwenden. Klicke auf das Modi-Symbol in der Seitenleiste, um die Tabs zu wechseln.",
 		"done": "Fertig",
 		"goToMcp": "Zum MCP-Tab gehen",
-		"goToModes": "Zum Modi-Tab gehen",
+		"goToModes": "Zu den Modi-Einstellungen gehen",
 		"moreInfoMcp": "{{name}} MCP-Dokumentation anzeigen",
 		"validationRequired": "Bitte gib einen Wert für {{paramName}} an",
 		"prerequisites": "Voraussetzungen"

+ 9 - 0
webview-ui/src/i18n/locales/de/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "Auf Standardwerte zurücksetzen",
 		"description": "Definiere Roos Expertise und Persönlichkeit für diesen Modus. Diese Beschreibung prägt, wie Roo sich präsentiert und an Aufgaben herangeht."
 	},
+	"description": {
+		"title": "Kurzbeschreibung (für Menschen)",
+		"resetToDefault": "Auf Standardbeschreibung zurücksetzen",
+		"description": "Eine kurze Beschreibung, die im Dropdown-Menü der Modusauswahl angezeigt wird."
+	},
 	"whenToUse": {
 		"title": "Wann zu verwenden (optional)",
 		"description": "Beschreibe, wann dieser Modus verwendet werden sollte. Dies hilft dem Orchestrator, den richtigen Modus für eine Aufgabe auszuwählen.",
@@ -145,6 +150,10 @@
 			"label": "Verfügbare Werkzeuge",
 			"description": "Wähle, welche Werkzeuge dieser Modus verwenden kann."
 		},
+		"description": {
+			"label": "Kurzbeschreibung (für Menschen)",
+			"description": "Eine kurze Beschreibung, die im Dropdown-Menü der Modusauswahl angezeigt wird."
+		},
 		"customInstructions": {
 			"label": "Benutzerdefinierte Anweisungen (optional)",
 			"description": "Fügen Sie verhaltensspezifische Richtlinien für diesen Modus hinzu."

+ 6 - 0
webview-ui/src/i18n/locales/en/chat.json

@@ -106,6 +106,12 @@
 	"selectMode": "Select mode for interaction",
 	"selectApiConfig": "Select API configuration",
 	"enhancePrompt": "Enhance prompt with additional context",
+	"modeSelector": {
+		"title": "Modes",
+		"marketplace": "Mode Marketplace",
+		"settings": "Mode Settings",
+		"description": "Specialized personas that tailor Roo's behavior."
+	},
 	"enhancePromptDescription": "The 'Enhance Prompt' button helps improve your prompt by providing additional context, clarification, or rephrasing. Try typing a prompt in here and clicking the button again to see how it works.",
 	"addImages": "Add images to message",
 	"sendMessage": "Send message",

+ 1 - 1
webview-ui/src/i18n/locales/en/marketplace.json

@@ -92,7 +92,7 @@
 		"whatNextMode": "You can now use this mode. Click the Modes icon in the sidebar to switch tabs.",
 		"done": "Done",
 		"goToMcp": "Go to MCP Tab",
-		"goToModes": "Go to Modes Tab",
+		"goToModes": "Go to Modes Settings",
 		"moreInfoMcp": "View {{name}} MCP documentation",
 		"validationRequired": "Please provide a value for {{paramName}}"
 	},

+ 11 - 2
webview-ui/src/i18n/locales/en/prompts.json

@@ -34,9 +34,14 @@
 		"resetToDefault": "Reset to default",
 		"description": "Define Roo's expertise and personality for this mode. This description shapes how Roo presents itself and approaches tasks."
 	},
+	"description": {
+		"title": "Short description (for humans)",
+		"resetToDefault": "Reset to default description",
+		"description": "A brief description shown in the mode selector dropdown."
+	},
 	"whenToUse": {
 		"title": "When to Use (optional)",
-		"description": "Describe when this mode should be used. This helps the Orchestrator choose the right mode for a task.",
+		"description": "Guidance for Roo for when this mode should be used. This helps the Orchestrator choose the right mode for a task.",
 		"resetToDefault": "Reset to default 'When to Use' description"
 	},
 	"customInstructions": {
@@ -137,9 +142,13 @@
 			"label": "Role Definition",
 			"description": "Define Roo's expertise and personality for this mode."
 		},
+		"description": {
+			"label": "Short description (for humans)",
+			"description": "A brief description shown in the mode selector dropdown."
+		},
 		"whenToUse": {
 			"label": "When to Use (optional)",
-			"description": "Provide a clear description of when this mode is most effective and what types of tasks it excels at."
+			"description": "Guidance for Roo for when this mode should be used. This helps the Orchestrator choose the right mode for a task."
 		},
 		"tools": {
 			"label": "Available Tools",

+ 6 - 0
webview-ui/src/i18n/locales/es/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "mantén shift para arrastrar archivos",
 	"dragFilesImages": "mantén shift para arrastrar archivos/imágenes",
 	"enhancePromptDescription": "El botón 'Mejorar el mensaje' ayuda a mejorar tu petición proporcionando contexto adicional, aclaraciones o reformulaciones. Intenta escribir una petición aquí y haz clic en el botón nuevamente para ver cómo funciona.",
+	"modeSelector": {
+		"title": "Modos",
+		"marketplace": "Marketplace de Modos",
+		"settings": "Configuración de Modos",
+		"description": "Personalidades especializadas que adaptan el comportamiento de Roo."
+	},
 	"errorReadingFile": "Error al leer el archivo:",
 	"noValidImages": "No se procesaron imágenes válidas",
 	"separator": "Separador",

+ 1 - 1
webview-ui/src/i18n/locales/es/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "Ahora puedes usar este modo. Haz clic en el icono Modos en la barra lateral para cambiar de pestaña.",
 		"done": "Hecho",
 		"goToMcp": "Ir a la pestaña MCP",
-		"goToModes": "Ir a la pestaña Modos",
+		"goToModes": "Ir a la configuración de Modos",
 		"moreInfoMcp": "Ver documentación MCP de {{name}}",
 		"validationRequired": "Por favor proporciona un valor para {{paramName}}",
 		"prerequisites": "Requisitos previos"

+ 9 - 0
webview-ui/src/i18n/locales/es/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "Restablecer a valores predeterminados",
 		"description": "Define la experiencia y personalidad de Roo para este modo. Esta descripción determina cómo Roo se presenta y aborda las tareas."
 	},
+	"description": {
+		"title": "Descripción breve (para humanos)",
+		"resetToDefault": "Restablecer a la descripción predeterminada",
+		"description": "Una breve descripción que se muestra en el menú desplegable del selector de modo."
+	},
 	"whenToUse": {
 		"title": "Cuándo usar (opcional)",
 		"description": "Describe cuándo se debe usar este modo. Esto ayuda al Orchestrator a elegir el modo correcto para una tarea.",
@@ -145,6 +150,10 @@
 			"label": "Herramientas disponibles",
 			"description": "Selecciona qué herramientas puede usar este modo."
 		},
+		"description": {
+			"label": "Descripción breve (para humanos)",
+			"description": "Una breve descripción que se muestra en el menú desplegable del selector de modo."
+		},
 		"customInstructions": {
 			"label": "Instrucciones personalizadas (opcional)",
 			"description": "Agrega directrices de comportamiento específicas para este modo."

+ 6 - 0
webview-ui/src/i18n/locales/fr/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "maintenir Maj pour glisser des fichiers",
 	"dragFilesImages": "maintenir Maj pour glisser des fichiers/images",
 	"enhancePromptDescription": "Le bouton 'Améliorer la requête' aide à améliorer votre demande en fournissant un contexte supplémentaire, des clarifications ou des reformulations. Essayez de taper une demande ici et cliquez à nouveau sur le bouton pour voir comment cela fonctionne.",
+	"modeSelector": {
+		"title": "Modes",
+		"marketplace": "Marketplace de Modes",
+		"settings": "Paramètres des Modes",
+		"description": "Personas spécialisés qui adaptent le comportement de Roo."
+	},
 	"errorReadingFile": "Erreur lors de la lecture du fichier :",
 	"noValidImages": "Aucune image valide n'a été traitée",
 	"separator": "Séparateur",

+ 1 - 1
webview-ui/src/i18n/locales/fr/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "Vous pouvez maintenant utiliser ce mode. Cliquez sur l'icône Modes dans la barre latérale pour changer d'onglet.",
 		"done": "Terminé",
 		"goToMcp": "Aller à l'onglet MCP",
-		"goToModes": "Aller à l'onglet Modes",
+		"goToModes": "Aller aux paramètres des Modes",
 		"moreInfoMcp": "Voir la documentation MCP de {{name}}",
 		"validationRequired": "Veuillez fournir une valeur pour {{paramName}}",
 		"prerequisites": "Prérequis"

+ 9 - 0
webview-ui/src/i18n/locales/fr/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "Réinitialiser aux valeurs par défaut",
 		"description": "Définissez l'expertise et la personnalité de Roo pour ce mode. Cette description façonne la manière dont Roo se présente et aborde les tâches."
 	},
+	"description": {
+		"title": "Description courte (pour humains)",
+		"resetToDefault": "Réinitialiser à la description par défaut",
+		"description": "Une brève description affichée dans le menu déroulant du sélecteur de mode."
+	},
 	"whenToUse": {
 		"title": "Quand utiliser (optionnel)",
 		"description": "Décrivez quand ce mode doit être utilisé. Cela aide l'Orchestrateur à choisir le mode approprié pour une tâche.",
@@ -145,6 +150,10 @@
 			"label": "Outils disponibles",
 			"description": "Sélectionnez quels outils ce mode peut utiliser."
 		},
+		"description": {
+			"label": "Description courte (pour humains)",
+			"description": "Une brève description affichée dans le menu déroulant du sélecteur de mode."
+		},
 		"customInstructions": {
 			"label": "Instructions personnalisées (optionnel)",
 			"description": "Ajoutez des directives comportementales spécifiques à ce mode."

+ 6 - 0
webview-ui/src/i18n/locales/hi/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "फ़ाइलें खींचने के लिए shift दबाकर रखें",
 	"dragFilesImages": "फ़ाइलें/चित्र खींचने के लिए shift दबाकर रखें",
 	"enhancePromptDescription": "'प्रॉम्प्ट बढ़ाएँ' बटन अतिरिक्त संदर्भ, स्पष्टीकरण या पुनर्विचार प्रदान करके आपके अनुरोध को बेहतर बनाने में मदद करता है। यहां अनुरोध लिखकर देखें और यह कैसे काम करता है यह देखने के लिए बटन पर फिर से क्लिक करें।",
+	"modeSelector": {
+		"title": "मोड्स",
+		"marketplace": "मोड मार्केटप्लेस",
+		"settings": "मोड सेटिंग्स",
+		"description": "विशेष व्यक्तित्व जो Roo के व्यवहार को अनुकूलित करते हैं।"
+	},
 	"errorReadingFile": "फ़ाइल पढ़ने में त्रुटि:",
 	"noValidImages": "कोई मान्य चित्र प्रोसेस नहीं किया गया",
 	"separator": "विभाजक",

+ 1 - 1
webview-ui/src/i18n/locales/hi/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "अब आप इस मोड का उपयोग कर सकते हैं। टैब स्विच करने के लिए साइडबार में मोड आइकन पर क्लिक करें।",
 		"done": "पूर्ण",
 		"goToMcp": "MCP टैब पर जाएं",
-		"goToModes": "मोड टैब पर जाएं",
+		"goToModes": "मोड सेटिंग्स पर जाएं",
 		"moreInfoMcp": "{{name}} MCP दस्तावेज़ देखें",
 		"validationRequired": "कृपया {{paramName}} के लिए एक मान प्रदान करें",
 		"prerequisites": "आवश्यकताएं"

+ 9 - 0
webview-ui/src/i18n/locales/hi/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "डिफ़ॉल्ट पर रीसेट करें",
 		"description": "इस मोड के लिए Roo की विशेषज्ञता और व्यक्तित्व परिभाषित करें। यह विवरण Roo के स्वयं को प्रस्तुत करने और कार्यों से निपटने के तरीके को आकार देता है।"
 	},
+	"description": {
+		"title": "संक्षिप्त विवरण (मनुष्यों के लिए)",
+		"resetToDefault": "डिफ़ॉल्ट विवरण पर रीसेट करें",
+		"description": "मोड सेलेक्टर ड्रॉपडाउन में दिखाया गया संक्षिप्त विवरण।"
+	},
 	"whenToUse": {
 		"title": "कब उपयोग करें (वैकल्पिक)",
 		"description": "बताएं कि इस मोड का उपयोग कब किया जाना चाहिए। यह Orchestrator को किसी कार्य के लिए सही मोड चुनने में मदद करता है।",
@@ -145,6 +150,10 @@
 			"label": "उपलब्ध टूल्स",
 			"description": "चुनें कि यह मोड कौन से टूल्स उपयोग कर सकता है।"
 		},
+		"description": {
+			"label": "संक्षिप्त विवरण (मनुष्यों के लिए)",
+			"description": "मोड सेलेक्टर ड्रॉपडाउन में दिखाया गया संक्षिप्त विवरण।"
+		},
 		"customInstructions": {
 			"label": "कस्टम निर्देश (वैकल्पिक)",
 			"description": "इस मोड के लिए विशिष्ट व्यवहार दिशानिर्देश जोड़ें।"

+ 6 - 0
webview-ui/src/i18n/locales/id/chat.json

@@ -113,6 +113,12 @@
 	"selectApiConfig": "Pilih konfigurasi API",
 	"enhancePrompt": "Tingkatkan prompt dengan konteks tambahan",
 	"enhancePromptDescription": "Tombol 'Tingkatkan Prompt' membantu memperbaiki prompt kamu dengan memberikan konteks tambahan, klarifikasi, atau penyusunan ulang. Coba ketik prompt di sini dan klik tombol lagi untuk melihat cara kerjanya.",
+	"modeSelector": {
+		"title": "Mode",
+		"marketplace": "Marketplace Mode",
+		"settings": "Pengaturan Mode",
+		"description": "Persona khusus yang menyesuaikan perilaku Roo."
+	},
 	"addImages": "Tambahkan gambar ke pesan",
 	"sendMessage": "Kirim pesan",
 	"typeMessage": "Ketik pesan...",

+ 1 - 1
webview-ui/src/i18n/locales/id/marketplace.json

@@ -92,7 +92,7 @@
 		"whatNextMode": "Anda sekarang dapat menggunakan mode ini. Klik ikon Mode di sidebar untuk beralih tab.",
 		"done": "Selesai",
 		"goToMcp": "Ke Tab MCP",
-		"goToModes": "Ke Tab Mode",
+		"goToModes": "Ke Pengaturan Mode",
 		"moreInfoMcp": "Lihat dokumentasi MCP {{name}}",
 		"validationRequired": "Silakan berikan nilai untuk {{paramName}}"
 	},

+ 9 - 0
webview-ui/src/i18n/locales/id/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "Reset ke default",
 		"description": "Tentukan keahlian dan kepribadian Roo untuk mode ini. Deskripsi ini membentuk bagaimana Roo mempresentasikan dirinya dan mendekati tugas."
 	},
+	"description": {
+		"title": "Deskripsi singkat (untuk manusia)",
+		"resetToDefault": "Setel ulang ke deskripsi default",
+		"description": "Deskripsi singkat yang ditampilkan di dropdown pemilih mode."
+	},
 	"whenToUse": {
 		"title": "Kapan Menggunakan (opsional)",
 		"description": "Jelaskan kapan mode ini harus digunakan. Ini membantu Orchestrator memilih mode yang tepat untuk suatu tugas.",
@@ -145,6 +150,10 @@
 			"label": "Tools yang Tersedia",
 			"description": "Pilih tools mana yang dapat digunakan mode ini."
 		},
+		"description": {
+			"label": "Deskripsi singkat (untuk manusia)",
+			"description": "Deskripsi singkat yang ditampilkan di dropdown pemilih mode."
+		},
 		"customInstructions": {
 			"label": "Instruksi Kustom (opsional)",
 			"description": "Tambahkan panduan perilaku khusus untuk mode ini."

+ 6 - 0
webview-ui/src/i18n/locales/it/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "tieni premuto shift per trascinare file",
 	"dragFilesImages": "tieni premuto shift per trascinare file/immagini",
 	"enhancePromptDescription": "Il pulsante 'Migliora prompt' aiuta a migliorare la tua richiesta fornendo contesto aggiuntivo, chiarimenti o riformulazioni. Prova a digitare una richiesta qui e fai di nuovo clic sul pulsante per vedere come funziona.",
+	"modeSelector": {
+		"title": "Modalità",
+		"marketplace": "Marketplace delle Modalità",
+		"settings": "Impostazioni Modalità",
+		"description": "Personalità specializzate che adattano il comportamento di Roo."
+	},
 	"errorReadingFile": "Errore nella lettura del file:",
 	"noValidImages": "Nessuna immagine valida è stata elaborata",
 	"separator": "Separatore",

+ 1 - 1
webview-ui/src/i18n/locales/it/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "Ora puoi utilizzare questa modalità. Clicca sull'icona delle modalità nella barra laterale per cambiare scheda.",
 		"done": "Fatto",
 		"goToMcp": "Vai alla scheda MCP",
-		"goToModes": "Vai alla scheda Modalità",
+		"goToModes": "Vai alle impostazioni Modalità",
 		"moreInfoMcp": "Visualizza documentazione MCP {{name}}",
 		"validationRequired": "Fornisci un valore per {{paramName}}",
 		"prerequisites": "Prerequisiti"

+ 9 - 0
webview-ui/src/i18n/locales/it/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "Ripristina predefiniti",
 		"description": "Definisci l'esperienza e la personalità di Roo per questa modalità. Questa descrizione modella come Roo si presenta e affronta i compiti."
 	},
+	"description": {
+		"title": "Descrizione breve (per umani)",
+		"resetToDefault": "Ripristina alla descrizione predefinita",
+		"description": "Una breve descrizione mostrata nel menu a discesa del selettore di modalità."
+	},
 	"whenToUse": {
 		"title": "Quando utilizzare (opzionale)",
 		"description": "Descrivi quando questa modalità dovrebbe essere utilizzata. Questo aiuta l'Orchestrator a scegliere la modalità giusta per un compito.",
@@ -137,6 +142,10 @@
 			"label": "Definizione del ruolo",
 			"description": "Definisci l'esperienza e la personalità di Roo per questa modalità."
 		},
+		"description": {
+			"label": "Descrizione breve (per umani)",
+			"description": "Una breve descrizione mostrata nel menu a discesa del selettore di modalità."
+		},
 		"whenToUse": {
 			"label": "Quando utilizzare (opzionale)",
 			"description": "Fornisci una chiara descrizione di quando questa modalità è più efficace e per quali tipi di compiti eccelle."

+ 6 - 0
webview-ui/src/i18n/locales/ja/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "ファイルをドラッグするにはShiftキーを押したまま",
 	"dragFilesImages": "ファイル/画像をドラッグするにはShiftキーを押したまま",
 	"enhancePromptDescription": "「プロンプトを強化」ボタンは、追加コンテキスト、説明、または言い換えを提供することで、リクエストを改善します。ここにリクエストを入力し、ボタンを再度クリックして動作を確認してください。",
+	"modeSelector": {
+		"title": "モード",
+		"marketplace": "モードマーケットプレイス",
+		"settings": "モード設定",
+		"description": "Rooの動作をカスタマイズする専門的なペルソナ。"
+	},
 	"errorReadingFile": "ファイル読み込みエラー:",
 	"noValidImages": "有効な画像が処理されませんでした",
 	"separator": "区切り",

+ 1 - 1
webview-ui/src/i18n/locales/ja/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "このモードを使用できるようになりました。サイドバーのモードアイコンをクリックしてタブを切り替えてください。",
 		"done": "完了",
 		"goToMcp": "MCPタブに移動",
-		"goToModes": "モードタブに移動",
+		"goToModes": "モード設定に移動",
 		"moreInfoMcp": "{{name}} MCPドキュメントを表示",
 		"validationRequired": "{{paramName}}の値を入力してください",
 		"prerequisites": "前提条件"

+ 9 - 0
webview-ui/src/i18n/locales/ja/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "デフォルトにリセット",
 		"description": "このモードのRooの専門知識と個性を定義します。この説明は、Rooが自身をどのように表現し、タスクにどのように取り組むかを形作ります。"
 	},
+	"description": {
+		"title": "短い説明(人間向け)",
+		"resetToDefault": "デフォルトの説明にリセット",
+		"description": "モードセレクタのドロップダウンに表示される簡単な説明。"
+	},
 	"whenToUse": {
 		"title": "使用タイミング(オプション)",
 		"description": "このモードをいつ使用すべきかを説明します。これはOrchestratorがタスクに適切なモードを選択するのに役立ちます。",
@@ -145,6 +150,10 @@
 			"label": "利用可能なツール",
 			"description": "このモードが使用できるツールを選択します。"
 		},
+		"description": {
+			"label": "短い説明(人間向け)",
+			"description": "モードセレクタのドロップダウンに表示される簡単な説明。"
+		},
 		"customInstructions": {
 			"label": "カスタム指示(オプション)",
 			"description": "このモードに特化した行動ガイドラインを追加します。"

+ 6 - 0
webview-ui/src/i18n/locales/ko/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "파일을 드래그하려면 shift 키 누르기",
 	"dragFilesImages": "파일/이미지를 드래그하려면 shift 키 누르기",
 	"enhancePromptDescription": "'프롬프트 향상' 버튼은 추가 컨텍스트, 명확화 또는 재구성을 제공하여 요청을 개선합니다. 여기에 요청을 입력한 다음 버튼을 다시 클릭하여 작동 방식을 확인해보세요.",
+	"modeSelector": {
+		"title": "모드",
+		"marketplace": "모드 마켓플레이스",
+		"settings": "모드 설정",
+		"description": "Roo의 행동을 맞춤화하는 전문화된 페르소나."
+	},
 	"errorReadingFile": "파일 읽기 오류:",
 	"noValidImages": "처리된 유효한 이미지가 없습니다",
 	"separator": "구분자",

+ 1 - 1
webview-ui/src/i18n/locales/ko/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "이제 이 모드를 사용할 수 있습니다. 사이드바의 모드 아이콘을 클릭하여 탭을 전환하세요.",
 		"done": "완료",
 		"goToMcp": "MCP 탭으로 이동",
-		"goToModes": "모드 으로 이동",
+		"goToModes": "모드 설정으로 이동",
 		"moreInfoMcp": "{{name}} MCP 문서 보기",
 		"validationRequired": "{{paramName}}에 대한 값을 입력해주세요",
 		"prerequisites": "전제 조건"

+ 9 - 0
webview-ui/src/i18n/locales/ko/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "기본값으로 재설정",
 		"description": "이 모드에 대한 Roo의 전문성과 성격을 정의하세요. 이 설명은 Roo가 자신을 어떻게 표현하고 작업에 접근하는지 형성합니다."
 	},
+	"description": {
+		"title": "짧은 설명 (사람용)",
+		"resetToDefault": "기본 설명으로 재설정",
+		"description": "모드 선택기 드롭다운에 표시되는 간단한 설명입니다."
+	},
 	"whenToUse": {
 		"title": "사용 시기 (선택 사항)",
 		"description": "이 모드를 언제 사용해야 하는지 설명합니다. 이는 Orchestrator가 작업에 적합한 모드를 선택하는 데 도움이 됩니다.",
@@ -145,6 +150,10 @@
 			"label": "사용 가능한 도구",
 			"description": "이 모드가 사용할 수 있는 도구를 선택하세요."
 		},
+		"description": {
+			"label": "짧은 설명 (사람용)",
+			"description": "모드 선택기 드롭다운에 표시되는 간단한 설명입니다."
+		},
 		"customInstructions": {
 			"label": "사용자 지정 지침 (선택 사항)",
 			"description": "이 모드에 대한 특정 행동 지침을 추가하세요."

+ 6 - 0
webview-ui/src/i18n/locales/nl/chat.json

@@ -99,6 +99,12 @@
 	"selectApiConfig": "Selecteer API-configuratie",
 	"enhancePrompt": "Prompt verbeteren met extra context",
 	"enhancePromptDescription": "De knop 'Prompt verbeteren' helpt je prompt te verbeteren door extra context, verduidelijking of herformulering te bieden. Probeer hier een prompt te typen en klik opnieuw op de knop om te zien hoe het werkt.",
+	"modeSelector": {
+		"title": "Modi",
+		"marketplace": "Modus Marktplaats",
+		"settings": "Modus Instellingen",
+		"description": "Gespecialiseerde persona's die het gedrag van Roo aanpassen."
+	},
 	"addImages": "Afbeeldingen toevoegen aan bericht",
 	"sendMessage": "Bericht verzenden",
 	"typeMessage": "Typ een bericht...",

+ 1 - 1
webview-ui/src/i18n/locales/nl/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "Je kunt deze modus nu gebruiken. Klik op het modi-pictogram in de zijbalk om van tabblad te wisselen.",
 		"done": "Gereed",
 		"goToMcp": "Ga naar MCP-tabblad",
-		"goToModes": "Ga naar Modi-tabblad",
+		"goToModes": "Ga naar Modi-instellingen",
 		"moreInfoMcp": "{{name}} MCP-documentatie bekijken",
 		"validationRequired": "Geef een waarde op voor {{paramName}}",
 		"prerequisites": "Vereisten"

+ 9 - 0
webview-ui/src/i18n/locales/nl/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "Terugzetten naar standaard",
 		"description": "Definieer Roo's expertise en persoonlijkheid voor deze modus. Deze beschrijving bepaalt hoe Roo zich presenteert en taken benadert."
 	},
+	"description": {
+		"title": "Korte beschrijving (voor mensen)",
+		"resetToDefault": "Terugzetten naar standaardbeschrijving",
+		"description": "Een korte beschrijving die wordt getoond in de modusselectie dropdown."
+	},
 	"whenToUse": {
 		"title": "Wanneer te gebruiken (optioneel)",
 		"description": "Beschrijf wanneer deze modus gebruikt moet worden. Dit helpt de Orchestrator om de juiste modus voor een taak te kiezen.",
@@ -145,6 +150,10 @@
 			"label": "Beschikbare tools",
 			"description": "Selecteer welke tools deze modus kan gebruiken."
 		},
+		"description": {
+			"label": "Korte beschrijving (voor mensen)",
+			"description": "Een korte beschrijving die wordt getoond in de modusselectie dropdown."
+		},
 		"customInstructions": {
 			"label": "Aangepaste instructies (optioneel)",
 			"description": "Voeg gedragsrichtlijnen toe die specifiek zijn voor deze modus."

+ 6 - 0
webview-ui/src/i18n/locales/pl/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "przytrzymaj shift, aby przeciągnąć pliki",
 	"dragFilesImages": "przytrzymaj shift, aby przeciągnąć pliki/obrazy",
 	"enhancePromptDescription": "Przycisk 'Ulepsz podpowiedź' pomaga ulepszyć Twoją prośbę, dostarczając dodatkowy kontekst, wyjaśnienia lub przeformułowania. Spróbuj wpisać prośbę tutaj i kliknij przycisk ponownie, aby zobaczyć, jak to działa.",
+	"modeSelector": {
+		"title": "Tryby",
+		"marketplace": "Marketplace Trybów",
+		"settings": "Ustawienia Trybów",
+		"description": "Wyspecjalizowane persony, które dostosowują zachowanie Roo."
+	},
 	"errorReadingFile": "Błąd odczytu pliku:",
 	"noValidImages": "Nie przetworzono żadnych prawidłowych obrazów",
 	"separator": "Separator",

+ 1 - 1
webview-ui/src/i18n/locales/pl/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "Możesz teraz używać tego trybu. Kliknij ikonę Tryby na pasku bocznym, aby przełączyć zakładki.",
 		"done": "Gotowe",
 		"goToMcp": "Przejdź do zakładki MCP",
-		"goToModes": "Przejdź do zakładki Tryby",
+		"goToModes": "Przejdź do ustawień Trybów",
 		"moreInfoMcp": "Zobacz dokumentację MCP {{name}}",
 		"validationRequired": "Podaj wartość dla {{paramName}}",
 		"prerequisites": "Wymagania wstępne"

+ 9 - 0
webview-ui/src/i18n/locales/pl/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "Przywróć domyślne",
 		"description": "Zdefiniuj wiedzę specjalistyczną i osobowość Roo dla tego trybu. Ten opis kształtuje, jak Roo prezentuje się i podchodzi do zadań."
 	},
+	"description": {
+		"title": "Krótki opis (dla ludzi)",
+		"resetToDefault": "Przywróć domyślny opis",
+		"description": "Krótki opis wyświetlany w rozwijanej liście wyboru trybu."
+	},
 	"whenToUse": {
 		"title": "Kiedy używać (opcjonalne)",
 		"description": "Opisz, kiedy ten tryb powinien być używany. Pomaga to Orchestratorowi wybrać odpowiedni tryb dla zadania.",
@@ -145,6 +150,10 @@
 			"label": "Dostępne narzędzia",
 			"description": "Wybierz, których narzędzi może używać ten tryb."
 		},
+		"description": {
+			"label": "Krótki opis (dla ludzi)",
+			"description": "Krótki opis wyświetlany w rozwijanej liście wyboru trybu."
+		},
 		"customInstructions": {
 			"label": "Niestandardowe instrukcje (opcjonalne)",
 			"description": "Dodaj wytyczne dotyczące zachowania specyficzne dla tego trybu."

+ 6 - 0
webview-ui/src/i18n/locales/pt-BR/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "segure shift para arrastar arquivos",
 	"dragFilesImages": "segure shift para arrastar arquivos/imagens",
 	"enhancePromptDescription": "O botão 'Aprimorar prompt' ajuda a melhorar seu pedido fornecendo contexto adicional, esclarecimentos ou reformulações. Tente digitar um pedido aqui e clique no botão novamente para ver como funciona.",
+	"modeSelector": {
+		"title": "Modos",
+		"marketplace": "Marketplace de Modos",
+		"settings": "Configurações de Modos",
+		"description": "Personas especializadas que adaptam o comportamento do Roo."
+	},
 	"errorReadingFile": "Erro ao ler arquivo:",
 	"noValidImages": "Nenhuma imagem válida foi processada",
 	"separator": "Separador",

+ 1 - 1
webview-ui/src/i18n/locales/pt-BR/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "Agora você pode usar este modo. Clique no ícone Modos na barra lateral para trocar de aba.",
 		"done": "Concluído",
 		"goToMcp": "Ir para aba MCP",
-		"goToModes": "Ir para aba Modos",
+		"goToModes": "Ir para configurações de Modos",
 		"moreInfoMcp": "Ver documentação MCP do {{name}}",
 		"validationRequired": "Por favor, forneça um valor para {{paramName}}",
 		"prerequisites": "Pré-requisitos"

+ 9 - 0
webview-ui/src/i18n/locales/pt-BR/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "Restaurar para padrão",
 		"description": "Defina a expertise e personalidade do Roo para este modo. Esta descrição molda como o Roo se apresenta e aborda tarefas."
 	},
+	"description": {
+		"title": "Descrição curta (para humanos)",
+		"resetToDefault": "Redefinir para descrição padrão",
+		"description": "Uma breve descrição exibida no menu suspenso do seletor de modo."
+	},
 	"whenToUse": {
 		"title": "Quando usar (opcional)",
 		"description": "Descreva quando este modo deve ser usado. Isso ajuda o Orchestrator a escolher o modo certo para uma tarefa.",
@@ -145,6 +150,10 @@
 			"label": "Ferramentas disponíveis",
 			"description": "Selecione quais ferramentas este modo pode usar."
 		},
+		"description": {
+			"label": "Descrição curta (para humanos)",
+			"description": "Uma breve descrição exibida no menu suspenso do seletor de modo."
+		},
 		"customInstructions": {
 			"label": "Instruções personalizadas (opcional)",
 			"description": "Adicione diretrizes comportamentais específicas para este modo."

+ 6 - 0
webview-ui/src/i18n/locales/ru/chat.json

@@ -99,6 +99,12 @@
 	"selectApiConfig": "Выберите конфигурацию API",
 	"enhancePrompt": "Улучшить запрос с дополнительным контекстом",
 	"enhancePromptDescription": "Кнопка 'Улучшить запрос' помогает сделать ваш запрос лучше, предоставляя дополнительный контекст, уточнения или переформулировку. Попробуйте ввести запрос и снова нажать кнопку, чтобы увидеть, как это работает.",
+	"modeSelector": {
+		"title": "Режимы",
+		"marketplace": "Маркетплейс режимов",
+		"settings": "Настройки режимов",
+		"description": "Специализированные персоны, которые настраивают поведение Roo."
+	},
 	"addImages": "Добавить изображения к сообщению",
 	"sendMessage": "Отправить сообщение",
 	"typeMessage": "Введите сообщение...",

+ 1 - 1
webview-ui/src/i18n/locales/ru/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "Теперь вы можете использовать этот режим. Нажмите на иконку Режимы в боковой панели для переключения вкладок.",
 		"done": "Готово",
 		"goToMcp": "Перейти во вкладку MCP",
-		"goToModes": "Перейти во вкладку Режимы",
+		"goToModes": "Перейти в настройки Режимов",
 		"moreInfoMcp": "Просмотреть документацию MCP {{name}}",
 		"validationRequired": "Пожалуйста, укажите значение для {{paramName}}",
 		"prerequisites": "Предварительные требования"

+ 9 - 0
webview-ui/src/i18n/locales/ru/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "Сбросить по умолчанию",
 		"description": "Определите экспертность и личность Roo для этого режима. Это описание формирует, как Roo будет себя вести и выполнять задачи."
 	},
+	"description": {
+		"title": "Краткое описание (для людей)",
+		"resetToDefault": "Сбросить до описания по умолчанию",
+		"description": "Краткое описание, отображаемое в выпадающем списке выбора режима."
+	},
 	"whenToUse": {
 		"title": "Когда использовать (необязательно)",
 		"description": "Опишите, когда следует использовать этот режим. Это помогает Orchestrator выбрать правильный режим для задачи.",
@@ -145,6 +150,10 @@
 			"label": "Доступные инструменты",
 			"description": "Выберите, какие инструменты может использовать этот режим."
 		},
+		"description": {
+			"label": "Краткое описание (для людей)",
+			"description": "Краткое описание, отображаемое в выпадающем списке выбора режима."
+		},
 		"customInstructions": {
 			"label": "Пользовательские инструкции (необязательно)",
 			"description": "Добавьте рекомендации по поведению, специфичные для этого режима."

+ 6 - 0
webview-ui/src/i18n/locales/tr/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "dosyaları sürüklemek için shift tuşuna basılı tutun",
 	"dragFilesImages": "dosyaları/resimleri sürüklemek için shift tuşuna basılı tutun",
 	"enhancePromptDescription": "'İstemi geliştir' düğmesi, ek bağlam, açıklama veya yeniden ifade sağlayarak isteğinizi iyileştirmeye yardımcı olur. Buraya bir istek yazıp düğmeye tekrar tıklayarak nasıl çalıştığını görebilirsiniz.",
+	"modeSelector": {
+		"title": "Modlar",
+		"marketplace": "Mod Pazaryeri",
+		"settings": "Mod Ayarları",
+		"description": "Roo'nun davranışını özelleştiren uzmanlaşmış kişilikler."
+	},
 	"errorReadingFile": "Dosya okuma hatası:",
 	"noValidImages": "Hiçbir geçerli resim işlenmedi",
 	"separator": "Ayırıcı",

+ 1 - 1
webview-ui/src/i18n/locales/tr/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "Artık bu modu kullanabilirsiniz. Sekmeleri değiştirmek için kenar çubuğundaki Modlar simgesine tıklayın.",
 		"done": "Tamamlandı",
 		"goToMcp": "MCP Sekmesine Git",
-		"goToModes": "Modlar Sekmesine Git",
+		"goToModes": "Modlar Ayarlarına Git",
 		"moreInfoMcp": "{{name}} MCP belgelerini görüntüle",
 		"validationRequired": "Lütfen {{paramName}} için bir değer sağlayın",
 		"prerequisites": "Ön koşullar"

+ 9 - 0
webview-ui/src/i18n/locales/tr/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "Varsayılana sıfırla",
 		"description": "Bu mod için Roo'nun uzmanlığını ve kişiliğini tanımlayın. Bu açıklama, Roo'nun kendini nasıl sunduğunu ve görevlere nasıl yaklaştığını şekillendirir."
 	},
+	"description": {
+		"title": "Kısa açıklama (insanlar için)",
+		"resetToDefault": "Varsayılan açıklamaya sıfırla",
+		"description": "Mod seçici açılır menüsünde gösterilen kısa bir açıklama."
+	},
 	"whenToUse": {
 		"title": "Ne zaman kullanılmalı (isteğe bağlı)",
 		"description": "Bu modun ne zaman kullanılması gerektiğini açıklayın. Bu, Orchestrator'ın bir görev için doğru modu seçmesine yardımcı olur.",
@@ -145,6 +150,10 @@
 			"label": "Kullanılabilir Araçlar",
 			"description": "Bu modun hangi araçları kullanabileceğini seçin."
 		},
+		"description": {
+			"label": "Kısa açıklama (insanlar için)",
+			"description": "Mod seçici açılır menüsünde gösterilen kısa bir açıklama."
+		},
 		"customInstructions": {
 			"label": "Özel Talimatlar (isteğe bağlı)",
 			"description": "Bu mod için özel davranış yönergeleri ekleyin."

+ 6 - 0
webview-ui/src/i18n/locales/vi/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "giữ shift để kéo tệp",
 	"dragFilesImages": "giữ shift để kéo tệp/hình ảnh",
 	"enhancePromptDescription": "Nút 'Nâng cao yêu cầu' giúp cải thiện yêu cầu của bạn bằng cách cung cấp ngữ cảnh bổ sung, làm rõ hoặc diễn đạt lại. Hãy thử nhập yêu cầu tại đây và nhấp vào nút một lần nữa để xem cách thức hoạt động.",
+	"modeSelector": {
+		"title": "Chế độ",
+		"marketplace": "Chợ Chế độ",
+		"settings": "Cài đặt Chế độ",
+		"description": "Các nhân cách chuyên biệt điều chỉnh hành vi của Roo."
+	},
 	"errorReadingFile": "Lỗi khi đọc tệp:",
 	"noValidImages": "Không có hình ảnh hợp lệ nào được xử lý",
 	"separator": "Dấu phân cách",

+ 1 - 1
webview-ui/src/i18n/locales/vi/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "Bây giờ bạn có thể sử dụng chế độ này. Nhấp vào biểu tượng Chế độ trong thanh bên để chuyển tab.",
 		"done": "Hoàn thành",
 		"goToMcp": "Đi đến Tab MCP",
-		"goToModes": "Đi đến Tab Chế độ",
+		"goToModes": "Đi đến Cài đặt Chế độ",
 		"moreInfoMcp": "Xem tài liệu MCP {{name}}",
 		"validationRequired": "Vui lòng cung cấp giá trị cho {{paramName}}",
 		"prerequisites": "Điều kiện tiên quyết"

+ 9 - 0
webview-ui/src/i18n/locales/vi/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "Đặt lại về mặc định",
 		"description": "Xác định chuyên môn và tính cách của Roo cho chế độ này. Mô tả này định hình cách Roo giới thiệu bản thân và tiếp cận nhiệm vụ."
 	},
+	"description": {
+		"title": "Mô tả ngắn (cho con người)",
+		"resetToDefault": "Đặt lại về mô tả mặc định",
+		"description": "Mô tả ngắn gọn hiển thị trong menu thả xuống bộ chọn chế độ."
+	},
 	"whenToUse": {
 		"title": "Khi nào nên sử dụng (tùy chọn)",
 		"description": "Mô tả khi nào nên sử dụng chế độ này. Điều này giúp Orchestrator chọn chế độ phù hợp cho một nhiệm vụ.",
@@ -145,6 +150,10 @@
 			"label": "Công cụ có sẵn",
 			"description": "Chọn công cụ nào chế độ này có thể sử dụng."
 		},
+		"description": {
+			"label": "Mô tả ngắn (cho con người)",
+			"description": "Mô tả ngắn gọn hiển thị trong menu thả xuống bộ chọn chế độ."
+		},
 		"customInstructions": {
 			"label": "Hướng dẫn tùy chỉnh (tùy chọn)",
 			"description": "Thêm hướng dẫn hành vi dành riêng cho chế độ này."

+ 6 - 0
webview-ui/src/i18n/locales/zh-CN/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "Shift+拖拽文件",
 	"dragFilesImages": "Shift+拖拽文件/图片",
 	"enhancePromptDescription": "'增强提示'按钮通过提供额外上下文、澄清或重新表述来帮助改进您的请求。尝试在此处输入请求,然后再次点击按钮查看其工作原理。",
+	"modeSelector": {
+		"title": "模式",
+		"marketplace": "模式市场",
+		"settings": "模式设置",
+		"description": "专门定制Roo行为的角色。"
+	},
 	"errorReadingFile": "读取文件时出错:",
 	"noValidImages": "没有处理有效图片",
 	"separator": "分隔符",

+ 1 - 1
webview-ui/src/i18n/locales/zh-CN/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "现在您可以使用此模式。点击侧边栏中的模式图标切换标签页。",
 		"done": "完成",
 		"goToMcp": "转到 MCP 标签页",
-		"goToModes": "转到模式标签页",
+		"goToModes": "转到模式设置",
 		"moreInfoMcp": "查看 {{name}} MCP 文档",
 		"validationRequired": "请为 {{paramName}} 提供值",
 		"prerequisites": "前置条件"

+ 9 - 0
webview-ui/src/i18n/locales/zh-CN/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "重置为默认值",
 		"description": "设定专业领域和应答风格"
 	},
+	"description": {
+		"title": "简短描述(给人看的)",
+		"resetToDefault": "重置为默认描述",
+		"description": "在模式选择下拉菜单中显示的简短描述。"
+	},
 	"whenToUse": {
 		"title": "使用场景(可选)",
 		"description": "描述何时应该使用此模式。这有助于 Orchestrator 为任务选择合适的模式。",
@@ -145,6 +150,10 @@
 			"label": "可用工具",
 			"description": "选择可用工具"
 		},
+		"description": {
+			"label": "简短描述(给人看的)",
+			"description": "在模式选择下拉菜单中显示的简短描述。"
+		},
 		"customInstructions": {
 			"label": "自定义指令(可选)",
 			"description": "设置专属规则"

+ 6 - 0
webview-ui/src/i18n/locales/zh-TW/chat.json

@@ -106,6 +106,12 @@
 	"dragFiles": "按住 Shift 鍵拖曳檔案",
 	"dragFilesImages": "按住 Shift 鍵拖曳檔案/圖片",
 	"enhancePromptDescription": "「增強提示」按鈕透過提供額外內容、說明或重新表述來幫助改進您的請求。嘗試在此處輸入請求,然後再次點選按鈕以了解其運作方式。",
+	"modeSelector": {
+		"title": "模式",
+		"marketplace": "模式市集",
+		"settings": "模式設定",
+		"description": "專門定制Roo行為的角色。"
+	},
 	"errorReadingFile": "讀取檔案時發生錯誤:",
 	"noValidImages": "未處理到任何有效圖片",
 	"separator": "分隔符號",

+ 1 - 1
webview-ui/src/i18n/locales/zh-TW/marketplace.json

@@ -91,7 +91,7 @@
 		"whatNextMode": "現在您可以使用此模式。點擊側邊欄中的模式圖示以切換標籤頁。",
 		"done": "完成",
 		"goToMcp": "前往 MCP 標籤頁",
-		"goToModes": "前往模式標籤頁",
+		"goToModes": "前往模式設定",
 		"moreInfoMcp": "檢視 {{name}} MCP 文件",
 		"validationRequired": "請為 {{paramName}} 提供值",
 		"prerequisites": "前置條件"

+ 9 - 0
webview-ui/src/i18n/locales/zh-TW/prompts.json

@@ -34,6 +34,11 @@
 		"resetToDefault": "重設為預設值",
 		"description": "定義此模式下 Roo 的專業知識和個性。此描述會形塑 Roo 如何展現自己並處理工作。"
 	},
+	"description": {
+		"title": "簡短描述(給人看的)",
+		"resetToDefault": "重置為預設描述",
+		"description": "在模式選擇下拉選單中顯示的簡短描述。"
+	},
 	"whenToUse": {
 		"title": "使用時機(選用)",
 		"description": "描述何時應使用此模式。這有助於 Orchestrator 為任務選擇適當的模式。",
@@ -145,6 +150,10 @@
 			"label": "可用工具",
 			"description": "選擇此模式可使用的工具。"
 		},
+		"description": {
+			"label": "簡短描述(給人看的)",
+			"description": "在模式選擇下拉選單中顯示的簡短描述。"
+		},
 		"customInstructions": {
 			"label": "自訂指令(選用)",
 			"description": "為此模式新增特定的行為指南。"

+ 1 - 1
webview-ui/src/utils/context-mentions.ts

@@ -143,7 +143,7 @@ export function getContextMenuOptions(
 					type: ContextMenuOptionType.Mode,
 					value: mode.slug,
 					label: mode.name,
-					description: (mode.whenToUse || mode.roleDefinition).split("\n")[0],
+					description: (mode.description || mode.whenToUse || mode.roleDefinition).split("\n")[0],
 				}))
 
 		return matchingModes.length > 0 ? matchingModes : [{ type: ContextMenuOptionType.NoResults }]

Некоторые файлы не были показаны из-за большого количества измененных файлов