From 9619796bc2a8392f1fa657a7091abbd29e130efd Mon Sep 17 00:00:00 2001 From: Himanshu Date: Tue, 28 Jan 2025 22:23:10 +0530 Subject: [PATCH 01/30] add pearai provider --- .gitignore | 2 + src/api/index.ts | 3 + src/api/providers/pearai.ts | 19 ++++++ src/core/webview/ClineProvider.ts | 25 ++++++++ src/shared/api.ts | 5 ++ .../src/components/settings/ApiOptions.tsx | 62 ++++++++++++++++++- 6 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 src/api/providers/pearai.ts diff --git a/.gitignore b/.gitignore index b508d9dc6ee..72e8f2f26f0 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ roo-cline-*.vsix # Test environment .test_env .vscode-test/ +.aider* +.env diff --git a/src/api/index.ts b/src/api/index.ts index 641c50d719b..704cb97d831 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -14,6 +14,7 @@ import { DeepSeekHandler } from "./providers/deepseek" import { MistralHandler } from "./providers/mistral" import { VsCodeLmHandler } from "./providers/vscode-lm" import { ApiStream } from "./transform/stream" +import { PearAiHandler } from "./providers/pearai" export interface SingleCompletionHandler { completePrompt(prompt: string): Promise @@ -53,6 +54,8 @@ export function buildApiHandler(configuration: ApiConfiguration): ApiHandler { return new VsCodeLmHandler(options) case "mistral": return new MistralHandler(options) + case "pearai": + return new PearAiHandler(options) default: return new AnthropicHandler(options) } diff --git a/src/api/providers/pearai.ts b/src/api/providers/pearai.ts new file mode 100644 index 00000000000..6b39106eb2e --- /dev/null +++ b/src/api/providers/pearai.ts @@ -0,0 +1,19 @@ +import { OpenAiHandler } from "./openai" +import { ApiHandlerOptions } from "../../shared/api" + +export class PearAiHandler extends OpenAiHandler { + constructor(options: ApiHandlerOptions) { + if (!options.pearaiApiKey) { + throw new Error("PearAI API key is required. Please provide it in the settings.") + } + super({ + ...options, + // Map PearAI specific options to OpenAI options for compatibility + openAiApiKey: options.pearaiApiKey, + openAiBaseUrl: + options.pearaiBaseUrl ?? + "https://stingray-app-gb2an.ondigitalocean.app/pearai-server-api2/integrations/cline", + openAiStreamingEnabled: true, + }) + } +} diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index d2db67ff4b9..b423bdb3820 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -63,6 +63,7 @@ type SecretKey = | "openAiNativeApiKey" | "deepSeekApiKey" | "mistralApiKey" + | "pearaiApiKey" type GlobalStateKey = | "apiProvider" | "apiModelId" @@ -97,6 +98,10 @@ type GlobalStateKey = | "openRouterModelId" | "openRouterModelInfo" | "openRouterBaseUrl" + | "pearaiModelId" + | "pearaiModelInfo" + | "pearaiBaseUrl" + | "pearaiApiKey" | "openRouterUseMiddleOutTransform" | "allowedCommands" | "soundEnabled" @@ -1363,6 +1368,10 @@ export class ClineProvider implements vscode.WebviewViewProvider { openRouterUseMiddleOutTransform, vsCodeLmModelSelector, mistralApiKey, + pearaiApiKey, + pearaiBaseUrl, + pearaiModelId, + pearaiModelInfo, } = apiConfiguration await this.updateGlobalState("apiProvider", apiProvider) await this.updateGlobalState("apiModelId", apiModelId) @@ -1401,6 +1410,10 @@ export class ClineProvider implements vscode.WebviewViewProvider { await this.updateGlobalState("openRouterUseMiddleOutTransform", openRouterUseMiddleOutTransform) await this.updateGlobalState("vsCodeLmModelSelector", vsCodeLmModelSelector) await this.storeSecret("mistralApiKey", mistralApiKey) + await this.updateGlobalState("pearaiModelId", pearaiModelId) + await this.updateGlobalState("pearaiModelInfo", pearaiModelInfo) + await this.storeSecret("pearaiApiKey", pearaiApiKey) + await this.updateGlobalState("pearaiBaseUrl", pearaiBaseUrl) if (this.cline) { this.cline.api = buildApiHandler(apiConfiguration) } @@ -2019,6 +2032,10 @@ export class ClineProvider implements vscode.WebviewViewProvider { openAiNativeApiKey, deepSeekApiKey, mistralApiKey, + pearaiApiKey, + pearaiBaseUrl, + pearaiModelId, + pearaiModelInfo, azureApiVersion, openAiStreamingEnabled, openRouterModelId, @@ -2089,6 +2106,10 @@ export class ClineProvider implements vscode.WebviewViewProvider { this.getSecret("openAiNativeApiKey") as Promise, this.getSecret("deepSeekApiKey") as Promise, this.getSecret("mistralApiKey") as Promise, + this.getSecret("pearaiApiKey") as Promise, + this.getGlobalState("pearaiBaseUrl") as Promise, + this.getGlobalState("pearaiModelId") as Promise, + this.getGlobalState("pearaiModelInfo") as Promise, this.getGlobalState("azureApiVersion") as Promise, this.getGlobalState("openAiStreamingEnabled") as Promise, this.getGlobalState("openRouterModelId") as Promise, @@ -2176,6 +2197,10 @@ export class ClineProvider implements vscode.WebviewViewProvider { openAiNativeApiKey, deepSeekApiKey, mistralApiKey, + pearaiApiKey, + pearaiBaseUrl, + pearaiModelId, + pearaiModelInfo, azureApiVersion, openAiStreamingEnabled, openRouterModelId, diff --git a/src/shared/api.ts b/src/shared/api.ts index 950b94b051d..81617d39503 100644 --- a/src/shared/api.ts +++ b/src/shared/api.ts @@ -14,6 +14,7 @@ export type ApiProvider = | "deepseek" | "vscode-lm" | "mistral" + | "pearai" export interface ApiHandlerOptions { apiModelId?: string @@ -57,6 +58,10 @@ export interface ApiHandlerOptions { deepSeekBaseUrl?: string deepSeekApiKey?: string includeMaxTokens?: boolean + pearaiApiKey?: string + pearaiBaseUrl?: string + pearaiModelId?: string + pearaiModelInfo?: ModelInfo } export type ApiConfiguration = ApiHandlerOptions & { diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index 1be00c74e14..73551bcfb75 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -1,6 +1,12 @@ import { Checkbox, Dropdown, Pane } from "vscrui" import type { DropdownOption } from "vscrui" -import { VSCodeLink, VSCodeRadio, VSCodeRadioGroup, VSCodeTextField } from "@vscode/webview-ui-toolkit/react" +import { + VSCodeButton, + VSCodeLink, + VSCodeRadio, + VSCodeRadioGroup, + VSCodeTextField, +} from "@vscode/webview-ui-toolkit/react" import { Fragment, memo, useCallback, useEffect, useMemo, useState } from "react" import { useEvent, useInterval } from "react-use" import { @@ -39,6 +45,8 @@ import OpenRouterModelPicker, { import OpenAiModelPicker from "./OpenAiModelPicker" import GlamaModelPicker from "./GlamaModelPicker" +const PEARAI_DEFAULT_URL = "https://stingray-app-gb2an.ondigitalocean.app/pearai-server-api2/integrations/cline" + interface ApiOptionsProps { apiErrorMessage?: string modelIdErrorMessage?: string @@ -52,6 +60,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) = const [anthropicBaseUrlSelected, setAnthropicBaseUrlSelected] = useState(!!apiConfiguration?.anthropicBaseUrl) const [azureApiVersionSelected, setAzureApiVersionSelected] = useState(!!apiConfiguration?.azureApiVersion) const [openRouterBaseUrlSelected, setOpenRouterBaseUrlSelected] = useState(!!apiConfiguration?.openRouterBaseUrl) + const [pearaiBaseUrlSelected, setPearaiBaseUrlSelected] = useState(!!apiConfiguration?.pearaiBaseUrl) const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false) const { selectedProvider, selectedModelId, selectedModelInfo } = useMemo(() => { @@ -134,6 +143,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) = }} style={{ minWidth: 130, position: "relative", zIndex: OPENROUTER_MODEL_PICKER_Z_INDEX + 1 }} options={[ + { value: "pearai", label: "PearAI" }, { value: "openrouter", label: "OpenRouter" }, { value: "anthropic", label: "Anthropic" }, { value: "gemini", label: "Google Gemini" }, @@ -151,6 +161,47 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) = /> + {selectedProvider === "pearai" && ( +
+ + PearAI API Key + + + Base URL + + {apiConfiguration?.pearaiBaseUrl && apiConfiguration.pearaiBaseUrl !== PEARAI_DEFAULT_URL && ( + { + handleInputChange("pearaiBaseUrl")({ + target: { + value: PEARAI_DEFAULT_URL, + }, + }) + }}> + Reset to default URL + + )} +

+ This key is stored locally and only used to make API requests from this extension. +

+
+ )} + {selectedProvider === "anthropic" && (
)} @@ -1607,7 +1583,7 @@ export function normalizeApiConfiguration(apiConfiguration?: ApiConfiguration) { case "pearai": return { selectedProvider: provider, - selectedModelId: apiConfiguration?.pearaiModelId || "", + selectedModelId: apiConfiguration?.pearaiModelId || "pearai_model", selectedModelInfo: apiConfiguration?.pearaiModelInfo || openAiModelInfoSaneDefaults, } default: From 7e0acff9334d169f08e2be47fec16f4a7965c8b1 Mon Sep 17 00:00:00 2001 From: nang-dev Date: Tue, 28 Jan 2025 17:52:12 -0500 Subject: [PATCH 03/30] Added pearai api config --- src/shared/checkExistApiConfig.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/checkExistApiConfig.ts b/src/shared/checkExistApiConfig.ts index 8cb8055cc84..2b850e7db39 100644 --- a/src/shared/checkExistApiConfig.ts +++ b/src/shared/checkExistApiConfig.ts @@ -4,6 +4,7 @@ export function checkExistKey(config: ApiConfiguration | undefined) { return config ? [ config.apiKey, + config.pearaiApiKey, config.glamaApiKey, config.openRouterApiKey, config.awsRegion, From fe68b50ec3a8b1153a4a8c234d221a3437ff71cd Mon Sep 17 00:00:00 2001 From: nang-dev Date: Tue, 28 Jan 2025 18:25:01 -0500 Subject: [PATCH 04/30] Added pearai welcome default --- src/core/webview/ClineProvider.ts | 2 +- .../src/components/welcome/WelcomeView.tsx | 29 +++++++------------ 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 647db94f620..a5bb874fa11 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1327,7 +1327,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { // Update mode's default config const { mode } = await this.getState() if (mode) { - const currentApiConfigName = await this.getGlobalState("currentApiConfigName") + const currentApiConfigName = (await this.getGlobalState("currentApiConfigName")) ?? "default" const listApiConfig = await this.configManager.listConfig() const config = listApiConfig?.find((c) => c.name === currentApiConfigName) if (config?.id) { diff --git a/webview-ui/src/components/welcome/WelcomeView.tsx b/webview-ui/src/components/welcome/WelcomeView.tsx index 3e3bbd7cd17..1af25a14c8d 100644 --- a/webview-ui/src/components/welcome/WelcomeView.tsx +++ b/webview-ui/src/components/welcome/WelcomeView.tsx @@ -1,28 +1,22 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" -import { useEffect, useState } from "react" import { useExtensionState } from "../../context/ExtensionStateContext" -import { validateApiConfiguration } from "../../utils/validate" import { vscode } from "../../utils/vscode" -import ApiOptions from "../settings/ApiOptions" const WelcomeView = () => { - const { apiConfiguration } = useExtensionState() - - const [apiErrorMessage, setApiErrorMessage] = useState(undefined) - - const disableLetsGoButton = apiErrorMessage != null - const handleSubmit = () => { - vscode.postMessage({ type: "apiConfiguration", apiConfiguration }) + vscode.postMessage({ + type: "apiConfiguration", + apiConfiguration: { + apiProvider: "pearai", + pearaiApiKey: "temp", // TODO: Change this to use api-key + pearaiBaseUrl: "http://localhost:8000/integrations/cline", + }, + }) } - useEffect(() => { - setApiErrorMessage(validateApiConfiguration(apiConfiguration)) - }, [apiConfiguration]) - return (
-

Hi, I'm Roo!

+

Welcome to PearAI's Coding Agent (Powered by Roo Code / Cline)!

I can do all kinds of tasks thanks to the latest breakthroughs in agentic coding capabilities and access to tools that let me create & edit files, explore complex projects, use the browser, and execute @@ -30,11 +24,8 @@ const WelcomeView = () => { my own capabilities.

- To get started, this extension needs an API provider. -
- - + Let's go!
From eba3d14b7ea39f007f660968b09100c8ffc25d4f Mon Sep 17 00:00:00 2001 From: nang-dev Date: Tue, 28 Jan 2025 20:22:36 -0500 Subject: [PATCH 05/30] Added pearai with anthropic --- src/api/providers/pearai.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/providers/pearai.ts b/src/api/providers/pearai.ts index 09b9bed4720..0931f7fe265 100644 --- a/src/api/providers/pearai.ts +++ b/src/api/providers/pearai.ts @@ -1,7 +1,8 @@ import { OpenAiHandler } from "./openai" import { ApiHandlerOptions, PEARAI_URL } from "../../shared/api" +import { AnthropicHandler } from "./anthropic" -export class PearAiHandler extends OpenAiHandler { +export class PearAiHandler extends AnthropicHandler { constructor(options: ApiHandlerOptions) { if (!options.pearaiApiKey) { throw new Error("PearAI API key not found. Please login to PearAI.") From fada5e2a930c05dbbf4890092c01667bbe0a7d4f Mon Sep 17 00:00:00 2001 From: Nang Date: Wed, 29 Jan 2025 11:43:58 -0500 Subject: [PATCH 06/30] Added working anthropic server --- src/api/providers/anthropic.ts | 5 ++++- src/api/providers/pearai.ts | 6 ++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/api/providers/anthropic.ts b/src/api/providers/anthropic.ts index e65b82ddef5..ac976cad956 100644 --- a/src/api/providers/anthropic.ts +++ b/src/api/providers/anthropic.ts @@ -83,7 +83,10 @@ export class AnthropicHandler implements ApiHandler, SingleCompletionHandler { case "claude-3-opus-20240229": case "claude-3-haiku-20240307": return { - headers: { "anthropic-beta": "prompt-caching-2024-07-31" }, + headers: { + "anthropic-beta": "prompt-caching-2024-07-31", + "authorization": `Bearer ${this.options.apiKey}`, + }, } default: return undefined diff --git a/src/api/providers/pearai.ts b/src/api/providers/pearai.ts index 0931f7fe265..9fe9e48ff85 100644 --- a/src/api/providers/pearai.ts +++ b/src/api/providers/pearai.ts @@ -9,10 +9,8 @@ export class PearAiHandler extends AnthropicHandler { } super({ ...options, - // Map PearAI specific options to OpenAI options for compatibility - openAiApiKey: options.pearaiApiKey, - openAiBaseUrl: PEARAI_URL, - openAiStreamingEnabled: true, + apiKey: options.pearaiApiKey, + anthropicBaseUrl: PEARAI_URL, }) } } From b00d1ea504dcc6ae9d6e07a0b10bec143987b6ab Mon Sep 17 00:00:00 2001 From: nang-dev Date: Thu, 30 Jan 2025 20:50:42 -0500 Subject: [PATCH 07/30] Added login logout p2p call working --- package-lock.json | 4 +- package.json | 10 ++--- src/core/webview/ClineProvider.ts | 27 +++++++----- src/extension.ts | 17 +++++++ src/shared/ExtensionMessage.ts | 1 + src/shared/WebviewMessage.ts | 1 + src/shared/checkExistApiConfig.ts | 2 +- .../src/components/settings/ApiOptions.tsx | 44 ++++++++++++------- .../src/components/welcome/WelcomeView.tsx | 14 ++---- 9 files changed, 77 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index bb49b3942db..3cb6e115cda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "roo-cline", + "name": "pearai-roo-cline", "version": "3.3.4", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "roo-cline", + "name": "pearai-roo-cline", "version": "3.3.4", "dependencies": { "@anthropic-ai/bedrock-sdk": "^0.10.2", diff --git a/package.json b/package.json index 6b87a6d5077..f3b9db2bba3 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "roo-cline", - "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", + "name": "pearai-roo-cline", + "displayName": "PearAI Roo Code / Cline", + "description": "PearAI's integration of Roo Code / Cline, a coding agent.", + "publisher": "PearAI", "version": "3.3.4", "icon": "assets/icons/rocket.png", "galleryBanner": { @@ -13,7 +13,7 @@ "vscode": "^1.84.0" }, "author": { - "name": "Roo Vet" + "name": "PearAI" }, "repository": { "type": "git", diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index a5bb874fa11..f6ac11cf32b 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -45,9 +45,6 @@ import { CustomSupportPrompts, supportPrompt } from "../../shared/support-prompt import { ACTION_NAMES } from "../CodeActionProvider" -// Todo: Remove -const PEARAI_TOKEN = "temp" - /* https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts @@ -66,7 +63,8 @@ type SecretKey = | "openAiNativeApiKey" | "deepSeekApiKey" | "mistralApiKey" - | "pearaiApiKey" + | "pearai-token" + | "pearai-refresh" // Array of custom modes type GlobalStateKey = | "apiProvider" | "apiModelId" @@ -130,8 +128,6 @@ type GlobalStateKey = | "experiments" // Map of experiment IDs to their enabled state | "autoApprovalEnabled" | "customModes" - | "pearai-token" - | "pearai-refresh" // Array of custom modes export const GlobalFileNames = { apiConversationHistory: "api_conversation_history.json", @@ -1278,6 +1274,19 @@ export class ClineProvider implements vscode.WebviewViewProvider { await this.updateGlobalState("mode", defaultModeSlug) await this.postStateToWebview() } + break + case "openPearAiAuth": + const extensionUrl = `${vscode.env.uriScheme}://pearai.pearai/auth` + const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(extensionUrl)) + + await vscode.env.openExternal( + await vscode.env.asExternalUri( + vscode.Uri.parse( + `https://trypear.ai/signin?callback=${callbackUri.toString()}`, // Change to localhost if running locally + ), + ), + ) + break } }, null, @@ -1373,7 +1382,6 @@ export class ClineProvider implements vscode.WebviewViewProvider { openRouterUseMiddleOutTransform, vsCodeLmModelSelector, mistralApiKey, - pearaiApiKey, pearaiBaseUrl, pearaiModelId, pearaiModelInfo, @@ -1415,7 +1423,6 @@ export class ClineProvider implements vscode.WebviewViewProvider { await this.updateGlobalState("openRouterUseMiddleOutTransform", openRouterUseMiddleOutTransform) await this.updateGlobalState("vsCodeLmModelSelector", vsCodeLmModelSelector) await this.storeSecret("mistralApiKey", mistralApiKey) - await this.updateGlobalState("pearai-token", PEARAI_TOKEN) await this.updateGlobalState("pearaiBaseUrl", PEARAI_URL) await this.updateGlobalState("pearaiModelId", pearaiModelId) await this.updateGlobalState("pearaiModelInfo", pearaiModelInfo) @@ -2112,8 +2119,8 @@ export class ClineProvider implements vscode.WebviewViewProvider { this.getSecret("openAiNativeApiKey") as Promise, this.getSecret("deepSeekApiKey") as Promise, this.getSecret("mistralApiKey") as Promise, - this.getGlobalState("pearai-token") as Promise, - this.getGlobalState("pearai-refresh") as Promise, + this.getSecret("pearai-token") as Promise, + this.getSecret("pearai-refresh") as Promise, this.getGlobalState("pearaiBaseUrl") as Promise, this.getGlobalState("pearaiModelId") as Promise, this.getGlobalState("pearaiModelInfo") as Promise, diff --git a/src/extension.ts b/src/extension.ts index 332759a3811..7fcef7ae986 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -52,6 +52,23 @@ export function activate(context: vscode.ExtensionContext) { }), ) + context.subscriptions.push( + vscode.commands.registerCommand("pearai-roo-cline.pearaiLogin", async (data) => { + console.dir("Logged in to PearAI:") + console.dir(data) + context.secrets.store("pearai-token", data.accessToken) + context.secrets.store("pearai-refresh", data.refreshToken) + }), + ) + + context.subscriptions.push( + vscode.commands.registerCommand("pearai-roo-cline.pearAILogout", async () => { + console.dir("Logged out of PearAI:") + context.secrets.delete("pearai-token") + context.secrets.delete("pearai-refresh") + }), + ) + context.subscriptions.push( vscode.commands.registerCommand("roo-cline.mcpButtonClicked", () => { sidebarProvider.postMessageToWebview({ type: "action", action: "mcpButtonClicked" }) diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 4cd6370697c..d7df6667a46 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -50,6 +50,7 @@ export interface ExtensionMessage { | "historyButtonClicked" | "promptsButtonClicked" | "didBecomeVisible" + | "updatePearAIAuth" invoke?: "sendMessage" | "primaryButtonClick" | "secondaryButtonClick" state?: ExtensionState images?: string[] diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 357a237caf2..d0d8e81c698 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -81,6 +81,7 @@ export interface WebviewMessage { | "deleteCustomMode" | "setopenAiCustomModelInfo" | "openCustomModesSettings" + | "openPearAiAuth" text?: string disabled?: boolean askResponse?: ClineAskResponse diff --git a/src/shared/checkExistApiConfig.ts b/src/shared/checkExistApiConfig.ts index 2b850e7db39..f225eb22d8e 100644 --- a/src/shared/checkExistApiConfig.ts +++ b/src/shared/checkExistApiConfig.ts @@ -4,7 +4,6 @@ export function checkExistKey(config: ApiConfiguration | undefined) { return config ? [ config.apiKey, - config.pearaiApiKey, config.glamaApiKey, config.openRouterApiKey, config.awsRegion, @@ -17,6 +16,7 @@ export function checkExistKey(config: ApiConfiguration | undefined) { config.deepSeekApiKey, config.mistralApiKey, config.vsCodeLmModelSelector, + config.pearaiBaseUrl, ].some((key) => key !== undefined) : false } diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index ca7087ca92c..1f80fc8a23a 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -32,7 +32,6 @@ import { openRouterDefaultModelInfo, vertexDefaultModelId, vertexModels, - PEARAI_URL, } from "../../../../src/shared/api" import { ExtensionMessage } from "../../../../src/shared/ExtensionMessage" import { useExtensionState } from "../../context/ExtensionStateContext" @@ -161,20 +160,35 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) = {selectedProvider === "pearai" && (
- - PearAI API Key - -

+ {!apiConfiguration?.pearaiApiKey ? ( + <> + { + vscode.postMessage({ + type: "openPearAiAuth", + }) + }}> + Login to PearAI + +

+ Connect your PearAI account to use servers. +

+ + ) : ( +

+ User already logged in to PearAI. Click 'Done' to proceed! +

+ )}
)} diff --git a/webview-ui/src/components/welcome/WelcomeView.tsx b/webview-ui/src/components/welcome/WelcomeView.tsx index 1af25a14c8d..4ff6c1d8152 100644 --- a/webview-ui/src/components/welcome/WelcomeView.tsx +++ b/webview-ui/src/components/welcome/WelcomeView.tsx @@ -1,6 +1,6 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" -import { useExtensionState } from "../../context/ExtensionStateContext" import { vscode } from "../../utils/vscode" +import { PEARAI_URL } from "../../../../src/shared/api" const WelcomeView = () => { const handleSubmit = () => { @@ -8,8 +8,7 @@ const WelcomeView = () => { type: "apiConfiguration", apiConfiguration: { apiProvider: "pearai", - pearaiApiKey: "temp", // TODO: Change this to use api-key - pearaiBaseUrl: "http://localhost:8000/integrations/cline", + pearaiBaseUrl: `${PEARAI_URL}/integrations/cline`, }, }) } @@ -17,16 +16,11 @@ const WelcomeView = () => { return (

Welcome to PearAI's Coding Agent (Powered by Roo Code / Cline)!

-

- I can do all kinds of tasks thanks to the latest breakthroughs in agentic coding capabilities and access - to tools that let me create & edit files, explore complex projects, use the browser, and execute - terminal commands (with your permission, of course). I can even use MCP to create new tools and extend - my own capabilities. -

+

Ask me to code new features or fix bugs!

- Let's go! + Proceed
From b015df36e5b575a1420273f0b7b9fc8a142b2435 Mon Sep 17 00:00:00 2001 From: nang-dev Date: Thu, 30 Jan 2025 22:39:38 -0500 Subject: [PATCH 08/30] Fixed capitalization --- src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extension.ts b/src/extension.ts index 7fcef7ae986..635cf7b777a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -62,7 +62,7 @@ export function activate(context: vscode.ExtensionContext) { ) context.subscriptions.push( - vscode.commands.registerCommand("pearai-roo-cline.pearAILogout", async () => { + vscode.commands.registerCommand("pearai-roo-cline.pearaiLogout", async () => { console.dir("Logged out of PearAI:") context.secrets.delete("pearai-token") context.secrets.delete("pearai-refresh") From a1f8937b9509d16773b1a049947a11b41951febb Mon Sep 17 00:00:00 2001 From: nang-dev Date: Fri, 31 Jan 2025 14:51:53 -0500 Subject: [PATCH 09/30] Plus button working after login --- src/extension.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/extension.ts b/src/extension.ts index 635cf7b777a..4de3ff400e5 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -58,6 +58,7 @@ export function activate(context: vscode.ExtensionContext) { console.dir(data) context.secrets.store("pearai-token", data.accessToken) context.secrets.store("pearai-refresh", data.refreshToken) + vscode.commands.executeCommand("roo-cline.plusButtonClicked") }), ) From 7594550219e9edf3a842f09b63a292365fc84ac9 Mon Sep 17 00:00:00 2001 From: nang-dev Date: Fri, 31 Jan 2025 16:55:26 -0500 Subject: [PATCH 10/30] Added client side error --- src/api/providers/pearai.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/api/providers/pearai.ts b/src/api/providers/pearai.ts index 9fe9e48ff85..ba79fb2149e 100644 --- a/src/api/providers/pearai.ts +++ b/src/api/providers/pearai.ts @@ -1,10 +1,25 @@ import { OpenAiHandler } from "./openai" +import * as vscode from "vscode" import { ApiHandlerOptions, PEARAI_URL } from "../../shared/api" import { AnthropicHandler } from "./anthropic" export class PearAiHandler extends AnthropicHandler { constructor(options: ApiHandlerOptions) { if (!options.pearaiApiKey) { + vscode.window.showErrorMessage("PearAI API key not found.", "Login to PearAI").then(async (selection) => { + if (selection === "Login to PearAI") { + const extensionUrl = `${vscode.env.uriScheme}://pearai.pearai/auth` + const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(extensionUrl)) + + vscode.env.openExternal( + await vscode.env.asExternalUri( + vscode.Uri.parse( + `https://trypear.ai/signin?callback=${callbackUri.toString()}`, // Change to localhost if running locally + ), + ), + ) + } + }) throw new Error("PearAI API key not found. Please login to PearAI.") } super({ From 833c1b11a56a50433f77a59b49430493e8bde6fe Mon Sep 17 00:00:00 2001 From: nang-dev Date: Fri, 31 Jan 2025 17:43:22 -0500 Subject: [PATCH 11/30] Added wording tweak --- webview-ui/src/components/chat/ChatView.tsx | 9 +++------ webview-ui/src/components/welcome/WelcomeView.tsx | 9 ++++++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index b5d90c80f99..ffdc3448ce4 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -935,13 +935,10 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie }}> {showAnnouncement && }
-

What can I do for you?

+

PearAI Coding Agent (Powered by Roo Code / Cline)

- Thanks to the latest breakthroughs in agentic coding capabilities, I can handle complex - software development tasks step-by-step. With tools that let me create & edit files, explore - complex projects, use the browser, and execute terminal commands (after you grant - permission), I can assist you in ways that go beyond code completion or tech support. I can - even use MCP to create new tools and extend my own capabilities. + Ask me to create a new feature, fix a bug, anything else. I can create & edit files, explore + complex projects, use the browser, and execute terminal commands!

{taskHistory.length > 0 && } diff --git a/webview-ui/src/components/welcome/WelcomeView.tsx b/webview-ui/src/components/welcome/WelcomeView.tsx index 4ff6c1d8152..362e6e8081a 100644 --- a/webview-ui/src/components/welcome/WelcomeView.tsx +++ b/webview-ui/src/components/welcome/WelcomeView.tsx @@ -15,12 +15,15 @@ const WelcomeView = () => { return (
-

Welcome to PearAI's Coding Agent (Powered by Roo Code / Cline)!

-

Ask me to code new features or fix bugs!

+

Welcome to PearAI Coding Agent (Powered by Roo Code / Cline)!

+

+ Ask me to create a new feature, fix a bug, anything else. I can create & edit files, explore complex + projects, use the browser, and execute terminal commands! +

- Proceed + Next
From dea407fea875e86e7c796be46e4a74c5015e5f30 Mon Sep 17 00:00:00 2001 From: nang-dev Date: Fri, 7 Feb 2025 12:35:23 -0500 Subject: [PATCH 12/30] Added package.json --- .husky/pre-push | 8 ++++---- package.json | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.husky/pre-push b/.husky/pre-push index ab7d11b507f..7eaabbc9384 100644 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,9 +1,9 @@ branch="$(git rev-parse --abbrev-ref HEAD)" -if [ "$branch" = "main" ]; then - echo "You can't push directly to main - please check out a branch." - exit 1 -fi +# if [ "$branch" = "main" ]; then +# echo "You can't push directly to main - please check out a branch." +# exit 1 +# fi npm run compile diff --git a/package.json b/package.json index 5c4097cd6ef..44b2e7b2f15 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,9 @@ }, "repository": { "type": "git", - "url": "https://github.com/RooVetGit/Roo-Code" + "url": "https://github.com/trypear/PearAI-Roo-Code" }, - "homepage": "https://github.com/RooVetGit/Roo-Code", + "homepage": "https://github.com/trypear/PearAI-Roo-Code", "categories": [ "AI", "Chat", @@ -51,16 +51,16 @@ "main": "./dist/extension.js", "contributes": { "viewsContainers": { - "activitybar": [ + "auxiliarybar": [ { - "id": "roo-cline-ActivityBar", - "title": "Roo Code", + "id": "pearai-roo-cline", + "title": "PearAI Agent", "icon": "$(rocket)" } ] }, "views": { - "roo-cline-ActivityBar": [ + "pearai-roo-cline": [ { "type": "webview", "id": "roo-cline.SidebarProvider", From baa0f57ade146a5e21672bd3c309594902ac709e Mon Sep 17 00:00:00 2001 From: Himanshu Date: Sat, 1 Feb 2025 12:50:23 +0530 Subject: [PATCH 13/30] add aider in gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 95f71065c06..ca8bc23f0ec 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ roo-cline-*.vsix # Docs docs/_site/ + +# aider +.aider* From f5c73e5aa98e89f33b8ce11d412eb53fd97516e5 Mon Sep 17 00:00:00 2001 From: Himanshu Date: Mon, 3 Feb 2025 23:56:17 +0530 Subject: [PATCH 14/30] input box - recent chats --- package-lock.json | 86 ++ package.json | 2 + webview-ui/package-lock.json | 797 +++++++++++++++++- webview-ui/package.json | 3 + .../src/components/chat/ChatTextArea.tsx | 272 +++--- webview-ui/src/components/chat/ChatView.tsx | 65 +- .../src/components/history/HistoryPreview.tsx | 20 +- .../src/components/ui/ShortcutsButton.tsx | 55 ++ .../src/components/ui/button-pear-scn.tsx | 48 ++ webview-ui/src/components/ui/index.tsx | 364 ++++++++ webview-ui/src/components/ui/select.tsx | 135 +++ 11 files changed, 1699 insertions(+), 148 deletions(-) create mode 100644 webview-ui/src/components/ui/ShortcutsButton.tsx create mode 100644 webview-ui/src/components/ui/button-pear-scn.tsx create mode 100644 webview-ui/src/components/ui/index.tsx create mode 100644 webview-ui/src/components/ui/select.tsx diff --git a/package-lock.json b/package-lock.json index 5dc9c8bfddb..28fde46dc60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@anthropic-ai/vertex-sdk": "^0.4.1", "@aws-sdk/client-bedrock-runtime": "^3.706.0", "@google/generative-ai": "^0.18.0", + "@heroicons/react": "^2.2.0", "@mistralai/mistralai": "^1.3.6", "@modelcontextprotocol/sdk": "^1.0.1", "@types/clone-deep": "^4.0.4", @@ -41,6 +42,7 @@ "pdf-parse": "^1.1.1", "puppeteer-chromium-resolver": "^23.0.0", "puppeteer-core": "^23.4.0", + "react-tooltip": "^5.28.0", "serialize-error": "^11.0.3", "simple-git": "^3.27.0", "sound-play": "^1.1.0", @@ -3127,6 +3129,31 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.13", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", + "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "license": "MIT" + }, "node_modules/@google/generative-ai": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.18.0.tgz", @@ -3135,6 +3162,15 @@ "node": ">=18.0.0" } }, + "node_modules/@heroicons/react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz", + "integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16 || ^19.0.0-rc" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -7087,6 +7123,12 @@ "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", "dev": true }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, "node_modules/cli-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", @@ -13086,12 +13128,49 @@ "node": ">= 0.8" } }, + "node_modules/react": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", + "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.25.0" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, + "node_modules/react-tooltip": { + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.28.0.tgz", + "integrity": "sha512-R5cO3JPPXk6FRbBHMO0rI9nkUG/JKfalBSQfZedZYzmqaZQgq7GLzF8vcCWx6IhUCKg0yPqJhXIzmIO5ff15xg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.6.1", + "classnames": "^2.3.0" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -13503,6 +13582,13 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/scheduler": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", + "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", + "license": "MIT", + "peer": true + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", diff --git a/package.json b/package.json index 44b2e7b2f15..f22c404af4c 100644 --- a/package.json +++ b/package.json @@ -273,6 +273,7 @@ "@anthropic-ai/vertex-sdk": "^0.4.1", "@aws-sdk/client-bedrock-runtime": "^3.706.0", "@google/generative-ai": "^0.18.0", + "@heroicons/react": "^2.2.0", "@mistralai/mistralai": "^1.3.6", "@modelcontextprotocol/sdk": "^1.0.1", "@types/clone-deep": "^4.0.4", @@ -301,6 +302,7 @@ "pdf-parse": "^1.1.1", "puppeteer-chromium-resolver": "^23.0.0", "puppeteer-core": "^23.4.0", + "react-tooltip": "^5.28.0", "serialize-error": "^11.0.3", "simple-git": "^3.27.0", "sound-play": "^1.1.0", diff --git a/webview-ui/package-lock.json b/webview-ui/package-lock.json index 0334c86798f..5738e9092d7 100644 --- a/webview-ui/package-lock.json +++ b/webview-ui/package-lock.json @@ -8,6 +8,9 @@ "name": "webview-ui", "version": "0.1.0", "dependencies": { + "@headlessui/react": "^2.2.0", + "@radix-ui/react-icons": "^1.3.2", + "@radix-ui/react-select": "^2.1.5", "@radix-ui/react-slot": "^1.1.1", "@tailwindcss/vite": "^4.0.0", "@vscode/webview-ui-toolkit": "^1.4.0", @@ -1164,6 +1167,84 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.13", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", + "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.26.28", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", + "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react/node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "license": "MIT" + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "license": "MIT" + }, + "node_modules/@headlessui/react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.0.tgz", + "integrity": "sha512-RzCEg+LXsuI7mHiSomsu/gBJSjpupm6A1qIZ5sWjd7JhARNlMiSA4kKfJpCKwU9tE+zMRterhhrP74PvfJrpXQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.26.16", + "@react-aria/focus": "^3.17.1", + "@react-aria/interactions": "^3.21.3", + "@tanstack/react-virtual": "^3.8.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -1800,6 +1881,67 @@ "node": ">= 8" } }, + "node_modules/@radix-ui/number": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", + "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.1.tgz", + "integrity": "sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz", + "integrity": "sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", @@ -1815,6 +1957,252 @@ } } }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.4.tgz", + "integrity": "sha512-XDUI0IVYVSwjMXxM6P4Dfti7AH+Y4oS/TB+sglZ/EXc7cqLwGAmp1NlMrcUjj7ks6R5WTZuWKv44FBbLpwU3sA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz", + "integrity": "sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-icons": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz", + "integrity": "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==", + "license": "MIT", + "peerDependencies": { + "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.1.tgz", + "integrity": "sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz", + "integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.5.tgz", + "integrity": "sha512-eVV7N8jBXAXnyrc+PsOF89O9AfVgGnbLxUtBb0clJ8y8ENMWLARGMI/1/SBRLz7u4HqxLgN71BJ17eono3wcjA==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.4", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.1", + "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-slot": "1.1.1", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", @@ -1833,6 +2221,238 @@ } } }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz", + "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.1.tgz", + "integrity": "sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", + "license": "MIT" + }, + "node_modules/@react-aria/focus": { + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.19.1.tgz", + "integrity": "sha512-bix9Bu1Ue7RPcYmjwcjhB14BMu2qzfJ3tMQLqDc9pweJA66nOw8DThy3IfVr8Z7j2PHktOLf9kcbiZpydKHqzg==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.23.0", + "@react-aria/utils": "^3.27.0", + "@react-types/shared": "^3.27.0", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/interactions": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.23.0.tgz", + "integrity": "sha512-0qR1atBIWrb7FzQ+Tmr3s8uH5mQdyRH78n0krYaG8tng9+u1JlSi8DGRSaC9ezKyNB84m7vHT207xnHXGeJ3Fg==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.7", + "@react-aria/utils": "^3.27.0", + "@react-types/shared": "^3.27.0", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.7.tgz", + "integrity": "sha512-GQygZaGlmYjmYM+tiNBA5C6acmiDWF52Nqd40bBp0Znk4M4hP+LTmI0lpI1BuKMw45T8RIhrAsICIfKwZvi2Gg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/utils": { + "version": "3.27.0", + "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.27.0.tgz", + "integrity": "sha512-p681OtApnKOdbeN8ITfnnYqfdHS0z7GE+4l8EXlfLnr70Rp/9xicBO6d2rU+V/B3JujDw2gPWxYKEnEeh0CGCw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.7", + "@react-stately/utils": "^3.10.5", + "@react-types/shared": "^3.27.0", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/utils": { + "version": "3.10.5", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.10.5.tgz", + "integrity": "sha512-iMQSGcpaecghDIh3mZEpZfoFH3ExBwTtuBEcvZ2XnGzCgQjeYXcMdIUwAfVQLXFTdHUHGF6Gu6/dFrYsCzySBQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/shared": { + "version": "3.27.0", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.27.0.tgz", + "integrity": "sha512-gvznmLhi6JPEf0bsq7SwRYTHAKKq/wcmKqFez9sRdbED+SPMUmK5omfZ6w3EwUFQHbYUa4zPBYedQ7Knv70RMw==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, "node_modules/@rollup/pluginutils": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", @@ -2784,6 +3404,15 @@ "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" } }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@tailwindcss/node": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.0.0.tgz", @@ -3017,6 +3646,33 @@ "vite": "^5.2.0 || ^6" } }, + "node_modules/@tanstack/react-virtual": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.12.0.tgz", + "integrity": "sha512-6krceiPN07kpxXmU6m8AY7EL0X1gHLu8m3nJdh4phvktzVNxkQfBmSwnRUpoUjGQO1PAn8wSAhYaL8hY1cS1vw==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.12.0.tgz", + "integrity": "sha512-7mDINtua3v/pOnn6WUmuT9dPXYSO7WidFej7JzoAfqEOcbbpt/iZ1WPqd+eg+FnrL9nUJK8radqj4iAU51Zchg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@testing-library/dom": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", @@ -3344,7 +4000,7 @@ "version": "18.3.5", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz", "integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^18.0.0" @@ -3997,6 +4653,18 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/aria-query": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", @@ -5143,6 +5811,12 @@ "node": ">=8" } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", @@ -6410,6 +7084,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -10046,6 +10729,75 @@ "react": ">=16.8" } }, + "node_modules/react-remove-scroll": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", + "integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-textarea-autosize": { "version": "8.5.7", "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.7.tgz", @@ -11957,6 +12709,27 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-composed-ref": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.4.0.tgz", @@ -12002,6 +12775,28 @@ } } }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", diff --git a/webview-ui/package.json b/webview-ui/package.json index 7616446955b..f84ebb36b3e 100644 --- a/webview-ui/package.json +++ b/webview-ui/package.json @@ -13,6 +13,9 @@ "build-storybook": "storybook build" }, "dependencies": { + "@headlessui/react": "^2.2.0", + "@radix-ui/react-icons": "^1.3.2", + "@radix-ui/react-select": "^2.1.5", "@radix-ui/react-slot": "^1.1.1", "@tailwindcss/vite": "^4.0.0", "@vscode/webview-ui-toolkit": "^1.4.0", diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index 99c75df13d2..5467a0e8e7f 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -16,6 +16,97 @@ import { vscode } from "../../utils/vscode" import { WebviewMessage } from "../../../../src/shared/WebviewMessage" import { Mode, getAllModes } from "../../../../src/shared/modes" import { CaretIcon } from "../common/CaretIcon" +import { Button } from "../ui/button-pear-scn" +import { ArrowTurnDownLeftIcon, TrashIcon } from "@heroicons/react/16/solid" +import { getFontSize, lightGray, vscEditorBackground, vscFocusBorder, vscInputBackground } from "../ui" +import styled from "styled-components" +import { Listbox } from "@headlessui/react" +import { ImageIcon } from "@radix-ui/react-icons" + +const StyledListboxButton = styled(Listbox.Button)` + border: solid 1px ${lightGray}30; + background-color: ${vscEditorBackground}; + border-radius: 4px; + padding: 4px 8px; + display: flex; + align-items: center; + gap: 2px; + user-select: none; + cursor: pointer; + font-size: ${getFontSize() - 3}px; + color: ${lightGray}; + &:focus { + outline: none; + } +` + +const StyledListboxOptions = styled(Listbox.Options)<{ newSession: boolean }>` + position: absolute; + bottom: 100%; + left: 0; + margin-bottom: 4px; + list-style: none; + padding: 6px; + white-space: nowrap; + cursor: default; + z-index: 50; + border: 1px solid ${lightGray}30; + border-radius: 10px; + background-color: ${vscEditorBackground}; + max-height: 300px; + min-width: 100px; + overflow-y: auto; + font-size: ${getFontSize() - 2}px; + user-select: none; + outline: none; + + &::-webkit-scrollbar { + display: none; + } + + scrollbar-width: none; + -ms-overflow-style: none; + + & > * { + margin: 4px 0; + } +` + +interface ListboxOptionProps { + isCurrentModel?: boolean +} + +const StyledListboxOption = styled(Listbox.Option)` + cursor: pointer; + border-radius: 6px; + padding: 5px 4px; + + &:hover { + background: ${(props) => (props.isCurrentModel ? `${lightGray}66` : `${lightGray}33`)}; + } + + background: ${(props) => (props.isCurrentModel ? `${lightGray}66` : "transparent")}; +` + +const StyledTrashIcon = styled(TrashIcon)` + cursor: pointer; + flex-shrink: 0; + margin-left: 8px; + &:hover { + color: red; + } +` + +const Divider = styled.div` + height: 2px; + background-color: ${lightGray}35; + margin: 0px 4px; +` + +const ListboxWrapper = styled.div` + position: relative; + display: inline-block; +` interface ChatTextAreaProps { inputValue: string @@ -498,35 +589,6 @@ const ChatTextArea = forwardRef( [updateCursorPosition], ) - const selectStyle = { - fontSize: "11px", - cursor: textAreaDisabled ? "not-allowed" : "pointer", - backgroundColor: "transparent", - border: "none", - color: "var(--vscode-foreground)", - opacity: textAreaDisabled ? 0.5 : 0.8, - outline: "none", - paddingLeft: "20px", - paddingRight: "6px", - WebkitAppearance: "none" as const, - MozAppearance: "none" as const, - appearance: "none" as const, - } - - const optionStyle = { - backgroundColor: "var(--vscode-dropdown-background)", - color: "var(--vscode-dropdown-foreground)", - } - - const caretContainerStyle = { - position: "absolute" as const, - left: 6, - top: "50%", - transform: "translateY(-45%)", - pointerEvents: "none" as const, - opacity: textAreaDisabled ? 0.5 : 0.8, - } - return (
( display: "flex", flexDirection: "column", gap: "8px", - backgroundColor: "var(--vscode-input-background)", + backgroundColor: vscEditorBackground, margin: "10px 15px", padding: "8px", outline: "none", border: "1px solid", - borderColor: isFocused ? "var(--vscode-focusBorder)" : "transparent", - borderRadius: "2px", + borderColor: "transparent", + borderRadius: "12px", }} onDrop={async (e) => { e.preventDefault() @@ -668,7 +730,7 @@ const ChatTextArea = forwardRef( onHeightChange?.(height) }} placeholder={placeholderText} - minRows={3} + minRows={2} maxRows={15} autoFocus={true} style={{ @@ -686,6 +748,8 @@ const ChatTextArea = forwardRef( overflowY: "auto", border: "none", padding: "2px", + paddingTop: "8px", + paddingBottom: "8px", paddingRight: "8px", marginBottom: thumbnailsHeight > 0 ? `${thumbnailsHeight + 16}px` : 0, cursor: textAreaDisabled ? "not-allowed" : undefined, @@ -724,13 +788,12 @@ const ChatTextArea = forwardRef( style={{ display: "flex", alignItems: "center", + gap: "8px", }}> -
- -
- -
-
- -
- -
- -
-
+ disabled={textAreaDisabled}> + + {currentApiConfigName} + + + + {(listApiConfigMeta || []).map((config) => ( + + {config.name} + + ))} + + + Edit... + + + +
( /> )}
- !shouldDisableImages && onSelectImages()} - style={{ fontSize: 16.5 }} - /> - !textAreaDisabled && onSend()} - style={{ fontSize: 15 }} /> +
diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index a05a5cda607..31e112824c6 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -970,6 +970,27 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie flexDirection: "column", overflow: "hidden", }}> + {messages.length === 0 && ( + handleSendMessage(inputValue, selectedImages)} + onSelectImages={selectImages} + shouldDisableImages={shouldDisableImages} + onHeightChange={() => { + if (isAtBottom) { + scrollToBottomAuto() + } + }} + mode={mode} + setMode={setMode} + /> + )} {task ? ( {showAnnouncement && } -
+ {/*

PearAI Coding Agent (Powered by Roo Code / Cline)

Ask me to create a new feature, fix a bug, anything else. I can create & edit files, explore complex projects, use the browser, and execute terminal commands!

-
+
*/} {taskHistory.length > 0 && } )} @@ -1113,25 +1134,27 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie )} )} - handleSendMessage(inputValue, selectedImages)} - onSelectImages={selectImages} - shouldDisableImages={shouldDisableImages} - onHeightChange={() => { - if (isAtBottom) { - scrollToBottomAuto() - } - }} - mode={mode} - setMode={setMode} - /> + {messages.length > 0 && ( + handleSendMessage(inputValue, selectedImages)} + onSelectImages={selectImages} + shouldDisableImages={shouldDisableImages} + onHeightChange={() => { + if (isAtBottom) { + scrollToBottomAuto() + } + }} + mode={mode} + setMode={setMode} + /> + )} ) } diff --git a/webview-ui/src/components/history/HistoryPreview.tsx b/webview-ui/src/components/history/HistoryPreview.tsx index 08aca2a44dc..719ad77edf1 100644 --- a/webview-ui/src/components/history/HistoryPreview.tsx +++ b/webview-ui/src/components/history/HistoryPreview.tsx @@ -3,6 +3,8 @@ import { useExtensionState } from "../../context/ExtensionStateContext" import { vscode } from "../../utils/vscode" import { memo } from "react" import { formatLargeNumber } from "../../utils/format" +import { vscEditorBackground } from "../ui" +import { CounterClockwiseClockIcon } from "@radix-ui/react-icons" type HistoryPreviewProps = { showHistoryView: () => void @@ -30,20 +32,23 @@ const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => { } return ( -
+