From 73c2f82f8d0ed2eceb6b351bee62bb1f1e4e9a3b Mon Sep 17 00:00:00 2001 From: Roo Code Date: Wed, 16 Jul 2025 03:04:41 +0000 Subject: [PATCH 1/4] fix: prevent empty mode names from being saved (fixes #5766) - Add frontend validation in ModesView to prevent empty names from being saved - Add onBlur handler to restore original name if field is left empty - Add backend validation in CustomModesManager.updateCustomMode using modeConfigSchema - Provide user feedback when validation fails - Trim whitespace from mode names before validation This prevents YAML parsing errors caused by empty mode name fields. --- src/core/config/CustomModesManager.ts | 12 +++++++++ webview-ui/src/components/modes/ModesView.tsx | 25 +++++++++++++++---- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/core/config/CustomModesManager.ts b/src/core/config/CustomModesManager.ts index b4bcfa62d6d..f625e7bedb0 100644 --- a/src/core/config/CustomModesManager.ts +++ b/src/core/config/CustomModesManager.ts @@ -401,6 +401,18 @@ export class CustomModesManager { public async updateCustomMode(slug: string, config: ModeConfig): Promise { try { + // Validate the mode configuration before saving + const validationResult = modeConfigSchema.safeParse(config) + if (!validationResult.success) { + const errorMessages = validationResult.error.errors + .map((err) => `${err.path.join(".")}: ${err.message}`) + .join(", ") + const errorMessage = `Invalid mode configuration: ${errorMessages}` + logger.error("Mode validation failed", { slug, errors: validationResult.error.errors }) + vscode.window.showErrorMessage(t("common:customModes.errors.updateFailed", { error: errorMessage })) + return + } + const isProjectMode = config.source === "project" let targetPath: string diff --git a/webview-ui/src/components/modes/ModesView.tsx b/webview-ui/src/components/modes/ModesView.tsx index 620797290dd..df2251ed3ef 100644 --- a/webview-ui/src/components/modes/ModesView.tsx +++ b/webview-ui/src/components/modes/ModesView.tsx @@ -729,11 +729,26 @@ const ModesView = ({ onDone }: ModesViewProps) => { onChange={(e) => { const customMode = findModeBySlug(visualMode, customModes) if (customMode) { - updateCustomMode(visualMode, { - ...customMode, - name: e.target.value, - source: customMode.source || "global", - }) + const newName = e.target.value.trim() + // Only update if the name is not empty + if (newName.length > 0) { + updateCustomMode(visualMode, { + ...customMode, + name: newName, + source: customMode.source || "global", + }) + } + } + }} + onBlur={(e) => { + const customMode = findModeBySlug(visualMode, customModes) + if (customMode) { + const newName = e.target.value.trim() + // If the field is empty on blur, restore the original name + if (newName.length === 0) { + // Force re-render by updating the input value + e.target.value = customMode.name + } } }} className="w-full" From 48b7d765453a2ed849f0b64db7033fc9eac35453 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Wed, 16 Jul 2025 19:03:09 +0000 Subject: [PATCH 2/4] fix: improve UX by allowing users to empty mode name field - Remove restriction that prevented users from emptying the name field - Remove onBlur handler that automatically restored original name - Allow backend validation to handle empty names and show appropriate errors - Users can now type freely but invalid saves are prevented by backend validation Addresses feedback from @daniel-lxs in PR #5767 --- webview-ui/src/components/modes/ModesView.tsx | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/webview-ui/src/components/modes/ModesView.tsx b/webview-ui/src/components/modes/ModesView.tsx index df2251ed3ef..54cd57f16ed 100644 --- a/webview-ui/src/components/modes/ModesView.tsx +++ b/webview-ui/src/components/modes/ModesView.tsx @@ -730,25 +730,13 @@ const ModesView = ({ onDone }: ModesViewProps) => { const customMode = findModeBySlug(visualMode, customModes) if (customMode) { const newName = e.target.value.trim() - // Only update if the name is not empty - if (newName.length > 0) { - updateCustomMode(visualMode, { - ...customMode, - name: newName, - source: customMode.source || "global", - }) - } - } - }} - onBlur={(e) => { - const customMode = findModeBySlug(visualMode, customModes) - if (customMode) { - const newName = e.target.value.trim() - // If the field is empty on blur, restore the original name - if (newName.length === 0) { - // Force re-render by updating the input value - e.target.value = customMode.name - } + // Allow users to type freely, including emptying the field + // The backend validation will handle empty names and show errors + updateCustomMode(visualMode, { + ...customMode, + name: newName, + source: customMode.source || "global", + }) } }} className="w-full" From 30275599eff8b4bbb3412eb37e76111354c320ca Mon Sep 17 00:00:00 2001 From: Roo Code Date: Mon, 4 Aug 2025 14:08:28 +0000 Subject: [PATCH 3/4] fix: allow emptying mode name field but prevent saving when invalid - Modified onBlur handler to check if name is empty before saving - If empty, revert to original name instead of saving empty value - This provides better UX as requested in PR review --- webview-ui/src/components/modes/ModesView.tsx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/webview-ui/src/components/modes/ModesView.tsx b/webview-ui/src/components/modes/ModesView.tsx index 28702e8df3d..5d3700ac074 100644 --- a/webview-ui/src/components/modes/ModesView.tsx +++ b/webview-ui/src/components/modes/ModesView.tsx @@ -757,17 +757,23 @@ const ModesView = ({ onDone }: ModesViewProps) => { onChange={(e) => { const newName = e.target.value // Allow users to type freely, including emptying the field - // The backend validation will handle empty names and show errors setLocalModeName(newName) }} onBlur={() => { const customMode = findModeBySlug(visualMode, customModes) if (customMode) { - updateCustomMode(visualMode, { - ...customMode, - name: localModeName.trim(), - source: customMode.source || "global", - }) + const trimmedName = localModeName.trim() + // Only update if the name is not empty + if (trimmedName) { + updateCustomMode(visualMode, { + ...customMode, + name: trimmedName, + source: customMode.source || "global", + }) + } else { + // Revert to the original name if empty + setLocalModeName(customMode.name) + } } // Clear the editing state setCurrentEditingModeSlug(null) From 16bb8e3c6d82d23363ba68d44e655f7e7749a28a Mon Sep 17 00:00:00 2001 From: Roo Code Date: Mon, 4 Aug 2025 14:21:04 +0000 Subject: [PATCH 4/4] fix: add proper JSON formatting to source map writes for Windows compatibility --- webview-ui/src/vite-plugins/sourcemapPlugin.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webview-ui/src/vite-plugins/sourcemapPlugin.ts b/webview-ui/src/vite-plugins/sourcemapPlugin.ts index 9eb1e7b642a..1449c888f2d 100644 --- a/webview-ui/src/vite-plugins/sourcemapPlugin.ts +++ b/webview-ui/src/vite-plugins/sourcemapPlugin.ts @@ -88,8 +88,8 @@ export function sourcemapPlugin(): Plugin { }) } - // Write back the updated source map - fs.writeFileSync(mapPath, JSON.stringify(mapContent)) + // Write back the updated source map with proper formatting + fs.writeFileSync(mapPath, JSON.stringify(mapContent, null, 2)) console.log(`Updated source map for ${jsFile}`) } catch (error) { console.error(`Error processing source map for ${jsFile}:`, error)