From 2b7c2665466d949b045adcb72c31918510e71da2 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Wed, 9 Jul 2025 15:03:04 -0400 Subject: [PATCH 01/21] Update icons in chattextarea (#5520) * Update icons in chattextarea * fix: update icons in ChatTextArea and IndexingStatusBadge components * fix: update Camera icon to Image and fix alignment - Changed Camera icon to Image icon from lucide-react - Fixed alignment issue by adjusting gap and removing extra margin - Updated tests to work with new Lucide icon structure * fix: revert alignment changes for Image icon - Keep original alignment with gap-0.5 and mr-1 to match send and enhance buttons --------- Co-authored-by: Daniel Riccio --- .../src/components/chat/ChatTextArea.tsx | 78 ++++++++++++++----- .../components/chat/IndexingStatusBadge.tsx | 24 +++--- .../chat/__tests__/ChatTextArea.spec.tsx | 9 ++- .../__tests__/IndexingStatusBadge.spec.tsx | 6 +- 4 files changed, 81 insertions(+), 36 deletions(-) diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index b522b43ecc..3d70f4a4ca 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -25,9 +25,8 @@ 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" -import { IconButton } from "./IconButton" -import { IndexingStatusDot } from "./IndexingStatusBadge" +import { VolumeX, Pin, Check, Image, WandSparkles, SendHorizontal } from "lucide-react" +import { IndexingStatusBadge } from "./IndexingStatusBadge" import { cn } from "@/lib/utils" import { usePromptHistory } from "./hooks/usePromptHistory" @@ -962,24 +961,49 @@ const ChatTextArea = forwardRef( )}
- + onClick={!sendingDisabled ? handleEnhancePrompt : undefined} + className={cn( + "relative inline-flex items-center justify-center", + "bg-transparent border-none p-1.5", + "rounded-md min-w-[28px] min-h-[28px]", + "opacity-60 hover:opacity-100 text-vscode-descriptionForeground hover:text-vscode-foreground", + "transition-all duration-150", + "hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]", + "focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder", + "active:bg-[rgba(255,255,255,0.1)]", + !sendingDisabled && "cursor-pointer", + sendingDisabled && + "opacity-40 cursor-not-allowed grayscale-[30%] hover:bg-transparent hover:border-[rgba(255,255,255,0.08)] active:bg-transparent", + )}> + +
- + onClick={!sendingDisabled ? onSend : undefined} + className={cn( + "relative inline-flex items-center justify-center", + "bg-transparent border-none p-1.5", + "rounded-md min-w-[28px] min-h-[28px]", + "opacity-60 hover:opacity-100 text-vscode-descriptionForeground hover:text-vscode-foreground", + "transition-all duration-150", + "hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]", + "focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder", + "active:bg-[rgba(255,255,255,0.1)]", + !sendingDisabled && "cursor-pointer", + sendingDisabled && + "opacity-40 cursor-not-allowed grayscale-[30%] hover:bg-transparent hover:border-[rgba(255,255,255,0.08)] active:bg-transparent", + )}> + +
{!inputValue && ( @@ -1145,14 +1169,28 @@ const ChatTextArea = forwardRef(
- - +
diff --git a/webview-ui/src/components/chat/IndexingStatusBadge.tsx b/webview-ui/src/components/chat/IndexingStatusBadge.tsx index f3c268c2ba..0a42b97abf 100644 --- a/webview-ui/src/components/chat/IndexingStatusBadge.tsx +++ b/webview-ui/src/components/chat/IndexingStatusBadge.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useMemo } from "react" +import { Database } from "lucide-react" import { cn } from "@src/lib/utils" import { vscode } from "@src/utils/vscode" import { useAppTranslation } from "@/i18n/TranslationContext" @@ -6,11 +7,11 @@ import { useTooltip } from "@/hooks/useTooltip" import { CodeIndexPopover } from "./CodeIndexPopover" import type { IndexingStatus, IndexingStatusUpdateMessage } from "@roo/ExtensionMessage" -interface IndexingStatusDotProps { +interface IndexingStatusBadgeProps { className?: string } -export const IndexingStatusDot: React.FC = ({ className }) => { +export const IndexingStatusBadge: React.FC = ({ className }) => { const { t } = useAppTranslation() const { showTooltip, handleMouseEnter, handleMouseLeave, cleanup } = useTooltip({ delay: 300 }) const [isHovered, setIsHovered] = useState(false) @@ -77,23 +78,23 @@ export const IndexingStatusDot: React.FC = ({ className handleMouseLeave() } - // Get status color classes based on status and hover state + // Get status color classes for the badge dot const getStatusColorClass = () => { const statusColors = { Standby: { - default: "bg-vscode-descriptionForeground/40", - hover: "bg-vscode-descriptionForeground/60", + default: "bg-vscode-descriptionForeground/60", + hover: "bg-vscode-descriptionForeground/80", }, Indexing: { - default: "bg-yellow-500/40 animate-pulse", + default: "bg-yellow-500 animate-pulse", hover: "bg-yellow-500 animate-pulse", }, Indexed: { - default: "bg-green-500/40", + default: "bg-green-500", hover: "bg-green-500", }, Error: { - default: "bg-red-500/40", + default: "bg-red-500", hover: "bg-red-500", }, } @@ -117,12 +118,17 @@ export const IndexingStatusDot: React.FC = ({ className "hover:opacity-100 hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]", "focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder", "active:bg-[rgba(255,255,255,0.1)]", + "cursor-pointer", className, )} aria-label={getTooltipText()}> + {/* File search icon */} + + + {/* Status dot badge */} diff --git a/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx b/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx index 86e200f0a3..75324c97f4 100644 --- a/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx +++ b/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx @@ -38,8 +38,8 @@ vi.mock("@src/context/ExtensionStateContext") const getEnhancePromptButton = () => { return screen.getByRole("button", { name: (_, element) => { - // Find the button with the sparkle icon - return element.querySelector(".codicon-sparkle") !== null + // Find the button with the wand sparkles icon (Lucide React) + return element.querySelector(".lucide-wand-sparkles") !== null }, }) } @@ -154,8 +154,9 @@ describe("ChatTextArea", () => { const enhanceButton = getEnhancePromptButton() fireEvent.click(enhanceButton) - const loadingSpinner = screen.getByText("", { selector: ".codicon-loading" }) - expect(loadingSpinner).toBeInTheDocument() + // Check if the WandSparkles icon has the animate-spin class + const animatingIcon = enhanceButton.querySelector(".animate-spin") + expect(animatingIcon).toBeInTheDocument() }) }) diff --git a/webview-ui/src/components/chat/__tests__/IndexingStatusBadge.spec.tsx b/webview-ui/src/components/chat/__tests__/IndexingStatusBadge.spec.tsx index 8a44082f58..37eb291530 100644 --- a/webview-ui/src/components/chat/__tests__/IndexingStatusBadge.spec.tsx +++ b/webview-ui/src/components/chat/__tests__/IndexingStatusBadge.spec.tsx @@ -3,7 +3,7 @@ import { render, screen, fireEvent, waitFor, act } from "@/utils/test-utils" import { vscode } from "@src/utils/vscode" -import { IndexingStatusDot } from "../IndexingStatusBadge" +import { IndexingStatusBadge } from "../IndexingStatusBadge" vi.mock("@/i18n/setup", () => ({ __esModule: true, @@ -104,9 +104,9 @@ vi.mock("@/i18n/TranslationContext", () => ({ }), })) -describe("IndexingStatusDot", () => { +describe("IndexingStatusBadge", () => { const renderComponent = (props = {}) => { - return render() + return render() } beforeEach(() => { From a732f18ea59960f232c6bcff53fdd688e4ca67c5 Mon Sep 17 00:00:00 2001 From: Roomote Bot Date: Wed, 9 Jul 2025 13:02:56 -0700 Subject: [PATCH 02/21] fix: respect .gitignore patterns for directories in list_files tool (#5393) (#5394) Co-authored-by: Matt Rubens Co-authored-by: Daniel <57051444+daniel-lxs@users.noreply.github.com> --- .../__tests__/gitignore-integration.spec.ts | 209 ++++++++++++++++++ .../glob/__tests__/gitignore-test.spec.ts | 147 ++++++++++++ src/services/glob/list-files.ts | 132 +++++------ 3 files changed, 424 insertions(+), 64 deletions(-) create mode 100644 src/services/glob/__tests__/gitignore-integration.spec.ts create mode 100644 src/services/glob/__tests__/gitignore-test.spec.ts diff --git a/src/services/glob/__tests__/gitignore-integration.spec.ts b/src/services/glob/__tests__/gitignore-integration.spec.ts new file mode 100644 index 0000000000..1361816b17 --- /dev/null +++ b/src/services/glob/__tests__/gitignore-integration.spec.ts @@ -0,0 +1,209 @@ +import { vi, describe, it, expect, beforeEach, afterEach } from "vitest" +import * as path from "path" +import * as fs from "fs" +import * as os from "os" + +// Mock ripgrep to avoid filesystem dependencies +vi.mock("../../ripgrep", () => ({ + getBinPath: vi.fn().mockResolvedValue("/mock/path/to/rg"), +})) + +// Mock vscode +vi.mock("vscode", () => ({ + env: { + appRoot: "/mock/app/root", + }, +})) + +// Mock child_process to simulate ripgrep behavior +vi.mock("child_process", () => ({ + spawn: vi.fn(), +})) + +vi.mock("../../path", () => ({ + arePathsEqual: vi.fn().mockReturnValue(false), +})) + +import { listFiles } from "../list-files" +import * as childProcess from "child_process" + +describe("list-files gitignore integration", () => { + let tempDir: string + let originalCwd: string + + beforeEach(async () => { + vi.clearAllMocks() + + // Create a temporary directory for testing + tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "roo-gitignore-test-")) + originalCwd = process.cwd() + }) + + afterEach(async () => { + process.chdir(originalCwd) + // Clean up temp directory + await fs.promises.rm(tempDir, { recursive: true, force: true }) + }) + + it("should properly filter directories based on .gitignore patterns", async () => { + // Setup test directory structure + await fs.promises.mkdir(path.join(tempDir, "src")) + await fs.promises.mkdir(path.join(tempDir, "node_modules")) + await fs.promises.mkdir(path.join(tempDir, "build")) + await fs.promises.mkdir(path.join(tempDir, "dist")) + await fs.promises.mkdir(path.join(tempDir, "allowed-dir")) + + // Create .gitignore file + await fs.promises.writeFile(path.join(tempDir, ".gitignore"), "node_modules/\nbuild/\ndist/\n*.log\n") + + // Create some files + await fs.promises.writeFile(path.join(tempDir, "src", "index.ts"), "console.log('hello')") + await fs.promises.writeFile(path.join(tempDir, "allowed-dir", "file.txt"), "content") + + // Mock ripgrep to return files that would not be gitignored + const mockSpawn = vi.mocked(childProcess.spawn) + const mockProcess = { + stdout: { + on: vi.fn((event, callback) => { + if (event === "data") { + // Simulate ripgrep output (files that are not gitignored) + const files = + [path.join(tempDir, "src", "index.ts"), path.join(tempDir, "allowed-dir", "file.txt")].join( + "\n", + ) + "\n" + setTimeout(() => callback(files), 10) + } + }), + }, + stderr: { + on: vi.fn(), + }, + on: vi.fn((event, callback) => { + if (event === "close") { + setTimeout(() => callback(0), 20) + } + }), + kill: vi.fn(), + } + + mockSpawn.mockReturnValue(mockProcess as any) + + // Call listFiles in recursive mode + const [files, didHitLimit] = await listFiles(tempDir, true, 100) + + // Filter out only directories from the results + const directoriesInResult = files.filter((f) => f.endsWith("/")) + + // Verify that gitignored directories are NOT included + expect(directoriesInResult).not.toContain(path.join(tempDir, "node_modules") + "/") + expect(directoriesInResult).not.toContain(path.join(tempDir, "build") + "/") + expect(directoriesInResult).not.toContain(path.join(tempDir, "dist") + "/") + + // Verify that allowed directories ARE included + expect(directoriesInResult).toContain(path.join(tempDir, "src") + "/") + expect(directoriesInResult).toContain(path.join(tempDir, "allowed-dir") + "/") + }) + + it("should handle nested .gitignore files correctly", async () => { + // Setup nested directory structure + await fs.promises.mkdir(path.join(tempDir, "src"), { recursive: true }) + await fs.promises.mkdir(path.join(tempDir, "src", "components")) + await fs.promises.mkdir(path.join(tempDir, "src", "temp")) + await fs.promises.mkdir(path.join(tempDir, "src", "utils")) + + // Create root .gitignore + await fs.promises.writeFile(path.join(tempDir, ".gitignore"), "node_modules/\n") + + // Create nested .gitignore in src/ + await fs.promises.writeFile(path.join(tempDir, "src", ".gitignore"), "temp/\n") + + // Mock ripgrep + const mockSpawn = vi.mocked(childProcess.spawn) + const mockProcess = { + stdout: { + on: vi.fn((event, callback) => { + if (event === "data") { + setTimeout(() => callback(""), 10) + } + }), + }, + stderr: { + on: vi.fn(), + }, + on: vi.fn((event, callback) => { + if (event === "close") { + setTimeout(() => callback(0), 20) + } + }), + kill: vi.fn(), + } + + mockSpawn.mockReturnValue(mockProcess as any) + + // Call listFiles in recursive mode + const [files, didHitLimit] = await listFiles(tempDir, true, 100) + + // Filter out only directories from the results + const directoriesInResult = files.filter((f) => f.endsWith("/")) + + // Verify that nested gitignored directories are NOT included + expect(directoriesInResult).not.toContain(path.join(tempDir, "src", "temp") + "/") + + // Verify that allowed directories ARE included + expect(directoriesInResult).toContain(path.join(tempDir, "src") + "/") + expect(directoriesInResult).toContain(path.join(tempDir, "src", "components") + "/") + expect(directoriesInResult).toContain(path.join(tempDir, "src", "utils") + "/") + }) + + it("should respect .gitignore in non-recursive mode too", async () => { + // Setup test directory structure + await fs.promises.mkdir(path.join(tempDir, "src")) + await fs.promises.mkdir(path.join(tempDir, "node_modules")) + await fs.promises.mkdir(path.join(tempDir, "allowed-dir")) + + // Create .gitignore file + await fs.promises.writeFile(path.join(tempDir, ".gitignore"), "node_modules/\n") + + // Mock ripgrep for non-recursive mode + const mockSpawn = vi.mocked(childProcess.spawn) + const mockProcess = { + stdout: { + on: vi.fn((event, callback) => { + if (event === "data") { + // In non-recursive mode, ripgrep should now respect .gitignore + const files = [path.join(tempDir, "src"), path.join(tempDir, "allowed-dir")].join("\n") + "\n" + setTimeout(() => callback(files), 10) + } + }), + }, + stderr: { + on: vi.fn(), + }, + on: vi.fn((event, callback) => { + if (event === "close") { + setTimeout(() => callback(0), 20) + } + }), + kill: vi.fn(), + } + + mockSpawn.mockReturnValue(mockProcess as any) + + // Call listFiles in NON-recursive mode + const [files, didHitLimit] = await listFiles(tempDir, false, 100) + + // Verify ripgrep was called without --no-ignore-vcs (should respect .gitignore) + const [rgPath, args] = mockSpawn.mock.calls[0] + expect(args).not.toContain("--no-ignore-vcs") + + // Filter out only directories from the results + const directoriesInResult = files.filter((f) => f.endsWith("/")) + + // Verify that gitignored directories are NOT included even in non-recursive mode + expect(directoriesInResult).not.toContain(path.join(tempDir, "node_modules") + "/") + + // Verify that allowed directories ARE included + expect(directoriesInResult).toContain(path.join(tempDir, "src") + "/") + expect(directoriesInResult).toContain(path.join(tempDir, "allowed-dir") + "/") + }) +}) diff --git a/src/services/glob/__tests__/gitignore-test.spec.ts b/src/services/glob/__tests__/gitignore-test.spec.ts new file mode 100644 index 0000000000..cef884b584 --- /dev/null +++ b/src/services/glob/__tests__/gitignore-test.spec.ts @@ -0,0 +1,147 @@ +import { vi, describe, it, expect, beforeEach, afterEach } from "vitest" +import * as path from "path" +import * as fs from "fs" +import * as os from "os" + +// Mock ripgrep to avoid filesystem dependencies +vi.mock("../../ripgrep", () => ({ + getBinPath: vi.fn().mockResolvedValue("/mock/path/to/rg"), +})) + +// Mock vscode +vi.mock("vscode", () => ({ + env: { + appRoot: "/mock/app/root", + }, +})) + +vi.mock("child_process", () => ({ + spawn: vi.fn(), +})) + +vi.mock("../../path", () => ({ + arePathsEqual: vi.fn().mockReturnValue(false), +})) + +import { listFiles } from "../list-files" +import * as childProcess from "child_process" + +describe("list-files gitignore support", () => { + let tempDir: string + let originalCwd: string + + beforeEach(async () => { + vi.clearAllMocks() + + // Create a temporary directory for testing + tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "roo-test-")) + originalCwd = process.cwd() + process.chdir(tempDir) + }) + + afterEach(async () => { + process.chdir(originalCwd) + // Clean up temp directory + await fs.promises.rm(tempDir, { recursive: true, force: true }) + }) + + it("should respect .gitignore patterns for directories in recursive mode", async () => { + // Setup test directory structure + await fs.promises.mkdir(path.join(tempDir, "src")) + await fs.promises.mkdir(path.join(tempDir, "node_modules")) + await fs.promises.mkdir(path.join(tempDir, "build")) + await fs.promises.mkdir(path.join(tempDir, "ignored-dir")) + + // Create .gitignore file + await fs.promises.writeFile(path.join(tempDir, ".gitignore"), "node_modules/\nbuild/\nignored-dir/\n") + + // Create some files + await fs.promises.writeFile(path.join(tempDir, "src", "index.ts"), "") + await fs.promises.writeFile(path.join(tempDir, "node_modules", "package.json"), "") + await fs.promises.writeFile(path.join(tempDir, "build", "output.js"), "") + await fs.promises.writeFile(path.join(tempDir, "ignored-dir", "file.txt"), "") + + // Mock ripgrep to return only non-ignored files + const mockSpawn = vi.mocked(childProcess.spawn) + const mockProcess = { + stdout: { + on: vi.fn((event, callback) => { + if (event === "data") { + // Ripgrep should respect .gitignore and only return src/index.ts + setTimeout(() => callback(`${path.join(tempDir, "src", "index.ts")}\n`), 10) + } + }), + }, + stderr: { + on: vi.fn(), + }, + on: vi.fn((event, callback) => { + if (event === "close") { + setTimeout(() => callback(0), 20) + } + }), + kill: vi.fn(), + } + + mockSpawn.mockReturnValue(mockProcess as any) + + // Call listFiles in recursive mode + const [files, didHitLimit] = await listFiles(tempDir, true, 100) + + // Verify that gitignored directories are not included + const directoriesInResult = files.filter((f) => f.endsWith("/")) + + expect(directoriesInResult).not.toContain(path.join(tempDir, "node_modules") + "/") + expect(directoriesInResult).not.toContain(path.join(tempDir, "build") + "/") + expect(directoriesInResult).not.toContain(path.join(tempDir, "ignored-dir") + "/") + + // But src/ should be included + expect(directoriesInResult).toContain(path.join(tempDir, "src") + "/") + }) + + it("should handle nested .gitignore files", async () => { + // Setup nested directory structure + await fs.promises.mkdir(path.join(tempDir, "src"), { recursive: true }) + await fs.promises.mkdir(path.join(tempDir, "src", "components")) + await fs.promises.mkdir(path.join(tempDir, "src", "temp")) + + // Create root .gitignore + await fs.promises.writeFile(path.join(tempDir, ".gitignore"), "node_modules/\n") + + // Create nested .gitignore in src/ + await fs.promises.writeFile(path.join(tempDir, "src", ".gitignore"), "temp/\n") + + // Mock ripgrep + const mockSpawn = vi.mocked(childProcess.spawn) + const mockProcess = { + stdout: { + on: vi.fn((event, callback) => { + if (event === "data") { + setTimeout(() => callback(""), 10) + } + }), + }, + stderr: { + on: vi.fn(), + }, + on: vi.fn((event, callback) => { + if (event === "close") { + setTimeout(() => callback(0), 20) + } + }), + kill: vi.fn(), + } + + mockSpawn.mockReturnValue(mockProcess as any) + + // Call listFiles in recursive mode + const [files, didHitLimit] = await listFiles(tempDir, true, 100) + + // Verify that nested gitignored directories are not included + const directoriesInResult = files.filter((f) => f.endsWith("/")) + + expect(directoriesInResult).not.toContain(path.join(tempDir, "src", "temp") + "/") + expect(directoriesInResult).toContain(path.join(tempDir, "src") + "/") + expect(directoriesInResult).toContain(path.join(tempDir, "src", "components") + "/") + }) +}) diff --git a/src/services/glob/list-files.ts b/src/services/glob/list-files.ts index 3fb1b2e154..3164ed1eb0 100644 --- a/src/services/glob/list-files.ts +++ b/src/services/glob/list-files.ts @@ -3,6 +3,7 @@ import * as path from "path" import * as fs from "fs" import * as childProcess from "child_process" import * as vscode from "vscode" +import ignore from "ignore" import { arePathsEqual } from "../../utils/path" import { getBinPath } from "../../services/ripgrep" import { DIRS_TO_IGNORE } from "./constants" @@ -34,9 +35,9 @@ export async function listFiles(dirPath: string, recursive: boolean, limit: numb // Get files using ripgrep const files = await listFilesWithRipgrep(rgPath, dirPath, recursive, limit) - // Get directories with proper filtering - const gitignorePatterns = await parseGitignoreFile(dirPath, recursive) - const directories = await listFilteredDirectories(dirPath, recursive, gitignorePatterns) + // Get directories with proper filtering using ignore library + const ignoreInstance = await createIgnoreInstance(dirPath) + const directories = await listFilteredDirectories(dirPath, recursive, ignoreInstance) // Combine and format the results return formatAndCombineResults(files, directories, limit) @@ -134,8 +135,8 @@ function buildNonRecursiveArgs(): string[] { args.push("-g", "*") args.push("--maxdepth", "1") // ripgrep uses maxdepth, not max-depth - // Don't respect .gitignore in non-recursive mode (consistent with original behavior) - args.push("--no-ignore-vcs") + // Respect .gitignore in non-recursive mode too + // (ripgrep respects .gitignore by default) // Apply directory exclusions for non-recursive searches for (const dir of DIRS_TO_IGNORE) { @@ -153,37 +154,61 @@ function buildNonRecursiveArgs(): string[] { } /** - * Parse the .gitignore file if it exists and is relevant + * Create an ignore instance that handles .gitignore files properly + * This replaces the custom gitignore parsing with the proper ignore library */ -async function parseGitignoreFile(dirPath: string, recursive: boolean): Promise { - if (!recursive) { - return [] // Only needed for recursive mode +async function createIgnoreInstance(dirPath: string): Promise> { + const ignoreInstance = ignore() + const absolutePath = path.resolve(dirPath) + + // Find all .gitignore files from the target directory up to the root + const gitignoreFiles = await findGitignoreFiles(absolutePath) + + // Add patterns from all .gitignore files + for (const gitignoreFile of gitignoreFiles) { + try { + const content = await fs.promises.readFile(gitignoreFile, "utf8") + ignoreInstance.add(content) + } catch (err) { + // Continue if we can't read a .gitignore file + console.warn(`Error reading .gitignore at ${gitignoreFile}: ${err}`) + } } - const absolutePath = path.resolve(dirPath) - const gitignorePath = path.join(absolutePath, ".gitignore") + // Always ignore .gitignore files themselves + ignoreInstance.add(".gitignore") - try { - // Check if .gitignore exists - const exists = await fs.promises - .access(gitignorePath) - .then(() => true) - .catch(() => false) + return ignoreInstance +} - if (!exists) { - return [] +/** + * Find all .gitignore files from the given directory up to the workspace root + */ +async function findGitignoreFiles(startPath: string): Promise { + const gitignoreFiles: string[] = [] + let currentPath = startPath + + // Walk up the directory tree looking for .gitignore files + while (currentPath && currentPath !== path.dirname(currentPath)) { + const gitignorePath = path.join(currentPath, ".gitignore") + + try { + await fs.promises.access(gitignorePath) + gitignoreFiles.push(gitignorePath) + } catch { + // .gitignore doesn't exist at this level, continue } - // Read and parse .gitignore file - const content = await fs.promises.readFile(gitignorePath, "utf8") - return content - .split("\n") - .map((line) => line.trim()) - .filter((line) => line && !line.startsWith("#")) - } catch (err) { - console.warn(`Error reading .gitignore: ${err}`) - return [] // Continue without gitignore patterns on error + // Move up one directory + const parentPath = path.dirname(currentPath) + if (parentPath === currentPath) { + break // Reached root + } + currentPath = parentPath } + + // Return in reverse order (root .gitignore first, then more specific ones) + return gitignoreFiles.reverse() } /** @@ -192,7 +217,7 @@ async function parseGitignoreFile(dirPath: string, recursive: boolean): Promise< async function listFilteredDirectories( dirPath: string, recursive: boolean, - gitignorePatterns: string[], + ignoreInstance: ReturnType, ): Promise { const absolutePath = path.resolve(dirPath) const directories: string[] = [] @@ -209,7 +234,7 @@ async function listFilteredDirectories( const fullDirPath = path.join(currentPath, dirName) // Check if this directory should be included - if (shouldIncludeDirectory(dirName, recursive, gitignorePatterns)) { + if (shouldIncludeDirectory(dirName, fullDirPath, dirPath, ignoreInstance)) { // Add the directory to our results (with trailing slash) const formattedPath = fullDirPath.endsWith("/") ? fullDirPath : `${fullDirPath}/` directories.push(formattedPath) @@ -236,7 +261,12 @@ async function listFilteredDirectories( /** * Determine if a directory should be included in results based on filters */ -function shouldIncludeDirectory(dirName: string, recursive: boolean, gitignorePatterns: string[]): boolean { +function shouldIncludeDirectory( + dirName: string, + fullDirPath: string, + basePath: string, + ignoreInstance: ReturnType, +): boolean { // Skip hidden directories if configured to ignore them if (dirName.startsWith(".") && DIRS_TO_IGNORE.includes(".*")) { return false @@ -247,8 +277,13 @@ function shouldIncludeDirectory(dirName: string, recursive: boolean, gitignorePa return false } - // Check against gitignore patterns in recursive mode - if (recursive && gitignorePatterns.length > 0 && isIgnoredByGitignore(dirName, gitignorePatterns)) { + // Check against gitignore patterns using the ignore library + // Calculate relative path from the base directory + const relativePath = path.relative(basePath, fullDirPath) + const normalizedPath = relativePath.replace(/\\/g, "/") + + // Check if the directory is ignored by .gitignore + if (ignoreInstance.ignores(normalizedPath) || ignoreInstance.ignores(normalizedPath + "/")) { return false } @@ -277,37 +312,6 @@ function isDirectoryExplicitlyIgnored(dirName: string): boolean { return false } -/** - * Check if a directory matches any gitignore patterns - */ -function isIgnoredByGitignore(dirName: string, gitignorePatterns: string[]): boolean { - for (const pattern of gitignorePatterns) { - // Directory patterns (ending with /) - if (pattern.endsWith("/")) { - const dirPattern = pattern.slice(0, -1) - if (dirName === dirPattern) { - return true - } - if (pattern.startsWith("**/") && dirName === dirPattern.slice(3)) { - return true - } - } - // Simple name patterns - else if (dirName === pattern) { - return true - } - // Wildcard patterns - else if (pattern.includes("*")) { - const regexPattern = pattern.replace(/\\/g, "\\\\").replace(/\./g, "\\.").replace(/\*/g, ".*") - const regex = new RegExp(`^${regexPattern}$`) - if (regex.test(dirName)) { - return true - } - } - } - - return false -} /** * Combine file and directory results and format them properly From dfcba654a6fd4c57156a8a6e008e35239705657a Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Wed, 9 Jul 2025 16:03:20 -0400 Subject: [PATCH 03/21] Tweak alignment of indexing dot (#5523) --- webview-ui/src/components/chat/IndexingStatusBadge.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webview-ui/src/components/chat/IndexingStatusBadge.tsx b/webview-ui/src/components/chat/IndexingStatusBadge.tsx index 0a42b97abf..ff5a0171b5 100644 --- a/webview-ui/src/components/chat/IndexingStatusBadge.tsx +++ b/webview-ui/src/components/chat/IndexingStatusBadge.tsx @@ -128,7 +128,7 @@ export const IndexingStatusBadge: React.FC = ({ classN {/* Status dot badge */} From 76b13dfd7ac611b96a676aaf62304fd7cfe04147 Mon Sep 17 00:00:00 2001 From: dlab-anton Date: Thu, 10 Jul 2025 03:07:18 +0700 Subject: [PATCH 04/21] feat ui/ux: overflow button in header actions (#3060) Co-authored-by: hannesrudolph Co-authored-by: Daniel Riccio --- src/package.json | 73 ++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/src/package.json b/src/package.json index 58c62c207f..2bbe9eabb2 100644 --- a/src/package.json +++ b/src/package.json @@ -218,34 +218,29 @@ "group": "navigation@1", "when": "view == roo-cline.SidebarProvider" }, - { - "command": "roo-cline.mcpButtonClicked", - "group": "navigation@2", - "when": "view == roo-cline.SidebarProvider" - }, - { - "command": "roo-cline.marketplaceButtonClicked", - "group": "navigation@3", - "when": "view == roo-cline.SidebarProvider" - }, { "command": "roo-cline.historyButtonClicked", - "group": "navigation@4", - "when": "view == roo-cline.SidebarProvider" - }, - { - "command": "roo-cline.popoutButtonClicked", - "group": "navigation@5", - "when": "view == roo-cline.SidebarProvider" - }, - { - "command": "roo-cline.accountButtonClicked", - "group": "navigation@6", "when": "view == roo-cline.SidebarProvider" }, { "command": "roo-cline.settingsButtonClicked", - "group": "navigation@7", + "group": "navigation@3", + "when": "view == roo-cline.SidebarProvider" + }, + { + "command": "roo-cline.mcpButtonClicked", + "when": "view == roo-cline.SidebarProvider" + }, + { + "command": "roo-cline.marketplaceButtonClicked", + "when": "view == roo-cline.SidebarProvider" + }, + { + "command": "roo-cline.popoutButtonClicked", + "when": "view == roo-cline.SidebarProvider" + }, + { + "command": "roo-cline.accountButtonClicked", "when": "view == roo-cline.SidebarProvider" } ], @@ -255,29 +250,29 @@ "group": "navigation@1", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, - { - "command": "roo-cline.mcpButtonClicked", - "group": "navigation@2", - "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" - }, - { - "command": "roo-cline.marketplaceButtonClicked", - "group": "navigation@3", - "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" - }, { "command": "roo-cline.historyButtonClicked", - "group": "navigation@4", - "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" - }, - { - "command": "roo-cline.accountButtonClicked", - "group": "navigation@5", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, { "command": "roo-cline.settingsButtonClicked", - "group": "navigation@6", + "group": "navigation@3", + "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" + }, + { + "command": "roo-cline.mcpButtonClicked", + "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" + }, + { + "command": "roo-cline.marketplaceButtonClicked", + "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" + }, + { + "command": "roo-cline.popoutButtonClicked", + "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" + }, + { + "command": "roo-cline.accountButtonClicked", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" } ] From c6412b4339789fefdbd7b521490c04ba91484fa4 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Wed, 9 Jul 2025 16:27:55 -0400 Subject: [PATCH 05/21] Add modes to the overflow menu (#5525) --- src/package.json | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/package.json b/src/package.json index 2bbe9eabb2..aac0e5f0bc 100644 --- a/src/package.json +++ b/src/package.json @@ -75,6 +75,11 @@ "title": "%command.newTask.title%", "icon": "$(add)" }, + { + "command": "roo-cline.promptsButtonClicked", + "title": "%command.prompts.title%", + "icon": "$(organization)" + }, { "command": "roo-cline.mcpButtonClicked", "title": "%command.mcpServers.title%", @@ -227,20 +232,29 @@ "group": "navigation@3", "when": "view == roo-cline.SidebarProvider" }, + { + "command": "roo-cline.promptsButtonClicked", + "group": "overflow", + "when": "view == roo-cline.SidebarProvider" + }, { "command": "roo-cline.mcpButtonClicked", + "group": "overflow", "when": "view == roo-cline.SidebarProvider" }, { "command": "roo-cline.marketplaceButtonClicked", + "group": "overflow", "when": "view == roo-cline.SidebarProvider" }, { "command": "roo-cline.popoutButtonClicked", + "group": "overflow", "when": "view == roo-cline.SidebarProvider" }, { "command": "roo-cline.accountButtonClicked", + "group": "overflow", "when": "view == roo-cline.SidebarProvider" } ], @@ -259,20 +273,29 @@ "group": "navigation@3", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, + { + "command": "roo-cline.promptsButtonClicked", + "group": "overflow", + "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" + }, { "command": "roo-cline.mcpButtonClicked", + "group": "overflow", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, { "command": "roo-cline.marketplaceButtonClicked", + "group": "overflow", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, { "command": "roo-cline.popoutButtonClicked", + "group": "overflow", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, { "command": "roo-cline.accountButtonClicked", + "group": "overflow", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" } ] From 12ae900660139c113f91a06a75e6f61cbff5d464 Mon Sep 17 00:00:00 2001 From: Daniel <57051444+daniel-lxs@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:49:32 -0500 Subject: [PATCH 06/21] fix: handle null/empty custom modes files to prevent 'Cannot read properties of null' error (#5526) * fix: handle null/empty custom modes files to prevent 'Cannot read properties of null' error - Fix SimpleInstaller to ensure existingData is always an object after yaml.parse - Fix CustomModesManager.parseYamlSafely to return empty object instead of null - Ensure customModes array is always initialized in both install and remove operations - Add tests for empty/null file handling scenarios - Update existing tests to match correct behavior * fix: handle null/undefined settings in updateModesInFile and loadModesFromFile - Ensure settings object exists before accessing customModes property - Initialize customModes as empty array if undefined - Prevent 'Cannot read properties of null' error during mode import - Add proper validation in loadModesFromFile before schema check --- src/core/config/CustomModesManager.ts | 20 +++- src/services/marketplace/SimpleInstaller.ts | 51 +++++---- .../__tests__/SimpleInstaller.spec.ts | 100 ++++++++++++++++++ 3 files changed, 147 insertions(+), 24 deletions(-) diff --git a/src/core/config/CustomModesManager.ts b/src/core/config/CustomModesManager.ts index 9f29185eba..b4bcfa62d6 100644 --- a/src/core/config/CustomModesManager.ts +++ b/src/core/config/CustomModesManager.ts @@ -148,7 +148,9 @@ export class CustomModesManager { cleanedContent = this.cleanInvisibleCharacters(cleanedContent) try { - return yaml.parse(cleanedContent) + const parsed = yaml.parse(cleanedContent) + // Ensure we never return null or undefined + return parsed ?? {} } catch (yamlError) { // For .roomodes files, try JSON as fallback if (filePath.endsWith(ROOMODES_FILENAME)) { @@ -180,6 +182,12 @@ export class CustomModesManager { try { const content = await fs.readFile(filePath, "utf-8") const settings = this.parseYamlSafely(content, filePath) + + // Ensure settings has customModes property + if (!settings || typeof settings !== "object" || !settings.customModes) { + return [] + } + const result = customModesSettingsSchema.safeParse(settings) if (!result.success) { @@ -458,7 +466,15 @@ export class CustomModesManager { settings = { customModes: [] } } - settings.customModes = operation(settings.customModes || []) + // Ensure settings is an object and has customModes property + if (!settings || typeof settings !== "object") { + settings = { customModes: [] } + } + if (!settings.customModes) { + settings.customModes = [] + } + + settings.customModes = operation(settings.customModes) await fs.writeFile(filePath, yaml.stringify(settings, { lineWidth: 0 }), "utf-8") } diff --git a/src/services/marketplace/SimpleInstaller.ts b/src/services/marketplace/SimpleInstaller.ts index 91f5bcad26..2274b65343 100644 --- a/src/services/marketplace/SimpleInstaller.ts +++ b/src/services/marketplace/SimpleInstaller.ts @@ -47,7 +47,9 @@ export class SimpleInstaller { let existingData: any = { customModes: [] } try { const existing = await fs.readFile(filePath, "utf-8") - existingData = yaml.parse(existing) || { customModes: [] } + const parsed = yaml.parse(existing) + // Ensure we have a valid object with customModes array + existingData = parsed && typeof parsed === "object" ? parsed : { customModes: [] } } catch (error: any) { if (error.code === "ENOENT") { // File doesn't exist, use default structure - this is fine @@ -253,7 +255,9 @@ export class SimpleInstaller { let existingData: any try { - existingData = yaml.parse(existing) + const parsed = yaml.parse(existing) + // Ensure we have a valid object + existingData = parsed && typeof parsed === "object" ? parsed : {} } catch (parseError) { // If we can't parse the file, we can't safely remove a mode const fileName = target === "project" ? ".roomodes" : "custom-modes.yaml" @@ -263,27 +267,30 @@ export class SimpleInstaller { ) } - if (existingData?.customModes) { - // Parse the item content to get the slug - let content: string - if (Array.isArray(item.content)) { - // Array of McpInstallationMethod objects - use first method - content = item.content[0].content - } else { - content = item.content - } - const modeData = yaml.parse(content || "") - - if (!modeData.slug) { - return // Nothing to remove if no slug - } - - // Remove mode with matching slug - existingData.customModes = existingData.customModes.filter((mode: any) => mode.slug !== modeData.slug) - - // Always write back the file, even if empty - await fs.writeFile(filePath, yaml.stringify(existingData, { lineWidth: 0 }), "utf-8") + // Ensure customModes array exists + if (!existingData.customModes) { + existingData.customModes = [] } + + // Parse the item content to get the slug + let content: string + if (Array.isArray(item.content)) { + // Array of McpInstallationMethod objects - use first method + content = item.content[0].content + } else { + content = item.content + } + const modeData = yaml.parse(content || "") + + if (!modeData.slug) { + return // Nothing to remove if no slug + } + + // Remove mode with matching slug + existingData.customModes = existingData.customModes.filter((mode: any) => mode.slug !== modeData.slug) + + // Always write back the file, even if empty + await fs.writeFile(filePath, yaml.stringify(existingData, { lineWidth: 0 }), "utf-8") } catch (error: any) { if (error.code === "ENOENT") { // File doesn't exist, nothing to remove diff --git a/src/services/marketplace/__tests__/SimpleInstaller.spec.ts b/src/services/marketplace/__tests__/SimpleInstaller.spec.ts index 4934d0a6bc..546eb16f9a 100644 --- a/src/services/marketplace/__tests__/SimpleInstaller.spec.ts +++ b/src/services/marketplace/__tests__/SimpleInstaller.spec.ts @@ -89,6 +89,59 @@ describe("SimpleInstaller", () => { expect(writtenData.customModes.find((m: any) => m.slug === "test")).toBeDefined() }) + it("should handle empty .roomodes file", async () => { + // Empty file content + mockFs.readFile.mockResolvedValueOnce("") + mockFs.writeFile.mockResolvedValueOnce(undefined as any) + + const result = await installer.installItem(mockModeItem, { target: "project" }) + + expect(result.filePath).toBe(path.join("/test/workspace", ".roomodes")) + expect(mockFs.writeFile).toHaveBeenCalled() + + // Verify the written content contains the new mode + const writtenContent = mockFs.writeFile.mock.calls[0][1] as string + const writtenData = yaml.parse(writtenContent) + expect(writtenData.customModes).toHaveLength(1) + expect(writtenData.customModes[0].slug).toBe("test") + }) + + it("should handle .roomodes file with null content", async () => { + // File exists but yaml.parse returns null + mockFs.readFile.mockResolvedValueOnce("---\n") + mockFs.writeFile.mockResolvedValueOnce(undefined as any) + + const result = await installer.installItem(mockModeItem, { target: "project" }) + + expect(result.filePath).toBe(path.join("/test/workspace", ".roomodes")) + expect(mockFs.writeFile).toHaveBeenCalled() + + // Verify the written content contains the new mode + const writtenContent = mockFs.writeFile.mock.calls[0][1] as string + const writtenData = yaml.parse(writtenContent) + expect(writtenData.customModes).toHaveLength(1) + expect(writtenData.customModes[0].slug).toBe("test") + }) + + it("should handle .roomodes file without customModes property", async () => { + // File has valid YAML but no customModes property + const contentWithoutCustomModes = yaml.stringify({ someOtherProperty: "value" }) + mockFs.readFile.mockResolvedValueOnce(contentWithoutCustomModes) + mockFs.writeFile.mockResolvedValueOnce(undefined as any) + + const result = await installer.installItem(mockModeItem, { target: "project" }) + + expect(result.filePath).toBe(path.join("/test/workspace", ".roomodes")) + expect(mockFs.writeFile).toHaveBeenCalled() + + // Verify the written content contains the new mode and preserves other properties + const writtenContent = mockFs.writeFile.mock.calls[0][1] as string + const writtenData = yaml.parse(writtenContent) + expect(writtenData.customModes).toHaveLength(1) + expect(writtenData.customModes[0].slug).toBe("test") + expect(writtenData.someOtherProperty).toBe("value") + }) + it("should throw error when .roomodes contains invalid YAML", async () => { const invalidYaml = "invalid: yaml: content: {" @@ -224,5 +277,52 @@ describe("SimpleInstaller", () => { expect(mockFs.writeFile).not.toHaveBeenCalled() }) + + it("should handle empty .roomodes file during removal", async () => { + // Empty file content + mockFs.readFile.mockResolvedValueOnce("") + mockFs.writeFile.mockResolvedValueOnce(undefined as any) + + // Should not throw + await installer.removeItem(mockModeItem, { target: "project" }) + + // Should write back a valid structure with empty customModes + expect(mockFs.writeFile).toHaveBeenCalled() + const writtenContent = mockFs.writeFile.mock.calls[0][1] as string + const writtenData = yaml.parse(writtenContent) + expect(writtenData.customModes).toEqual([]) + }) + + it("should handle .roomodes file with null content during removal", async () => { + // File exists but yaml.parse returns null + mockFs.readFile.mockResolvedValueOnce("---\n") + mockFs.writeFile.mockResolvedValueOnce(undefined as any) + + // Should not throw + await installer.removeItem(mockModeItem, { target: "project" }) + + // Should write back a valid structure with empty customModes + expect(mockFs.writeFile).toHaveBeenCalled() + const writtenContent = mockFs.writeFile.mock.calls[0][1] as string + const writtenData = yaml.parse(writtenContent) + expect(writtenData.customModes).toEqual([]) + }) + + it("should handle .roomodes file without customModes property during removal", async () => { + // File has valid YAML but no customModes property + const contentWithoutCustomModes = yaml.stringify({ someOtherProperty: "value" }) + mockFs.readFile.mockResolvedValueOnce(contentWithoutCustomModes) + mockFs.writeFile.mockResolvedValueOnce(undefined as any) + + // Should not throw + await installer.removeItem(mockModeItem, { target: "project" }) + + // Should write back the file with the same content (no modes to remove) + expect(mockFs.writeFile).toHaveBeenCalled() + const writtenContent = mockFs.writeFile.mock.calls[0][1] as string + const writtenData = yaml.parse(writtenContent) + expect(writtenData.customModes).toEqual([]) + expect(writtenData.someOtherProperty).toBe("value") + }) }) }) From 8824a719ebdc4577edb422c1e50434c73d793787 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Wed, 9 Jul 2025 16:50:29 -0400 Subject: [PATCH 07/21] Fix nightly build again (#5527) --- src/package.json | 66 +++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/src/package.json b/src/package.json index aac0e5f0bc..79c5a54caa 100644 --- a/src/package.json +++ b/src/package.json @@ -223,38 +223,39 @@ "group": "navigation@1", "when": "view == roo-cline.SidebarProvider" }, - { - "command": "roo-cline.historyButtonClicked", - "when": "view == roo-cline.SidebarProvider" - }, { "command": "roo-cline.settingsButtonClicked", - "group": "navigation@3", + "group": "navigation@2", "when": "view == roo-cline.SidebarProvider" }, { - "command": "roo-cline.promptsButtonClicked", - "group": "overflow", - "when": "view == roo-cline.SidebarProvider" - }, - { - "command": "roo-cline.mcpButtonClicked", - "group": "overflow", + "command": "roo-cline.historyButtonClicked", + "group": "overflow@1", "when": "view == roo-cline.SidebarProvider" }, { "command": "roo-cline.marketplaceButtonClicked", - "group": "overflow", + "group": "overflow@2", "when": "view == roo-cline.SidebarProvider" }, { - "command": "roo-cline.popoutButtonClicked", - "group": "overflow", + "command": "roo-cline.promptsButtonClicked", + "group": "overflow@3", + "when": "view == roo-cline.SidebarProvider" + }, + { + "command": "roo-cline.mcpButtonClicked", + "group": "overflow@4", "when": "view == roo-cline.SidebarProvider" }, { "command": "roo-cline.accountButtonClicked", - "group": "overflow", + "group": "overflow@5", + "when": "view == roo-cline.SidebarProvider" + }, + { + "command": "roo-cline.popoutButtonClicked", + "group": "overflow@6", "when": "view == roo-cline.SidebarProvider" } ], @@ -264,38 +265,39 @@ "group": "navigation@1", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, - { - "command": "roo-cline.historyButtonClicked", - "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" - }, { "command": "roo-cline.settingsButtonClicked", - "group": "navigation@3", + "group": "navigation@2", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, { - "command": "roo-cline.promptsButtonClicked", - "group": "overflow", - "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" - }, - { - "command": "roo-cline.mcpButtonClicked", - "group": "overflow", + "command": "roo-cline.historyButtonClicked", + "group": "overflow@1", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, { "command": "roo-cline.marketplaceButtonClicked", - "group": "overflow", + "group": "overflow@2", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, { - "command": "roo-cline.popoutButtonClicked", - "group": "overflow", + "command": "roo-cline.promptsButtonClicked", + "group": "overflow@3", + "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" + }, + { + "command": "roo-cline.mcpButtonClicked", + "group": "overflow@4", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, { "command": "roo-cline.accountButtonClicked", - "group": "overflow", + "group": "overflow@5", + "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" + }, + { + "command": "roo-cline.popoutButtonClicked", + "group": "overflow@6", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" } ] From dd00fc8a0f0823878aa5a6be737ca0cca4fd7c21 Mon Sep 17 00:00:00 2001 From: Daniel <57051444+daniel-lxs@users.noreply.github.com> Date: Wed, 9 Jul 2025 16:24:53 -0500 Subject: [PATCH 08/21] feat: Replace title attributes with StandardTooltip in ChatTextArea (#5528) feat: Replace title attributes with StandardTooltip in ChatTextArea buttons - Added StandardTooltip wrapper for Stop TTS button - Replaced title attributes with StandardTooltip for Enhance Prompt button - Replaced title attributes with StandardTooltip for Send Message button - Replaced title attributes with StandardTooltip for Add Images button Note: The stopTts translation key needs to be added to the localization files --- .../src/components/chat/ChatTextArea.tsx | 141 +++++++++--------- webview-ui/src/i18n/locales/ca/chat.json | 1 + webview-ui/src/i18n/locales/de/chat.json | 1 + webview-ui/src/i18n/locales/en/chat.json | 1 + webview-ui/src/i18n/locales/es/chat.json | 1 + webview-ui/src/i18n/locales/fr/chat.json | 1 + webview-ui/src/i18n/locales/hi/chat.json | 1 + webview-ui/src/i18n/locales/id/chat.json | 1 + webview-ui/src/i18n/locales/it/chat.json | 1 + webview-ui/src/i18n/locales/ja/chat.json | 1 + webview-ui/src/i18n/locales/ko/chat.json | 1 + webview-ui/src/i18n/locales/nl/chat.json | 1 + webview-ui/src/i18n/locales/pl/chat.json | 1 + webview-ui/src/i18n/locales/pt-BR/chat.json | 1 + webview-ui/src/i18n/locales/ru/chat.json | 1 + webview-ui/src/i18n/locales/tr/chat.json | 1 + webview-ui/src/i18n/locales/vi/chat.json | 1 + webview-ui/src/i18n/locales/zh-CN/chat.json | 1 + webview-ui/src/i18n/locales/zh-TW/chat.json | 1 + 19 files changed, 91 insertions(+), 68 deletions(-) diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index 3d70f4a4ca..ee622239e2 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -951,59 +951,63 @@ const ChatTextArea = forwardRef( /> {isTtsPlaying && ( - + + + )}
- + + +
- + + +
{!inputValue && ( @@ -1170,27 +1174,28 @@ const ChatTextArea = forwardRef(
- + + +
diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index 848306a1cf..8ad87049e3 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "Millora la sol·licitud amb context addicional", "addImages": "Afegeix imatges al missatge", "sendMessage": "Envia el missatge", + "stopTts": "Atura la síntesi de veu", "typeMessage": "Escriu un missatge...", "typeTask": "Escriu la teva tasca aquí...", "addContext": "@ per afegir context, / per canviar de mode", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index f28448ce54..88f6a46dbb 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "Prompt mit zusätzlichem Kontext verbessern", "addImages": "Bilder zur Nachricht hinzufügen", "sendMessage": "Nachricht senden", + "stopTts": "Text-in-Sprache beenden", "typeMessage": "Nachricht eingeben...", "typeTask": "Gib deine Aufgabe hier ein...", "addContext": "@ für Kontext, / zum Moduswechsel", diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index 0c49fbaac7..6117ad431e 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -120,6 +120,7 @@ "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", + "stopTts": "Stop text-to-speech", "typeMessage": "Type a message...", "typeTask": "Type your task here...", "addContext": "@ to add context, / to switch modes", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index 71a26f6c10..086fd92f9d 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "Mejorar el mensaje con contexto adicional", "addImages": "Agregar imágenes al mensaje", "sendMessage": "Enviar mensaje", + "stopTts": "Detener texto a voz", "typeMessage": "Escribe un mensaje...", "typeTask": "Escribe tu tarea aquí...", "addContext": "@ para agregar contexto, / para cambiar modos", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index 19531f2554..8e917d1f21 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "Améliorer la requête avec un contexte supplémentaire", "addImages": "Ajouter des images au message", "sendMessage": "Envoyer le message", + "stopTts": "Arrêter la synthèse vocale", "typeMessage": "Écrivez un message...", "typeTask": "Écrivez votre tâche ici...", "addContext": "@ pour ajouter du contexte, / pour changer de mode", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index a45317d2da..385549f987 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "अतिरिक्त संदर्भ के साथ प्रॉम्प्ट बढ़ाएँ", "addImages": "संदेश में चित्र जोड़ें", "sendMessage": "संदेश भेजें", + "stopTts": "टेक्स्ट-टू-स्पीच बंद करें", "typeMessage": "एक संदेश लिखें...", "typeTask": "अपना कार्य यहां लिखें...", "addContext": "संदर्भ जोड़ने के लिए @, मोड बदलने के लिए /", diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json index 7df325b7f9..74722db3ba 100644 --- a/webview-ui/src/i18n/locales/id/chat.json +++ b/webview-ui/src/i18n/locales/id/chat.json @@ -126,6 +126,7 @@ }, "addImages": "Tambahkan gambar ke pesan", "sendMessage": "Kirim pesan", + "stopTts": "Hentikan text-to-speech", "typeMessage": "Ketik pesan...", "typeTask": "Bangun, cari, tanya sesuatu", "addContext": "@ untuk menambah konteks, / untuk ganti mode", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index 4b368f214f..be4dde8aeb 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "Migliora prompt con contesto aggiuntivo", "addImages": "Aggiungi immagini al messaggio", "sendMessage": "Invia messaggio", + "stopTts": "Interrompi sintesi vocale", "typeMessage": "Scrivi un messaggio...", "typeTask": "Scrivi la tua attività qui...", "addContext": "@ per aggiungere contesto, / per cambiare modalità", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index 5a19b64945..c2466cc046 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "追加コンテキストでプロンプトを強化", "addImages": "メッセージに画像を追加", "sendMessage": "メッセージを送信", + "stopTts": "テキスト読み上げを停止", "typeMessage": "メッセージを入力...", "typeTask": "ここにタスクを入力...", "addContext": "コンテキスト追加は@、モード切替は/", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index f3ed7699ca..4649806225 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "추가 컨텍스트로 프롬프트 향상", "addImages": "메시지에 이미지 추가", "sendMessage": "메시지 보내기", + "stopTts": "텍스트 음성 변환 중지", "typeMessage": "메시지 입력...", "typeTask": "여기에 작업 입력...", "addContext": "컨텍스트 추가는 @, 모드 전환은 /", diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json index 874fb74bc7..c9df4af471 100644 --- a/webview-ui/src/i18n/locales/nl/chat.json +++ b/webview-ui/src/i18n/locales/nl/chat.json @@ -112,6 +112,7 @@ }, "addImages": "Afbeeldingen toevoegen aan bericht", "sendMessage": "Bericht verzenden", + "stopTts": "Stop tekst-naar-spraak", "typeMessage": "Typ een bericht...", "typeTask": "Typ hier je taak...", "addContext": "@ om context toe te voegen, / om van modus te wisselen", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index 254f18c9ba..1cf631935c 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "Ulepsz podpowiedź dodatkowym kontekstem", "addImages": "Dodaj obrazy do wiadomości", "sendMessage": "Wyślij wiadomość", + "stopTts": "Zatrzymaj syntezę mowy", "typeMessage": "Wpisz wiadomość...", "typeTask": "Wpisz swoje zadanie tutaj...", "addContext": "@ aby dodać kontekst, / aby zmienić tryb", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index bebfe0c722..acc828a139 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "Aprimorar prompt com contexto adicional", "addImages": "Adicionar imagens à mensagem", "sendMessage": "Enviar mensagem", + "stopTts": "Parar conversão de texto em fala", "typeMessage": "Digite uma mensagem...", "typeTask": "Digite sua tarefa aqui...", "addContext": "@ para adicionar contexto, / para alternar modos", diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index 4ac8f4854a..94172ef9f0 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -112,6 +112,7 @@ }, "addImages": "Добавить изображения к сообщению", "sendMessage": "Отправить сообщение", + "stopTts": "Остановить синтез речи", "typeMessage": "Введите сообщение...", "typeTask": "Введите вашу задачу здесь...", "addContext": "@ для добавления контекста, / для смены режима", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index 56a9f54cb7..3776eaca92 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "Ek bağlamla istemi geliştir", "addImages": "Mesaja resim ekle", "sendMessage": "Mesaj gönder", + "stopTts": "Metin okumayı durdur", "typeMessage": "Bir mesaj yazın...", "typeTask": "Görevinizi buraya yazın...", "addContext": "Bağlam eklemek için @, mod değiştirmek için /", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index 574df08da1..0e069124af 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "Nâng cao yêu cầu với ngữ cảnh bổ sung", "addImages": "Thêm hình ảnh vào tin nhắn", "sendMessage": "Gửi tin nhắn", + "stopTts": "Dừng chuyển văn bản thành giọng nói", "typeMessage": "Nhập tin nhắn...", "typeTask": "Nhập nhiệm vụ của bạn tại đây...", "addContext": "@ để thêm ngữ cảnh, / để chuyển chế độ", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index f6e51cfa49..e8dbbb97dd 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "增强提示词", "addImages": "添加图片到消息", "sendMessage": "发送消息", + "stopTts": "停止文本转语音", "typeMessage": "输入消息...", "typeTask": "在此处输入您的任务...", "addContext": "@添加上下文,/切换模式", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index 54aeacf15c..323238eb25 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -105,6 +105,7 @@ "enhancePrompt": "使用額外內容增強提示", "addImages": "新增圖片到訊息中", "sendMessage": "傳送訊息", + "stopTts": "停止文字轉語音", "typeMessage": "輸入訊息...", "typeTask": "在此處輸入您的工作...", "addContext": "輸入 @ 新增內容,輸入 / 切換模式", From ffb998bb11acd56cebe3ece0141de1caa561aba7 Mon Sep 17 00:00:00 2001 From: Chris Estreich Date: Wed, 9 Jul 2025 14:41:24 -0700 Subject: [PATCH 09/21] v3.23.4 (#5529) --- .changeset/neat-ends-stick.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/neat-ends-stick.md diff --git a/.changeset/neat-ends-stick.md b/.changeset/neat-ends-stick.md new file mode 100644 index 0000000000..487d4537ea --- /dev/null +++ b/.changeset/neat-ends-stick.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +v3.23.4 From 5f0860798e1fc62fe6268dd10179412059a3efd0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:01:52 -0700 Subject: [PATCH 10/21] Changeset version bump (#5531) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Chris Estreich --- .changeset/neat-ends-stick.md | 5 ----- CHANGELOG.md | 8 ++++++++ src/package.json | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) delete mode 100644 .changeset/neat-ends-stick.md diff --git a/.changeset/neat-ends-stick.md b/.changeset/neat-ends-stick.md deleted file mode 100644 index 487d4537ea..0000000000 --- a/.changeset/neat-ends-stick.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -v3.23.4 diff --git a/CHANGELOG.md b/CHANGELOG.md index e94c518a66..06dd526e25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Roo Code Changelog +## [3.23.4] - 2025-07-09 + +- Update chat area icons for better discoverability & consistency +- Fix a bug that allowed `list_files` to return directory results that should be excluded by .gitignore +- Add an overflow header menu to make the UI a little tidier (thanks @dlab-anton) +- Fix a bug the issue where null custom modes configuration files cause a 'Cannot read properties of null' error (thanks @daniel-lxs!) +- Replace native title attributes with StandardTooltip component for consistency (thanks @daniel-lxs!) + ## [3.23.3] - 2025-07-09 - Remove erroneous line from announcement modal diff --git a/src/package.json b/src/package.json index 79c5a54caa..77a4d5b19c 100644 --- a/src/package.json +++ b/src/package.json @@ -3,7 +3,7 @@ "displayName": "%extension.displayName%", "description": "%extension.description%", "publisher": "RooVeterinaryInc", - "version": "3.23.3", + "version": "3.23.4", "icon": "assets/icons/icon.png", "galleryBanner": { "color": "#617A91", From 7a8848de3be3b0e8efa11e0119e121c8f32f6a18 Mon Sep 17 00:00:00 2001 From: Vivek Soni Date: Thu, 10 Jul 2025 04:38:35 +0530 Subject: [PATCH 11/21] fix: use decodeURIComponent in openFile (#5504) * fix: use decodeURIComponent in openFile * feat: add error handling for decodeURIComponent and tests - Added try-catch block around decodeURIComponent to handle invalid escape sequences - Falls back to original path if decoding fails - Added comprehensive unit tests for the openFile function - Tests cover invalid URI encoding, valid encoding, and various edge cases * fix: update test to handle dynamic workspace paths in CI * fix: handle Windows path separators in open-file tests --------- Co-authored-by: Vivek Soni Co-authored-by: Daniel Riccio --- .../misc/__tests__/open-file.spec.ts | 240 ++++++++++++++++++ src/integrations/misc/open-file.ts | 12 +- 2 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 src/integrations/misc/__tests__/open-file.spec.ts diff --git a/src/integrations/misc/__tests__/open-file.spec.ts b/src/integrations/misc/__tests__/open-file.spec.ts new file mode 100644 index 0000000000..e8f9be259d --- /dev/null +++ b/src/integrations/misc/__tests__/open-file.spec.ts @@ -0,0 +1,240 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest" +import * as vscode from "vscode" +import * as path from "path" +import * as os from "os" +import { openFile } from "../open-file" + +// Mock vscode module +vi.mock("vscode", () => ({ + Uri: { + file: vi.fn((path: string) => ({ fsPath: path })), + }, + workspace: { + fs: { + stat: vi.fn(), + writeFile: vi.fn(), + }, + openTextDocument: vi.fn(), + }, + window: { + showTextDocument: vi.fn(), + showErrorMessage: vi.fn(), + tabGroups: { + all: [], + }, + activeTextEditor: undefined, + }, + commands: { + executeCommand: vi.fn(), + }, + FileType: { + Directory: 2, + File: 1, + }, + Selection: vi.fn((startLine: number, startChar: number, endLine: number, endChar: number) => ({ + start: { line: startLine, character: startChar }, + end: { line: endLine, character: endChar }, + })), + TabInputText: vi.fn(), +})) + +// Mock utils +vi.mock("../../utils/path", () => { + const nodePath = require("path") + return { + arePathsEqual: vi.fn((a: string, b: string) => a === b), + getWorkspacePath: vi.fn(() => { + // In tests, we need to return a consistent workspace path + // The actual workspace is /Users/roocode/rc2 in local, but varies in CI + const cwd = process.cwd() + // If we're in the src directory, go up one level to get workspace root + if (cwd.endsWith("/src")) { + return nodePath.dirname(cwd) + } + return cwd + }), + } +}) + +// Mock i18n +vi.mock("../../i18n", () => ({ + t: vi.fn((key: string, params?: any) => { + // Return the key without namespace prefix to match actual behavior + if (key.startsWith("common:")) { + return key.replace("common:", "") + } + return key + }), +})) + +describe("openFile", () => { + beforeEach(() => { + vi.clearAllMocks() + vi.spyOn(console, "warn").mockImplementation(() => {}) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + describe("decodeURIComponent error handling", () => { + it("should handle invalid URI encoding gracefully", async () => { + const invalidPath = "test%ZZinvalid.txt" // Invalid percent encoding + const mockDocument = { uri: { fsPath: invalidPath } } + + vi.mocked(vscode.workspace.fs.stat).mockResolvedValue({ + type: vscode.FileType.File, + ctime: 0, + mtime: 0, + size: 0, + }) + vi.mocked(vscode.workspace.openTextDocument).mockResolvedValue(mockDocument as any) + vi.mocked(vscode.window.showTextDocument).mockResolvedValue({} as any) + + await openFile(invalidPath) + + // Should log a warning about decode failure + expect(console.warn).toHaveBeenCalledWith( + "Failed to decode file path: URIError: URI malformed. Using original path.", + ) + + // Should still attempt to open the file with the original path + expect(vscode.workspace.openTextDocument).toHaveBeenCalled() + expect(vscode.window.showErrorMessage).not.toHaveBeenCalled() + }) + + it("should successfully decode valid URI-encoded paths", async () => { + const encodedPath = "./%5Btest%5D/file.txt" // [test] encoded + const decodedPath = "./[test]/file.txt" + const mockDocument = { uri: { fsPath: decodedPath } } + + vi.mocked(vscode.workspace.fs.stat).mockResolvedValue({ + type: vscode.FileType.File, + ctime: 0, + mtime: 0, + size: 0, + }) + vi.mocked(vscode.workspace.openTextDocument).mockResolvedValue(mockDocument as any) + vi.mocked(vscode.window.showTextDocument).mockResolvedValue({} as any) + + await openFile(encodedPath) + + // Should not log any warnings + expect(console.warn).not.toHaveBeenCalled() + + // Should use the decoded path - verify it contains the decoded brackets + // On Windows, the path will include backslashes instead of forward slashes + const expectedPathSegment = process.platform === "win32" ? "[test]\\file.txt" : "[test]/file.txt" + expect(vscode.Uri.file).toHaveBeenCalledWith(expect.stringContaining(expectedPathSegment)) + expect(vscode.workspace.openTextDocument).toHaveBeenCalled() + expect(vscode.window.showErrorMessage).not.toHaveBeenCalled() + }) + + it("should handle paths with special characters that need encoding", async () => { + const pathWithSpecialChars = "./[brackets]/file with spaces.txt" + const mockDocument = { uri: { fsPath: pathWithSpecialChars } } + + vi.mocked(vscode.workspace.fs.stat).mockResolvedValue({ + type: vscode.FileType.File, + ctime: 0, + mtime: 0, + size: 0, + }) + vi.mocked(vscode.workspace.openTextDocument).mockResolvedValue(mockDocument as any) + vi.mocked(vscode.window.showTextDocument).mockResolvedValue({} as any) + + await openFile(pathWithSpecialChars) + + // Should work without errors + expect(console.warn).not.toHaveBeenCalled() + expect(vscode.workspace.openTextDocument).toHaveBeenCalled() + expect(vscode.window.showErrorMessage).not.toHaveBeenCalled() + }) + + it("should handle already decoded paths without double-decoding", async () => { + const normalPath = "./normal/file.txt" + const mockDocument = { uri: { fsPath: normalPath } } + + vi.mocked(vscode.workspace.fs.stat).mockResolvedValue({ + type: vscode.FileType.File, + ctime: 0, + mtime: 0, + size: 0, + }) + vi.mocked(vscode.workspace.openTextDocument).mockResolvedValue(mockDocument as any) + vi.mocked(vscode.window.showTextDocument).mockResolvedValue({} as any) + + await openFile(normalPath) + + // Should work without errors + expect(console.warn).not.toHaveBeenCalled() + expect(vscode.workspace.openTextDocument).toHaveBeenCalled() + expect(vscode.window.showErrorMessage).not.toHaveBeenCalled() + }) + }) + + describe("error handling", () => { + it("should show error message when file does not exist", async () => { + const nonExistentPath = "./does/not/exist.txt" + + vi.mocked(vscode.workspace.fs.stat).mockRejectedValue(new Error("File not found")) + + await openFile(nonExistentPath) + + expect(vscode.window.showErrorMessage).toHaveBeenCalledWith("errors.could_not_open_file") + }) + + it("should handle generic errors", async () => { + const testPath = "./test.txt" + + vi.mocked(vscode.workspace.fs.stat).mockRejectedValue("Not an Error object") + + await openFile(testPath) + + expect(vscode.window.showErrorMessage).toHaveBeenCalledWith("errors.could_not_open_file") + }) + }) + + describe("directory handling", () => { + it("should reveal directories in explorer", async () => { + const dirPath = "./components" + + vi.mocked(vscode.workspace.fs.stat).mockResolvedValue({ + type: vscode.FileType.Directory, + ctime: 0, + mtime: 0, + size: 0, + }) + + await openFile(dirPath) + + expect(vscode.commands.executeCommand).toHaveBeenCalledWith( + "revealInExplorer", + expect.objectContaining({ fsPath: expect.stringContaining("components") }), + ) + expect(vscode.commands.executeCommand).toHaveBeenCalledWith("list.expand") + expect(vscode.workspace.openTextDocument).not.toHaveBeenCalled() + }) + }) + + describe("file creation", () => { + it("should create new files when create option is true", async () => { + const newFilePath = "./new/file.txt" + const content = "Hello, world!" + + vi.mocked(vscode.workspace.fs.stat).mockRejectedValue(new Error("File not found")) + vi.mocked(vscode.workspace.openTextDocument).mockResolvedValue({} as any) + vi.mocked(vscode.window.showTextDocument).mockResolvedValue({} as any) + + await openFile(newFilePath, { create: true, content }) + + // On Windows, the path will include backslashes instead of forward slashes + const expectedPathSegment = process.platform === "win32" ? "new\\file.txt" : "new/file.txt" + expect(vscode.workspace.fs.writeFile).toHaveBeenCalledWith( + expect.objectContaining({ fsPath: expect.stringContaining(expectedPathSegment) }), + Buffer.from(content, "utf8"), + ) + expect(vscode.workspace.openTextDocument).toHaveBeenCalled() + }) + }) +}) diff --git a/src/integrations/misc/open-file.ts b/src/integrations/misc/open-file.ts index f05c10dc96..a9ab44f7e5 100644 --- a/src/integrations/misc/open-file.ts +++ b/src/integrations/misc/open-file.ts @@ -12,9 +12,19 @@ interface OpenFileOptions { export async function openFile(filePath: string, options: OpenFileOptions = {}) { try { + // Store the original path for error messages before any modifications + const originalFilePathForError = filePath + + // Try to decode the URI component, but if it fails, use the original path + try { + filePath = decodeURIComponent(filePath) + } catch (decodeError) { + // If decoding fails (e.g., invalid escape sequences), continue with the original path + console.warn(`Failed to decode file path: ${decodeError}. Using original path.`) + } + const workspaceRoot = getWorkspacePath() const homeDir = os.homedir() - const originalFilePathForError = filePath // Keep original for error messages const attemptPaths: string[] = [] From be1eaa51eb4651b6a824afb8290cb7a06769b478 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Wed, 9 Jul 2025 19:21:47 -0400 Subject: [PATCH 12/21] Make account tab visible (#5534) * Make account tab visible * Fix order --- src/package.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/package.json b/src/package.json index 77a4d5b19c..2da9d7d554 100644 --- a/src/package.json +++ b/src/package.json @@ -228,6 +228,11 @@ "group": "navigation@2", "when": "view == roo-cline.SidebarProvider" }, + { + "command": "roo-cline.accountButtonClicked", + "group": "navigation@3", + "when": "view == roo-cline.SidebarProvider" + }, { "command": "roo-cline.historyButtonClicked", "group": "overflow@1", @@ -248,14 +253,9 @@ "group": "overflow@4", "when": "view == roo-cline.SidebarProvider" }, - { - "command": "roo-cline.accountButtonClicked", - "group": "overflow@5", - "when": "view == roo-cline.SidebarProvider" - }, { "command": "roo-cline.popoutButtonClicked", - "group": "overflow@6", + "group": "overflow@5", "when": "view == roo-cline.SidebarProvider" } ], @@ -270,6 +270,11 @@ "group": "navigation@2", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, + { + "command": "roo-cline.accountButtonClicked", + "group": "navigation@3", + "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" + }, { "command": "roo-cline.historyButtonClicked", "group": "overflow@1", @@ -290,14 +295,9 @@ "group": "overflow@4", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, - { - "command": "roo-cline.accountButtonClicked", - "group": "overflow@5", - "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" - }, { "command": "roo-cline.popoutButtonClicked", - "group": "overflow@6", + "group": "overflow@5", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" } ] From 45f3d88ddf3bd99dbf13c8c14584b3610388bdb1 Mon Sep 17 00:00:00 2001 From: Daniel <57051444+daniel-lxs@users.noreply.github.com> Date: Wed, 9 Jul 2025 18:22:05 -0500 Subject: [PATCH 13/21] fix(embeddings): Translate error messages before sending to UI (#5535) fix(embeddings): translate error messages before sending to UI - Import t() function from i18n module - Wrap error messages with t() translation function in _initializeEmbedder() - Ensures proper localization of error messages in the UI - Falls back to original message if no translation exists --- src/services/code-index/manager.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/services/code-index/manager.ts b/src/services/code-index/manager.ts index 7002283226..bd782da84c 100644 --- a/src/services/code-index/manager.ts +++ b/src/services/code-index/manager.ts @@ -12,6 +12,7 @@ import { CacheManager } from "./cache-manager" import fs from "fs/promises" import ignore from "ignore" import path from "path" +import { t } from "../../i18n" export class CodeIndexManager { // --- Singleton Implementation --- @@ -261,12 +262,16 @@ export class CodeIndexManager { // Validate embedder configuration before proceeding const validationResult = await this._serviceFactory.validateEmbedder(embedder) if (!validationResult.valid) { - // Set error state with clear message - this._stateManager.setSystemState( - "Error", - validationResult.error || "Embedder configuration validation failed", - ) - throw new Error(validationResult.error || "Invalid embedder configuration") + const errorMessage = validationResult.error || "Embedder configuration validation failed" + // Always attempt translation, use original as fallback + let translatedMessage = t(errorMessage) + // If translation returns a different value (stripped namespace), use original + if (translatedMessage !== errorMessage && !translatedMessage.includes(":")) { + translatedMessage = errorMessage + } + + this._stateManager.setSystemState("Error", translatedMessage) + throw new Error(translatedMessage) } // (Re)Initialize orchestrator From e64fb150b524a068e47a34d29c7418ae028d0f13 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Wed, 9 Jul 2025 19:31:50 -0400 Subject: [PATCH 14/21] chore: add changeset for v3.23.5 patch release (#5536) --- .changeset/v3.23.5.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/v3.23.5.md diff --git a/.changeset/v3.23.5.md b/.changeset/v3.23.5.md new file mode 100644 index 0000000000..fcb48941a7 --- /dev/null +++ b/.changeset/v3.23.5.md @@ -0,0 +1,7 @@ +--- +"roo-cline": patch +--- + +- Fix: use decodeURIComponent in openFile (thanks @vivekfyi!) +- Fix(embeddings): Translate error messages before sending to UI (thanks @daniel-lxs!) +- Make account tab visible From 6e473f5449880080e57173707a64ccedd4988e4e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 19:39:48 -0400 Subject: [PATCH 15/21] Changeset version bump (#5537) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens --- .changeset/v3.23.5.md | 7 ------- CHANGELOG.md | 6 ++++++ src/package.json | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) delete mode 100644 .changeset/v3.23.5.md diff --git a/.changeset/v3.23.5.md b/.changeset/v3.23.5.md deleted file mode 100644 index fcb48941a7..0000000000 --- a/.changeset/v3.23.5.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"roo-cline": patch ---- - -- Fix: use decodeURIComponent in openFile (thanks @vivekfyi!) -- Fix(embeddings): Translate error messages before sending to UI (thanks @daniel-lxs!) -- Make account tab visible diff --git a/CHANGELOG.md b/CHANGELOG.md index 06dd526e25..8250c4466a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Roo Code Changelog +## [3.23.5] - 2025-07-09 + +- Fix: use decodeURIComponent in openFile (thanks @vivekfyi!) +- Fix(embeddings): Translate error messages before sending to UI (thanks @daniel-lxs!) +- Make account tab visible + ## [3.23.4] - 2025-07-09 - Update chat area icons for better discoverability & consistency diff --git a/src/package.json b/src/package.json index 2da9d7d554..1fac66f4e1 100644 --- a/src/package.json +++ b/src/package.json @@ -3,7 +3,7 @@ "displayName": "%extension.displayName%", "description": "%extension.description%", "publisher": "RooVeterinaryInc", - "version": "3.23.4", + "version": "3.23.5", "icon": "assets/icons/icon.png", "galleryBanner": { "color": "#617A91", From 08c9420350369cf478f3303a8a5e80462bb75f0f Mon Sep 17 00:00:00 2001 From: Will Li Date: Wed, 9 Jul 2025 17:57:10 -0700 Subject: [PATCH 16/21] fix (#5540) --- src/activate/registerCommands.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/activate/registerCommands.ts b/src/activate/registerCommands.ts index 8e84981d8a..bd925b0e90 100644 --- a/src/activate/registerCommands.ts +++ b/src/activate/registerCommands.ts @@ -14,6 +14,7 @@ import { registerHumanRelayCallback, unregisterHumanRelayCallback, handleHumanRe import { handleNewTask } from "./handleTask" import { CodeIndexManager } from "../services/code-index/manager" import { importSettingsWithFeedback } from "../core/config/importExport" +import { MdmService } from "../services/mdm/MdmService" import { t } from "../i18n" /** @@ -226,7 +227,17 @@ export const openClineInNewTab = async ({ context, outputChannel }: Omit editor.viewColumn || 0)) // Check if there are any visible text editors, otherwise open a new group From cdde7b3aa82655d251b6a28de592e3673b05a8f7 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Thu, 10 Jul 2025 07:07:16 -0400 Subject: [PATCH 17/21] Grok 4 (#5559) --- .changeset/red-symbols-grab.md | 5 ++++ packages/types/src/providers/xai.ts | 43 ++++++++++++++++++----------- 2 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 .changeset/red-symbols-grab.md diff --git a/.changeset/red-symbols-grab.md b/.changeset/red-symbols-grab.md new file mode 100644 index 0000000000..30e4e4ef27 --- /dev/null +++ b/.changeset/red-symbols-grab.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +Grok 4 diff --git a/packages/types/src/providers/xai.ts b/packages/types/src/providers/xai.ts index 4f2cedd14b..12dc8a145c 100644 --- a/packages/types/src/providers/xai.ts +++ b/packages/types/src/providers/xai.ts @@ -3,26 +3,19 @@ import type { ModelInfo } from "../model.js" // https://docs.x.ai/docs/api-reference export type XAIModelId = keyof typeof xaiModels -export const xaiDefaultModelId: XAIModelId = "grok-3" +export const xaiDefaultModelId: XAIModelId = "grok-4" export const xaiModels = { - "grok-2-1212": { + "grok-4": { maxTokens: 8192, - contextWindow: 131072, - supportsImages: false, - supportsPromptCache: false, - inputPrice: 2.0, - outputPrice: 10.0, - description: "xAI's Grok-2 model (version 1212) with 128K context window", - }, - "grok-2-vision-1212": { - maxTokens: 8192, - contextWindow: 32768, + contextWindow: 256000, supportsImages: true, - supportsPromptCache: false, - inputPrice: 2.0, - outputPrice: 10.0, - description: "xAI's Grok-2 Vision model (version 1212) with image support and 32K context window", + supportsPromptCache: true, + inputPrice: 3.0, + outputPrice: 15.0, + cacheWritesPrice: 0.75, + cacheReadsPrice: 0.75, + description: "xAI's Grok-4 model with 256K context window", }, "grok-3": { maxTokens: 8192, @@ -70,4 +63,22 @@ export const xaiModels = { description: "xAI's Grok-3 mini fast model with 128K context window", supportsReasoningEffort: true, }, + "grok-2-1212": { + maxTokens: 8192, + contextWindow: 131072, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 2.0, + outputPrice: 10.0, + description: "xAI's Grok-2 model (version 1212) with 128K context window", + }, + "grok-2-vision-1212": { + maxTokens: 8192, + contextWindow: 32768, + supportsImages: true, + supportsPromptCache: false, + inputPrice: 2.0, + outputPrice: 10.0, + description: "xAI's Grok-2 Vision model (version 1212) with image support and 32K context window", + }, } as const satisfies Record From 5cfd98dc3350a002e323f5634c619d068985fe54 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 07:10:05 -0400 Subject: [PATCH 18/21] Changeset version bump (#5560) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens --- .changeset/red-symbols-grab.md | 5 ----- CHANGELOG.md | 4 ++++ src/package.json | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) delete mode 100644 .changeset/red-symbols-grab.md diff --git a/.changeset/red-symbols-grab.md b/.changeset/red-symbols-grab.md deleted file mode 100644 index 30e4e4ef27..0000000000 --- a/.changeset/red-symbols-grab.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -Grok 4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8250c4466a..ca9b46d596 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Roo Code Changelog +## [3.23.6] - 2025-07-10 + +- Grok 4 + ## [3.23.5] - 2025-07-09 - Fix: use decodeURIComponent in openFile (thanks @vivekfyi!) diff --git a/src/package.json b/src/package.json index 1fac66f4e1..14f6607742 100644 --- a/src/package.json +++ b/src/package.json @@ -3,7 +3,7 @@ "displayName": "%extension.displayName%", "description": "%extension.description%", "publisher": "RooVeterinaryInc", - "version": "3.23.5", + "version": "3.23.6", "icon": "assets/icons/icon.png", "galleryBanner": { "color": "#617A91", From 4771864a8c05eb7b146a04ea9ad474a8091ab253 Mon Sep 17 00:00:00 2001 From: shubhamgupta731 Date: Thu, 10 Jul 2025 18:57:28 +0530 Subject: [PATCH 19/21] Expand Vertex AI region config to include all available regions in GCP Vertex AI (#5557) Co-authored-by: Shubham Gupta Co-authored-by: Daniel Riccio --- packages/types/src/providers/vertex.ts | 28 ++++++++- .../providers/__tests__/Vertex.spec.tsx | 61 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 webview-ui/src/components/settings/providers/__tests__/Vertex.spec.tsx diff --git a/packages/types/src/providers/vertex.ts b/packages/types/src/providers/vertex.ts index b048c19403..c405621f82 100644 --- a/packages/types/src/providers/vertex.ts +++ b/packages/types/src/providers/vertex.ts @@ -277,9 +277,35 @@ export const vertexModels = { export const VERTEX_REGIONS = [ { value: "global", label: "global" }, - { value: "us-east5", label: "us-east5" }, { value: "us-central1", label: "us-central1" }, + { value: "us-east1", label: "us-east1" }, + { value: "us-east4", label: "us-east4" }, + { value: "us-east5", label: "us-east5" }, + { value: "us-west1", label: "us-west1" }, + { value: "us-west2", label: "us-west2" }, + { value: "us-west3", label: "us-west3" }, + { value: "us-west4", label: "us-west4" }, + { value: "northamerica-northeast1", label: "northamerica-northeast1" }, + { value: "northamerica-northeast2", label: "northamerica-northeast2" }, + { value: "southamerica-east1", label: "southamerica-east1" }, { value: "europe-west1", label: "europe-west1" }, + { value: "europe-west2", label: "europe-west2" }, + { value: "europe-west3", label: "europe-west3" }, { value: "europe-west4", label: "europe-west4" }, + { value: "europe-west6", label: "europe-west6" }, + { value: "europe-central2", label: "europe-central2" }, + { value: "asia-east1", label: "asia-east1" }, + { value: "asia-east2", label: "asia-east2" }, + { value: "asia-northeast1", label: "asia-northeast1" }, + { value: "asia-northeast2", label: "asia-northeast2" }, + { value: "asia-northeast3", label: "asia-northeast3" }, + { value: "asia-south1", label: "asia-south1" }, + { value: "asia-south2", label: "asia-south2" }, { value: "asia-southeast1", label: "asia-southeast1" }, + { value: "asia-southeast2", label: "asia-southeast2" }, + { value: "australia-southeast1", label: "australia-southeast1" }, + { value: "australia-southeast2", label: "australia-southeast2" }, + { value: "me-west1", label: "me-west1" }, + { value: "me-central1", label: "me-central1" }, + { value: "africa-south1", label: "africa-south1" }, ] diff --git a/webview-ui/src/components/settings/providers/__tests__/Vertex.spec.tsx b/webview-ui/src/components/settings/providers/__tests__/Vertex.spec.tsx new file mode 100644 index 0000000000..4ef949f9e0 --- /dev/null +++ b/webview-ui/src/components/settings/providers/__tests__/Vertex.spec.tsx @@ -0,0 +1,61 @@ +// Tests for VERTEX_REGIONS "global" region handling + +import { describe, it, expect } from "vitest" +import { VERTEX_REGIONS } from "../../../../../../packages/types/src/providers/vertex" + +describe("VERTEX_REGIONS", () => { + it('should include the "global" region as the first entry', () => { + expect(VERTEX_REGIONS[0]).toEqual({ value: "global", label: "global" }) + }) + + it('should contain "global" region exactly once', () => { + const globalRegions = VERTEX_REGIONS.filter((r: { value: string; label: string }) => r.value === "global") + expect(globalRegions).toHaveLength(1) + }) + + it('should contain all expected regions including "global"', () => { + // The expected list is the imported VERTEX_REGIONS itself + expect(VERTEX_REGIONS).toEqual([ + { value: "global", label: "global" }, + { value: "us-central1", label: "us-central1" }, + { value: "us-east1", label: "us-east1" }, + { value: "us-east4", label: "us-east4" }, + { value: "us-east5", label: "us-east5" }, + { value: "us-west1", label: "us-west1" }, + { value: "us-west2", label: "us-west2" }, + { value: "us-west3", label: "us-west3" }, + { value: "us-west4", label: "us-west4" }, + { value: "northamerica-northeast1", label: "northamerica-northeast1" }, + { value: "northamerica-northeast2", label: "northamerica-northeast2" }, + { value: "southamerica-east1", label: "southamerica-east1" }, + { value: "europe-west1", label: "europe-west1" }, + { value: "europe-west2", label: "europe-west2" }, + { value: "europe-west3", label: "europe-west3" }, + { value: "europe-west4", label: "europe-west4" }, + { value: "europe-west6", label: "europe-west6" }, + { value: "europe-central2", label: "europe-central2" }, + { value: "asia-east1", label: "asia-east1" }, + { value: "asia-east2", label: "asia-east2" }, + { value: "asia-northeast1", label: "asia-northeast1" }, + { value: "asia-northeast2", label: "asia-northeast2" }, + { value: "asia-northeast3", label: "asia-northeast3" }, + { value: "asia-south1", label: "asia-south1" }, + { value: "asia-south2", label: "asia-south2" }, + { value: "asia-southeast1", label: "asia-southeast1" }, + { value: "asia-southeast2", label: "asia-southeast2" }, + { value: "australia-southeast1", label: "australia-southeast1" }, + { value: "australia-southeast2", label: "australia-southeast2" }, + { value: "me-west1", label: "me-west1" }, + { value: "me-central1", label: "me-central1" }, + { value: "africa-south1", label: "africa-south1" }, + ]) + }) + + it('should contain "asia-east1" region exactly once', () => { + const asiaEast1Regions = VERTEX_REGIONS.filter( + (r: { value: string; label: string }) => r.value === "asia-east1" && r.label === "asia-east1", + ) + expect(asiaEast1Regions).toHaveLength(1) + expect(asiaEast1Regions[0]).toEqual({ value: "asia-east1", label: "asia-east1" }) + }) +}) From a7b5cbd722d5cc908c4356af9ffe4535b0bd7806 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Thu, 10 Jul 2025 09:47:47 -0400 Subject: [PATCH 20/21] Soften the language for incompatible profiles (#5561) --- src/i18n/locales/ca/common.json | 2 +- src/i18n/locales/de/common.json | 2 +- src/i18n/locales/en/common.json | 2 +- src/i18n/locales/es/common.json | 2 +- src/i18n/locales/fr/common.json | 2 +- src/i18n/locales/hi/common.json | 2 +- src/i18n/locales/id/common.json | 2 +- src/i18n/locales/it/common.json | 2 +- src/i18n/locales/ja/common.json | 2 +- src/i18n/locales/ko/common.json | 2 +- src/i18n/locales/nl/common.json | 2 +- src/i18n/locales/pl/common.json | 2 +- src/i18n/locales/pt-BR/common.json | 2 +- src/i18n/locales/ru/common.json | 2 +- src/i18n/locales/tr/common.json | 2 +- src/i18n/locales/vi/common.json | 2 +- src/i18n/locales/zh-CN/common.json | 2 +- src/i18n/locales/zh-TW/common.json | 2 +- webview-ui/src/i18n/locales/ca/chat.json | 2 +- webview-ui/src/i18n/locales/de/chat.json | 2 +- webview-ui/src/i18n/locales/en/chat.json | 2 +- webview-ui/src/i18n/locales/es/chat.json | 2 +- webview-ui/src/i18n/locales/fr/chat.json | 2 +- webview-ui/src/i18n/locales/hi/chat.json | 2 +- webview-ui/src/i18n/locales/id/chat.json | 2 +- webview-ui/src/i18n/locales/it/chat.json | 2 +- webview-ui/src/i18n/locales/ja/chat.json | 2 +- webview-ui/src/i18n/locales/ko/chat.json | 2 +- webview-ui/src/i18n/locales/nl/chat.json | 2 +- webview-ui/src/i18n/locales/pl/chat.json | 2 +- webview-ui/src/i18n/locales/pt-BR/chat.json | 2 +- webview-ui/src/i18n/locales/ru/chat.json | 2 +- webview-ui/src/i18n/locales/tr/chat.json | 2 +- webview-ui/src/i18n/locales/vi/chat.json | 2 +- webview-ui/src/i18n/locales/zh-CN/chat.json | 2 +- webview-ui/src/i18n/locales/zh-TW/chat.json | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index 04938e3625..0caa3fca47 100644 --- a/src/i18n/locales/ca/common.json +++ b/src/i18n/locales/ca/common.json @@ -58,7 +58,7 @@ "cannot_access_path": "No es pot accedir a la ruta {{path}}: {{error}}", "settings_import_failed": "Ha fallat la importació de la configuració: {{error}}.", "mistake_limit_guidance": "Això pot indicar un error en el procés de pensament del model o la incapacitat d'utilitzar una eina correctament, que es pot mitigar amb orientació de l'usuari (p. ex. \"Prova de dividir la tasca en passos més petits\").", - "violated_organization_allowlist": "Ha fallat l'execució de la tasca: el perfil actual infringeix la configuració de la teva organització", + "violated_organization_allowlist": "Ha fallat l'execució de la tasca: el perfil actual no és compatible amb la configuració de la teva organització", "condense_failed": "Ha fallat la condensació del context", "condense_not_enough_messages": "No hi ha prou missatges per condensar el context", "condensed_recently": "El context s'ha condensat recentment; s'omet aquest intent", diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index 9fa27c89c6..bf9af547ca 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "Zugriff auf Pfad {{path}} nicht möglich: {{error}}", "settings_import_failed": "Fehler beim Importieren der Einstellungen: {{error}}.", "mistake_limit_guidance": "Dies kann auf einen Fehler im Denkprozess des Modells oder die Unfähigkeit hinweisen, ein Tool richtig zu verwenden, was durch Benutzerführung behoben werden kann (z.B. \"Versuche, die Aufgabe in kleinere Schritte zu unterteilen\").", - "violated_organization_allowlist": "Aufgabe konnte nicht ausgeführt werden: Das aktuelle Profil verstößt gegen die Einstellungen deiner Organisation", + "violated_organization_allowlist": "Aufgabe konnte nicht ausgeführt werden: Das aktuelle Profil ist nicht kompatibel mit den Einstellungen deiner Organisation", "condense_failed": "Fehler beim Verdichten des Kontexts", "condense_not_enough_messages": "Nicht genügend Nachrichten zum Verdichten des Kontexts", "condensed_recently": "Kontext wurde kürzlich verdichtet; dieser Versuch wird übersprungen", diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index f907a5745b..3004038d42 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "Cannot access path {{path}}: {{error}}", "settings_import_failed": "Settings import failed: {{error}}.", "mistake_limit_guidance": "This may indicate a failure in the model's thought process or inability to use a tool properly, which can be mitigated with some user guidance (e.g. \"Try breaking down the task into smaller steps\").", - "violated_organization_allowlist": "Failed to run task: the current profile violates your organization settings", + "violated_organization_allowlist": "Failed to run task: the current profile isn't compatible with your organization settings", "condense_failed": "Failed to condense context", "condense_not_enough_messages": "Not enough messages to condense context", "condensed_recently": "Context was condensed recently; skipping this attempt", diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index 68750e888f..1a16dbf1ae 100644 --- a/src/i18n/locales/es/common.json +++ b/src/i18n/locales/es/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "No se puede acceder a la ruta {{path}}: {{error}}", "settings_import_failed": "Error al importar la configuración: {{error}}.", "mistake_limit_guidance": "Esto puede indicar un fallo en el proceso de pensamiento del modelo o la incapacidad de usar una herramienta correctamente, lo cual puede mitigarse con orientación del usuario (ej. \"Intenta dividir la tarea en pasos más pequeños\").", - "violated_organization_allowlist": "Error al ejecutar la tarea: el perfil actual infringe la configuración de tu organización", + "violated_organization_allowlist": "Error al ejecutar la tarea: el perfil actual no es compatible con la configuración de tu organización", "condense_failed": "Error al condensar el contexto", "condense_not_enough_messages": "No hay suficientes mensajes para condensar el contexto", "condensed_recently": "El contexto se condensó recientemente; se omite este intento", diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index e985fe9468..98945f305d 100644 --- a/src/i18n/locales/fr/common.json +++ b/src/i18n/locales/fr/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "Impossible d'accéder au chemin {{path}} : {{error}}", "settings_import_failed": "Échec de l'importation des paramètres : {{error}}", "mistake_limit_guidance": "Cela peut indiquer un échec dans le processus de réflexion du modèle ou une incapacité à utiliser un outil correctement, ce qui peut être atténué avec des conseils de l'utilisateur (par ex. \"Essaie de diviser la tâche en étapes plus petites\").", - "violated_organization_allowlist": "Échec de l'exécution de la tâche : le profil actuel enfreint les paramètres de votre organisation", + "violated_organization_allowlist": "Échec de l'exécution de la tâche : le profil actuel n'est pas compatible avec les paramètres de votre organisation", "condense_failed": "Échec de la condensation du contexte", "condense_not_enough_messages": "Pas assez de messages pour condenser le contexte", "condensed_recently": "Le contexte a été condensé récemment ; cette tentative est ignorée", diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index a16a22ece5..7daa0046ec 100644 --- a/src/i18n/locales/hi/common.json +++ b/src/i18n/locales/hi/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "पाथ {{path}} तक पहुंच नहीं पा रहे हैं: {{error}}", "settings_import_failed": "सेटिंग्स इम्पोर्ट करने में विफल: {{error}}।", "mistake_limit_guidance": "यह मॉडल की सोच प्रक्रिया में विफलता या किसी टूल का सही उपयोग न कर पाने का संकेत हो सकता है, जिसे उपयोगकर्ता के मार्गदर्शन से ठीक किया जा सकता है (जैसे \"कार्य को छोटे चरणों में बांटने की कोशिश करें\")।", - "violated_organization_allowlist": "कार्य चलाने में विफल: वर्तमान प्रोफ़ाइल आपके संगठन की सेटिंग्स का उल्लंघन करती है", + "violated_organization_allowlist": "कार्य चलाने में विफल: वर्तमान प्रोफ़ाइल आपके संगठन की सेटिंग्स के साथ संगत नहीं है", "condense_failed": "संदर्भ को संक्षिप्त करने में विफल", "condense_not_enough_messages": "संदर्भ को संक्षिप्त करने के लिए पर्याप्त संदेश नहीं हैं", "condensed_recently": "संदर्भ हाल ही में संक्षिप्त किया गया था; इस प्रयास को छोड़ा जा रहा है", diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index d40bce9186..c021dab4cd 100644 --- a/src/i18n/locales/id/common.json +++ b/src/i18n/locales/id/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "Tidak dapat mengakses path {{path}}: {{error}}", "settings_import_failed": "Impor pengaturan gagal: {{error}}.", "mistake_limit_guidance": "Ini mungkin menunjukkan kegagalan dalam proses pemikiran model atau ketidakmampuan untuk menggunakan tool dengan benar, yang dapat diatasi dengan beberapa panduan pengguna (misalnya \"Coba bagi tugas menjadi langkah-langkah yang lebih kecil\").", - "violated_organization_allowlist": "Gagal menjalankan tugas: profil saat ini melanggar pengaturan organisasi kamu", + "violated_organization_allowlist": "Gagal menjalankan tugas: profil saat ini tidak kompatibel dengan pengaturan organisasi kamu", "condense_failed": "Gagal mengompres konteks", "condense_not_enough_messages": "Tidak cukup pesan untuk mengompres konteks", "condensed_recently": "Konteks baru saja dikompres; melewati percobaan ini", diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index a6782267ce..ff45cd8f1e 100644 --- a/src/i18n/locales/it/common.json +++ b/src/i18n/locales/it/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "Impossibile accedere al percorso {{path}}: {{error}}", "settings_import_failed": "Importazione delle impostazioni fallita: {{error}}.", "mistake_limit_guidance": "Questo può indicare un fallimento nel processo di pensiero del modello o l'incapacità di utilizzare correttamente uno strumento, che può essere mitigato con la guida dell'utente (ad es. \"Prova a suddividere l'attività in passaggi più piccoli\").", - "violated_organization_allowlist": "Impossibile eseguire l'attività: il profilo corrente viola le impostazioni della tua organizzazione", + "violated_organization_allowlist": "Impossibile eseguire l'attività: il profilo corrente non è compatibile con le impostazioni della tua organizzazione", "condense_failed": "Impossibile condensare il contesto", "condense_not_enough_messages": "Non ci sono abbastanza messaggi per condensare il contesto", "condensed_recently": "Il contesto è stato condensato di recente; questo tentativo viene saltato", diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index 9722281d0c..4d9b88d114 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "パス {{path}} にアクセスできません:{{error}}", "settings_import_failed": "設定のインポートに失敗しました:{{error}}", "mistake_limit_guidance": "これは、モデルの思考プロセスの失敗やツールを適切に使用できないことを示している可能性があり、ユーザーのガイダンスによって軽減できます(例:「タスクをより小さなステップに分割してみてください」)。", - "violated_organization_allowlist": "タスクの実行に失敗しました: 現在のプロファイルは組織の設定に違反しています", + "violated_organization_allowlist": "タスクの実行に失敗しました: 現在のプロファイルは組織の設定と互換性がありません", "condense_failed": "コンテキストの圧縮に失敗しました", "condense_not_enough_messages": "コンテキストを圧縮するのに十分なメッセージがありません", "condensed_recently": "コンテキストは最近圧縮されました;この試行をスキップします", diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index 81c80154d0..34d9bced71 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "경로 {{path}}에 접근할 수 없습니다: {{error}}", "settings_import_failed": "설정 가져오기 실패: {{error}}.", "mistake_limit_guidance": "이는 모델의 사고 과정 실패나 도구를 제대로 사용하지 못하는 것을 나타낼 수 있으며, 사용자 가이드를 통해 완화할 수 있습니다 (예: \"작업을 더 작은 단계로 나누어 시도해보세요\").", - "violated_organization_allowlist": "작업 실행 실패: 현재 프로필이 조직 설정을 위반합니다", + "violated_organization_allowlist": "작업 실행 실패: 현재 프로필이 조직 설정과 호환되지 않습니다", "condense_failed": "컨텍스트 압축에 실패했습니다", "condense_not_enough_messages": "컨텍스트를 압축할 메시지가 충분하지 않습니다", "condensed_recently": "컨텍스트가 최근 압축되었습니다; 이 시도를 건너뜁니다", diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index 68ad31e728..dff1bb83f7 100644 --- a/src/i18n/locales/nl/common.json +++ b/src/i18n/locales/nl/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "Kan pad {{path}} niet openen: {{error}}", "settings_import_failed": "Importeren van instellingen mislukt: {{error}}.", "mistake_limit_guidance": "Dit kan duiden op een fout in het denkproces van het model of het onvermogen om een tool correct te gebruiken, wat kan worden verminderd met gebruikersbegeleiding (bijv. \"Probeer de taak op te delen in kleinere stappen\").", - "violated_organization_allowlist": "Taak uitvoeren mislukt: het huidige profiel schendt de instellingen van uw organisatie", + "violated_organization_allowlist": "Taak uitvoeren mislukt: het huidige profiel is niet compatibel met de instellingen van uw organisatie", "condense_failed": "Comprimeren van context mislukt", "condense_not_enough_messages": "Niet genoeg berichten om context te comprimeren", "condensed_recently": "Context is recent gecomprimeerd; deze poging wordt overgeslagen", diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index 7dc510e71c..33c58b4752 100644 --- a/src/i18n/locales/pl/common.json +++ b/src/i18n/locales/pl/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "Nie można uzyskać dostępu do ścieżki {{path}}: {{error}}", "settings_import_failed": "Nie udało się zaimportować ustawień: {{error}}.", "mistake_limit_guidance": "To może wskazywać na błąd w procesie myślowym modelu lub niezdolność do prawidłowego użycia narzędzia, co można złagodzić poprzez wskazówki użytkownika (np. \"Spróbuj podzielić zadanie na mniejsze kroki\").", - "violated_organization_allowlist": "Nie udało się uruchomić zadania: bieżący profil narusza ustawienia Twojej organizacji", + "violated_organization_allowlist": "Nie udało się uruchomić zadania: bieżący profil nie jest kompatybilny z ustawieniami Twojej organizacji", "condense_failed": "Nie udało się skondensować kontekstu", "condense_not_enough_messages": "Za mało wiadomości do skondensowania kontekstu", "condensed_recently": "Kontekst został niedawno skondensowany; pomijanie tej próby", diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index 7ee3b8a658..ce9dc113e2 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/src/i18n/locales/pt-BR/common.json @@ -58,7 +58,7 @@ "cannot_access_path": "Não é possível acessar o caminho {{path}}: {{error}}", "settings_import_failed": "Falha ao importar configurações: {{error}}", "mistake_limit_guidance": "Isso pode indicar uma falha no processo de pensamento do modelo ou incapacidade de usar uma ferramenta adequadamente, o que pode ser mitigado com orientação do usuário (ex. \"Tente dividir a tarefa em etapas menores\").", - "violated_organization_allowlist": "Falha ao executar a tarefa: o perfil atual viola as configurações da sua organização", + "violated_organization_allowlist": "Falha ao executar a tarefa: o perfil atual não é compatível com as configurações da sua organização", "condense_failed": "Falha ao condensar o contexto", "condense_not_enough_messages": "Não há mensagens suficientes para condensar o contexto", "condensed_recently": "O contexto foi condensado recentemente; pulando esta tentativa", diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 8e100bff9a..a3b6c322b2 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "Невозможно получить доступ к пути {{path}}: {{error}}", "settings_import_failed": "Не удалось импортировать настройки: {{error}}.", "mistake_limit_guidance": "Это может указывать на сбой в процессе мышления модели или неспособность правильно использовать инструмент, что можно смягчить с помощью руководства пользователя (например, \"Попробуйте разбить задачу на более мелкие шаги\").", - "violated_organization_allowlist": "Не удалось выполнить задачу: текущий профиль нарушает настройки вашей организации", + "violated_organization_allowlist": "Не удалось выполнить задачу: текущий профиль несовместим с настройками вашей организации", "condense_failed": "Не удалось сжать контекст", "condense_not_enough_messages": "Недостаточно сообщений для сжатия контекста", "condensed_recently": "Контекст был недавно сжат; пропускаем эту попытку", diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index df8212cf3c..042fa88d15 100644 --- a/src/i18n/locales/tr/common.json +++ b/src/i18n/locales/tr/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "{{path}} yoluna erişilemiyor: {{error}}", "settings_import_failed": "Ayarlar içe aktarılamadı: {{error}}.", "mistake_limit_guidance": "Bu, modelin düşünce sürecindeki bir başarısızlığı veya bir aracı düzgün kullanamama durumunu gösterebilir, bu da kullanıcı rehberliği ile hafifletilebilir (örn. \"Görevi daha küçük adımlara bölmeyi deneyin\").", - "violated_organization_allowlist": "Görev yürütülemedi: Geçerli profil kuruluşunuzun ayarlarını ihlal ediyor", + "violated_organization_allowlist": "Görev yürütülemedi: Geçerli profil kuruluşunuzun ayarlarıyla uyumlu değil", "condense_failed": "Bağlam sıkıştırılamadı", "condense_not_enough_messages": "Bağlamı sıkıştırmak için yeterli mesaj yok", "condensed_recently": "Bağlam yakın zamanda sıkıştırıldı; bu deneme atlanıyor", diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index 6710cd136d..183ae7b41a 100644 --- a/src/i18n/locales/vi/common.json +++ b/src/i18n/locales/vi/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "Không thể truy cập đường dẫn {{path}}: {{error}}", "settings_import_failed": "Nhập cài đặt thất bại: {{error}}.", "mistake_limit_guidance": "Điều này có thể cho thấy sự thất bại trong quá trình suy nghĩ của mô hình hoặc không thể sử dụng công cụ đúng cách, có thể được giảm thiểu bằng hướng dẫn của người dùng (ví dụ: \"Hãy thử chia nhỏ nhiệm vụ thành các bước nhỏ hơn\").", - "violated_organization_allowlist": "Không thể chạy tác vụ: hồ sơ hiện tại vi phạm cài đặt của tổ chức của bạn", + "violated_organization_allowlist": "Không thể chạy tác vụ: hồ sơ hiện tại không tương thích với cài đặt của tổ chức của bạn", "condense_failed": "Không thể nén ngữ cảnh", "condense_not_enough_messages": "Không đủ tin nhắn để nén ngữ cảnh", "condensed_recently": "Ngữ cảnh đã được nén gần đây; bỏ qua lần thử này", diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index 5a8fc51ef1..a45efa4b1c 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -59,7 +59,7 @@ "cannot_access_path": "无法访问路径 {{path}}:{{error}}", "settings_import_failed": "设置导入失败:{{error}}。", "mistake_limit_guidance": "这可能表明模型思维过程失败或无法正确使用工具,可通过用户指导来缓解(例如\"尝试将任务分解为更小的步骤\")。", - "violated_organization_allowlist": "执行任务失败:当前配置文件违反了您的组织设置", + "violated_organization_allowlist": "执行任务失败:当前配置文件与您的组织设置不兼容", "condense_failed": "压缩上下文失败", "condense_not_enough_messages": "没有足够的对话来压缩上下文", "condensed_recently": "上下文最近已压缩;跳过此次尝试", diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index 2bfad5e00f..3fbbc050f4 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/src/i18n/locales/zh-TW/common.json @@ -54,7 +54,7 @@ "cannot_access_path": "無法存取路徑 {{path}}:{{error}}", "settings_import_failed": "設定匯入失敗:{{error}}。", "mistake_limit_guidance": "這可能表明模型思維過程失敗或無法正確使用工具,可透過使用者指導來緩解(例如「嘗試將工作分解為更小的步驟」)。", - "violated_organization_allowlist": "執行工作失敗:目前設定檔違反了您的組織設定", + "violated_organization_allowlist": "執行工作失敗:目前設定檔與您的組織設定不相容", "condense_failed": "壓縮上下文失敗", "condense_not_enough_messages": "沒有足夠的訊息來壓縮上下文", "condensed_recently": "上下文最近已壓縮;跳過此次嘗試", diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index 8ad87049e3..6accf68fcb 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "ADVERTÈNCIA: S'ha activat una substitució personalitzada d'instruccions del sistema. Això pot trencar greument la funcionalitat i causar un comportament impredictible.", - "profileViolationWarning": "El perfil actual infringeix la configuració de la teva organització", + "profileViolationWarning": "El perfil actual no és compatible amb la configuració de la teva organització", "shellIntegration": { "title": "Advertència d'execució d'ordres", "description": "La teva ordre s'està executant sense la integració de shell del terminal VSCode. Per suprimir aquest advertiment, pots desactivar la integració de shell a la secció Terminal de la configuració de Roo Code o solucionar problemes d'integració del terminal VSCode utilitzant l'enllaç a continuació.", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index 88f6a46dbb..fcbbdb2b68 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "WARNUNG: Benutzerdefinierte Systemaufforderung aktiv. Dies kann die Funktionalität erheblich beeinträchtigen und zu unvorhersehbarem Verhalten führen.", - "profileViolationWarning": "Das aktuelle Profil verstößt gegen die Einstellungen deiner Organisation", + "profileViolationWarning": "Das aktuelle Profil ist nicht kompatibel mit den Einstellungen deiner Organisation", "shellIntegration": { "title": "Befehlsausführungswarnung", "description": "Dein Befehl wird ohne VSCode Terminal-Shell-Integration ausgeführt. Um diese Warnung zu unterdrücken, kannst du die Shell-Integration im Abschnitt Terminal der Roo Code Einstellungen deaktivieren oder die VSCode Terminal-Integration mit dem Link unten beheben.", diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index 6117ad431e..326f52c74d 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -294,7 +294,7 @@ } }, "systemPromptWarning": "WARNING: Custom system prompt override active. This can severely break functionality and cause unpredictable behavior.", - "profileViolationWarning": "The current profile violates your organization's settings", + "profileViolationWarning": "The current profile isn't compatible with your organization's settings", "shellIntegration": { "title": "Command Execution Warning", "description": "Your command is being executed without VSCode terminal shell integration. To suppress this warning you can disable shell integration in the Terminal section of the Roo Code settings or troubleshoot VSCode terminal integration using the link below.", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index 086fd92f9d..9bea6bd2c4 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "ADVERTENCIA: Anulación de instrucciones del sistema personalizada activa. Esto puede romper gravemente la funcionalidad y causar un comportamiento impredecible.", - "profileViolationWarning": "El perfil actual infringe la configuración de tu organización", + "profileViolationWarning": "El perfil actual no es compatible con la configuración de tu organización", "shellIntegration": { "title": "Advertencia de ejecución de comandos", "description": "Tu comando se está ejecutando sin la integración de shell de terminal de VSCode. Para suprimir esta advertencia, puedes desactivar la integración de shell en la sección Terminal de la configuración de Roo Code o solucionar problemas de integración de terminal de VSCode usando el enlace de abajo.", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index 8e917d1f21..d7748fb15c 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "AVERTISSEMENT : Remplacement d'instructions système personnalisées actif. Cela peut gravement perturber la fonctionnalité et provoquer un comportement imprévisible.", - "profileViolationWarning": "Le profil actuel enfreint les paramètres de votre organisation", + "profileViolationWarning": "Le profil actuel n'est pas compatible avec les paramètres de votre organisation", "shellIntegration": { "title": "Avertissement d'exécution de commande", "description": "Votre commande est exécutée sans l'intégration shell du terminal VSCode. Pour supprimer cet avertissement, vous pouvez désactiver l'intégration shell dans la section Terminal des paramètres de Roo Code ou résoudre les problèmes d'intégration du terminal VSCode en utilisant le lien ci-dessous.", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 385549f987..7979f624e0 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "चेतावनी: कस्टम सिस्टम प्रॉम्प्ट ओवरराइड सक्रिय है। यह कार्यक्षमता को गंभीर रूप से बाधित कर सकता है और अनियमित व्यवहार का कारण बन सकता है.", - "profileViolationWarning": "वर्तमान प्रोफ़ाइल आपके संगठन की सेटिंग्स का उल्लंघन करती है", + "profileViolationWarning": "वर्तमान प्रोफ़ाइल आपके संगठन की सेटिंग्स के साथ संगत नहीं है", "shellIntegration": { "title": "कमांड निष्पादन चेतावनी", "description": "आपका कमांड VSCode टर्मिनल शेल इंटीग्रेशन के बिना निष्पादित हो रहा है। इस चेतावनी को दबाने के लिए आप Roo Code सेटिंग्स के Terminal अनुभाग में शेल इंटीग्रेशन को अक्षम कर सकते हैं या नीचे दिए गए लिंक का उपयोग करके VSCode टर्मिनल इंटीग्रेशन की समस्या का समाधान कर सकते हैं।", diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json index 74722db3ba..2134b48bfc 100644 --- a/webview-ui/src/i18n/locales/id/chat.json +++ b/webview-ui/src/i18n/locales/id/chat.json @@ -301,7 +301,7 @@ } }, "systemPromptWarning": "PERINGATAN: Override system prompt kustom aktif. Ini dapat merusak fungsionalitas secara serius dan menyebabkan perilaku yang tidak terduga.", - "profileViolationWarning": "Profil saat ini melanggar pengaturan organisasi kamu", + "profileViolationWarning": "Profil saat ini tidak kompatibel dengan pengaturan organisasi kamu", "shellIntegration": { "title": "Peringatan Eksekusi Perintah", "description": "Perintah kamu dijalankan tanpa integrasi shell terminal VSCode. Untuk menekan peringatan ini kamu bisa menonaktifkan integrasi shell di bagian Terminal dari pengaturan Roo Code atau troubleshoot integrasi terminal VSCode menggunakan link di bawah.", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index be4dde8aeb..ed886e6ef9 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "ATTENZIONE: Sovrascrittura personalizzata delle istruzioni di sistema attiva. Questo può compromettere gravemente le funzionalità e causare comportamenti imprevedibili.", - "profileViolationWarning": "Il profilo corrente viola le impostazioni della tua organizzazione", + "profileViolationWarning": "Il profilo corrente non è compatibile con le impostazioni della tua organizzazione", "shellIntegration": { "title": "Avviso di esecuzione comando", "description": "Il tuo comando viene eseguito senza l'integrazione shell del terminale VSCode. Per sopprimere questo avviso puoi disattivare l'integrazione shell nella sezione Terminal delle impostazioni di Roo Code o risolvere i problemi di integrazione del terminale VSCode utilizzando il link qui sotto.", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index c2466cc046..61c2820299 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "警告:カスタムシステムプロンプトの上書きが有効です。これにより機能が深刻に損なわれ、予測不可能な動作が発生する可能性があります。", - "profileViolationWarning": "現在のプロファイルは組織の設定に違反しています", + "profileViolationWarning": "現在のプロファイルは組織の設定と互換性がありません", "shellIntegration": { "title": "コマンド実行警告", "description": "コマンドはVSCodeターミナルシェル統合なしで実行されています。この警告を非表示にするには、Roo Code設定Terminalセクションでシェル統合を無効にするか、以下のリンクを使用してVSCodeターミナル統合のトラブルシューティングを行ってください。", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index 4649806225..9ac8e90644 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "경고: 사용자 정의 시스템 프롬프트 재정의가 활성화되었습니다. 이로 인해 기능이 심각하게 손상되고 예측할 수 없는 동작이 발생할 수 있습니다.", - "profileViolationWarning": "현재 프로필이 조직 설정을 위반합니다", + "profileViolationWarning": "현재 프로필이 조직 설정과 호환되지 않습니다", "shellIntegration": { "title": "명령 실행 경고", "description": "명령이 VSCode 터미널 쉘 통합 없이 실행되고 있습니다. 이 경고를 숨기려면 Roo Code 설정Terminal 섹션에서 쉘 통합을 비활성화하거나 아래 링크를 사용하여 VSCode 터미널 통합 문제를 해결하세요.", diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json index c9df4af471..5b2da04160 100644 --- a/webview-ui/src/i18n/locales/nl/chat.json +++ b/webview-ui/src/i18n/locales/nl/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "WAARSCHUWING: Aangepaste systeemprompt actief. Dit kan de functionaliteit ernstig verstoren en onvoorspelbaar gedrag veroorzaken.", - "profileViolationWarning": "Het huidige profiel schendt de instellingen van uw organisatie", + "profileViolationWarning": "Het huidige profiel is niet compatibel met de instellingen van uw organisatie", "shellIntegration": { "title": "Waarschuwing commando-uitvoering", "description": "Je commando wordt uitgevoerd zonder VSCode-terminal shell-integratie. Om deze waarschuwing te onderdrukken kun je shell-integratie uitschakelen in het gedeelte Terminal van de Roo Code-instellingen of de VSCode-terminalintegratie oplossen via de onderstaande link.", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index 1cf631935c..5226ef51ea 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "OSTRZEŻENIE: Aktywne niestandardowe zastąpienie instrukcji systemowych. Może to poważnie zakłócić funkcjonalność i powodować nieprzewidywalne zachowanie.", - "profileViolationWarning": "Bieżący profil narusza ustawienia Twojej organizacji", + "profileViolationWarning": "Bieżący profil nie jest kompatybilny z ustawieniami Twojej organizacji", "shellIntegration": { "title": "Ostrzeżenie wykonania polecenia", "description": "Twoje polecenie jest wykonywane bez integracji powłoki terminala VSCode. Aby ukryć to ostrzeżenie, możesz wyłączyć integrację powłoki w sekcji Terminal w ustawieniach Roo Code lub rozwiązać problemy z integracją terminala VSCode korzystając z poniższego linku.", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index acc828a139..eca50fbd33 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "AVISO: Substituição personalizada de instrução do sistema ativa. Isso pode comprometer gravemente a funcionalidade e causar comportamento imprevisível.", - "profileViolationWarning": "O perfil atual viola as configurações da sua organização", + "profileViolationWarning": "O perfil atual não é compatível com as configurações da sua organização", "shellIntegration": { "title": "Aviso de execução de comando", "description": "Seu comando está sendo executado sem a integração de shell do terminal VSCode. Para suprimir este aviso, você pode desativar a integração de shell na seção Terminal das configurações do Roo Code ou solucionar problemas de integração do terminal VSCode usando o link abaixo.", diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index 94172ef9f0..72ae883703 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "ПРЕДУПРЕЖДЕНИЕ: Активна пользовательская системная подсказка. Это может серьезно нарушить работу и вызвать непредсказуемое поведение.", - "profileViolationWarning": "Текущий профиль нарушает настройки вашей организации", + "profileViolationWarning": "Текущий профиль несовместим с настройками вашей организации", "shellIntegration": { "title": "Предупреждение о выполнении команды", "description": "Ваша команда выполняется без интеграции оболочки терминала VSCode. Чтобы скрыть это предупреждение, вы можете отключить интеграцию оболочки в разделе Terminal в настройках Roo Code или устранить проблемы с интеграцией терминала VSCode, используя ссылку ниже.", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index 3776eaca92..4f108d7ac3 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "UYARI: Özel sistem komut geçersiz kılma aktif. Bu işlevselliği ciddi şekilde bozabilir ve öngörülemeyen davranışlara neden olabilir.", - "profileViolationWarning": "Geçerli profil kuruluşunuzun ayarlarını ihlal ediyor", + "profileViolationWarning": "Geçerli profil kuruluşunuzun ayarlarıyla uyumlu değil", "shellIntegration": { "title": "Komut Çalıştırma Uyarısı", "description": "Komutunuz VSCode terminal kabuk entegrasyonu olmadan çalıştırılıyor. Bu uyarıyı gizlemek için Roo Code ayarları'nın Terminal bölümünden kabuk entegrasyonunu devre dışı bırakabilir veya aşağıdaki bağlantıyı kullanarak VSCode terminal entegrasyonu sorunlarını giderebilirsiniz.", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index 0e069124af..0f0ea71ec3 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "CẢNH BÁO: Đã kích hoạt ghi đè lệnh nhắc hệ thống tùy chỉnh. Điều này có thể phá vỡ nghiêm trọng chức năng và gây ra hành vi không thể dự đoán.", - "profileViolationWarning": "Hồ sơ hiện tại vi phạm cài đặt của tổ chức của bạn", + "profileViolationWarning": "Hồ sơ hiện tại không tương thích với cài đặt của tổ chức của bạn", "shellIntegration": { "title": "Cảnh báo thực thi lệnh", "description": "Lệnh của bạn đang được thực thi mà không có tích hợp shell terminal VSCode. Để ẩn cảnh báo này, bạn có thể vô hiệu hóa tích hợp shell trong phần Terminal của cài đặt Roo Code hoặc khắc phục sự cố tích hợp terminal VSCode bằng liên kết bên dưới.", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index e8dbbb97dd..6e883b751a 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "警告:自定义系统提示词覆盖已激活。这可能严重破坏功能并导致不可预测的行为。", - "profileViolationWarning": "当前配置文件违反了您的组织设置", + "profileViolationWarning": "当前配置文件与您的组织设置不兼容", "shellIntegration": { "title": "命令执行警告", "description": "您的命令正在没有 VSCode 终端 shell 集成的情况下执行。要隐藏此警告,您可以在 Roo Code 设置Terminal 部分禁用 shell 集成,或使用下方链接排查 VSCode 终端集成问题。", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index 323238eb25..75d214db03 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -281,7 +281,7 @@ } }, "systemPromptWarning": "警告:自訂系統提示詞覆蓋已啟用。這可能嚴重破壞功能並導致不可預測的行為。", - "profileViolationWarning": "目前設定檔違反了您的組織設定", + "profileViolationWarning": "目前設定檔與您的組織設定不相容", "shellIntegration": { "title": "命令執行警告", "description": "您的命令正在沒有 VSCode 終端機 shell 整合的情況下執行。要隱藏此警告,您可以在 Roo Code 設定Terminal 部分停用 shell 整合,或使用下方連結排查 VSCode 終端機整合問題。", From 356d421344a92c555b4b38768e8d1891539472d4 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Thu, 10 Jul 2025 10:12:16 -0400 Subject: [PATCH 21/21] Run nightly build on push (#5563) --- .github/workflows/nightly-publish.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/nightly-publish.yml b/.github/workflows/nightly-publish.yml index 93471d0790..8ce4c5ca6a 100644 --- a/.github/workflows/nightly-publish.yml +++ b/.github/workflows/nightly-publish.yml @@ -1,10 +1,7 @@ name: Nightly Publish on: - workflow_run: - workflows: ["Code QA Roo Code"] - types: - - completed + push: branches: [main] workflow_dispatch: # Allows manual triggering.