Browse Source

Merge pull request #753 from RooVetGit/visual_fixes

Slight visual fixes
Matt Rubens 11 months ago
parent
commit
f2d7cbebbe

+ 8 - 4
src/core/__tests__/mode-validator.test.ts

@@ -9,8 +9,8 @@ describe("mode-validator", () => {
 			it("allows all code mode tools", () => {
 				const mode = getModeConfig(codeMode)
 				// Code mode has all groups
-				Object.entries(TOOL_GROUPS).forEach(([_, tools]) => {
-					tools.forEach((tool) => {
+				Object.entries(TOOL_GROUPS).forEach(([_, config]) => {
+					config.tools.forEach((tool: string) => {
 						expect(isToolAllowedForMode(tool, codeMode, [])).toBe(true)
 					})
 				})
@@ -25,7 +25,11 @@ describe("mode-validator", () => {
 			it("allows configured tools", () => {
 				const mode = getModeConfig(architectMode)
 				// Architect mode has read, browser, and mcp groups
-				const architectTools = [...TOOL_GROUPS.read, ...TOOL_GROUPS.browser, ...TOOL_GROUPS.mcp]
+				const architectTools = [
+					...TOOL_GROUPS.read.tools,
+					...TOOL_GROUPS.browser.tools,
+					...TOOL_GROUPS.mcp.tools,
+				]
 				architectTools.forEach((tool) => {
 					expect(isToolAllowedForMode(tool, architectMode, [])).toBe(true)
 				})
@@ -36,7 +40,7 @@ describe("mode-validator", () => {
 			it("allows configured tools", () => {
 				const mode = getModeConfig(askMode)
 				// Ask mode has read, browser, and mcp groups
-				const askTools = [...TOOL_GROUPS.read, ...TOOL_GROUPS.browser, ...TOOL_GROUPS.mcp]
+				const askTools = [...TOOL_GROUPS.read.tools, ...TOOL_GROUPS.browser.tools, ...TOOL_GROUPS.mcp.tools]
 				askTools.forEach((tool) => {
 					expect(isToolAllowedForMode(tool, askMode, [])).toBe(true)
 				})

+ 1 - 1
src/core/prompts/tools/index.ts

@@ -66,7 +66,7 @@ export function getToolDescriptionsForMode(
 		const groupName = getGroupName(groupEntry)
 		const toolGroup = TOOL_GROUPS[groupName]
 		if (toolGroup) {
-			toolGroup.forEach((tool) => {
+			toolGroup.tools.forEach((tool) => {
 				if (isToolAllowedForMode(tool as ToolName, mode, customModes ?? [], experiments ?? {})) {
 					tools.add(tool)
 				}

+ 6 - 3
src/shared/modes.ts

@@ -59,7 +59,8 @@ export function getToolsForMode(groups: readonly GroupEntry[]): string[] {
 	// Add tools from each group
 	groups.forEach((group) => {
 		const groupName = getGroupName(group)
-		TOOL_GROUPS[groupName].forEach((tool) => tools.add(tool))
+		const groupConfig = TOOL_GROUPS[groupName]
+		groupConfig.tools.forEach((tool: string) => tools.add(tool))
 	})
 
 	// Always add required tools
@@ -190,8 +191,10 @@ export function isToolAllowedForMode(
 		const groupName = getGroupName(group)
 		const options = getGroupOptions(group)
 
-		// If the tool isn't in this group, continue to next group
-		if (!TOOL_GROUPS[groupName].includes(tool)) {
+		const groupConfig = TOOL_GROUPS[groupName]
+
+		// If the tool isn't in this group's tools, continue to next group
+		if (!groupConfig.tools.includes(tool)) {
 			continue
 		}
 

+ 25 - 9
src/shared/tool-groups.ts

@@ -1,5 +1,8 @@
-// Define tool group values
-export type ToolGroupValues = readonly string[]
+// Define tool group configuration
+export type ToolGroupConfig = {
+	tools: readonly string[]
+	alwaysAvailable?: boolean // Whether this group is always available and shouldn't show in prompts view
+}
 
 // Map of tool slugs to their display names
 export const TOOL_DISPLAY_NAMES = {
@@ -20,13 +23,26 @@ export const TOOL_DISPLAY_NAMES = {
 } as const
 
 // Define available tool groups
-export const TOOL_GROUPS: Record<string, ToolGroupValues> = {
-	read: ["read_file", "search_files", "list_files", "list_code_definition_names"],
-	edit: ["write_to_file", "apply_diff", "insert_content", "search_and_replace"],
-	browser: ["browser_action"],
-	command: ["execute_command"],
-	mcp: ["use_mcp_tool", "access_mcp_resource"],
-	modes: ["switch_mode", "new_task"],
+export const TOOL_GROUPS: Record<string, ToolGroupConfig> = {
+	read: {
+		tools: ["read_file", "search_files", "list_files", "list_code_definition_names"],
+	},
+	edit: {
+		tools: ["write_to_file", "apply_diff", "insert_content", "search_and_replace"],
+	},
+	browser: {
+		tools: ["browser_action"],
+	},
+	command: {
+		tools: ["execute_command"],
+	},
+	mcp: {
+		tools: ["use_mcp_tool", "access_mcp_resource"],
+	},
+	modes: {
+		tools: ["switch_mode", "new_task"],
+		alwaysAvailable: true,
+	},
 }
 
 export type ToolGroup = keyof typeof TOOL_GROUPS

+ 1 - 1
webview-ui/src/components/chat/ChatView.tsx

@@ -994,7 +994,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
 					}}>
 					{showAnnouncement && <Announcement version={version} hideAnnouncement={hideAnnouncement} />}
 					<div style={{ padding: "0 20px", flexShrink: 0 }}>
-						<h2>What can I do for you?</h2>
+						<h2>What can Roo do for you?</h2>
 						<p>
 							Thanks to the latest breakthroughs in agentic coding capabilities, I can handle complex
 							software development tasks step-by-step. With tools that let me create & edit files, explore

+ 41 - 41
webview-ui/src/components/prompts/PromptsView.tsx

@@ -26,8 +26,8 @@ import {
 import { TOOL_GROUPS, GROUP_DISPLAY_NAMES, ToolGroup } from "../../../../src/shared/tool-groups"
 import { vscode } from "../../utils/vscode"
 
-// Get all available groups from GROUP_DISPLAY_NAMES
-const availableGroups = Object.keys(TOOL_GROUPS) as ToolGroup[]
+// Get all available groups that should show in prompts view
+const availableGroups = (Object.keys(TOOL_GROUPS) as ToolGroup[]).filter((group) => !TOOL_GROUPS[group].alwaysAvailable)
 
 type PromptsViewProps = {
 	onDone: () => void
@@ -65,6 +65,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 	const [isToolsEditMode, setIsToolsEditMode] = useState(false)
 	const [isCreateModeDialogOpen, setIsCreateModeDialogOpen] = useState(false)
 	const [activeSupportTab, setActiveSupportTab] = useState<SupportPromptType>("ENHANCE")
+	const [selectedModeTab, setSelectedModeTab] = useState<string>(mode)
 
 	// Direct update functions
 	const updateAgentPrompt = useCallback(
@@ -110,26 +111,23 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 			text: slug,
 		})
 	}, [])
-
-	// Handle mode switching with explicit state initialization
+	// Handle mode tab selection without actually switching modes
 	const handleModeSwitch = useCallback(
 		(modeConfig: ModeConfig) => {
-			if (modeConfig.slug === mode) return // Prevent unnecessary updates
-
-			// First switch the mode
-			switchMode(modeConfig.slug)
+			if (modeConfig.slug === selectedModeTab) return // Prevent unnecessary updates
 
-			// Exit tools edit mode when switching modes
+			// Update selected tab and reset tools edit mode
+			setSelectedModeTab(modeConfig.slug)
 			setIsToolsEditMode(false)
 		},
-		[mode, switchMode, setIsToolsEditMode],
+		[selectedModeTab, setIsToolsEditMode],
 	)
 
 	// Helper function to get current mode's config
 	const getCurrentMode = useCallback((): ModeConfig | undefined => {
-		const findMode = (m: ModeConfig): boolean => m.slug === mode
+		const findMode = (m: ModeConfig): boolean => m.slug === selectedModeTab
 		return customModes?.find(findMode) || modes.find(findMode)
-	}, [mode, customModes, modes])
+	}, [selectedModeTab, customModes, modes])
 
 	// Helper function to safely access mode properties
 	const getModeProperty = <T extends keyof ModeConfig>(
@@ -155,6 +153,11 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 		}
 	}, [isCreateModeDialogOpen])
 
+	// Keep selected tab in sync with actual mode
+	useEffect(() => {
+		setSelectedModeTab(mode)
+	}, [mode])
+
 	// Helper function to generate a unique slug from a name
 	const generateSlug = useCallback((name: string, attempt = 0): string => {
 		const baseSlug = name
@@ -184,22 +187,13 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 			groups: newModeGroups,
 		}
 		updateCustomMode(newModeSlug, newMode)
-		switchMode(newModeSlug)
 		setIsCreateModeDialogOpen(false)
 		setNewModeName("")
 		setNewModeSlug("")
 		setNewModeRoleDefinition("")
 		setNewModeCustomInstructions("")
 		setNewModeGroups(availableGroups)
-	}, [
-		newModeName,
-		newModeSlug,
-		newModeRoleDefinition,
-		newModeCustomInstructions,
-		newModeGroups,
-		updateCustomMode,
-		switchMode,
-	])
+	}, [newModeName, newModeSlug, newModeRoleDefinition, newModeCustomInstructions, newModeGroups, updateCustomMode])
 
 	const isNameOrSlugTaken = useCallback(
 		(name: string, slug: string) => {
@@ -479,7 +473,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 							padding: "4px 0",
 						}}>
 						{modes.map((modeConfig) => {
-							const isActive = mode === modeConfig.slug
+							const isActive = selectedModeTab === modeConfig.slug
 							return (
 								<button
 									key={modeConfig.slug}
@@ -507,20 +501,22 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 
 				<div style={{ marginBottom: "20px" }}>
 					{/* Only show name and delete for custom modes */}
-					{mode && findModeBySlug(mode, customModes) && (
+					{selectedModeTab && findModeBySlug(selectedModeTab, customModes) && (
 						<div style={{ display: "flex", gap: "12px", marginBottom: "16px" }}>
 							<div style={{ flex: 1 }}>
 								<div style={{ fontWeight: "bold", marginBottom: "4px" }}>Name</div>
 								<div style={{ display: "flex", gap: "8px" }}>
 									<VSCodeTextField
-										value={getModeProperty(findModeBySlug(mode, customModes), "name") ?? ""}
+										value={
+											getModeProperty(findModeBySlug(selectedModeTab, customModes), "name") ?? ""
+										}
 										onChange={(e: Event | React.FormEvent<HTMLElement>) => {
 											const target =
 												(e as CustomEvent)?.detail?.target ||
 												((e as any).target as HTMLInputElement)
-											const customMode = findModeBySlug(mode, customModes)
+											const customMode = findModeBySlug(selectedModeTab, customModes)
 											if (customMode) {
-												updateCustomMode(mode, {
+												updateCustomMode(selectedModeTab, {
 													...customMode,
 													name: target.value,
 												})
@@ -534,7 +530,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 										onClick={() => {
 											vscode.postMessage({
 												type: "deleteCustomMode",
-												slug: mode,
+												slug: selectedModeTab,
 											})
 										}}>
 										<span className="codicon codicon-trash"></span>
@@ -552,7 +548,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 								marginBottom: "4px",
 							}}>
 							<div style={{ fontWeight: "bold" }}>Role Definition</div>
-							{!findModeBySlug(mode, customModes) && (
+							{!findModeBySlug(selectedModeTab, customModes) && (
 								<VSCodeButton
 									appearance="icon"
 									onClick={() => {
@@ -578,24 +574,28 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 						</div>
 						<VSCodeTextArea
 							value={(() => {
-								const customMode = findModeBySlug(mode, customModes)
-								const prompt = customModePrompts?.[mode] as PromptComponent
-								return customMode?.roleDefinition ?? prompt?.roleDefinition ?? getRoleDefinition(mode)
+								const customMode = findModeBySlug(selectedModeTab, customModes)
+								const prompt = customModePrompts?.[selectedModeTab] as PromptComponent
+								return (
+									customMode?.roleDefinition ??
+									prompt?.roleDefinition ??
+									getRoleDefinition(selectedModeTab)
+								)
 							})()}
 							onChange={(e) => {
 								const value =
 									(e as CustomEvent)?.detail?.target?.value ||
 									((e as any).target as HTMLTextAreaElement).value
-								const customMode = findModeBySlug(mode, customModes)
+								const customMode = findModeBySlug(selectedModeTab, customModes)
 								if (customMode) {
 									// For custom modes, update the JSON file
-									updateCustomMode(mode, {
+									updateCustomMode(selectedModeTab, {
 										...customMode,
 										roleDefinition: value.trim() || "",
 									})
 								} else {
 									// For built-in modes, update the prompts
-									updateAgentPrompt(mode, {
+									updateAgentPrompt(selectedModeTab, {
 										roleDefinition: value.trim() || undefined,
 									})
 								}
@@ -760,25 +760,25 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 						</div>
 						<VSCodeTextArea
 							value={(() => {
-								const customMode = findModeBySlug(mode, customModes)
-								const prompt = customModePrompts?.[mode] as PromptComponent
+								const customMode = findModeBySlug(selectedModeTab, customModes)
+								const prompt = customModePrompts?.[selectedModeTab] as PromptComponent
 								return customMode?.customInstructions ?? prompt?.customInstructions ?? ""
 							})()}
 							onChange={(e) => {
 								const value =
 									(e as CustomEvent)?.detail?.target?.value ||
 									((e as any).target as HTMLTextAreaElement).value
-								const customMode = findModeBySlug(mode, customModes)
+								const customMode = findModeBySlug(selectedModeTab, customModes)
 								if (customMode) {
 									// For custom modes, update the JSON file
-									updateCustomMode(mode, {
+									updateCustomMode(selectedModeTab, {
 										...customMode,
 										customInstructions: value.trim() || undefined,
 									})
 								} else {
 									// For built-in modes, update the prompts
-									const existingPrompt = customModePrompts?.[mode] as PromptComponent
-									updateAgentPrompt(mode, {
+									const existingPrompt = customModePrompts?.[selectedModeTab] as PromptComponent
+									updateAgentPrompt(selectedModeTab, {
 										...existingPrompt,
 										customInstructions: value.trim() || undefined,
 									})