From f8b29e718da11fdf57c317c12de39a40a37627e7 Mon Sep 17 00:00:00 2001 From: Nissa Seru <119150866+nissa-seru@users.noreply.github.com> Date: Sat, 1 Feb 2025 20:45:56 -0500 Subject: [PATCH 01/40] Add command fixes --- src/core/prompts/sections/system-info.ts | 3 +- src/core/prompts/tools/execute-command.ts | 2 +- src/utils/__tests__/shell.test.ts | 222 +++++++++++++++++++++ src/utils/shell.ts | 227 ++++++++++++++++++++++ webview-ui/tsconfig.json | 15 +- 5 files changed, 464 insertions(+), 5 deletions(-) create mode 100644 src/utils/__tests__/shell.test.ts create mode 100644 src/utils/shell.ts diff --git a/src/core/prompts/sections/system-info.ts b/src/core/prompts/sections/system-info.ts index 2e04a6fb00..c5a5ec1c28 100644 --- a/src/core/prompts/sections/system-info.ts +++ b/src/core/prompts/sections/system-info.ts @@ -2,6 +2,7 @@ import defaultShell from "default-shell" import os from "os" import osName from "os-name" import { Mode, ModeConfig, getModeBySlug, defaultModeSlug, isToolAllowedForMode } from "../../../shared/modes" +import { getShell } from "../../../utils/shell" export function getSystemInfoSection(cwd: string, currentMode: Mode, customModes?: ModeConfig[]): string { const findModeBySlug = (slug: string, modes?: ModeConfig[]) => modes?.find((m) => m.slug === slug) @@ -14,7 +15,7 @@ export function getSystemInfoSection(cwd: string, currentMode: Mode, customModes SYSTEM INFORMATION Operating System: ${osName()} -Default Shell: ${defaultShell} +Default Shell: ${getShell()} Home Directory: ${os.homedir().toPosix()} Current Working Directory: ${cwd.toPosix()} diff --git a/src/core/prompts/tools/execute-command.ts b/src/core/prompts/tools/execute-command.ts index e773a2f72c..b0a88a858d 100644 --- a/src/core/prompts/tools/execute-command.ts +++ b/src/core/prompts/tools/execute-command.ts @@ -2,7 +2,7 @@ import { ToolArgs } from "./types" export function getExecuteCommandDescription(args: ToolArgs): string | undefined { return `## execute_command -Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: ${args.cwd} +Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: ${args.cwd} Parameters: - command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions. Usage: diff --git a/src/utils/__tests__/shell.test.ts b/src/utils/__tests__/shell.test.ts new file mode 100644 index 0000000000..dee997a752 --- /dev/null +++ b/src/utils/__tests__/shell.test.ts @@ -0,0 +1,222 @@ +import * as vscode from "vscode" +import { userInfo } from "os" +import { getShell } from "../shell" + +describe("Shell Detection Tests", () => { + let originalPlatform: string + let originalEnv: NodeJS.ProcessEnv + let originalGetConfig: any + let originalUserInfo: any + + // Helper to mock VS Code configuration + function mockVsCodeConfig(platformKey: string, defaultProfileName: string | null, profiles: Record) { + vscode.workspace.getConfiguration = () => + ({ + get: (key: string) => { + if (key === `defaultProfile.${platformKey}`) { + return defaultProfileName + } + if (key === `profiles.${platformKey}`) { + return profiles + } + return undefined + }, + }) as any + } + + beforeEach(() => { + // Store original references + originalPlatform = process.platform + originalEnv = { ...process.env } + originalGetConfig = vscode.workspace.getConfiguration + originalUserInfo = userInfo + + // Clear environment variables for a clean test + delete process.env.SHELL + delete process.env.COMSPEC + + // Default userInfo() mock + ;(userInfo as any) = () => ({ shell: null }) + }) + + afterEach(() => { + // Restore everything + Object.defineProperty(process, "platform", { value: originalPlatform }) + process.env = originalEnv + vscode.workspace.getConfiguration = originalGetConfig + ;(userInfo as any) = originalUserInfo + }) + + // -------------------------------------------------------------------------- + // Windows Shell Detection + // -------------------------------------------------------------------------- + describe("Windows Shell Detection", () => { + beforeEach(() => { + Object.defineProperty(process, "platform", { value: "win32" }) + }) + + it("uses explicit PowerShell 7 path from VS Code config (profile path)", () => { + mockVsCodeConfig("windows", "PowerShell", { + PowerShell: { path: "C:\\Program Files\\PowerShell\\7\\pwsh.exe" }, + }) + expect(getShell()).toBe("C:\\Program Files\\PowerShell\\7\\pwsh.exe") + }) + + it("uses PowerShell 7 path if source is 'PowerShell' but no explicit path", () => { + mockVsCodeConfig("windows", "PowerShell", { + PowerShell: { source: "PowerShell" }, + }) + expect(getShell()).toBe("C:\\Program Files\\PowerShell\\7\\pwsh.exe") + }) + + it("falls back to legacy PowerShell if profile includes 'powershell' but no path/source", () => { + mockVsCodeConfig("windows", "PowerShell", { + PowerShell: {}, + }) + expect(getShell()).toBe("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe") + }) + + it("uses WSL bash when profile indicates WSL source", () => { + mockVsCodeConfig("windows", "WSL", { + WSL: { source: "WSL" }, + }) + expect(getShell()).toBe("/bin/bash") + }) + + it("uses WSL bash when profile name includes 'wsl'", () => { + mockVsCodeConfig("windows", "Ubuntu WSL", { + "Ubuntu WSL": {}, + }) + expect(getShell()).toBe("/bin/bash") + }) + + it("defaults to cmd.exe if no special profile is matched", () => { + mockVsCodeConfig("windows", "CommandPrompt", { + CommandPrompt: {}, + }) + expect(getShell()).toBe("C:\\Windows\\System32\\cmd.exe") + }) + + it("respects userInfo() if no VS Code config is available", () => { + vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any + ;(userInfo as any) = () => ({ shell: "C:\\Custom\\PowerShell.exe" }) + + expect(getShell()).toBe("C:\\Custom\\PowerShell.exe") + }) + + it("respects an odd COMSPEC if no userInfo shell is available", () => { + vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any + process.env.COMSPEC = "D:\\CustomCmd\\cmd.exe" + + expect(getShell()).toBe("D:\\CustomCmd\\cmd.exe") + }) + }) + + // -------------------------------------------------------------------------- + // macOS Shell Detection + // -------------------------------------------------------------------------- + describe("macOS Shell Detection", () => { + beforeEach(() => { + Object.defineProperty(process, "platform", { value: "darwin" }) + }) + + it("uses VS Code profile path if available", () => { + mockVsCodeConfig("osx", "MyCustomShell", { + MyCustomShell: { path: "/usr/local/bin/fish" }, + }) + expect(getShell()).toBe("/usr/local/bin/fish") + }) + + it("falls back to userInfo().shell if no VS Code config is available", () => { + vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any + ;(userInfo as any) = () => ({ shell: "/opt/homebrew/bin/zsh" }) + expect(getShell()).toBe("/opt/homebrew/bin/zsh") + }) + + it("falls back to SHELL env var if no userInfo shell is found", () => { + vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any + process.env.SHELL = "/usr/local/bin/zsh" + expect(getShell()).toBe("/usr/local/bin/zsh") + }) + + it("falls back to /bin/zsh if no config, userInfo, or env variable is set", () => { + vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any + expect(getShell()).toBe("/bin/zsh") + }) + }) + + // -------------------------------------------------------------------------- + // Linux Shell Detection + // -------------------------------------------------------------------------- + describe("Linux Shell Detection", () => { + beforeEach(() => { + Object.defineProperty(process, "platform", { value: "linux" }) + }) + + it("uses VS Code profile path if available", () => { + mockVsCodeConfig("linux", "CustomProfile", { + CustomProfile: { path: "/usr/bin/fish" }, + }) + expect(getShell()).toBe("/usr/bin/fish") + }) + + it("falls back to userInfo().shell if no VS Code config is available", () => { + vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any + ;(userInfo as any) = () => ({ shell: "/usr/bin/zsh" }) + expect(getShell()).toBe("/usr/bin/zsh") + }) + + it("falls back to SHELL env var if no userInfo shell is found", () => { + vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any + process.env.SHELL = "/usr/bin/fish" + expect(getShell()).toBe("/usr/bin/fish") + }) + + it("falls back to /bin/bash if nothing is set", () => { + vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any + expect(getShell()).toBe("/bin/bash") + }) + }) + + // -------------------------------------------------------------------------- + // Unknown Platform & Error Handling + // -------------------------------------------------------------------------- + describe("Unknown Platform / Error Handling", () => { + it("falls back to /bin/sh for unknown platforms", () => { + Object.defineProperty(process, "platform", { value: "sunos" }) + vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any + expect(getShell()).toBe("/bin/sh") + }) + + it("handles VS Code config errors gracefully, falling back to userInfo shell if present", () => { + Object.defineProperty(process, "platform", { value: "linux" }) + vscode.workspace.getConfiguration = () => { + throw new Error("Configuration error") + } + ;(userInfo as any) = () => ({ shell: "/bin/bash" }) + expect(getShell()).toBe("/bin/bash") + }) + + it("handles userInfo errors gracefully, falling back to environment variable if present", () => { + Object.defineProperty(process, "platform", { value: "darwin" }) + vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any + ;(userInfo as any) = () => { + throw new Error("userInfo error") + } + process.env.SHELL = "/bin/zsh" + expect(getShell()).toBe("/bin/zsh") + }) + + it("falls back fully to default shell paths if everything fails", () => { + Object.defineProperty(process, "platform", { value: "linux" }) + vscode.workspace.getConfiguration = () => { + throw new Error("Configuration error") + } + ;(userInfo as any) = () => { + throw new Error("userInfo error") + } + delete process.env.SHELL + expect(getShell()).toBe("/bin/bash") + }) + }) +}) diff --git a/src/utils/shell.ts b/src/utils/shell.ts new file mode 100644 index 0000000000..8871550a0e --- /dev/null +++ b/src/utils/shell.ts @@ -0,0 +1,227 @@ +import * as vscode from "vscode" +import { userInfo } from "os" + +const SHELL_PATHS = { + // Windows paths + POWERSHELL_7: "C:\\Program Files\\PowerShell\\7\\pwsh.exe", + POWERSHELL_LEGACY: "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", + CMD: "C:\\Windows\\System32\\cmd.exe", + WSL_BASH: "/bin/bash", + // Unix paths + MAC_DEFAULT: "/bin/zsh", + LINUX_DEFAULT: "/bin/bash", + CSH: "/bin/csh", + BASH: "/bin/bash", + KSH: "/bin/ksh", + SH: "/bin/sh", + ZSH: "/bin/zsh", + DASH: "/bin/dash", + TCSH: "/bin/tcsh", + FALLBACK: "/bin/sh", +} as const + +interface MacTerminalProfile { + path?: string +} + +type MacTerminalProfiles = Record + +interface WindowsTerminalProfile { + path?: string + source?: "PowerShell" | "WSL" +} + +type WindowsTerminalProfiles = Record + +interface LinuxTerminalProfile { + path?: string +} + +type LinuxTerminalProfiles = Record + +// ----------------------------------------------------- +// 1) VS Code Terminal Configuration Helpers +// ----------------------------------------------------- + +function getWindowsTerminalConfig() { + try { + const config = vscode.workspace.getConfiguration("terminal.integrated") + const defaultProfileName = config.get("defaultProfile.windows") + const profiles = config.get("profiles.windows") || {} + return { defaultProfileName, profiles } + } catch { + return { defaultProfileName: null, profiles: {} as WindowsTerminalProfiles } + } +} + +function getMacTerminalConfig() { + try { + const config = vscode.workspace.getConfiguration("terminal.integrated") + const defaultProfileName = config.get("defaultProfile.osx") + const profiles = config.get("profiles.osx") || {} + return { defaultProfileName, profiles } + } catch { + return { defaultProfileName: null, profiles: {} as MacTerminalProfiles } + } +} + +function getLinuxTerminalConfig() { + try { + const config = vscode.workspace.getConfiguration("terminal.integrated") + const defaultProfileName = config.get("defaultProfile.linux") + const profiles = config.get("profiles.linux") || {} + return { defaultProfileName, profiles } + } catch { + return { defaultProfileName: null, profiles: {} as LinuxTerminalProfiles } + } +} + +// ----------------------------------------------------- +// 2) Platform-Specific VS Code Shell Retrieval +// ----------------------------------------------------- + +/** Attempts to retrieve a shell path from VS Code config on Windows. */ +function getWindowsShellFromVSCode(): string | null { + const { defaultProfileName, profiles } = getWindowsTerminalConfig() + if (!defaultProfileName) { + return null + } + + const profile = profiles[defaultProfileName] + + // If the profile name indicates PowerShell, do version-based detection. + // In testing it was found these typically do not have a path, and this + // implementation manages to deductively get the corect version of PowerShell + if (defaultProfileName.toLowerCase().includes("powershell")) { + if (profile?.path) { + // If there's an explicit PowerShell path, return that + return profile.path + } else if (profile?.source === "PowerShell") { + // If the profile is sourced from PowerShell, assume the newest + return SHELL_PATHS.POWERSHELL_7 + } + // Otherwise, assume legacy Windows PowerShell + return SHELL_PATHS.POWERSHELL_LEGACY + } + + // If there's a specific path, return that immediately + if (profile.path) { + return profile.path + } + + // If the profile indicates WSL + if (profile?.source === "WSL" || defaultProfileName.toLowerCase().includes("wsl")) { + return SHELL_PATHS.WSL_BASH + } + + // If nothing special detected, we assume cmd + return SHELL_PATHS.CMD +} + +/** Attempts to retrieve a shell path from VS Code config on macOS. */ +function getMacShellFromVSCode(): string | null { + const { defaultProfileName, profiles } = getMacTerminalConfig() + if (!defaultProfileName) { + return null + } + + const profile = profiles[defaultProfileName] + return profile?.path || null +} + +/** Attempts to retrieve a shell path from VS Code config on Linux. */ +function getLinuxShellFromVSCode(): string | null { + const { defaultProfileName, profiles } = getLinuxTerminalConfig() + if (!defaultProfileName) { + return null + } + + const profile = profiles[defaultProfileName] + return profile?.path || null +} + +// ----------------------------------------------------- +// 3) General Fallback Helpers +// ----------------------------------------------------- + +/** + * Tries to get a user’s shell from os.userInfo() (works on Unix if the + * underlying system call is supported). Returns null on error or if not found. + */ +function getShellFromUserInfo(): string | null { + try { + const { shell } = userInfo() + return shell || null + } catch { + return null + } +} + +/** Returns the environment-based shell variable, or null if not set. */ +function getShellFromEnv(): string | null { + const { env } = process + + if (process.platform === "win32") { + // On Windows, COMSPEC typically holds cmd.exe + return env.COMSPEC || "C:\\Windows\\System32\\cmd.exe" + } + + if (process.platform === "darwin") { + // On macOS/Linux, SHELL is commonly the environment variable + return env.SHELL || "/bin/zsh" + } + + if (process.platform === "linux") { + // On Linux, SHELL is commonly the environment variable + return env.SHELL || "/bin/bash" + } + return null +} + +// ----------------------------------------------------- +// 4) Publicly Exposed Shell Getter +// ----------------------------------------------------- + +export function getShell(): string { + // 1. Check VS Code config first. + if (process.platform === "win32") { + // Special logic for Windows + const windowsShell = getWindowsShellFromVSCode() + if (windowsShell) { + return windowsShell + } + } else if (process.platform === "darwin") { + // macOS from VS Code + const macShell = getMacShellFromVSCode() + if (macShell) { + return macShell + } + } else if (process.platform === "linux") { + // Linux from VS Code + const linuxShell = getLinuxShellFromVSCode() + if (linuxShell) { + return linuxShell + } + } + + // 2. If no shell from VS Code, try userInfo() + const userInfoShell = getShellFromUserInfo() + if (userInfoShell) { + return userInfoShell + } + + // 3. If still nothing, try environment variable + const envShell = getShellFromEnv() + if (envShell) { + return envShell + } + + // 4. Finally, fall back to a default + if (process.platform === "win32") { + // On Windows, if we got here, we have no config, no COMSPEC, and one very messed up operating system. + // Use CMD as a last resort + return SHELL_PATHS.CMD + } + // On macOS/Linux, fallback to a POSIX shell - This is the behavior of our old shell detection method. + return SHELL_PATHS.FALLBACK +} diff --git a/webview-ui/tsconfig.json b/webview-ui/tsconfig.json index c725fcff3e..2243662462 100644 --- a/webview-ui/tsconfig.json +++ b/webview-ui/tsconfig.json @@ -1,7 +1,11 @@ { "compilerOptions": { "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, @@ -17,8 +21,13 @@ "jsx": "react-jsx", "baseUrl": ".", "paths": { - "@/*": ["./src/*"] + "@/*": [ + "./src/*" + ] } }, - "include": ["src", "../src/shared"] + "include": [ + "src", + "../src/shared", + ] } From e8a5e280b3c31e26fff2c7aef788395be8109be8 Mon Sep 17 00:00:00 2001 From: Nissa Seru <119150866+nissa-seru@users.noreply.github.com> Date: Sun, 2 Feb 2025 01:02:35 -0500 Subject: [PATCH 02/40] Update EditorUtils --- src/core/EditorUtils.ts | 33 +++++---- src/core/__tests__/EditorUtils.test.ts | 99 +++++++++++++++++++++----- 2 files changed, 103 insertions(+), 29 deletions(-) diff --git a/src/core/EditorUtils.ts b/src/core/EditorUtils.ts index e58a82f18f..7b2b9146f3 100644 --- a/src/core/EditorUtils.ts +++ b/src/core/EditorUtils.ts @@ -39,16 +39,14 @@ export class EditorUtils { return null } - // Optimize range creation by checking bounds first - const startLine = Math.max(0, currentLine.lineNumber - 1) - const endLine = Math.min(document.lineCount - 1, currentLine.lineNumber + 1) + // Always expand an empty selection to include full lines, + // using the full previous and next lines where available. + const startLineIndex = Math.max(0, currentLine.lineNumber - 1) + const endLineIndex = Math.min(document.lineCount - 1, currentLine.lineNumber + 1) - // Only create new positions if needed const effectiveRange = new vscode.Range( - startLine === currentLine.lineNumber ? range.start : new vscode.Position(startLine, 0), - endLine === currentLine.lineNumber - ? range.end - : new vscode.Position(endLine, document.lineAt(endLine).text.length), + new vscode.Position(startLineIndex, 0), + new vscode.Position(endLineIndex, document.lineAt(endLineIndex).text.length), ) return { @@ -97,12 +95,21 @@ export class EditorUtils { } static hasIntersectingRange(range1: vscode.Range, range2: vscode.Range): boolean { - return !( + // Use half-open interval semantics: + // If one range ends at or before the other's start, there's no intersection. + if ( + range1.end.line < range2.start.line || + (range1.end.line === range2.start.line && range1.end.character <= range2.start.character) + ) { + return false + } + if ( range2.end.line < range1.start.line || - range2.start.line > range1.end.line || - (range2.end.line === range1.start.line && range2.end.character < range1.start.character) || - (range2.start.line === range1.end.line && range2.start.character > range1.end.character) - ) + (range2.end.line === range1.start.line && range2.end.character <= range1.start.character) + ) { + return false + } + return true } static getEditorContext(editor?: vscode.TextEditor): EditorContext | null { diff --git a/src/core/__tests__/EditorUtils.test.ts b/src/core/__tests__/EditorUtils.test.ts index 88d64e6da8..1a01838693 100644 --- a/src/core/__tests__/EditorUtils.test.ts +++ b/src/core/__tests__/EditorUtils.test.ts @@ -1,20 +1,35 @@ import * as vscode from "vscode" import { EditorUtils } from "../EditorUtils" -// Mock VSCode API -jest.mock("vscode", () => ({ - Range: jest.fn().mockImplementation((startLine, startChar, endLine, endChar) => ({ - start: { line: startLine, character: startChar }, - end: { line: endLine, character: endChar }, - })), - Position: jest.fn().mockImplementation((line, character) => ({ - line, - character, - })), - workspace: { - getWorkspaceFolder: jest.fn(), - }, -})) +// Use simple classes to simulate VSCode's Range and Position behavior. +jest.mock("vscode", () => { + class MockPosition { + constructor( + public line: number, + public character: number, + ) {} + } + class MockRange { + start: MockPosition + end: MockPosition + constructor(start: MockPosition, end: MockPosition) { + this.start = start + this.end = end + } + } + + return { + Range: MockRange, + Position: MockPosition, + workspace: { + getWorkspaceFolder: jest.fn(), + }, + window: { activeTextEditor: undefined }, + languages: { + getDiagnostics: jest.fn(() => []), + }, + } +}) describe("EditorUtils", () => { let mockDocument: any @@ -30,7 +45,7 @@ describe("EditorUtils", () => { describe("getEffectiveRange", () => { it("should return selected text when available", () => { - const mockRange = new vscode.Range(0, 0, 0, 10) + const mockRange = new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 10)) mockDocument.getText.mockReturnValue("selected text") const result = EditorUtils.getEffectiveRange(mockDocument, mockRange) @@ -42,7 +57,7 @@ describe("EditorUtils", () => { }) it("should return null for empty line", () => { - const mockRange = new vscode.Range(0, 0, 0, 10) + const mockRange = new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 10)) mockDocument.getText.mockReturnValue("") mockDocument.lineAt.mockReturnValue({ text: "", lineNumber: 0 }) @@ -50,6 +65,58 @@ describe("EditorUtils", () => { expect(result).toBeNull() }) + + it("should expand empty selection to full lines", () => { + // Simulate a caret (empty selection) on line 2 at character 5. + const initialRange = new vscode.Range(new vscode.Position(2, 5), new vscode.Position(2, 5)) + // Return non-empty text for any line with text (lines 1, 2, and 3). + mockDocument.lineAt.mockImplementation((line: number) => { + return { text: `Line ${line} text`, lineNumber: line } + }) + mockDocument.getText.mockImplementation((range: any) => { + // If the range is exactly the empty initial selection, return an empty string. + if ( + range.start.line === initialRange.start.line && + range.start.character === initialRange.start.character && + range.end.line === initialRange.end.line && + range.end.character === initialRange.end.character + ) { + return "" + } + return "expanded text" + }) + + const result = EditorUtils.getEffectiveRange(mockDocument, initialRange) + + expect(result).not.toBeNull() + // Expected effective range: from the beginning of line 1 to the end of line 3. + expect(result?.range.start).toEqual({ line: 1, character: 0 }) + expect(result?.range.end).toEqual({ line: 3, character: 11 }) + expect(result?.text).toBe("expanded text") + }) + }) + + describe("hasIntersectingRange", () => { + it("should return false for ranges that only touch boundaries", () => { + // Range1: [0, 0) - [0, 10) and Range2: [0, 10) - [0, 20) + const range1 = new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 10)) + const range2 = new vscode.Range(new vscode.Position(0, 10), new vscode.Position(0, 20)) + expect(EditorUtils.hasIntersectingRange(range1, range2)).toBe(false) + }) + + it("should return true for overlapping ranges", () => { + // Range1: [0, 0) - [0, 15) and Range2: [0, 10) - [0, 20) + const range1 = new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 15)) + const range2 = new vscode.Range(new vscode.Position(0, 10), new vscode.Position(0, 20)) + expect(EditorUtils.hasIntersectingRange(range1, range2)).toBe(true) + }) + + it("should return false for non-overlapping ranges", () => { + // Range1: [0, 0) - [0, 10) and Range2: [1, 0) - [1, 5) + const range1 = new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 10)) + const range2 = new vscode.Range(new vscode.Position(1, 0), new vscode.Position(1, 5)) + expect(EditorUtils.hasIntersectingRange(range1, range2)).toBe(false) + }) }) describe("getFilePath", () => { From a01d923f2f82ebe8f3a8aa9eae28bef3d389f7cb Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sun, 2 Feb 2025 02:31:48 -0500 Subject: [PATCH 03/40] Make list of modes multi-line on the prompts page --- .changeset/breezy-badgers-refuse.md | 5 +++++ .../src/components/prompts/PromptsView.tsx | 16 ++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 .changeset/breezy-badgers-refuse.md diff --git a/.changeset/breezy-badgers-refuse.md b/.changeset/breezy-badgers-refuse.md new file mode 100644 index 0000000000..50cbbe9262 --- /dev/null +++ b/.changeset/breezy-badgers-refuse.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +Visual cleanup to the list of modes on the prompts tab diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index 68278785ff..eff9f99f48 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -472,13 +472,11 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
{modes.map((modeConfig) => { const isActive = mode === modeConfig.slug @@ -859,13 +857,11 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
{Object.keys(supportPrompt.default).map((type) => ( + + + Label + + + Item 1 + + Item 2⌘2 + + + + + + Submenu + + + Foo + + Bar + ⌘B + + + Baz + + + + + + + ), +} + +type DropdownMenuVariantProps = { + side?: "top" | "bottom" | "left" | "right" + align?: "start" | "center" | "end" + children?: React.ReactNode +} + +const DropdownMenuVariant = ({ side = "bottom", align = "center", children }: DropdownMenuVariantProps) => ( + + + + + + Foo + Bar + Baz + + +) + +export const Placements: Story = { + render: () => ( +
+ + + + + + + + + + + + +
+ ), +} + +export const Alignments: Story = { + render: () => ( +
+ + + + + + + + + +
+ ), +} diff --git a/webview-ui/src/stories/vscrui/Dropdown.stories.tsx b/webview-ui/src/stories/vscrui/Dropdown.stories.tsx new file mode 100644 index 0000000000..5509eb969f --- /dev/null +++ b/webview-ui/src/stories/vscrui/Dropdown.stories.tsx @@ -0,0 +1,47 @@ +import type { Meta, StoryObj } from "@storybook/react" + +import { Dropdown } from "vscrui" + +const meta = { + title: "@vscrui/Dropdown", + component: () => ( + + ), + parameters: { layout: "centered" }, + tags: ["autodocs"], + argTypes: {}, + args: {}, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + args: {}, + parameters: { + docs: { + source: { + code: ` +`, + language: "tsx", + }, + }, + }, +} From 41f25f09960224e53993bdead00dbb5bd44fd1b0 Mon Sep 17 00:00:00 2001 From: cte Date: Mon, 3 Feb 2025 12:16:35 -0800 Subject: [PATCH 21/40] Button tweaks --- webview-ui/.storybook/vscode.css | 2 +- webview-ui/src/components/ui/button.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webview-ui/.storybook/vscode.css b/webview-ui/.storybook/vscode.css index 07e261846a..8b1e23e890 100644 --- a/webview-ui/.storybook/vscode.css +++ b/webview-ui/.storybook/vscode.css @@ -14,7 +14,7 @@ --vscode-button-foreground: #ffffff; /* "button.foreground" */ --vscode-button-secondaryBackground: #313131; /* "button.secondaryBackground" */ --vscode-button-secondaryForeground: #cccccc; /* "button.secondaryForeground" */ - --vscode-disabledForeground: red; /* "disabledForeground" */ + --vscode-disabledForeground: #313131; /* "disabledForeground" */ --vscode-descriptionForeground: #9d9d9d; /* "descriptionForeground" */ --vscode-focusBorder: #0078d4; /* "focusBorder" */ --vscode-errorForeground: #f85149; /* "errorForeground" */ diff --git a/webview-ui/src/components/ui/button.tsx b/webview-ui/src/components/ui/button.tsx index db39bd2645..5bd00336b9 100644 --- a/webview-ui/src/components/ui/button.tsx +++ b/webview-ui/src/components/ui/button.tsx @@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", { variants: { variant: { From 0e02a89da4d967933576ca3a17d7b401fbd34b4b Mon Sep 17 00:00:00 2001 From: cte Date: Mon, 3 Feb 2025 12:18:28 -0800 Subject: [PATCH 22/40] Bring most of Tailwind's preflight.css back --- webview-ui/src/index.css | 17 +- webview-ui/src/preflight.css | 383 +++++++++++++++++++++++++++++++++++ 2 files changed, 397 insertions(+), 3 deletions(-) create mode 100644 webview-ui/src/preflight.css diff --git a/webview-ui/src/index.css b/webview-ui/src/index.css index c9ac7948e3..00decdc3e6 100644 --- a/webview-ui/src/index.css +++ b/webview-ui/src/index.css @@ -1,10 +1,21 @@ -/* @import "tailwindcss"; */ +/** + * Normally we'd import tailwind with the following: + * + * @import "tailwindcss"; + * + * However, we need to customize the preflight styles since the extension's + * current UI assumes there's no CSS resetting or normalization. + * + * We're excluding tailwind's default preflight and importing our own, which + * are based on the original (https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/preflight.css). + * + * Reference: https://tailwindcss.com/docs/preflight + */ @layer theme, base, components, utilities; @import "tailwindcss/theme.css" layer(theme); -/* https://tailwindcss.com/docs/preflight */ -/* @import "tailwindcss/preflight.css" layer(base); */ +@import "./preflight.css" layer(base); @import "tailwindcss/utilities.css" layer(utilities); @plugin "tailwindcss-animate"; diff --git a/webview-ui/src/preflight.css b/webview-ui/src/preflight.css new file mode 100644 index 0000000000..20e4dd9717 --- /dev/null +++ b/webview-ui/src/preflight.css @@ -0,0 +1,383 @@ +/* + 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) + 2. Remove default margins and padding + 3. Reset all borders. +*/ + +*, +::after, +::before, +::backdrop, +::file-selector-button { + box-sizing: border-box; /* 1 */ + /* margin: 0; */ /* 2 */ + padding: 0; /* 2 */ + border: 0 solid; /* 3 */ +} + +/* + 1. Use a consistent sensible line-height in all browsers. + 2. Prevent adjustments of font size after orientation changes in iOS. + 3. Use a more readable tab size. + 4. Use the user's configured `sans` font-family by default. + 5. Use the user's configured `sans` font-feature-settings by default. + 6. Use the user's configured `sans` font-variation-settings by default. + 7. Disable tap highlights on iOS. +*/ + +html, +:host { + line-height: 1.5; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + tab-size: 4; /* 3 */ + font-family: var( + --default-font-family, + ui-sans-serif, + system-ui, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji" + ); /* 4 */ + font-feature-settings: var(--default-font-feature-settings, normal); /* 5 */ + font-variation-settings: var(--default-font-variation-settings, normal); /* 6 */ + -webkit-tap-highlight-color: transparent; /* 7 */ +} + +/* + Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + line-height: inherit; +} + +/* + 1. Add the correct height in Firefox. + 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) + 3. Reset the default border style to a 1px solid border. +*/ + +hr { + height: 0; /* 1 */ + color: inherit; /* 2 */ + border-top-width: 1px; /* 3 */ +} + +/* + Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* + Remove the default font size and weight for headings. +*/ + +/* h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} */ + +/* + Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + -webkit-text-decoration: inherit; + text-decoration: inherit; +} + +/* + Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* + 1. Use the user's configured `mono` font-family by default. + 2. Use the user's configured `mono` font-feature-settings by default. + 3. Use the user's configured `mono` font-variation-settings by default. + 4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: var( + --default-mono-font-family, + ui-monospace, + SFMono-Regular, + Menlo, + Monaco, + Consolas, + "Liberation Mono", + "Courier New", + monospace + ); /* 4 */ + font-feature-settings: var(--default-mono-font-feature-settings, normal); /* 5 */ + font-variation-settings: var(--default-mono-font-variation-settings, normal); /* 6 */ + font-size: 1em; /* 4 */ +} + +/* + Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* + Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* + 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) + 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) + 3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; /* 1 */ + border-color: inherit; /* 2 */ + border-collapse: collapse; /* 3 */ +} + +/* + Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* + Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* + Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* + Make lists unstyled by default. +*/ + +ol, +ul, +menu { + list-style: none; +} + +/* + 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) + 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; /* 1 */ + vertical-align: middle; /* 2 */ +} + +/* + Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* + 1. Inherit font styles in all browsers. + 2. Remove border radius in all browsers. + 3. Remove background color in all browsers. + 4. Ensure consistent opacity for disabled states in all browsers. +*/ + +button, +input, +select, +optgroup, +textarea, +::file-selector-button { + font: inherit; /* 1 */ + font-feature-settings: inherit; /* 1 */ + font-variation-settings: inherit; /* 1 */ + letter-spacing: inherit; /* 1 */ + color: inherit; /* 1 */ + border-radius: 0; /* 2 */ + background-color: transparent; /* 3 */ + opacity: 1; /* 4 */ +} + +/* + Restore default font weight. +*/ + +:where(select:is([multiple], [size])) optgroup { + font-weight: bolder; +} + +/* + Restore indentation. +*/ + +:where(select:is([multiple], [size])) optgroup option { + padding-inline-start: 20px; +} + +/* + Restore space after button. +*/ + +::file-selector-button { + margin-inline-end: 4px; +} + +/* + 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) + 2. Set the default placeholder color to a semi-transparent version of the current text color. +*/ + +::placeholder { + opacity: 1; /* 1 */ + color: color-mix(in oklab, currentColor 50%, transparent); /* 2 */ +} + +/* + Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* + Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* + 1. Ensure date/time inputs have the same height when empty in iOS Safari. + 2. Ensure text alignment can be changed on date/time inputs in iOS Safari. +*/ + +::-webkit-date-and-time-value { + min-height: 1lh; /* 1 */ + text-align: inherit; /* 2 */ +} + +/* + Prevent height from changing on date/time inputs in macOS Safari when the input is set to `display: block`. +*/ + +::-webkit-datetime-edit { + display: inline-flex; +} + +/* + Remove excess padding from pseudo-elements in date/time inputs to ensure consistent height across browsers. +*/ + +::-webkit-datetime-edit-fields-wrapper { + padding: 0; +} + +::-webkit-datetime-edit, +::-webkit-datetime-edit-year-field, +::-webkit-datetime-edit-month-field, +::-webkit-datetime-edit-day-field, +::-webkit-datetime-edit-hour-field, +::-webkit-datetime-edit-minute-field, +::-webkit-datetime-edit-second-field, +::-webkit-datetime-edit-millisecond-field, +::-webkit-datetime-edit-meridiem-field { + padding-block: 0; +} + +/* + Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* + Correct the inability to style the border radius in iOS Safari. +*/ + +button, +input:where([type="button"], [type="reset"], [type="submit"]), +::file-selector-button { + appearance: button; +} + +/* + Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* + Make elements with the HTML hidden attribute stay hidden by default. +*/ + +[hidden]:where(:not([hidden="until-found"])) { + display: none !important; +} From e57e795a06ccf7c3f1085e9f610ff62640915681 Mon Sep 17 00:00:00 2001 From: cte Date: Mon, 3 Feb 2025 12:28:53 -0800 Subject: [PATCH 23/40] Fix test:integration --- webview-ui/package-lock.json | 1224 ++++++++++++++++++++++++++++++---- webview-ui/package.json | 12 +- 2 files changed, 1097 insertions(+), 139 deletions(-) diff --git a/webview-ui/package-lock.json b/webview-ui/package-lock.json index 36186e16db..b336da2b8e 100644 --- a/webview-ui/package-lock.json +++ b/webview-ui/package-lock.json @@ -33,12 +33,12 @@ "vscrui": "^0.2.0" }, "devDependencies": { - "@storybook/addon-essentials": "^8.5.3", - "@storybook/addon-interactions": "^8.5.3", + "@storybook/addon-essentials": "^8.5.2", + "@storybook/addon-interactions": "^8.5.2", "@storybook/blocks": "^8.5.2", - "@storybook/react": "^8.5.3", - "@storybook/react-vite": "^8.5.3", - "@storybook/test": "^8.5.3", + "@storybook/react": "^8.5.2", + "@storybook/react-vite": "^8.5.2", + "@storybook/test": "^8.5.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -60,7 +60,7 @@ "jest": "^27.5.1", "jest-environment-jsdom": "^27.5.1", "jest-simple-dot-reporter": "^1.0.5", - "storybook": "^8.5.3", + "storybook": "^8.5.2", "ts-jest": "^27.1.5", "typescript": "^4.9.5", "vite": "6.0.11" @@ -622,6 +622,70 @@ "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", "license": "MIT" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/darwin-arm64": { "version": "0.24.2", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", @@ -638,6 +702,326 @@ "node": ">=18" } }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", @@ -1963,6 +2347,32 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.1.tgz", + "integrity": "sha512-/pqA4DmqyCm8u5YIDzIdlLcEmuvxb0v8fZdFhVMszSpDTgbQKdw3/mB3eMUHIbubtJ6F9j+LtmyCnHTEqIHyzA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.32.1.tgz", + "integrity": "sha512-If3PDskT77q7zgqVqYuj7WG3WC08G1kwXGVFi9Jr8nY6eHucREHkfpX79c0ACAjLj3QIWKPJR7w4i+f5EdLH5Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.32.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.32.1.tgz", @@ -1976,6 +2386,214 @@ "darwin" ] }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.32.1.tgz", + "integrity": "sha512-sFvF+t2+TyUo/ZQqUcifrJIgznx58oFZbdHS9TvHq3xhPVL9nOp+yZ6LKrO9GWTP+6DbFtoyLDbjTpR62Mbr3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.32.1.tgz", + "integrity": "sha512-NbOa+7InvMWRcY9RG+B6kKIMD/FsnQPH0MWUvDlQB1iXnF/UcKSudCXZtv4lW+C276g3w5AxPbfry5rSYvyeYA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.32.1.tgz", + "integrity": "sha512-JRBRmwvHPXR881j2xjry8HZ86wIPK2CcDw0EXchE1UgU0ubWp9nvlT7cZYKc6bkypBt745b4bglf3+xJ7hXWWw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.32.1.tgz", + "integrity": "sha512-PKvszb+9o/vVdUzCCjL0sKHukEQV39tD3fepXxYrHE3sTKrRdCydI7uldRLbjLmDA3TFDmh418XH19NOsDRH8g==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.32.1.tgz", + "integrity": "sha512-9WHEMV6Y89eL606ReYowXuGF1Yb2vwfKWKdD1A5h+OYnPZSJvxbEjxTRKPgi7tkP2DSnW0YLab1ooy+i/FQp/Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.1.tgz", + "integrity": "sha512-tZWc9iEt5fGJ1CL2LRPw8OttkCBDs+D8D3oEM8mH8S1ICZCtFJhD7DZ3XMGM8kpqHvhGUTvNUYVDnmkj4BDXnw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.32.1.tgz", + "integrity": "sha512-FTYc2YoTWUsBz5GTTgGkRYYJ5NGJIi/rCY4oK/I8aKowx1ToXeoVVbIE4LGAjsauvlhjfl0MYacxClLld1VrOw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.32.1.tgz", + "integrity": "sha512-F51qLdOtpS6P1zJVRzYM0v6MrBNypyPEN1GfMiz0gPu9jN8ScGaEFIZQwteSsGKg799oR5EaP7+B2jHgL+d+Kw==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.32.1.tgz", + "integrity": "sha512-wO0WkfSppfX4YFm5KhdCCpnpGbtgQNj/tgvYzrVYFKDpven8w2N6Gg5nB6w+wAMO3AIfSTWeTjfVe+uZ23zAlg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.32.1.tgz", + "integrity": "sha512-iWswS9cIXfJO1MFYtI/4jjlrGb/V58oMu4dYJIKnR5UIwbkzR0PJ09O0PDZT0oJ3LYWXBSWahNf/Mjo6i1E5/g==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.32.1.tgz", + "integrity": "sha512-RKt8NI9tebzmEthMnfVgG3i/XeECkMPS+ibVZjZ6mNekpbbUmkNWuIN2yHsb/mBPyZke4nlI4YqIdFPgKuoyQQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.1.tgz", + "integrity": "sha512-WQFLZ9c42ECqEjwg/GHHsouij3pzLXkFdz0UxHa/0OM12LzvX7DzedlY0SIEly2v18YZLRhCRoHZDxbBSWoGYg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.32.1.tgz", + "integrity": "sha512-BLoiyHDOWoS3uccNSADMza6V6vCNiphi94tQlVIL5de+r6r/CCQuNnerf+1g2mnk2b6edp5dk0nhdZ7aEjOBsA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.32.1.tgz", + "integrity": "sha512-w2l3UnlgYTNNU+Z6wOR8YdaioqfEnwPjIsJ66KxKAf0p+AuL2FHeTX6qvM+p/Ue3XPBVNyVSfCrfZiQh7vZHLQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.32.1.tgz", + "integrity": "sha512-Am9H+TGLomPGkBnaPWie4F3x+yQ2rr4Bk2jpwy+iV+Gel9jLAu/KqT8k3X4jxFPW6Zf8OMnehyutsd+eHoq1WQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.32.1.tgz", + "integrity": "sha512-ar80GhdZb4DgmW3myIS9nRFYcpJRSME8iqWgzH2i44u+IdrzmiXVxeFnExQ5v4JYUSpg94bWjevMG8JHf1Da5Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", @@ -1997,9 +2615,9 @@ } }, "node_modules/@storybook/addon-actions": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.5.3.tgz", - "integrity": "sha512-7a+SD4EZdZocm+NG1Kx4yV6Aw7+YUlRIyGvKcxsGtYMOLaqrUewApqveXF83+FbYWMoezXcoZCLQFROtS/Z6Fw==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.5.2.tgz", + "integrity": "sha512-g0gLesVSFgstUq5QphsLeC1vEdwNHgqo2TE0m+STM47832xbxBwmK6uvBeqi416xZvnt1TTKaaBr4uCRRQ64Ww==", "dev": true, "license": "MIT", "dependencies": { @@ -2014,13 +2632,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/addon-backgrounds": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.5.3.tgz", - "integrity": "sha512-sZcw8/C/HIIgbRBY+0ZYTBc5Py8xvw3bt6lzSVQEXA2aygfJpO/jiQJlmOXTmK3g5F5pjFKaaCodfXT7V/9mzw==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.5.2.tgz", + "integrity": "sha512-l9WkI4QHfINeFQkW9K0joaM7WweKktwIIyUPEvyoupHT4n9ccJHAlWjH4SBmzwI1j1Zt0G3t+bq8mVk/YK6Fsg==", "dev": true, "license": "MIT", "dependencies": { @@ -2033,13 +2651,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/addon-controls": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.5.3.tgz", - "integrity": "sha512-A4UVQhPyC7FvV+fM50xvEZO26/2uE41Ns0TN0qq7U5EH0Dlj43Salgay6qT8fve6XAI4SgVjkujPVCSbLg/yVQ==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.5.2.tgz", + "integrity": "sha512-wkzw2vRff4zkzdvC/GOlB2PlV0i973u8igSLeg34TWNEAa4bipwVHnFfIojRuP9eN1bZL/0tjuU5pKnbTqH7aQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2052,20 +2670,20 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/addon-docs": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.5.3.tgz", - "integrity": "sha512-XVcQlHX963nuoeRkb7qQg89t/9CThdT46UV7jX3FFn08NEMhmDEa+4iVA4l+4xNgJ+Av6uX+u6yRGnM/910mLg==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.5.2.tgz", + "integrity": "sha512-pRLJ/Qb/3XHpjS7ZAMaOZYtqxOuI8wPxVKYQ6n5rfMSj2jFwt5tdDsEJdhj2t5lsY8HrzEZi8ExuW5I5RoUoIQ==", "dev": true, "license": "MIT", "dependencies": { "@mdx-js/react": "^3.0.0", - "@storybook/blocks": "8.5.3", - "@storybook/csf-plugin": "8.5.3", - "@storybook/react-dom-shim": "8.5.3", + "@storybook/blocks": "8.5.2", + "@storybook/csf-plugin": "8.5.2", + "@storybook/react-dom-shim": "8.5.2", "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", "ts-dedent": "^2.0.0" @@ -2075,25 +2693,25 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/addon-essentials": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.5.3.tgz", - "integrity": "sha512-0zbEWQQZCiYRUxMo6FrfwQER/vi+B8mCLLivdjbSVSvZsjmlpcaBA5uBjbsXfIRcedHlou4QiJXn+nR8thDlKA==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.5.2.tgz", + "integrity": "sha512-MfojJKxDg0bnjOE0MfLSaPweAud1Esjaf1D9M8EYnpeFnKGZApcGJNRpHCDiHrS5BMr8hHa58RDVc7ObFTI4Dw==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/addon-actions": "8.5.3", - "@storybook/addon-backgrounds": "8.5.3", - "@storybook/addon-controls": "8.5.3", - "@storybook/addon-docs": "8.5.3", - "@storybook/addon-highlight": "8.5.3", - "@storybook/addon-measure": "8.5.3", - "@storybook/addon-outline": "8.5.3", - "@storybook/addon-toolbars": "8.5.3", - "@storybook/addon-viewport": "8.5.3", + "@storybook/addon-actions": "8.5.2", + "@storybook/addon-backgrounds": "8.5.2", + "@storybook/addon-controls": "8.5.2", + "@storybook/addon-docs": "8.5.2", + "@storybook/addon-highlight": "8.5.2", + "@storybook/addon-measure": "8.5.2", + "@storybook/addon-outline": "8.5.2", + "@storybook/addon-toolbars": "8.5.2", + "@storybook/addon-viewport": "8.5.2", "ts-dedent": "^2.0.0" }, "funding": { @@ -2101,13 +2719,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/addon-highlight": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.5.3.tgz", - "integrity": "sha512-xhsr3W6KTvlOIIe+8JE9/sEOAgkW0yjMZzs47A+bWcxKwcFhAUgVLbAgEzjJ0u248rjGKlCJ2pswWefO+ZKJeg==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.5.2.tgz", + "integrity": "sha512-QjJfY+8e1bi6FeGfVlgxzv/I8DUyC83lZq8zfTY7nDUCVdmKi8VzmW0KgDo5PaEOFKs8x6LKJa+s5O0gFQaJMw==", "dev": true, "license": "MIT", "dependencies": { @@ -2118,19 +2736,19 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/addon-interactions": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/addon-interactions/-/addon-interactions-8.5.3.tgz", - "integrity": "sha512-nQuP65iFGgqfVp/O8NxNDUwLTWmQBW4bofUFaT4wzYn7Jk9zobOZYtgQvdqBZtNzBDYmLrfrCutEBj5jVPRyuQ==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-interactions/-/addon-interactions-8.5.2.tgz", + "integrity": "sha512-Gn9Egk2OS0BkkHd671Y0pIqBr4noAOLUfnpxhHE8r0Tt7FmJFeVSN+dqK7hQeUmKL5jdSY25FTYROg65JmtGOA==", "dev": true, "license": "MIT", "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/instrumenter": "8.5.3", - "@storybook/test": "8.5.3", + "@storybook/instrumenter": "8.5.2", + "@storybook/test": "8.5.2", "polished": "^4.2.2", "ts-dedent": "^2.2.0" }, @@ -2139,13 +2757,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/addon-measure": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.5.3.tgz", - "integrity": "sha512-unb0bRsnISXWiCBBECxNUUdM12hHpV+1uJUu5OJHtKb26YpiQvewDFLTLjuZJ3NIAfw+F5232Q7K88AWJV6weg==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.5.2.tgz", + "integrity": "sha512-g7Kvrx8dqzeYWetpWYVVu4HaRzLAZVlOAlZYNfCH/aJHcFKp/p5zhPXnZh8aorxeCLHW1QSKcliaA4BNPEvTeg==", "dev": true, "license": "MIT", "dependencies": { @@ -2157,13 +2775,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/addon-outline": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.5.3.tgz", - "integrity": "sha512-e1MkGN6XVdeRh2oUKGdqEDyAo2TD/47ashAAxw8DEiLRWgBMbQ+KBVH4EOG+dn5395jxh7YgRLJn/miqNnfN5g==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.5.2.tgz", + "integrity": "sha512-laMVLT1xluSqMa2mMzmS1kdKcjX0HI9Fw+7pM3r4drtGWtxpyBT32YFqKfWFIBhcd364ti2tDUz9FlygGQ1rKw==", "dev": true, "license": "MIT", "dependencies": { @@ -2175,13 +2793,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/addon-toolbars": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.5.3.tgz", - "integrity": "sha512-AWr9Per9WDrbFtNlbVlj6CiEwKOvOyoBt3bCuMHuRfTdqKwkwInEtyUi4//T8U+c1qs7KJBpsWV2vhIuc5sODg==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.5.2.tgz", + "integrity": "sha512-gHQtVCiq7HRqdYQLOmX8nhtV1Lqz4tOCj4BVodwwf8fUcHyNor+2FvGlQjngV2pIeCtxiM/qmG63UpTBp57ZMA==", "dev": true, "license": "MIT", "funding": { @@ -2189,13 +2807,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/addon-viewport": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.5.3.tgz", - "integrity": "sha512-OkLJ2B8+PiOEAd2HtRG6XewVjtw6AkBMgoSbfKCMr6TWSbuKrOeiwIMqqieAAPVNfsOQ8hTK6JGhr/KPRCKgRA==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.5.2.tgz", + "integrity": "sha512-W+7nrMQmxHcUNGsXjmb/fak1mD0a5vf4y1hBhSM7/131t8KBsvEu4ral8LTUhc4ZzuU1eIUM0Qth7SjqHqm5bA==", "dev": true, "license": "MIT", "dependencies": { @@ -2206,13 +2824,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/blocks": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.5.3.tgz", - "integrity": "sha512-a/PpHFmeBtVB9Q/6cNAnqfeCqMowsrI8nGka0Nl7BB3x1eJnS3I1Qo3Skht0LBEsmXOgXk4dwWxpeQL3qHMRkw==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.5.2.tgz", + "integrity": "sha512-C6Bz/YTG5ZuyAzglqgqozYUWaS39j1PnkVuMNots6S3Fp8ZJ6iZOlQ+rpumiuvnbfD5rkEZG+614RWNyNlFy7g==", "dev": true, "license": "MIT", "dependencies": { @@ -2227,7 +2845,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.5.3" + "storybook": "^8.5.2" }, "peerDependenciesMeta": { "react": { @@ -2239,13 +2857,13 @@ } }, "node_modules/@storybook/builder-vite": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-8.5.3.tgz", - "integrity": "sha512-MxriwzZSVidaXj3kpH/jCOJZUdF7ofcvxmvrMrNehH9UvXIGM6b73CBC5ucnptbnQ7qxYKdAZiMhQbPHZ9cqOQ==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-8.5.2.tgz", + "integrity": "sha512-5YWCHmWtZ6oBEqpcGvAmBXVfeX+zssIGWE/UUUnjkmlXO7tHvFccikOLV7/p5VCHH21AbXN8F6mnptEsMPbqqg==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/csf-plugin": "8.5.3", + "@storybook/csf-plugin": "8.5.2", "browser-assert": "^1.2.1", "ts-dedent": "^2.0.0" }, @@ -2254,14 +2872,14 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3", + "storybook": "^8.5.2", "vite": "^4.0.0 || ^5.0.0 || ^6.0.0" } }, "node_modules/@storybook/components": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.5.3.tgz", - "integrity": "sha512-iC9VbpM8Equ8wXI2syBzov+8wys4sGYW7Xfz67LdSVbCMhsH9FRtvgbDppJQC/ZDCofg4sTAHhWpDV/KAQ385A==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.5.2.tgz", + "integrity": "sha512-o5vNN30sGLTJBeGk5SKyekR4RfTpBTGs2LDjXGAmpl2MRhzd62ix8g+KIXSR0rQ55TCvKUl5VR2i99ttlRcEKw==", "dev": true, "license": "MIT", "funding": { @@ -2273,9 +2891,9 @@ } }, "node_modules/@storybook/core": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.5.3.tgz", - "integrity": "sha512-ZLlr2pltbj/hmC54lggJTnh09FCAJR62lIdiXNwa+V+/eJz0CfD8tfGmZGKPSmaQeZBpMwAOeRM97k2oLPF+0w==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.5.2.tgz", + "integrity": "sha512-rCOpXZo2XbdKVnZiv8oC9FId/gLkStpKGGL7hhdg/RyjcyUyTfhsvaf7LXKZH2A0n/UpwFxhF3idRfhgc1XiSg==", "dev": true, "license": "MIT", "dependencies": { @@ -2350,9 +2968,9 @@ } }, "node_modules/@storybook/csf-plugin": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.5.3.tgz", - "integrity": "sha512-u5oyXTFg3KIy4h9qoNyiCG2mJF3OpkLO/AcM4lMAwQVnBvz8pwITvr4jDZByVjGmcIbgKJQnWX+BwdK2NI4yAw==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.5.2.tgz", + "integrity": "sha512-EEQ3Vc9qIUbLH8tunzN/GSoyP3zPpNPKegZooYQbgVqA582Pel4Jnpn4uxGaOWtFCLhXMETV05X/7chGZtEujA==", "dev": true, "license": "MIT", "dependencies": { @@ -2363,7 +2981,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/csf/node_modules/type-fest": { @@ -2401,9 +3019,9 @@ } }, "node_modules/@storybook/instrumenter": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.5.3.tgz", - "integrity": "sha512-pxaTbGeju8MkwouIiaWX5DMWtpRruxqig8W3nZPOvzoSCCbQY+sLMQoyXxFlpGxLBjcvXivkL7AMVBKps5sFEQ==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.5.2.tgz", + "integrity": "sha512-BbaUw9GXVzRg3Km95t2mRu4W6C1n1erjzll5maBaVe2+lV9MbCvBcdYwGUgjFNlQ/ETgq6vLfLOEtziycq/B6g==", "dev": true, "license": "MIT", "dependencies": { @@ -2415,13 +3033,13 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/manager-api": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.5.3.tgz", - "integrity": "sha512-JtfuMgQpKIPU0ARn1jNPce8FmknpM0Ap0mppWl+KGAWWGadJPDaX/nrY/19dT1kRgIhyOnbX6tgJxII4E9dE5w==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.5.2.tgz", + "integrity": "sha512-Cn+oINA6BOO2GmGHinGsOWnEpoBnurlZ9ekMq7H/c1SYMvQWNg5RlELyrhsnyhNd83fqFZy9Asb0RXI8oqz7DQ==", "dev": true, "license": "MIT", "funding": { @@ -2433,9 +3051,9 @@ } }, "node_modules/@storybook/preview-api": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.5.3.tgz", - "integrity": "sha512-dUsuXW+KgDg4tWXOB6dk5j5gwwRUzbPvicHAY9mzbpSVScbWXuE5T/S/9hHlbtfkhFroWQgPx2eB8z3rai+7RQ==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.5.2.tgz", + "integrity": "sha512-AOOaBjwnkFU40Fi68fvAnK0gMWPz6o/AmH44yDGsHgbI07UgqxLBKCTpjCGPlyQd5ezEjmGwwFTmcmq5dG8DKA==", "dev": true, "license": "MIT", "funding": { @@ -2447,18 +3065,18 @@ } }, "node_modules/@storybook/react": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-8.5.3.tgz", - "integrity": "sha512-QIdBSjsnwV/J919i4Fi7DlwxDKHU815t0c4B/w2KTMtKKBkk+Bge+vgVi0/lNqD3eF4w3yjVWGbkzUQZ63yiPg==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-8.5.2.tgz", + "integrity": "sha512-hWzw9ZllfzsaBJdAoEqPQ2GdVNV4c7PkvIWM6z67epaOHqsdsKScbTMe+YAvFMPtLtOO8KblIrtU5PeD4KyMgw==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/components": "8.5.3", + "@storybook/components": "8.5.2", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "8.5.3", - "@storybook/preview-api": "8.5.3", - "@storybook/react-dom-shim": "8.5.3", - "@storybook/theming": "8.5.3" + "@storybook/manager-api": "8.5.2", + "@storybook/preview-api": "8.5.2", + "@storybook/react-dom-shim": "8.5.2", + "@storybook/theming": "8.5.2" }, "engines": { "node": ">=18.0.0" @@ -2468,10 +3086,10 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "@storybook/test": "8.5.3", + "@storybook/test": "8.5.2", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.5.3", + "storybook": "^8.5.2", "typescript": ">= 4.2.x" }, "peerDependenciesMeta": { @@ -2484,9 +3102,9 @@ } }, "node_modules/@storybook/react-dom-shim": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.5.3.tgz", - "integrity": "sha512-kNIGk6mpXW3Wy+uS9pH9b9w/54EPJnH+QXA6MX4EQgmxhMQlGlS/l/YZp+3jsVQW4YgTmqe740qB+ccJAKZxBQ==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.5.2.tgz", + "integrity": "sha512-lt7XoaeWI8iPlWnWzIm/Wam9TpRFhlqP0KZJoKwDyHiCByqkeMrw5MJREyWq626nf34bOW8D6vkuyTzCHGTxKg==", "dev": true, "license": "MIT", "funding": { @@ -2496,20 +3114,20 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/react-vite": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-8.5.3.tgz", - "integrity": "sha512-F30u2Xf+X774wrfQzWgg7vRVJmmJFbBVGdULsAGonkdy1FUeYo7puPiD2Qg6hBYNDyIyxDXVOukkOvTlG7IBRg==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-8.5.2.tgz", + "integrity": "sha512-MHsBuW23Qx6Kc55vwZ3zg6a5rkzReIcEPm38gm3vuf9vuvUsnXgvYRcu8xg3z8GakpsQNSZZJ/1sH48l0XvsSQ==", "dev": true, "license": "MIT", "dependencies": { "@joshwooding/vite-plugin-react-docgen-typescript": "0.4.2", "@rollup/pluginutils": "^5.0.2", - "@storybook/builder-vite": "8.5.3", - "@storybook/react": "8.5.3", + "@storybook/builder-vite": "8.5.2", + "@storybook/react": "8.5.2", "find-up": "^5.0.0", "magic-string": "^0.30.0", "react-docgen": "^7.0.0", @@ -2524,10 +3142,10 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "@storybook/test": "8.5.3", + "@storybook/test": "8.5.2", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.5.3", + "storybook": "^8.5.2", "vite": "^4.0.0 || ^5.0.0 || ^6.0.0" }, "peerDependenciesMeta": { @@ -2537,15 +3155,15 @@ } }, "node_modules/@storybook/test": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.5.3.tgz", - "integrity": "sha512-2smoDbtU6Qh4yk0uD18qGfW6ll7lZBzKlF58Ha1CgWR4o+jpeeTQcfDLH9gG6sNrpojF7AVzMh/aN9BDHD+Chg==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.5.2.tgz", + "integrity": "sha512-F5WfD75m25ZRS19cSxCzHWJ/rH8jWwIjhBlhU+UW+5xjnTS1cJuC1yPT/5Jw0/0Aj9zG1atyfBUYnNHYtsBDYQ==", "dev": true, "license": "MIT", "dependencies": { "@storybook/csf": "0.1.12", "@storybook/global": "^5.0.0", - "@storybook/instrumenter": "8.5.3", + "@storybook/instrumenter": "8.5.2", "@testing-library/dom": "10.4.0", "@testing-library/jest-dom": "6.5.0", "@testing-library/user-event": "14.5.2", @@ -2557,7 +3175,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.5.3" + "storybook": "^8.5.2" } }, "node_modules/@storybook/test/node_modules/@testing-library/jest-dom": { @@ -2617,9 +3235,9 @@ "license": "MIT" }, "node_modules/@storybook/theming": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.5.3.tgz", - "integrity": "sha512-Jvzw+gT1HNarkJo21WZBq5pU89qDN8u/pD3woSh/1c2h5RS6UylWjQHotPFpcBIQiUSrDFtvCU9xugJm4MD0+w==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.5.2.tgz", + "integrity": "sha512-vro8vJx16rIE0UehawEZbxFFA4/VGYS20PMKP6Y6Fpsce0t2/cF/U9qg3jOzVb/XDwfx+ne3/V+8rjfWx8wwJw==", "dev": true, "license": "MIT", "funding": { @@ -2672,6 +3290,22 @@ "@tailwindcss/oxide-win32-x64-msvc": "4.0.0" } }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.0.tgz", + "integrity": "sha512-EAhjU0+FIdyGPR+7MbBWubLLPtmOu+p7c2egTTFBRk/n//zYjNvVK0WhcBK5Y7oUB5mo4EjA2mCbY7dcEMWSRw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@tailwindcss/oxide-darwin-arm64": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.0.tgz", @@ -2688,6 +3322,150 @@ "node": ">= 10" } }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0.tgz", + "integrity": "sha512-+dOUUaXTkPKKhtUI9QtVaYg+MpmLh2CN0dHohiYXaBirEyPMkjaT0zbRgzQlNnQWjCVVXPQluIEb0OMEjSTH+Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.0.tgz", + "integrity": "sha512-CJhGDhxnrmu4SwyC62fA+wP24MhA/TZlIhRHqg1kRuIHoGoVR2uSSm1qxTxU37tSSZj8Up0q6jsBJCAP4k7rgQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.0.tgz", + "integrity": "sha512-Wy7Av0xzXfY2ujZBcYy4+7GQm25/J1iHvlQU2CfwdDCuPWfIjYzR6kggz+uVdSJyKV2s64znchBxRE8kV4uXSA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.0.tgz", + "integrity": "sha512-srwBo2l6pvM0swBntc1ucuhGsfFOLkqPRFQ3dWARRTfSkL1U9nAsob2MKc/n47Eva/W9pZZgMOuf7rDw8pK1Ew==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.0.tgz", + "integrity": "sha512-abhusswkduYWuezkBmgo0K0/erGq3M4Se5xP0fhc/0dKs0X/rJUYYCFWntHb3IGh3aVzdQ0SXJs93P76DbUqtw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.0.tgz", + "integrity": "sha512-hGtRYIUEx377/HlU49+jvVKKwU1MDSKYSMMs0JFO2Wp7LGxk5+0j5+RBk9NFnmp/lbp32yPTgIOO5m1BmDq36A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.0.tgz", + "integrity": "sha512-7xgQgSAThs0I14VAgmxpJnK6XFSZBxHMGoDXkLyYkEnu+8WRQMbCP93dkCUn2PIv+Q+JulRgc00PJ09uORSLXQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.0.tgz", + "integrity": "sha512-qEcgTIPcWY5ZE7f6VxQ/JPrSFMcehzVIlZj7sGE3mVd5YWreAT+Fl1vSP8q2pjnWXn0avZG3Iw7a2hJQAm+fTQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0.tgz", + "integrity": "sha512-bqT0AY8RXb8GMDy28JtngvqaOSB2YixbLPLvUo6I6lkvvUwA6Eqh2Tj60e2Lh7O/k083f8tYiB0WEK4wmTI7Jg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@tailwindcss/vite": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.0.tgz", @@ -3463,9 +4241,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", - "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz", + "integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3489,13 +4267,13 @@ } }, "node_modules/@vitest/utils": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", - "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz", + "integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.1.9", + "@vitest/pretty-format": "2.1.8", "loupe": "^3.1.2", "tinyrainbow": "^1.2.0" }, @@ -8199,6 +8977,186 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.1.tgz", + "integrity": "sha512-k33G9IzKUpHy/J/3+9MCO4e+PzaFblsgBjSGlpAaFikeBFm8B/CkO3cKU9oI4g+fjS2KlkLM/Bza9K/aw8wsNA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.1.tgz", + "integrity": "sha512-0SUW22fv/8kln2LnIdOCmSuXnxgxVC276W5KLTwoehiO0hxkacBxjHOL5EtHD8BAXg2BvuhsJPmVMasvby3LiQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.1.tgz", + "integrity": "sha512-sD32pFvlR0kDlqsOZmYqH/68SqUMPNj+0pucGxToXZi4XZgZmqeX/NkxNKCPsswAXU3UeYgDSpGhu05eAufjDg==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.1.tgz", + "integrity": "sha512-0+vClRIZ6mmJl/dxGuRsE197o1HDEeeRk6nzycSy2GofC2JsY4ifCRnvUWf/CUBQmlrvMzt6SMQNMSEu22csWQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.1.tgz", + "integrity": "sha512-UKMFrG4rL/uHNgelBsDwJcBqVpzNJbzsKkbI3Ja5fg00sgQnHw/VrzUTEc4jhZ+AN2BvQYz/tkHu4vt1kLuJyw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.1.tgz", + "integrity": "sha512-u1S+xdODy/eEtjADqirA774y3jLcm8RPtYztwReEXoZKdzgsHYPl0s5V52Tst+GKzqjebkULT86XMSxejzfISw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.1.tgz", + "integrity": "sha512-L0Tx0DtaNUTzXv0lbGCLB/c/qEADanHbu4QdcNOXLIe1i8i22rZRpbT3gpWYsCh9aSL9zFujY/WmEXIatWvXbw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.1.tgz", + "integrity": "sha512-QoOVnkIEFfbW4xPi+dpdft/zAKmgLgsRHfJalEPYuJDOWf7cLQzYg0DEh8/sn737FaeMJxHZRc1oBreiwZCjog==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.1.tgz", + "integrity": "sha512-NygcbThNBe4JElP+olyTI/doBNGJvLs3bFCRPdvuCcxZCcCZ71B858IHpdm7L1btZex0FvCmM17FK98Y9MRy1Q==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -10398,13 +11356,13 @@ } }, "node_modules/storybook": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.5.3.tgz", - "integrity": "sha512-2WtNBZ45u1AhviRU+U+ld588tH8gDa702dNSq5C8UBaE9PlOsazGsyp90dw1s9YRvi+ejrjKAupQAU0GwwUiVg==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.5.2.tgz", + "integrity": "sha512-pf84emQ7Pd5jBdT2gzlNs4kRaSI3pq0Lh8lSfV+YqIVXztXIHU+Lqyhek2Lhjb7btzA1tExrhJrgQUsIji7i7A==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/core": "8.5.3" + "@storybook/core": "8.5.2" }, "bin": { "getstorybook": "bin/index.cjs", diff --git a/webview-ui/package.json b/webview-ui/package.json index dcb4ffb25e..8229a6aa34 100644 --- a/webview-ui/package.json +++ b/webview-ui/package.json @@ -38,12 +38,12 @@ "vscrui": "^0.2.0" }, "devDependencies": { - "@storybook/addon-essentials": "^8.5.3", - "@storybook/addon-interactions": "^8.5.3", + "@storybook/addon-essentials": "^8.5.2", + "@storybook/addon-interactions": "^8.5.2", "@storybook/blocks": "^8.5.2", - "@storybook/react": "^8.5.3", - "@storybook/react-vite": "^8.5.3", - "@storybook/test": "^8.5.3", + "@storybook/react": "^8.5.2", + "@storybook/react-vite": "^8.5.2", + "@storybook/test": "^8.5.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -65,7 +65,7 @@ "jest": "^27.5.1", "jest-environment-jsdom": "^27.5.1", "jest-simple-dot-reporter": "^1.0.5", - "storybook": "^8.5.3", + "storybook": "^8.5.2", "ts-jest": "^27.1.5", "typescript": "^4.9.5", "vite": "6.0.11" From 684f89c1b14cf2a1cf80a75de378de1f81adc381 Mon Sep 17 00:00:00 2001 From: cte Date: Mon, 3 Feb 2025 12:30:17 -0800 Subject: [PATCH 24/40] Fix typo --- webview-ui/src/index.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webview-ui/src/index.css b/webview-ui/src/index.css index 00decdc3e6..8069ca9195 100644 --- a/webview-ui/src/index.css +++ b/webview-ui/src/index.css @@ -7,7 +7,8 @@ * current UI assumes there's no CSS resetting or normalization. * * We're excluding tailwind's default preflight and importing our own, which - * are based on the original (https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/preflight.css). + * is based on the original: + * https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/preflight.css * * Reference: https://tailwindcss.com/docs/preflight */ From 7e5d78d39826552d75f1b115ea8dfb20bd6bda9c Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Mon, 3 Feb 2025 22:36:11 -0500 Subject: [PATCH 25/40] Update snapshots --- .../prompts/__tests__/__snapshots__/system.test.ts.snap | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap b/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap index 02782416b1..2de14d7fbb 100644 --- a/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap +++ b/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap @@ -3331,7 +3331,7 @@ Example: Requesting to write to frontend-config.json ## execute_command -Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/path +Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/path Parameters: - command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions. Usage: @@ -3549,7 +3549,7 @@ RULES SYSTEM INFORMATION Operating System: Linux -Default Shell: /bin/bash +Default Shell: /bin/zsh Home Directory: /home/user Current Working Directory: /test/path @@ -4376,7 +4376,7 @@ Example: Requesting to write to frontend-config.json ## execute_command -Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/path +Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/path Parameters: - command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions. Usage: @@ -4948,7 +4948,7 @@ RULES SYSTEM INFORMATION Operating System: Linux -Default Shell: /bin/bash +Default Shell: /bin/zsh Home Directory: /home/user Current Working Directory: /test/path From ee2e7193d807d3ced1ffef89b8e0fb68a1add9a4 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Mon, 3 Feb 2025 23:08:18 -0500 Subject: [PATCH 26/40] Fix webview lints --- webview-ui/src/components/chat/ChatRow.tsx | 19 +++++++++++-------- webview-ui/src/components/chat/ChatView.tsx | 11 ++++++++--- .../src/components/welcome/WelcomeView.tsx | 2 +- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 1ec109f930..15b2666280 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -89,7 +89,7 @@ export const ChatRowContent = ({ } }, [isLast, message.say]) const [cost, apiReqCancelReason, apiReqStreamingFailedMessage] = useMemo(() => { - if (message.text != null && message.say === "api_req_started") { + if (message.text !== null && message.text !== undefined && message.say === "api_req_started") { const info: ClineApiReqInfo = JSON.parse(message.text) return [info.cost, info.cancelReason, info.streamingFailedMessage] } @@ -183,26 +183,26 @@ export const ChatRowContent = ({
) return [ - apiReqCancelReason != null ? ( + apiReqCancelReason !== null && apiReqCancelReason !== undefined ? ( apiReqCancelReason === "user_cancelled" ? ( getIconSpan("error", cancelledColor) ) : ( getIconSpan("error", errorColor) ) - ) : cost != null ? ( + ) : cost !== null && cost !== undefined ? ( getIconSpan("check", successColor) ) : apiRequestFailedMessage ? ( getIconSpan("error", errorColor) ) : ( ), - apiReqCancelReason != null ? ( + apiReqCancelReason !== null && apiReqCancelReason !== undefined ? ( apiReqCancelReason === "user_cancelled" ? ( API Request Cancelled ) : ( API Streaming Failed ) - ) : cost != null ? ( + ) : cost !== null && cost !== undefined ? ( API Request ) : apiRequestFailedMessage ? ( API Request Failed @@ -510,7 +510,8 @@ export const ChatRowContent = ({ style={{ ...headerStyle, marginBottom: - (cost == null && apiRequestFailedMessage) || apiReqStreamingFailedMessage + ((cost === null || cost === undefined) && apiRequestFailedMessage) || + apiReqStreamingFailedMessage ? 10 : 0, justifyContent: "space-between", @@ -524,13 +525,15 @@ export const ChatRowContent = ({
{icon} {title} - 0 ? 1 : 0 }}> + 0 ? 1 : 0 }}> ${Number(cost || 0)?.toFixed(4)}
- {((cost == null && apiRequestFailedMessage) || apiReqStreamingFailedMessage) && ( + {(((cost === null || cost === undefined) && apiRequestFailedMessage) || + apiReqStreamingFailedMessage) && ( <>

{apiRequestFailedMessage || apiReqStreamingFailedMessage} diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index d9cbe62453..b1142fd5db 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -275,7 +275,12 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie return true } else { const lastApiReqStarted = findLast(modifiedMessages, (message) => message.say === "api_req_started") - if (lastApiReqStarted && lastApiReqStarted.text != null && lastApiReqStarted.say === "api_req_started") { + if ( + lastApiReqStarted && + lastApiReqStarted.text !== null && + lastApiReqStarted.text !== undefined && + lastApiReqStarted.say === "api_req_started" + ) { const cost = JSON.parse(lastApiReqStarted.text).cost if (cost === undefined) { // api request has not finished yet @@ -718,9 +723,9 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie if (message.say === "api_req_started") { // get last api_req_started in currentGroup to check if it's cancelled. If it is then this api req is not part of the current browser session const lastApiReqStarted = [...currentGroup].reverse().find((m) => m.say === "api_req_started") - if (lastApiReqStarted?.text != null) { + if (lastApiReqStarted?.text !== null && lastApiReqStarted?.text !== undefined) { const info = JSON.parse(lastApiReqStarted.text) - const isCancelled = info.cancelReason != null + const isCancelled = info.cancelReason !== null && info.cancelReason !== undefined if (isCancelled) { endBrowserSession() result.push(message) diff --git a/webview-ui/src/components/welcome/WelcomeView.tsx b/webview-ui/src/components/welcome/WelcomeView.tsx index 3e3bbd7cd1..f8e6f3abdc 100644 --- a/webview-ui/src/components/welcome/WelcomeView.tsx +++ b/webview-ui/src/components/welcome/WelcomeView.tsx @@ -10,7 +10,7 @@ const WelcomeView = () => { const [apiErrorMessage, setApiErrorMessage] = useState(undefined) - const disableLetsGoButton = apiErrorMessage != null + const disableLetsGoButton = apiErrorMessage !== null && apiErrorMessage !== undefined const handleSubmit = () => { vscode.postMessage({ type: "apiConfiguration", apiConfiguration }) From 3d2ba7b361b70b4d36901eb10d1688a025e93781 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Mon, 3 Feb 2025 23:48:22 -0500 Subject: [PATCH 27/40] Code cleanup --- .../src/context/ExtensionStateContext.tsx | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index c7daf643e3..ac9243d572 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -142,23 +142,29 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode }, []) const handleInputChange = useCallback( + // Returns a function that handles an input change event for a specific API configuration field. + // The optional "softUpdate" flag determines whether to immediately update local state or send an external update. (field: keyof ApiConfiguration, softUpdate?: boolean) => (event: any) => { - if (softUpdate === true) { - setState((currentState) => { + // Use the functional form of setState to ensure the latest state is used in the update logic. + setState((currentState) => { + if (softUpdate) { + // Return a new state object with the updated apiConfiguration. + // This will trigger a re-render with the new configuration value. return { ...currentState, apiConfiguration: { ...currentState.apiConfiguration, [field]: event.target.value }, } - }) - return - } - setState((currentState) => { - vscode.postMessage({ - type: "upsertApiConfiguration", - text: currentState.currentApiConfigName, - apiConfiguration: { ...currentState.apiConfiguration, [field]: event.target.value }, - }) - return currentState // No state update needed + } else { + // For non-soft updates, send a message to the VS Code extension with the updated config. + // This side effect communicates the change without updating local React state. + vscode.postMessage({ + type: "upsertApiConfiguration", + text: currentState.currentApiConfigName, + apiConfiguration: { ...currentState.apiConfiguration, [field]: event.target.value }, + }) + // Return the unchanged state as no local state update is intended in this branch. + return currentState + } }) }, [], From 624c449fc1f7c8712122ec73dc155d99ce0bd72d Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 00:31:33 -0500 Subject: [PATCH 28/40] Improve the prompts for Architect and Ask --- .../__snapshots__/system.test.ts.snap | 12 ++++- src/shared/modes.ts | 28 +++++++++-- .../src/components/prompts/PromptsView.tsx | 47 +++++++++++++++---- 3 files changed, 74 insertions(+), 13 deletions(-) diff --git a/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap b/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap index 2de14d7fbb..20eff3ed27 100644 --- a/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap +++ b/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap @@ -3597,7 +3597,7 @@ Mock generic rules" `; exports[`addCustomInstructions should generate correct prompt for architect mode 1`] = ` -"You are Roo, a software architecture expert specializing in analyzing codebases, identifying patterns, and providing high-level technical guidance. You excel at understanding complex systems, evaluating architectural decisions, and suggesting improvements. You can edit markdown documentation files to help document architectural decisions and patterns. +"You are Roo, an experienced technical leader who is inquisitive and an excellent planner. Your goal is to gather information and get context to create a detailed plan for accomplishing the user's task, which the user will review and approve before they switch into another mode to implement the solution. ==== @@ -3898,6 +3898,11 @@ USER'S CUSTOM INSTRUCTIONS The following additional instructions are provided by the user, and should be followed to the best of your ability without interfering with the TOOL USE guidelines. +Mode-specific Instructions: +Depending on the user's request, you may need to do some information gathering (for example using read_file or search_files) to get more context about the task. You may also ask the user clarifying questions to get a better understanding of the task. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. (You can write the plan to a markdown file if it seems appropriate.) + +Then you might ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it. Finally once it seems like you've reached a good plan, use the switch_mode tool to request that the user switch to another mode to implement the solution. + Rules: # Rules from .clinerules-architect: Mock mode-specific rules @@ -3906,7 +3911,7 @@ Mock generic rules" `; exports[`addCustomInstructions should generate correct prompt for ask mode 1`] = ` -"You are Roo, a knowledgeable technical assistant focused on answering questions and providing information about software development, technology, and related topics. You can analyze code, explain concepts, and access external resources. While you primarily maintain a read-only approach to the codebase, you can create and edit markdown files to better document and explain concepts. Make sure to answer the user's questions and don't rush to switch to implementing code. +"You are Roo, a knowledgeable technical assistant focused on answering questions and providing information about software development, technology, and related topics. ==== @@ -4207,6 +4212,9 @@ USER'S CUSTOM INSTRUCTIONS The following additional instructions are provided by the user, and should be followed to the best of your ability without interfering with the TOOL USE guidelines. +Mode-specific Instructions: +You can analyze code, explain concepts, and access external resources. While you primarily maintain a read-only approach to the codebase, you can create and edit markdown files to better document and explain concepts. Make sure to answer the user's questions and don't rush to switch to implementing code. + Rules: # Rules from .clinerules-ask: Mock mode-specific rules diff --git a/src/shared/modes.ts b/src/shared/modes.ts index 3e9b0a32e2..f1b899cc5c 100644 --- a/src/shared/modes.ts +++ b/src/shared/modes.ts @@ -82,15 +82,19 @@ export const modes: readonly ModeConfig[] = [ slug: "architect", name: "Architect", roleDefinition: - "You are Roo, a software architecture expert specializing in analyzing codebases, identifying patterns, and providing high-level technical guidance. You excel at understanding complex systems, evaluating architectural decisions, and suggesting improvements. You can edit markdown documentation files to help document architectural decisions and patterns.", + "You are Roo, an experienced technical leader who is inquisitive and an excellent planner. Your goal is to gather information and get context to create a detailed plan for accomplishing the user's task, which the user will review and approve before they switch into another mode to implement the solution.", groups: ["read", ["edit", { fileRegex: "\\.md$", description: "Markdown files only" }], "browser", "mcp"], + customInstructions: + "Depending on the user's request, you may need to do some information gathering (for example using read_file or search_files) to get more context about the task. You may also ask the user clarifying questions to get a better understanding of the task. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. (You can write the plan to a markdown file if it seems appropriate.)\n\nThen you might ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it. Finally once it seems like you've reached a good plan, use the switch_mode tool to request that the user switch to another mode to implement the solution.", }, { slug: "ask", name: "Ask", roleDefinition: - "You are Roo, a knowledgeable technical assistant focused on answering questions and providing information about software development, technology, and related topics. You can analyze code, explain concepts, and access external resources. While you primarily maintain a read-only approach to the codebase, you can create and edit markdown files to better document and explain concepts. Make sure to answer the user's questions and don't rush to switch to implementing code.", + "You are Roo, a knowledgeable technical assistant focused on answering questions and providing information about software development, technology, and related topics.", groups: ["read", ["edit", { fileRegex: "\\.md$", description: "Markdown files only" }], "browser", "mcp"], + customInstructions: + "You can analyze code, explain concepts, and access external resources. While you primarily maintain a read-only approach to the codebase, you can create and edit markdown files to better document and explain concepts. Make sure to answer the user's questions and don't rush to switch to implementing code.", }, ] as const @@ -223,7 +227,15 @@ export function isToolAllowedForMode( // Create the mode-specific default prompts export const defaultPrompts: Readonly = Object.freeze( - Object.fromEntries(modes.map((mode) => [mode.slug, { roleDefinition: mode.roleDefinition }])), + Object.fromEntries( + modes.map((mode) => [ + mode.slug, + { + roleDefinition: mode.roleDefinition, + customInstructions: mode.customInstructions, + }, + ]), + ), ) // Helper function to safely get role definition @@ -235,3 +247,13 @@ export function getRoleDefinition(modeSlug: string, customModes?: ModeConfig[]): } return mode.roleDefinition } + +// Helper function to safely get custom instructions +export function getCustomInstructions(modeSlug: string, customModes?: ModeConfig[]): string { + const mode = getModeBySlug(modeSlug, customModes) + if (!mode) { + console.warn(`No mode found for slug: ${modeSlug}`) + return "" + } + return mode.customInstructions ?? "" +} diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index e76e5e43ac..caef1cf94e 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -12,6 +12,7 @@ import { Mode, PromptComponent, getRoleDefinition, + getCustomInstructions, getAllModes, ModeConfig, GroupEntry, @@ -272,12 +273,16 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { }) } - const handleAgentReset = (modeSlug: string) => { - // Only reset role definition for built-in modes + const handleAgentReset = (modeSlug: string, type: "roleDefinition" | "customInstructions") => { + // Only reset for built-in modes const existingPrompt = customModePrompts?.[modeSlug] as PromptComponent - updateAgentPrompt(modeSlug, { - ...existingPrompt, - roleDefinition: undefined, + const updatedPrompt = { ...existingPrompt } + delete updatedPrompt[type] // Remove the field entirely to ensure it reloads from defaults + + vscode.postMessage({ + type: "updatePrompt", + promptMode: modeSlug, + customPrompt: updatedPrompt, }) } @@ -554,7 +559,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { onClick={() => { const currentMode = getCurrentMode() if (currentMode?.slug) { - handleAgentReset(currentMode.slug) + handleAgentReset(currentMode.slug, "roleDefinition") } }} title="Reset to default" @@ -749,7 +754,29 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { {/* Role definition for both built-in and custom modes */}

-
Mode-specific Custom Instructions
+
+
Mode-specific Custom Instructions
+ {!findModeBySlug(selectedModeTab, customModes) && ( + { + const currentMode = getCurrentMode() + if (currentMode?.slug) { + handleAgentReset(currentMode.slug, "customInstructions") + } + }} + title="Reset to default" + data-testid="custom-instructions-reset"> + + + )} +
{ value={(() => { const customMode = findModeBySlug(selectedModeTab, customModes) const prompt = customModePrompts?.[selectedModeTab] as PromptComponent - return customMode?.customInstructions ?? prompt?.customInstructions ?? "" + return ( + customMode?.customInstructions ?? + prompt?.customInstructions ?? + getCustomInstructions(selectedModeTab, customModes) + ) })()} onChange={(e) => { const value = From 97128bc144dad2c3203b3d0c23d561454593d8f2 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 01:08:53 -0500 Subject: [PATCH 29/40] Slash commands for switching modes --- src/core/Cline.ts | 46 ++++++++++++++++++++- src/shared/__tests__/modes.test.ts | 64 +++++++++++++++++++++++++++++- src/shared/modes.ts | 33 +++++++++++++++ 3 files changed, 141 insertions(+), 2 deletions(-) diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 39013f0cb4..7595480efd 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -52,7 +52,7 @@ import { parseMentions } from "./mentions" import { AssistantMessageContent, parseAssistantMessage, ToolParamName, ToolUseName } from "./assistant-message" import { formatResponse } from "./prompts/responses" import { SYSTEM_PROMPT } from "./prompts/system" -import { modes, defaultModeSlug, getModeBySlug } from "../shared/modes" +import { modes, defaultModeSlug, getModeBySlug, parseSlashCommand } from "../shared/modes" import { truncateHalfConversation } from "./sliding-window" import { ClineProvider, GlobalFileNames } from "./webview/ClineProvider" import { detectCodeOmission } from "../integrations/editor/detect-omission" @@ -77,6 +77,29 @@ export class Cline { private terminalManager: TerminalManager private urlContentFetcher: UrlContentFetcher private browserSession: BrowserSession + + /** + * Processes a message for slash commands and handles mode switching if needed. + * @param message The message to process + * @returns The processed message with slash command removed if one was present + */ + private async handleSlashCommand(message: string): Promise { + if (!message) return message + + const { customModes } = (await this.providerRef.deref()?.getState()) ?? {} + const slashCommand = parseSlashCommand(message, customModes) + + if (slashCommand) { + // Switch mode before processing the remaining message + const provider = this.providerRef.deref() + if (provider) { + await provider.handleModeSwitch(slashCommand.modeSlug) + return slashCommand.remainingMessage + } + } + + return message + } private didEditFile: boolean = false customInstructions?: string diffStrategy?: DiffStrategy @@ -355,6 +378,11 @@ export class Cline { } async handleWebviewAskResponse(askResponse: ClineAskResponse, text?: string, images?: string[]) { + // Process slash command if present + if (text) { + text = await this.handleSlashCommand(text) + } + this.askResponse = askResponse this.askResponseText = text this.askResponseImages = images @@ -437,6 +465,22 @@ export class Cline { this.apiConversationHistory = [] await this.providerRef.deref()?.postStateToWebview() + // Check for slash command if task is provided + if (task) { + const { customModes } = (await this.providerRef.deref()?.getState()) ?? {} + const slashCommand = parseSlashCommand(task, customModes) + + if (slashCommand) { + // Switch mode before processing the remaining message + const provider = this.providerRef.deref() + if (provider) { + await provider.handleModeSwitch(slashCommand.modeSlug) + // Update task to be just the remaining message + task = slashCommand.remainingMessage + } + } + } + await this.say("text", task, images) let imageBlocks: Anthropic.ImageBlockParam[] = formatResponse.imageBlocks(images) diff --git a/src/shared/__tests__/modes.test.ts b/src/shared/__tests__/modes.test.ts index 44d237630c..e373bc20ca 100644 --- a/src/shared/__tests__/modes.test.ts +++ b/src/shared/__tests__/modes.test.ts @@ -1,4 +1,4 @@ -import { isToolAllowedForMode, FileRestrictionError, ModeConfig } from "../modes" +import { isToolAllowedForMode, FileRestrictionError, ModeConfig, parseSlashCommand } from "../modes" describe("isToolAllowedForMode", () => { const customModes: ModeConfig[] = [ @@ -332,3 +332,65 @@ describe("FileRestrictionError", () => { expect(error.name).toBe("FileRestrictionError") }) }) + +describe("parseSlashCommand", () => { + const customModes: ModeConfig[] = [ + { + slug: "custom-mode", + name: "Custom Mode", + roleDefinition: "Custom role", + groups: ["read"], + }, + ] + + it("returns null for non-slash messages", () => { + expect(parseSlashCommand("hello world")).toBeNull() + expect(parseSlashCommand("code help me")).toBeNull() + }) + + it("returns null for incomplete commands", () => { + expect(parseSlashCommand("/")).toBeNull() + expect(parseSlashCommand("/code")).toBeNull() + expect(parseSlashCommand("/code ")).toBeNull() + }) + + it("returns null for invalid mode slugs", () => { + expect(parseSlashCommand("/invalid help me")).toBeNull() + expect(parseSlashCommand("/nonexistent do something")).toBeNull() + }) + + it("successfully parses valid commands", () => { + expect(parseSlashCommand("/code help me write tests")).toEqual({ + modeSlug: "code", + remainingMessage: "help me write tests", + }) + + expect(parseSlashCommand("/ask what is typescript?")).toEqual({ + modeSlug: "ask", + remainingMessage: "what is typescript?", + }) + + expect(parseSlashCommand("/architect plan this feature")).toEqual({ + modeSlug: "architect", + remainingMessage: "plan this feature", + }) + }) + + it("preserves whitespace in remaining message", () => { + expect(parseSlashCommand("/code help me write tests ")).toEqual({ + modeSlug: "code", + remainingMessage: "help me write tests", + }) + }) + + it("handles custom modes", () => { + expect(parseSlashCommand("/custom-mode do something", customModes)).toEqual({ + modeSlug: "custom-mode", + remainingMessage: "do something", + }) + }) + + it("returns null for invalid custom mode slugs", () => { + expect(parseSlashCommand("/invalid-custom do something", customModes)).toBeNull() + }) +}) diff --git a/src/shared/modes.ts b/src/shared/modes.ts index f1b899cc5c..bf4735e3f7 100644 --- a/src/shared/modes.ts +++ b/src/shared/modes.ts @@ -257,3 +257,36 @@ export function getCustomInstructions(modeSlug: string, customModes?: ModeConfig } return mode.customInstructions ?? "" } + +// Slash command parsing types and functions +export type SlashCommandResult = { + modeSlug: string + remainingMessage: string +} | null + +export function parseSlashCommand(message: string, customModes?: ModeConfig[]): SlashCommandResult { + // Check if message starts with a slash + if (!message.startsWith("/")) { + return null + } + + // Extract command (everything between / and first space) + const parts = message.trim().split(/\s+/) + if (parts.length < 2) { + return null // Need both command and message + } + + const command = parts[0].substring(1) // Remove leading slash + const remainingMessage = parts.slice(1).join(" ") + + // Validate command is a valid mode slug + const mode = getModeBySlug(command, customModes) + if (!mode) { + return null + } + + return { + modeSlug: command, + remainingMessage, + } +} From 11fc6da3927c68b74b041da8e4fc563a30ca8164 Mon Sep 17 00:00:00 2001 From: cte Date: Tue, 4 Feb 2025 08:27:05 -0800 Subject: [PATCH 30/40] VSCode styling for shadcn/ui + expose `container` prop in dropdown portals --- webview-ui/src/components/ui/button.tsx | 10 +++++----- webview-ui/src/components/ui/dropdown-menu.tsx | 10 ++++++---- webview-ui/src/index.css | 9 +++++++-- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/webview-ui/src/components/ui/button.tsx b/webview-ui/src/components/ui/button.tsx index 5bd00336b9..370ff4a19f 100644 --- a/webview-ui/src/components/ui/button.tsx +++ b/webview-ui/src/components/ui/button.tsx @@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer active:opacity-90", { variants: { variant: { @@ -17,10 +17,10 @@ const buttonVariants = cva( link: "text-primary underline-offset-4 hover:underline", }, size: { - default: "h-9 px-4 py-2", - sm: "h-8 rounded-md px-3 text-xs", - lg: "h-10 rounded-md px-8", - icon: "h-9 w-9", + default: "h-7 px-3", + sm: "h-6 px-2 text-sm", + lg: "h-8 px-4 text-lg", + icon: "h-7 w-7", }, }, defaultVariants: { diff --git a/webview-ui/src/components/ui/dropdown-menu.tsx b/webview-ui/src/components/ui/dropdown-menu.tsx index 8508b55deb..098090fb31 100644 --- a/webview-ui/src/components/ui/dropdown-menu.tsx +++ b/webview-ui/src/components/ui/dropdown-menu.tsx @@ -53,9 +53,11 @@ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayNam const DropdownMenuContent = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( - + React.ComponentPropsWithoutRef & { + container?: HTMLElement + } +>(({ className, sideOffset = 4, container, ...props }, ref) => ( + svg]:size-4 [&>svg]:shrink-0", + "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0 active:opacity-90", inset && "pl-8", className, )} diff --git a/webview-ui/src/index.css b/webview-ui/src/index.css index 8069ca9195..194f421684 100644 --- a/webview-ui/src/index.css +++ b/webview-ui/src/index.css @@ -22,6 +22,11 @@ @plugin "tailwindcss-animate"; @theme { + --font-display: var(--vscode-font-family); + --text-sm: calc(var(--vscode-font-size) * 0.9); + --text-base: var(--vscode-font-size); + --text-lg: calc(var(--vscode-font-size) * 1.1); + --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); @@ -65,11 +70,11 @@ --secondary-foreground: var(--vscode-button-secondaryForeground); --muted: var(--vscode-disabledForeground); --muted-foreground: var(--vscode-descriptionForeground); - --accent: var(--vscode-input-border); + --accent: var(--vscode-list-hoverBackground); --accent-foreground: var(--vscode-button-foreground); --destructive: var(--vscode-errorForeground); --destructive-foreground: var(--vscode-button-foreground); - --border: var(--vscode-widget-border); + --border: var(--vscode-input-border); --input: var(--vscode-input-background); --ring: var(--vscode-input-border); --chart-1: var(--vscode-charts-red); From 14975311f50f40ecdd8e2d2d1d3ef79fed7c3717 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 13:29:47 -0500 Subject: [PATCH 31/40] v3.3.10 --- .changeset/nine-tables-cheat.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nine-tables-cheat.md diff --git a/.changeset/nine-tables-cheat.md b/.changeset/nine-tables-cheat.md new file mode 100644 index 0000000000..7e48c235bf --- /dev/null +++ b/.changeset/nine-tables-cheat.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +v3.3.10 From 1f3b07d62741c44eebf76d1b5f76f9aac37aeb07 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Feb 2025 02:52:52 +0000 Subject: [PATCH 32/40] changeset version bump --- .changeset/blue-masks-camp.md | 5 ----- .changeset/breezy-badgers-refuse.md | 5 ----- .changeset/nine-tables-cheat.md | 5 ----- CHANGELOG.md | 8 ++++++++ package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 11 insertions(+), 18 deletions(-) delete mode 100644 .changeset/blue-masks-camp.md delete mode 100644 .changeset/breezy-badgers-refuse.md delete mode 100644 .changeset/nine-tables-cheat.md diff --git a/.changeset/blue-masks-camp.md b/.changeset/blue-masks-camp.md deleted file mode 100644 index a67e1c4d53..0000000000 --- a/.changeset/blue-masks-camp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -Add shortcuts to the currently open tabs in the "Add File" section of @-mentions (thanks @olup!) diff --git a/.changeset/breezy-badgers-refuse.md b/.changeset/breezy-badgers-refuse.md deleted file mode 100644 index 50cbbe9262..0000000000 --- a/.changeset/breezy-badgers-refuse.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -Visual cleanup to the list of modes on the prompts tab diff --git a/.changeset/nine-tables-cheat.md b/.changeset/nine-tables-cheat.md deleted file mode 100644 index 7e48c235bf..0000000000 --- a/.changeset/nine-tables-cheat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -v3.3.10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fd17bd2b9..2ad73d058e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Roo Code Changelog +## 3.3.10 + +### Patch Changes + +- Add shortcuts to the currently open tabs in the "Add File" section of @-mentions (thanks @olup!) +- Visual cleanup to the list of modes on the prompts tab +- v3.3.10 + ## [3.3.9] - Add o3-mini-high and o3-mini-low diff --git a/package-lock.json b/package-lock.json index eecc0e681e..2c518b330e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "roo-cline", - "version": "3.3.9", + "version": "3.3.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "roo-cline", - "version": "3.3.9", + "version": "3.3.10", "dependencies": { "@anthropic-ai/bedrock-sdk": "^0.10.2", "@anthropic-ai/sdk": "^0.26.0", diff --git a/package.json b/package.json index a95ace9ee3..80528fdfd0 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Roo Code (prev. Roo Cline)", "description": "A VS Code plugin that enhances coding with AI-powered automation, multi-model support, and experimental features.", "publisher": "RooVeterinaryInc", - "version": "3.3.9", + "version": "3.3.10", "icon": "assets/icons/rocket.png", "galleryBanner": { "color": "#617A91", From 92cd81d66bd7b488095761fb5c1f7d3cd6dec255 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 22:22:03 -0500 Subject: [PATCH 33/40] Update CHANGELOG.md --- CHANGELOG.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ad73d058e..983d2bfac4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,19 @@ # Roo Code Changelog -## 3.3.10 - -### Patch Changes +## [3.3.10] - Add shortcuts to the currently open tabs in the "Add File" section of @-mentions (thanks @olup!) +- Fix pricing for o1-mini (thanks @hesara!) +- Fix context window size calculation (thanks @MuriloFP!) +- Improvements to experimental unified diff strategy and selection logic in code actions (thanks @nissa-seru!) +- Enable markdown formatting in o3 and o1 (thanks @nissa-seru!) +- Improved terminal shell detection logic (thanks @canvrno for the original and @nissa-seru for the port!) +- Fix occasional errors when switching between API profiles (thanks @samhvw8!) +- Visual improvements to the list of modes on the prompts tab +- Fix double-scrollbar in provider dropdown - Visual cleanup to the list of modes on the prompts tab -- v3.3.10 +- Improvements to the default prompts for Architect and Ask mode +- Allow switching between modes with slash messages like `/ask why is the sky blue?` ## [3.3.9] From 111020bb507abcea40c7cccc23d7592a4df03249 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 23:14:57 -0500 Subject: [PATCH 34/40] Removing docs (moving to another repo) --- .github/workflows/pages.yml | 44 ----- docs/Gemfile | 2 - docs/Gemfile.lock | 308 ---------------------------------- docs/_config.yml | 15 -- docs/getting-started/index.md | 10 -- docs/index.md | 9 - 6 files changed, 388 deletions(-) delete mode 100644 .github/workflows/pages.yml delete mode 100644 docs/Gemfile delete mode 100644 docs/Gemfile.lock delete mode 100644 docs/_config.yml delete mode 100644 docs/getting-started/index.md delete mode 100644 docs/index.md diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml deleted file mode 100644 index ac551ebc85..0000000000 --- a/.github/workflows/pages.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Deploy Jekyll site to Pages - -on: - push: - branches: ["main"] - workflow_dispatch: - -permissions: - contents: read - pages: write - id-token: write - -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - # Build job - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Setup Pages - uses: actions/configure-pages@v5 - - name: Build with Jekyll - uses: actions/jekyll-build-pages@v1 - with: - source: ./docs/ - destination: ./_site - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - - # Deployment job - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 diff --git a/docs/Gemfile b/docs/Gemfile deleted file mode 100644 index 91ceacd3cb..0000000000 --- a/docs/Gemfile +++ /dev/null @@ -1,2 +0,0 @@ -source 'https://rubygems.org' -gem 'github-pages', group: :jekyll_plugins \ No newline at end of file diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock deleted file mode 100644 index a08fc8bb22..0000000000 --- a/docs/Gemfile.lock +++ /dev/null @@ -1,308 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - activesupport (8.0.1) - base64 - benchmark (>= 0.3) - bigdecimal - concurrent-ruby (~> 1.0, >= 1.3.1) - connection_pool (>= 2.2.5) - drb - i18n (>= 1.6, < 2) - logger (>= 1.4.2) - minitest (>= 5.1) - securerandom (>= 0.3) - tzinfo (~> 2.0, >= 2.0.5) - uri (>= 0.13.1) - addressable (2.8.7) - public_suffix (>= 2.0.2, < 7.0) - base64 (0.2.0) - benchmark (0.4.0) - bigdecimal (3.1.9) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.12.2) - colorator (1.1.0) - commonmarker (0.23.11) - concurrent-ruby (1.3.5) - connection_pool (2.5.0) - csv (3.3.2) - dnsruby (1.72.3) - base64 (~> 0.2.0) - simpleidn (~> 0.2.1) - drb (2.2.1) - em-websocket (0.5.3) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0) - ethon (0.16.0) - ffi (>= 1.15.0) - eventmachine (1.2.7) - execjs (2.10.0) - faraday (2.12.2) - faraday-net_http (>= 2.0, < 3.5) - json - logger - faraday-net_http (3.4.0) - net-http (>= 0.5.0) - ffi (1.17.1-aarch64-linux-gnu) - ffi (1.17.1-aarch64-linux-musl) - ffi (1.17.1-arm-linux-gnu) - ffi (1.17.1-arm-linux-musl) - ffi (1.17.1-arm64-darwin) - ffi (1.17.1-x86_64-darwin) - ffi (1.17.1-x86_64-linux-gnu) - ffi (1.17.1-x86_64-linux-musl) - forwardable-extended (2.6.0) - gemoji (4.1.0) - github-pages (232) - github-pages-health-check (= 1.18.2) - jekyll (= 3.10.0) - jekyll-avatar (= 0.8.0) - jekyll-coffeescript (= 1.2.2) - jekyll-commonmark-ghpages (= 0.5.1) - jekyll-default-layout (= 0.1.5) - jekyll-feed (= 0.17.0) - jekyll-gist (= 1.5.0) - jekyll-github-metadata (= 2.16.1) - jekyll-include-cache (= 0.2.1) - jekyll-mentions (= 1.6.0) - jekyll-optional-front-matter (= 0.3.2) - jekyll-paginate (= 1.1.0) - jekyll-readme-index (= 0.3.0) - jekyll-redirect-from (= 0.16.0) - jekyll-relative-links (= 0.6.1) - jekyll-remote-theme (= 0.4.3) - jekyll-sass-converter (= 1.5.2) - jekyll-seo-tag (= 2.8.0) - jekyll-sitemap (= 1.4.0) - jekyll-swiss (= 1.0.0) - jekyll-theme-architect (= 0.2.0) - jekyll-theme-cayman (= 0.2.0) - jekyll-theme-dinky (= 0.2.0) - jekyll-theme-hacker (= 0.2.0) - jekyll-theme-leap-day (= 0.2.0) - jekyll-theme-merlot (= 0.2.0) - jekyll-theme-midnight (= 0.2.0) - jekyll-theme-minimal (= 0.2.0) - jekyll-theme-modernist (= 0.2.0) - jekyll-theme-primer (= 0.6.0) - jekyll-theme-slate (= 0.2.0) - jekyll-theme-tactile (= 0.2.0) - jekyll-theme-time-machine (= 0.2.0) - jekyll-titles-from-headings (= 0.5.3) - jemoji (= 0.13.0) - kramdown (= 2.4.0) - kramdown-parser-gfm (= 1.1.0) - liquid (= 4.0.4) - mercenary (~> 0.3) - minima (= 2.5.1) - nokogiri (>= 1.16.2, < 2.0) - rouge (= 3.30.0) - terminal-table (~> 1.4) - webrick (~> 1.8) - github-pages-health-check (1.18.2) - addressable (~> 2.3) - dnsruby (~> 1.60) - octokit (>= 4, < 8) - public_suffix (>= 3.0, < 6.0) - typhoeus (~> 1.3) - html-pipeline (2.14.3) - activesupport (>= 2) - nokogiri (>= 1.4) - http_parser.rb (0.8.0) - i18n (1.14.7) - concurrent-ruby (~> 1.0) - jekyll (3.10.0) - addressable (~> 2.4) - colorator (~> 1.0) - csv (~> 3.0) - em-websocket (~> 0.5) - i18n (>= 0.7, < 2) - jekyll-sass-converter (~> 1.0) - jekyll-watch (~> 2.0) - kramdown (>= 1.17, < 3) - liquid (~> 4.0) - mercenary (~> 0.3.3) - pathutil (~> 0.9) - rouge (>= 1.7, < 4) - safe_yaml (~> 1.0) - webrick (>= 1.0) - jekyll-avatar (0.8.0) - jekyll (>= 3.0, < 5.0) - jekyll-coffeescript (1.2.2) - coffee-script (~> 2.2) - coffee-script-source (~> 1.12) - jekyll-commonmark (1.4.0) - commonmarker (~> 0.22) - jekyll-commonmark-ghpages (0.5.1) - commonmarker (>= 0.23.7, < 1.1.0) - jekyll (>= 3.9, < 4.0) - jekyll-commonmark (~> 1.4.0) - rouge (>= 2.0, < 5.0) - jekyll-default-layout (0.1.5) - jekyll (>= 3.0, < 5.0) - jekyll-feed (0.17.0) - jekyll (>= 3.7, < 5.0) - jekyll-gist (1.5.0) - octokit (~> 4.2) - jekyll-github-metadata (2.16.1) - jekyll (>= 3.4, < 5.0) - octokit (>= 4, < 7, != 4.4.0) - jekyll-include-cache (0.2.1) - jekyll (>= 3.7, < 5.0) - jekyll-mentions (1.6.0) - html-pipeline (~> 2.3) - jekyll (>= 3.7, < 5.0) - jekyll-optional-front-matter (0.3.2) - jekyll (>= 3.0, < 5.0) - jekyll-paginate (1.1.0) - jekyll-readme-index (0.3.0) - jekyll (>= 3.0, < 5.0) - jekyll-redirect-from (0.16.0) - jekyll (>= 3.3, < 5.0) - jekyll-relative-links (0.6.1) - jekyll (>= 3.3, < 5.0) - jekyll-remote-theme (0.4.3) - addressable (~> 2.0) - jekyll (>= 3.5, < 5.0) - jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) - rubyzip (>= 1.3.0, < 3.0) - jekyll-sass-converter (1.5.2) - sass (~> 3.4) - jekyll-seo-tag (2.8.0) - jekyll (>= 3.8, < 5.0) - jekyll-sitemap (1.4.0) - jekyll (>= 3.7, < 5.0) - jekyll-swiss (1.0.0) - jekyll-theme-architect (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-cayman (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-dinky (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-hacker (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-leap-day (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-merlot (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-midnight (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-minimal (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-modernist (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-primer (0.6.0) - jekyll (> 3.5, < 5.0) - jekyll-github-metadata (~> 2.9) - jekyll-seo-tag (~> 2.0) - jekyll-theme-slate (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-tactile (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-time-machine (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-titles-from-headings (0.5.3) - jekyll (>= 3.3, < 5.0) - jekyll-watch (2.2.1) - listen (~> 3.0) - jemoji (0.13.0) - gemoji (>= 3, < 5) - html-pipeline (~> 2.2) - jekyll (>= 3.0, < 5.0) - json (2.9.1) - kramdown (2.4.0) - rexml - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - liquid (4.0.4) - listen (3.9.0) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - logger (1.6.5) - mercenary (0.3.6) - minima (2.5.1) - jekyll (>= 3.5, < 5.0) - jekyll-feed (~> 0.9) - jekyll-seo-tag (~> 2.1) - minitest (5.25.4) - net-http (0.6.0) - uri - nokogiri (1.18.2-aarch64-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.2-aarch64-linux-musl) - racc (~> 1.4) - nokogiri (1.18.2-arm-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.2-arm-linux-musl) - racc (~> 1.4) - nokogiri (1.18.2-arm64-darwin) - racc (~> 1.4) - nokogiri (1.18.2-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.18.2-x86_64-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.2-x86_64-linux-musl) - racc (~> 1.4) - octokit (4.25.1) - faraday (>= 1, < 3) - sawyer (~> 0.9) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (5.1.1) - racc (1.8.1) - rb-fsevent (0.11.2) - rb-inotify (0.11.1) - ffi (~> 1.0) - rexml (3.4.0) - rouge (3.30.0) - rubyzip (2.4.1) - safe_yaml (1.0.5) - sass (3.7.4) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - sawyer (0.9.2) - addressable (>= 2.3.5) - faraday (>= 0.17.3, < 3) - securerandom (0.4.1) - simpleidn (0.2.3) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - typhoeus (1.4.1) - ethon (>= 0.9.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unicode-display_width (1.8.0) - uri (1.0.2) - webrick (1.9.1) - -PLATFORMS - aarch64-linux-gnu - aarch64-linux-musl - arm-linux-gnu - arm-linux-musl - arm64-darwin - x86_64-darwin - x86_64-linux-gnu - x86_64-linux-musl - -DEPENDENCIES - github-pages - -BUNDLED WITH - 2.5.18 diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index 8d2cfe4a38..0000000000 --- a/docs/_config.yml +++ /dev/null @@ -1,15 +0,0 @@ -title: Roo Code Documentation -description: Documentation for the Roo Code project -remote_theme: just-the-docs/just-the-docs - -url: https://docs.roocode.com - -aux_links: - "Roo Code on GitHub": - - "//github.com/RooVetGit/Roo-Code" - -# Enable search -search_enabled: true - -# Enable dark mode -color_scheme: dark diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md deleted file mode 100644 index 9b0f385436..0000000000 --- a/docs/getting-started/index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Getting Started -layout: default -nav_order: 2 -has_children: true ---- - -# Getting Started with Roo Code - -This section will help you get up and running with Roo Code quickly. diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 0cf6022436..0000000000 --- a/docs/index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Home -layout: home -nav_order: 1 ---- - -# Welcome to Roo Code Documentation - -This is the documentation for Roo Code. Choose a section from the navigation menu to get started. From d145039d72e97af81ba6d6ba9e26a242576f99e0 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 23:55:16 -0500 Subject: [PATCH 35/40] Safer profile path check --- .changeset/heavy-feet-judge.md | 5 +++++ src/utils/__tests__/shell.test.ts | 6 ++++++ src/utils/shell.ts | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .changeset/heavy-feet-judge.md diff --git a/.changeset/heavy-feet-judge.md b/.changeset/heavy-feet-judge.md new file mode 100644 index 0000000000..b9b3ca0f7b --- /dev/null +++ b/.changeset/heavy-feet-judge.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +Safer shell profile path check diff --git a/src/utils/__tests__/shell.test.ts b/src/utils/__tests__/shell.test.ts index dee997a752..9c2b23aaa5 100644 --- a/src/utils/__tests__/shell.test.ts +++ b/src/utils/__tests__/shell.test.ts @@ -97,6 +97,12 @@ describe("Shell Detection Tests", () => { expect(getShell()).toBe("C:\\Windows\\System32\\cmd.exe") }) + it("handles undefined profile gracefully", () => { + // Mock a case where defaultProfileName exists but the profile doesn't + mockVsCodeConfig("windows", "NonexistentProfile", {}) + expect(getShell()).toBe("C:\\Windows\\System32\\cmd.exe") + }) + it("respects userInfo() if no VS Code config is available", () => { vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any ;(userInfo as any) = () => ({ shell: "C:\\Custom\\PowerShell.exe" }) diff --git a/src/utils/shell.ts b/src/utils/shell.ts index 8871550a0e..2f7ffb3a88 100644 --- a/src/utils/shell.ts +++ b/src/utils/shell.ts @@ -105,7 +105,7 @@ function getWindowsShellFromVSCode(): string | null { } // If there's a specific path, return that immediately - if (profile.path) { + if (profile?.path) { return profile.path } From 5297cad5e2f41f34e9add80f240dde5bda783a48 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 10:07:12 -0500 Subject: [PATCH 36/40] Revert "Merge pull request #764 from RooVetGit/slash_switch_modes" This reverts commit e3d7f25d262f0772b32d691012b6b140f597485e, reversing changes made to 55e8170369ddee3411ea85c76ff86f4b8b3bcf2b. --- src/core/Cline.ts | 46 +-------------------- src/shared/__tests__/modes.test.ts | 64 +----------------------------- src/shared/modes.ts | 33 --------------- 3 files changed, 2 insertions(+), 141 deletions(-) diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 7595480efd..39013f0cb4 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -52,7 +52,7 @@ import { parseMentions } from "./mentions" import { AssistantMessageContent, parseAssistantMessage, ToolParamName, ToolUseName } from "./assistant-message" import { formatResponse } from "./prompts/responses" import { SYSTEM_PROMPT } from "./prompts/system" -import { modes, defaultModeSlug, getModeBySlug, parseSlashCommand } from "../shared/modes" +import { modes, defaultModeSlug, getModeBySlug } from "../shared/modes" import { truncateHalfConversation } from "./sliding-window" import { ClineProvider, GlobalFileNames } from "./webview/ClineProvider" import { detectCodeOmission } from "../integrations/editor/detect-omission" @@ -77,29 +77,6 @@ export class Cline { private terminalManager: TerminalManager private urlContentFetcher: UrlContentFetcher private browserSession: BrowserSession - - /** - * Processes a message for slash commands and handles mode switching if needed. - * @param message The message to process - * @returns The processed message with slash command removed if one was present - */ - private async handleSlashCommand(message: string): Promise { - if (!message) return message - - const { customModes } = (await this.providerRef.deref()?.getState()) ?? {} - const slashCommand = parseSlashCommand(message, customModes) - - if (slashCommand) { - // Switch mode before processing the remaining message - const provider = this.providerRef.deref() - if (provider) { - await provider.handleModeSwitch(slashCommand.modeSlug) - return slashCommand.remainingMessage - } - } - - return message - } private didEditFile: boolean = false customInstructions?: string diffStrategy?: DiffStrategy @@ -378,11 +355,6 @@ export class Cline { } async handleWebviewAskResponse(askResponse: ClineAskResponse, text?: string, images?: string[]) { - // Process slash command if present - if (text) { - text = await this.handleSlashCommand(text) - } - this.askResponse = askResponse this.askResponseText = text this.askResponseImages = images @@ -465,22 +437,6 @@ export class Cline { this.apiConversationHistory = [] await this.providerRef.deref()?.postStateToWebview() - // Check for slash command if task is provided - if (task) { - const { customModes } = (await this.providerRef.deref()?.getState()) ?? {} - const slashCommand = parseSlashCommand(task, customModes) - - if (slashCommand) { - // Switch mode before processing the remaining message - const provider = this.providerRef.deref() - if (provider) { - await provider.handleModeSwitch(slashCommand.modeSlug) - // Update task to be just the remaining message - task = slashCommand.remainingMessage - } - } - } - await this.say("text", task, images) let imageBlocks: Anthropic.ImageBlockParam[] = formatResponse.imageBlocks(images) diff --git a/src/shared/__tests__/modes.test.ts b/src/shared/__tests__/modes.test.ts index e373bc20ca..44d237630c 100644 --- a/src/shared/__tests__/modes.test.ts +++ b/src/shared/__tests__/modes.test.ts @@ -1,4 +1,4 @@ -import { isToolAllowedForMode, FileRestrictionError, ModeConfig, parseSlashCommand } from "../modes" +import { isToolAllowedForMode, FileRestrictionError, ModeConfig } from "../modes" describe("isToolAllowedForMode", () => { const customModes: ModeConfig[] = [ @@ -332,65 +332,3 @@ describe("FileRestrictionError", () => { expect(error.name).toBe("FileRestrictionError") }) }) - -describe("parseSlashCommand", () => { - const customModes: ModeConfig[] = [ - { - slug: "custom-mode", - name: "Custom Mode", - roleDefinition: "Custom role", - groups: ["read"], - }, - ] - - it("returns null for non-slash messages", () => { - expect(parseSlashCommand("hello world")).toBeNull() - expect(parseSlashCommand("code help me")).toBeNull() - }) - - it("returns null for incomplete commands", () => { - expect(parseSlashCommand("/")).toBeNull() - expect(parseSlashCommand("/code")).toBeNull() - expect(parseSlashCommand("/code ")).toBeNull() - }) - - it("returns null for invalid mode slugs", () => { - expect(parseSlashCommand("/invalid help me")).toBeNull() - expect(parseSlashCommand("/nonexistent do something")).toBeNull() - }) - - it("successfully parses valid commands", () => { - expect(parseSlashCommand("/code help me write tests")).toEqual({ - modeSlug: "code", - remainingMessage: "help me write tests", - }) - - expect(parseSlashCommand("/ask what is typescript?")).toEqual({ - modeSlug: "ask", - remainingMessage: "what is typescript?", - }) - - expect(parseSlashCommand("/architect plan this feature")).toEqual({ - modeSlug: "architect", - remainingMessage: "plan this feature", - }) - }) - - it("preserves whitespace in remaining message", () => { - expect(parseSlashCommand("/code help me write tests ")).toEqual({ - modeSlug: "code", - remainingMessage: "help me write tests", - }) - }) - - it("handles custom modes", () => { - expect(parseSlashCommand("/custom-mode do something", customModes)).toEqual({ - modeSlug: "custom-mode", - remainingMessage: "do something", - }) - }) - - it("returns null for invalid custom mode slugs", () => { - expect(parseSlashCommand("/invalid-custom do something", customModes)).toBeNull() - }) -}) diff --git a/src/shared/modes.ts b/src/shared/modes.ts index bf4735e3f7..f1b899cc5c 100644 --- a/src/shared/modes.ts +++ b/src/shared/modes.ts @@ -257,36 +257,3 @@ export function getCustomInstructions(modeSlug: string, customModes?: ModeConfig } return mode.customInstructions ?? "" } - -// Slash command parsing types and functions -export type SlashCommandResult = { - modeSlug: string - remainingMessage: string -} | null - -export function parseSlashCommand(message: string, customModes?: ModeConfig[]): SlashCommandResult { - // Check if message starts with a slash - if (!message.startsWith("/")) { - return null - } - - // Extract command (everything between / and first space) - const parts = message.trim().split(/\s+/) - if (parts.length < 2) { - return null // Need both command and message - } - - const command = parts[0].substring(1) // Remove leading slash - const remainingMessage = parts.slice(1).join(" ") - - // Validate command is a valid mode slug - const mode = getModeBySlug(command, customModes) - if (!mode) { - return null - } - - return { - modeSlug: command, - remainingMessage, - } -} From ebd9084e56a621470302764e44cc6d1f28a83847 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 10:07:38 -0500 Subject: [PATCH 37/40] Use autocomplete instead for switching modes --- .../src/components/chat/ChatTextArea.tsx | 48 ++++++++++++++---- webview-ui/src/components/chat/ChatView.tsx | 2 +- .../src/components/chat/ContextMenu.tsx | 48 ++++++++++++++---- webview-ui/src/utils/context-mentions.ts | 50 +++++++++++++++++++ 4 files changed, 127 insertions(+), 21 deletions(-) diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index a20922db54..ae1b342dfe 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -179,6 +179,18 @@ const ChatTextArea = forwardRef( return } + if (type === ContextMenuOptionType.Mode && value) { + // Handle mode selection + setMode(value) + setInputValue("") + setShowContextMenu(false) + vscode.postMessage({ + type: "mode", + text: value, + }) + return + } + if ( type === ContextMenuOptionType.File || type === ContextMenuOptionType.Folder || @@ -242,7 +254,12 @@ const ChatTextArea = forwardRef( event.preventDefault() setSelectedMenuIndex((prevIndex) => { const direction = event.key === "ArrowUp" ? -1 : 1 - const options = getContextMenuOptions(searchQuery, selectedType, queryItems) + const options = getContextMenuOptions( + searchQuery, + selectedType, + queryItems, + getAllModes(customModes), + ) const optionsLength = options.length if (optionsLength === 0) return prevIndex @@ -272,9 +289,12 @@ const ChatTextArea = forwardRef( } if ((event.key === "Enter" || event.key === "Tab") && selectedMenuIndex !== -1) { event.preventDefault() - const selectedOption = getContextMenuOptions(searchQuery, selectedType, queryItems)[ - selectedMenuIndex - ] + const selectedOption = getContextMenuOptions( + searchQuery, + selectedType, + queryItems, + getAllModes(customModes), + )[selectedMenuIndex] if ( selectedOption && selectedOption.type !== ContextMenuOptionType.URL && @@ -340,6 +360,7 @@ const ChatTextArea = forwardRef( setInputValue, justDeletedSpaceAfterMention, queryItems, + customModes, ], ) @@ -360,13 +381,21 @@ const ChatTextArea = forwardRef( setShowContextMenu(showMenu) if (showMenu) { - const lastAtIndex = newValue.lastIndexOf("@", newCursorPosition - 1) - const query = newValue.slice(lastAtIndex + 1, newCursorPosition) - setSearchQuery(query) - if (query.length > 0) { + if (newValue.startsWith("/")) { + // Handle slash command + const query = newValue + setSearchQuery(query) setSelectedMenuIndex(0) } else { - setSelectedMenuIndex(3) // Set to "File" option by default + // Existing @ mention handling + const lastAtIndex = newValue.lastIndexOf("@", newCursorPosition - 1) + const query = newValue.slice(lastAtIndex + 1, newCursorPosition) + setSearchQuery(query) + if (query.length > 0) { + setSelectedMenuIndex(0) + } else { + setSelectedMenuIndex(3) // Set to "File" option by default + } } } else { setSearchQuery("") @@ -614,6 +643,7 @@ const ChatTextArea = forwardRef( setSelectedIndex={setSelectedMenuIndex} selectedType={selectedType} queryItems={queryItems} + modes={getAllModes(customModes)} />
)} diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index b1142fd5db..a102ca1fc2 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -878,7 +878,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie const placeholderText = useMemo(() => { const baseText = task ? "Type a message..." : "Type your task here..." - const contextText = "(@ to add context" + const contextText = "(@ to add context, / to switch modes" const imageText = shouldDisableImages ? "" : ", hold shift to drag in images" const helpText = imageText ? `\n${contextText}${imageText})` : `\n${contextText})` return baseText + helpText diff --git a/webview-ui/src/components/chat/ContextMenu.tsx b/webview-ui/src/components/chat/ContextMenu.tsx index 85ec865ccd..bd631a98d5 100644 --- a/webview-ui/src/components/chat/ContextMenu.tsx +++ b/webview-ui/src/components/chat/ContextMenu.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useMemo, useRef } from "react" import { ContextMenuOptionType, ContextMenuQueryItem, getContextMenuOptions } from "../../utils/context-mentions" import { removeLeadingNonAlphanumeric } from "../common/CodeAccordian" +import { ModeConfig } from "../../../../src/shared/modes" interface ContextMenuProps { onSelect: (type: ContextMenuOptionType, value?: string) => void @@ -10,6 +11,7 @@ interface ContextMenuProps { setSelectedIndex: (index: number) => void selectedType: ContextMenuOptionType | null queryItems: ContextMenuQueryItem[] + modes?: ModeConfig[] } const ContextMenu: React.FC = ({ @@ -20,12 +22,13 @@ const ContextMenu: React.FC = ({ setSelectedIndex, selectedType, queryItems, + modes, }) => { const menuRef = useRef(null) const filteredOptions = useMemo( - () => getContextMenuOptions(searchQuery, selectedType, queryItems), - [searchQuery, selectedType, queryItems], + () => getContextMenuOptions(searchQuery, selectedType, queryItems, modes), + [searchQuery, selectedType, queryItems, modes], ) useEffect(() => { @@ -46,6 +49,25 @@ const ContextMenu: React.FC = ({ const renderOptionContent = (option: ContextMenuQueryItem) => { switch (option.type) { + case ContextMenuOptionType.Mode: + return ( +
+ {option.label} + {option.description && ( + + {option.description} + + )} +
+ ) case ContextMenuOptionType.Problems: return Problems case ContextMenuOptionType.URL: @@ -101,6 +123,8 @@ const ContextMenu: React.FC = ({ const getIconForOption = (option: ContextMenuQueryItem): string => { switch (option.type) { + case ContextMenuOptionType.Mode: + return "symbol-misc" case ContextMenuOptionType.OpenedFile: return "window" case ContextMenuOptionType.File: @@ -174,15 +198,17 @@ const ContextMenu: React.FC = ({ overflow: "hidden", paddingTop: 0, }}> - + {option.type !== ContextMenuOptionType.Mode && getIconForOption(option) && ( + + )} {renderOptionContent(option)}
{(option.type === ContextMenuOptionType.File || diff --git a/webview-ui/src/utils/context-mentions.ts b/webview-ui/src/utils/context-mentions.ts index 5cce936b28..0fb57071ab 100644 --- a/webview-ui/src/utils/context-mentions.ts +++ b/webview-ui/src/utils/context-mentions.ts @@ -1,11 +1,20 @@ import { mentionRegex } from "../../../src/shared/context-mentions" import { Fzf } from "fzf" +import { ModeConfig } from "../../../src/shared/modes" export function insertMention( text: string, position: number, value: string, ): { newValue: string; mentionIndex: number } { + // Handle slash command + if (text.startsWith("/")) { + return { + newValue: value, + mentionIndex: 0, + } + } + const beforeCursor = text.slice(0, position) const afterCursor = text.slice(position) @@ -55,6 +64,7 @@ export enum ContextMenuOptionType { URL = "url", Git = "git", NoResults = "noResults", + Mode = "mode", // Add mode type } export interface ContextMenuQueryItem { @@ -69,7 +79,42 @@ export function getContextMenuOptions( query: string, selectedType: ContextMenuOptionType | null = null, queryItems: ContextMenuQueryItem[], + modes?: ModeConfig[], ): ContextMenuQueryItem[] { + // Handle slash commands for modes + if (query.startsWith("/")) { + const modeQuery = query.slice(1) + if (!modes?.length) return [{ type: ContextMenuOptionType.NoResults }] + + // Create searchable strings array for fzf + const searchableItems = modes.map((mode) => ({ + original: mode, + searchStr: mode.name, + })) + + // Initialize fzf instance for fuzzy search + const fzf = new Fzf(searchableItems, { + selector: (item) => item.searchStr, + }) + + // Get fuzzy matching items + const matchingModes = modeQuery + ? fzf.find(modeQuery).map((result) => ({ + type: ContextMenuOptionType.Mode, + value: result.item.original.slug, + label: result.item.original.name, + description: result.item.original.roleDefinition.split("\n")[0], + })) + : modes.map((mode) => ({ + type: ContextMenuOptionType.Mode, + value: mode.slug, + label: mode.name, + description: mode.roleDefinition.split("\n")[0], + })) + + return matchingModes.length > 0 ? matchingModes : [{ type: ContextMenuOptionType.NoResults }] + } + const workingChanges: ContextMenuQueryItem = { type: ContextMenuOptionType.Git, value: "git-changes", @@ -203,6 +248,11 @@ export function getContextMenuOptions( } export function shouldShowContextMenu(text: string, position: number): boolean { + // Handle slash command + if (text.startsWith("/")) { + return position <= text.length && !text.includes(" ") + } + const beforeCursor = text.slice(0, position) const atIndex = beforeCursor.lastIndexOf("@") From f3bbf34a9072834a330f6a80f1c762cafbe5ae5c Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Wed, 5 Feb 2025 00:27:26 -0500 Subject: [PATCH 38/40] v3.3.11 --- .changeset/gorgeous-insects-punch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/gorgeous-insects-punch.md diff --git a/.changeset/gorgeous-insects-punch.md b/.changeset/gorgeous-insects-punch.md new file mode 100644 index 0000000000..ce5300b3e8 --- /dev/null +++ b/.changeset/gorgeous-insects-punch.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +v3.3.11 From c32d3057d692a1435a456e37972c82d87de3d669 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Feb 2025 05:31:24 +0000 Subject: [PATCH 39/40] changeset version bump --- .changeset/gorgeous-insects-punch.md | 5 ----- .changeset/heavy-feet-judge.md | 5 ----- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 10 insertions(+), 13 deletions(-) delete mode 100644 .changeset/gorgeous-insects-punch.md delete mode 100644 .changeset/heavy-feet-judge.md diff --git a/.changeset/gorgeous-insects-punch.md b/.changeset/gorgeous-insects-punch.md deleted file mode 100644 index ce5300b3e8..0000000000 --- a/.changeset/gorgeous-insects-punch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -v3.3.11 diff --git a/.changeset/heavy-feet-judge.md b/.changeset/heavy-feet-judge.md deleted file mode 100644 index b9b3ca0f7b..0000000000 --- a/.changeset/heavy-feet-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -Safer shell profile path check diff --git a/CHANGELOG.md b/CHANGELOG.md index 983d2bfac4..4de56c4b00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Roo Code Changelog +## 3.3.11 + +### Patch Changes + +- v3.3.11 +- Safer shell profile path check + ## [3.3.10] - Add shortcuts to the currently open tabs in the "Add File" section of @-mentions (thanks @olup!) diff --git a/package-lock.json b/package-lock.json index 2c518b330e..59949791f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "roo-cline", - "version": "3.3.10", + "version": "3.3.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "roo-cline", - "version": "3.3.10", + "version": "3.3.11", "dependencies": { "@anthropic-ai/bedrock-sdk": "^0.10.2", "@anthropic-ai/sdk": "^0.26.0", diff --git a/package.json b/package.json index 80528fdfd0..69d391a282 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Roo Code (prev. Roo Cline)", "description": "A VS Code plugin that enhances coding with AI-powered automation, multi-model support, and experimental features.", "publisher": "RooVeterinaryInc", - "version": "3.3.10", + "version": "3.3.11", "icon": "assets/icons/rocket.png", "galleryBanner": { "color": "#617A91", From b5a8398d22d95fa04ab867d030e4d8d14836cff1 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Wed, 5 Feb 2025 00:34:24 -0500 Subject: [PATCH 40/40] Update CHANGELOG.md --- CHANGELOG.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4de56c4b00..0a3bbfef82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,9 @@ # Roo Code Changelog -## 3.3.11 +## [3.3.11] -### Patch Changes - -- v3.3.11 -- Safer shell profile path check +- Safer shell profile path check to avoid an error on Windows +- Autocomplete for slash commands ## [3.3.10]