mirror of
https://github.com/cline/cline.git
synced 2026-09-07 04:44:58 +08:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 62463284d9 | |||
| 21f13f56c3 | |||
| b737911cdc | |||
| 1de02e9ab2 | |||
| 08d4240e70 | |||
| fe13ce8d6f | |||
| 7fe7605a85 | |||
| f0e352489f | |||
| aff78bda7c | |||
| c7c1d37379 | |||
| e6da7c7282 | |||
| 78c3c5eff2 | |||
| 6b243ee826 | |||
| 14a056ed3e | |||
| 086879d149 |
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Migrate openSettings message to use state navigation handlers
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Migrate setActiveQuote to protobus
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
feat: added gemini flash 05-20
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Migrate updateTerminalConnectionTimeout to protobus
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
Fixing bug in toggle plan and act
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
scrollToSetting protobus migration
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
openMention protobus migration
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Migrate toggleWindsurfRule to protobus
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Migrate silentlyRefreshMcpMarketplace to protobus
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Migrate toggleCursorRule to protobus
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
browserRelaunchResult protobus migration
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
Remind VS code users of clines existence(Open Cline on AutoUpdate+KeyboardShortcuts+Lightbulb icons)
|
||||
Generated
+1
-1
@@ -44188,4 +44188,4 @@
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,16 @@
|
||||
"title": "Generate Commit Message with Cline",
|
||||
"category": "Cline",
|
||||
"icon": "$(robot)"
|
||||
},
|
||||
{
|
||||
"command": "cline.explainCode",
|
||||
"title": "Explain with Cline",
|
||||
"category": "Cline"
|
||||
},
|
||||
{
|
||||
"command": "cline.improveCode",
|
||||
"title": "Improve with Cline",
|
||||
"category": "Cline"
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
@@ -140,6 +150,14 @@
|
||||
{
|
||||
"command": "cline.generateGitCommitMessage",
|
||||
"when": "scmProvider == git"
|
||||
},
|
||||
{
|
||||
"command": "cline.focusChatInput",
|
||||
"key": "cmd+'",
|
||||
"mac": "cmd+'",
|
||||
"win": "ctrl+'",
|
||||
"linux": "ctrl+'",
|
||||
"when": "!editorHasSelection"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
|
||||
@@ -12,6 +12,7 @@ service BrowserService {
|
||||
rpc discoverBrowser(EmptyRequest) returns (BrowserConnection);
|
||||
rpc getDetectedChromePath(EmptyRequest) returns (ChromePath);
|
||||
rpc updateBrowserSettings(UpdateBrowserSettingsRequest) returns (Boolean);
|
||||
rpc relaunchChromeDebugMode(EmptyRequest) returns (String);
|
||||
}
|
||||
|
||||
message BrowserConnectionInfo {
|
||||
|
||||
@@ -10,12 +10,16 @@ import chalk from "chalk"
|
||||
import { createRequire } from "module"
|
||||
const require = createRequire(import.meta.url)
|
||||
const protoc = path.join(require.resolve("grpc-tools"), "../bin/protoc")
|
||||
const tsProtoPlugin = require.resolve("ts-proto/protoc-gen-ts_proto")
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const SCRIPT_DIR = path.dirname(__filename)
|
||||
const ROOT_DIR = path.resolve(SCRIPT_DIR, "..")
|
||||
|
||||
const isWindows = process.platform === "win32"
|
||||
const tsProtoPlugin = isWindows
|
||||
? path.join(ROOT_DIR, "node_modules", ".bin", "protoc-gen-ts_proto.cmd") // Use the .bin directory path for Windows
|
||||
: require.resolve("ts-proto/protoc-gen-ts_proto")
|
||||
|
||||
// List of gRPC services
|
||||
// To add a new service, simply add it to this map and run this script
|
||||
// The service handler will be automatically discovered and used by grpc-handler.ts
|
||||
@@ -30,6 +34,7 @@ const serviceNameMap = {
|
||||
web: "cline.WebService",
|
||||
models: "cline.ModelsService",
|
||||
slash: "cline.SlashService",
|
||||
ui: "cline.UiService",
|
||||
// Add new services here - no other code changes needed!
|
||||
}
|
||||
const serviceDirs = Object.keys(serviceNameMap).map((serviceKey) => path.join(ROOT_DIR, "src", "core", "controller", serviceKey))
|
||||
@@ -55,7 +60,7 @@ async function main() {
|
||||
|
||||
// Process all proto files
|
||||
console.log(chalk.cyan("Processing proto files from"), SCRIPT_DIR)
|
||||
const protoFiles = await globby("*.proto", { cwd: SCRIPT_DIR, absolute: true })
|
||||
const protoFiles = await globby("*.proto", { cwd: SCRIPT_DIR, realpath: true })
|
||||
|
||||
// Build the protoc command with proper path handling for cross-platform
|
||||
const tsProtocCommand = [
|
||||
|
||||
@@ -16,6 +16,9 @@ service FileService {
|
||||
|
||||
// Opens an image in the system viewer
|
||||
rpc openImage(StringRequest) returns (Empty);
|
||||
|
||||
// Opens a mention (file, path, git commit, problem, terminal, or URL)
|
||||
rpc openMention(StringRequest) returns (Empty);
|
||||
|
||||
// Deletes a rule file from either global or workspace rules directory
|
||||
rpc deleteRuleFile(RuleFileRequest) returns (RuleFile);
|
||||
@@ -37,6 +40,19 @@ service FileService {
|
||||
|
||||
// Toggle a Cline rule (enable or disable)
|
||||
rpc toggleClineRule(ToggleClineRuleRequest) returns (ToggleClineRules);
|
||||
|
||||
// Toggle a Cursor rule (enable or disable)
|
||||
rpc toggleCursorRule(ToggleCursorRuleRequest) returns (ClineRulesToggles);
|
||||
|
||||
// Toggle a Windsurf rule (enable or disable)
|
||||
rpc toggleWindsurfRule(ToggleWindsurfRuleRequest) returns (ClineRulesToggles);
|
||||
}
|
||||
|
||||
// Request to toggle a Windsurf rule
|
||||
message ToggleWindsurfRuleRequest {
|
||||
Metadata metadata = 1;
|
||||
string rule_path = 2; // Path to the rule file
|
||||
bool enabled = 3; // Whether to enable or disable the rule
|
||||
}
|
||||
|
||||
// Request to convert a list of URIs to relative paths
|
||||
@@ -119,3 +135,10 @@ message ToggleClineRules {
|
||||
ClineRulesToggles global_cline_rules_toggles = 1;
|
||||
ClineRulesToggles local_cline_rules_toggles = 2;
|
||||
}
|
||||
|
||||
// Request to toggle a Cursor rule
|
||||
message ToggleCursorRuleRequest {
|
||||
Metadata metadata = 1;
|
||||
string rule_path = 2; // Path to the rule file
|
||||
bool enabled = 3; // Whether to enable or disable the rule
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ service McpService {
|
||||
rpc restartMcpServer(StringRequest) returns (McpServers);
|
||||
rpc deleteMcpServer(StringRequest) returns (McpServers);
|
||||
rpc toggleToolAutoApprove(ToggleToolAutoApproveRequest) returns (McpServers);
|
||||
rpc refreshMcpMarketplace(EmptyRequest) returns (McpMarketplaceCatalog);
|
||||
}
|
||||
|
||||
message ToggleMcpServerRequest {
|
||||
@@ -85,3 +86,28 @@ message McpServer {
|
||||
message McpServers {
|
||||
repeated McpServer mcp_servers = 1;
|
||||
}
|
||||
|
||||
message McpMarketplaceItem {
|
||||
string mcp_id = 1;
|
||||
string github_url = 2;
|
||||
string name = 3;
|
||||
string author = 4;
|
||||
string description = 5;
|
||||
string codicon_icon = 6;
|
||||
string logo_url = 7;
|
||||
string category = 8;
|
||||
repeated string tags = 9;
|
||||
bool requires_api_key = 10;
|
||||
optional string readme_content = 11;
|
||||
optional string llms_installation_content = 12;
|
||||
bool is_recommended = 13;
|
||||
int32 github_stars = 14;
|
||||
int32 download_count = 15;
|
||||
string created_at = 16;
|
||||
string updated_at = 17;
|
||||
string last_github_sync = 18;
|
||||
}
|
||||
|
||||
message McpMarketplaceCatalog {
|
||||
repeated McpMarketplaceItem items = 1;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ service StateService {
|
||||
rpc toggleFavoriteModel(StringRequest) returns (Empty);
|
||||
rpc resetState(EmptyRequest) returns (Empty);
|
||||
rpc togglePlanActMode(TogglePlanActModeRequest) returns (Empty);
|
||||
rpc updateTerminalConnectionTimeout(Int64Request) returns (Int64);
|
||||
}
|
||||
|
||||
message State {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package cline;
|
||||
option java_package = "bot.cline.proto";
|
||||
option java_multiple_files = true;
|
||||
|
||||
import "common.proto";
|
||||
|
||||
// UiService provides methods for managing UI interactions
|
||||
service UiService {
|
||||
// Scrolls to a specific settings section in the settings view
|
||||
rpc scrollToSettings(StringRequest) returns (Empty);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { registerMethod } from "./index"
|
||||
import { discoverBrowser } from "./discoverBrowser"
|
||||
import { getBrowserConnectionInfo } from "./getBrowserConnectionInfo"
|
||||
import { getDetectedChromePath } from "./getDetectedChromePath"
|
||||
import { relaunchChromeDebugMode } from "./relaunchChromeDebugMode"
|
||||
import { testBrowserConnection } from "./testBrowserConnection"
|
||||
import { updateBrowserSettings } from "./updateBrowserSettings"
|
||||
|
||||
@@ -15,6 +16,7 @@ export function registerAllMethods(): void {
|
||||
registerMethod("discoverBrowser", discoverBrowser)
|
||||
registerMethod("getBrowserConnectionInfo", getBrowserConnectionInfo)
|
||||
registerMethod("getDetectedChromePath", getDetectedChromePath)
|
||||
registerMethod("relaunchChromeDebugMode", relaunchChromeDebugMode)
|
||||
registerMethod("testBrowserConnection", testBrowserConnection)
|
||||
registerMethod("updateBrowserSettings", updateBrowserSettings)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { EmptyRequest, String as StringMessage } from "../../../shared/proto/common"
|
||||
import { Controller } from "../index"
|
||||
import { BrowserSession } from "../../../services/browser/BrowserSession"
|
||||
|
||||
/**
|
||||
* Relaunch Chrome in debug mode
|
||||
* @param controller The controller instance
|
||||
* @param request The empty request message
|
||||
* @returns The browser relaunch result as a string message
|
||||
*/
|
||||
export async function relaunchChromeDebugMode(controller: Controller, request: EmptyRequest): Promise<StringMessage> {
|
||||
try {
|
||||
const { browserSettings } = await controller.getStateToPostToWebview()
|
||||
const browserSession = new BrowserSession(controller.context, browserSettings)
|
||||
|
||||
// Relaunch Chrome in debug mode
|
||||
await browserSession.relaunchChromeDebugMode(controller)
|
||||
|
||||
// The actual result will be sent via postMessageToWebview in the BrowserSession.relaunchChromeDebugMode method
|
||||
// Here we just return a message as a placeholder
|
||||
return {
|
||||
value: "Chrome relaunch initiated",
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`Error relaunching Chrome: ${error instanceof Error ? error.message : globalThis.String(error)}`)
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,13 @@ import { deleteRuleFile } from "./deleteRuleFile"
|
||||
import { getRelativePaths } from "./getRelativePaths"
|
||||
import { openFile } from "./openFile"
|
||||
import { openImage } from "./openImage"
|
||||
import { openMention } from "./openMention"
|
||||
import { searchCommits } from "./searchCommits"
|
||||
import { searchFiles } from "./searchFiles"
|
||||
import { selectImages } from "./selectImages"
|
||||
import { toggleClineRule } from "./toggleClineRule"
|
||||
import { toggleCursorRule } from "./toggleCursorRule"
|
||||
import { toggleWindsurfRule } from "./toggleWindsurfRule"
|
||||
|
||||
// Register all file service methods
|
||||
export function registerAllMethods(): void {
|
||||
@@ -23,8 +26,11 @@ export function registerAllMethods(): void {
|
||||
registerMethod("getRelativePaths", getRelativePaths)
|
||||
registerMethod("openFile", openFile)
|
||||
registerMethod("openImage", openImage)
|
||||
registerMethod("openMention", openMention)
|
||||
registerMethod("searchCommits", searchCommits)
|
||||
registerMethod("searchFiles", searchFiles)
|
||||
registerMethod("selectImages", selectImages)
|
||||
registerMethod("toggleClineRule", toggleClineRule)
|
||||
registerMethod("toggleCursorRule", toggleCursorRule)
|
||||
registerMethod("toggleWindsurfRule", toggleWindsurfRule)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Controller } from ".."
|
||||
import { Empty, StringRequest } from "../../../shared/proto/common"
|
||||
import { openMention as coreOpenMention } from "../../mentions"
|
||||
|
||||
/**
|
||||
* Opens a mention (file path, problem, terminal, or URL)
|
||||
* @param controller The controller instance
|
||||
* @param request The string request containing the mention text
|
||||
* @returns Empty response
|
||||
*/
|
||||
export async function openMention(controller: Controller, request: StringRequest): Promise<Empty> {
|
||||
coreOpenMention(request.value)
|
||||
return Empty.create()
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { ToggleCursorRuleRequest, ClineRulesToggles } from "../../../shared/proto/file"
|
||||
import type { Controller } from "../index"
|
||||
import { getWorkspaceState, updateWorkspaceState } from "../../../core/storage/state"
|
||||
import { ClineRulesToggles as AppClineRulesToggles } from "@shared/cline-rules"
|
||||
|
||||
/**
|
||||
* Toggles a Cursor rule (enable or disable)
|
||||
* @param controller The controller instance
|
||||
* @param request The toggle request
|
||||
* @returns The updated Cursor rule toggles
|
||||
*/
|
||||
export async function toggleCursorRule(controller: Controller, request: ToggleCursorRuleRequest): Promise<ClineRulesToggles> {
|
||||
const { rulePath, enabled } = request
|
||||
|
||||
if (!rulePath || typeof enabled !== "boolean") {
|
||||
console.error("toggleCursorRule: Missing or invalid parameters", {
|
||||
rulePath,
|
||||
enabled: typeof enabled === "boolean" ? enabled : `Invalid: ${typeof enabled}`,
|
||||
})
|
||||
throw new Error("Missing or invalid parameters for toggleCursorRule")
|
||||
}
|
||||
|
||||
// Update the toggles in workspace state
|
||||
const toggles = ((await getWorkspaceState(controller.context, "localCursorRulesToggles")) as AppClineRulesToggles) || {}
|
||||
toggles[rulePath] = enabled
|
||||
await updateWorkspaceState(controller.context, "localCursorRulesToggles", toggles)
|
||||
|
||||
// Get the current state to return in the response
|
||||
const cursorToggles = ((await getWorkspaceState(controller.context, "localCursorRulesToggles")) as AppClineRulesToggles) || {}
|
||||
|
||||
return {
|
||||
toggles: cursorToggles,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { ToggleWindsurfRuleRequest, ClineRulesToggles } from "../../../shared/proto/file"
|
||||
import type { Controller } from "../index"
|
||||
import { getWorkspaceState, updateWorkspaceState } from "../../../core/storage/state"
|
||||
import { ClineRulesToggles as AppClineRulesToggles } from "@shared/cline-rules"
|
||||
|
||||
/**
|
||||
* Toggles a Windsurf rule (enable or disable)
|
||||
* @param controller The controller instance
|
||||
* @param request The toggle request
|
||||
* @returns The updated Windsurf rule toggles
|
||||
*/
|
||||
export async function toggleWindsurfRule(controller: Controller, request: ToggleWindsurfRuleRequest): Promise<ClineRulesToggles> {
|
||||
const { rulePath, enabled } = request
|
||||
|
||||
if (!rulePath || typeof enabled !== "boolean") {
|
||||
console.error("toggleWindsurfRule: Missing or invalid parameters", {
|
||||
rulePath,
|
||||
enabled: typeof enabled === "boolean" ? enabled : `Invalid: ${typeof enabled}`,
|
||||
})
|
||||
throw new Error("Missing or invalid parameters for toggleWindsurfRule")
|
||||
}
|
||||
|
||||
// Update the toggles
|
||||
const toggles = ((await getWorkspaceState(controller.context, "localWindsurfRulesToggles")) as AppClineRulesToggles) || {}
|
||||
toggles[rulePath] = enabled
|
||||
await updateWorkspaceState(controller.context, "localWindsurfRulesToggles", toggles)
|
||||
|
||||
// Return the toggles directly
|
||||
return { toggles: toggles }
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import { handleTaskServiceRequest, handleTaskServiceStreamingRequest } from "./t
|
||||
import { handleWebServiceRequest, handleWebServiceStreamingRequest } from "./web/index"
|
||||
import { handleModelsServiceRequest, handleModelsServiceStreamingRequest } from "./models/index"
|
||||
import { handleSlashServiceRequest, handleSlashServiceStreamingRequest } from "./slash/index"
|
||||
import { handleUiServiceRequest, handleUiServiceStreamingRequest } from "./ui/index"
|
||||
|
||||
/**
|
||||
* Configuration for a service handler
|
||||
@@ -72,4 +73,8 @@ export const serviceHandlers: Record<string, ServiceHandlerConfig> = {
|
||||
requestHandler: handleSlashServiceRequest,
|
||||
streamingHandler: handleSlashServiceStreamingRequest,
|
||||
},
|
||||
"cline.UiService": {
|
||||
requestHandler: handleUiServiceRequest,
|
||||
streamingHandler: handleUiServiceStreamingRequest,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import { fileExistsAtPath } from "@utils/fs"
|
||||
import { getWorkingState } from "@utils/git"
|
||||
import { extractCommitMessage } from "@integrations/git/commit-message-generator"
|
||||
import { getTotalTasksSize } from "@utils/storage"
|
||||
import { openMention } from "../mentions"
|
||||
import { ensureMcpServersDirectoryExists, ensureSettingsDirectoryExists, GlobalFileNames } from "../storage/disk"
|
||||
import {
|
||||
getAllExtensionState,
|
||||
@@ -306,6 +305,11 @@ export class Controller {
|
||||
}
|
||||
}
|
||||
break
|
||||
case "togglePlanActMode":
|
||||
if (message.chatSettings) {
|
||||
await this.togglePlanActModeWithChatSettings(message.chatSettings, message.chatContent)
|
||||
}
|
||||
break
|
||||
case "optionsResponse":
|
||||
await this.postMessageToWebview({
|
||||
type: "invoke",
|
||||
@@ -313,11 +317,6 @@ export class Controller {
|
||||
text: message.text,
|
||||
})
|
||||
break
|
||||
case "relaunchChromeDebugMode":
|
||||
const { browserSettings } = await getAllExtensionState(this.context)
|
||||
const browserSession = new BrowserSession(this.context, browserSettings)
|
||||
await browserSession.relaunchChromeDebugMode(this)
|
||||
break
|
||||
case "didShowAnnouncement":
|
||||
await updateGlobalState(this.context, "lastShownAnnouncementId", this.latestAnnouncementId)
|
||||
await this.postStateToWebview()
|
||||
@@ -333,9 +332,6 @@ export class Controller {
|
||||
vscode.env.openExternal(vscode.Uri.parse(message.url))
|
||||
}
|
||||
break
|
||||
case "openMention":
|
||||
openMention(message.text)
|
||||
break
|
||||
case "showAccountViewClicked": {
|
||||
await this.postMessageToWebview({ type: "action", action: "accountButtonClicked" })
|
||||
break
|
||||
@@ -355,10 +351,6 @@ export class Controller {
|
||||
await this.fetchMcpMarketplace(message.bool)
|
||||
break
|
||||
}
|
||||
case "silentlyRefreshMcpMarketplace": {
|
||||
await this.silentlyRefreshMcpMarketplace()
|
||||
break
|
||||
}
|
||||
// case "openMcpMarketplaceServerDetails": {
|
||||
// if (message.text) {
|
||||
// const response = await fetch(`https://api.cline.bot/v1/mcp/marketplace/item?mcpId=${message.mcpId}`)
|
||||
@@ -394,32 +386,6 @@ export class Controller {
|
||||
|
||||
// break
|
||||
// }
|
||||
case "toggleWindsurfRule": {
|
||||
const { rulePath, enabled } = message
|
||||
if (rulePath && typeof enabled === "boolean") {
|
||||
const toggles =
|
||||
((await getWorkspaceState(this.context, "localWindsurfRulesToggles")) as ClineRulesToggles) || {}
|
||||
toggles[rulePath] = enabled
|
||||
await updateWorkspaceState(this.context, "localWindsurfRulesToggles", toggles)
|
||||
await this.postStateToWebview()
|
||||
} else {
|
||||
console.error("toggleWindsurfRule: Missing or invalid parameters")
|
||||
}
|
||||
break
|
||||
}
|
||||
case "toggleCursorRule": {
|
||||
const { rulePath, enabled } = message
|
||||
if (rulePath && typeof enabled === "boolean") {
|
||||
const toggles =
|
||||
((await getWorkspaceState(this.context, "localCursorRulesToggles")) as ClineRulesToggles) || {}
|
||||
toggles[rulePath] = enabled
|
||||
await updateWorkspaceState(this.context, "localCursorRulesToggles", toggles)
|
||||
await this.postStateToWebview()
|
||||
} else {
|
||||
console.error("toggleCursorRule: Missing or invalid parameters")
|
||||
}
|
||||
break
|
||||
}
|
||||
case "toggleWorkflow": {
|
||||
const { workflowPath, enabled } = message
|
||||
if (workflowPath && typeof enabled === "boolean") {
|
||||
@@ -457,20 +423,6 @@ export class Controller {
|
||||
break
|
||||
}
|
||||
// telemetry
|
||||
case "openSettings": {
|
||||
await this.postMessageToWebview({
|
||||
type: "action",
|
||||
action: "settingsButtonClicked",
|
||||
})
|
||||
break
|
||||
}
|
||||
case "scrollToSettings": {
|
||||
await this.postMessageToWebview({
|
||||
type: "scrollToSettings",
|
||||
text: message.text,
|
||||
})
|
||||
break
|
||||
}
|
||||
case "telemetrySetting": {
|
||||
if (message.telemetrySetting) {
|
||||
await this.updateTelemetrySetting(message.telemetrySetting)
|
||||
@@ -554,21 +506,6 @@ export class Controller {
|
||||
break
|
||||
}
|
||||
|
||||
case "updateTerminalConnectionTimeout": {
|
||||
if (message.shellIntegrationTimeout !== undefined) {
|
||||
const timeout = message.shellIntegrationTimeout
|
||||
|
||||
if (typeof timeout === "number" && !isNaN(timeout) && timeout > 0) {
|
||||
await updateGlobalState(this.context, "shellIntegrationTimeout", timeout)
|
||||
await this.postStateToWebview()
|
||||
} else {
|
||||
console.warn(
|
||||
`Invalid shell integration timeout value received: ${timeout}. ` + `Expected a positive number.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
// Add more switch case statements here as more webview message commands
|
||||
// are created within the webview context (i.e. inside media/main.js)
|
||||
}
|
||||
@@ -884,6 +821,40 @@ export class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
private async fetchMcpMarketplaceFromApiRPC(silent: boolean = false): Promise<McpMarketplaceCatalog | undefined> {
|
||||
try {
|
||||
const response = await axios.get("https://api.cline.bot/v1/mcp/marketplace", {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
|
||||
if (!response.data) {
|
||||
throw new Error("Invalid response from MCP marketplace API")
|
||||
}
|
||||
|
||||
const catalog: McpMarketplaceCatalog = {
|
||||
items: (response.data || []).map((item: any) => ({
|
||||
...item,
|
||||
githubStars: item.githubStars ?? 0,
|
||||
downloadCount: item.downloadCount ?? 0,
|
||||
tags: item.tags ?? [],
|
||||
})),
|
||||
}
|
||||
|
||||
// Store in global state
|
||||
await updateGlobalState(this.context, "mcpMarketplaceCatalog", catalog)
|
||||
return catalog
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch MCP marketplace:", error)
|
||||
if (!silent) {
|
||||
const errorMessage = error instanceof Error ? error.message : "Failed to fetch MCP marketplace"
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
async silentlyRefreshMcpMarketplace() {
|
||||
try {
|
||||
const catalog = await this.fetchMcpMarketplaceFromApi(true)
|
||||
@@ -898,6 +869,20 @@ export class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RPC variant that silently refreshes the MCP marketplace catalog and returns the result
|
||||
* Unlike silentlyRefreshMcpMarketplace, this doesn't post a message to the webview
|
||||
* @returns MCP marketplace catalog or undefined if refresh failed
|
||||
*/
|
||||
async silentlyRefreshMcpMarketplaceRPC() {
|
||||
try {
|
||||
return await this.fetchMcpMarketplaceFromApiRPC(true)
|
||||
} catch (error) {
|
||||
console.error("Failed to silently refresh MCP marketplace (RPC):", error)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
private async fetchMcpMarketplace(forceRefresh: boolean = false) {
|
||||
try {
|
||||
// Check if we have cached data
|
||||
|
||||
@@ -6,6 +6,7 @@ import { registerMethod } from "./index"
|
||||
import { addRemoteMcpServer } from "./addRemoteMcpServer"
|
||||
import { deleteMcpServer } from "./deleteMcpServer"
|
||||
import { downloadMcp } from "./downloadMcp"
|
||||
import { refreshMcpMarketplace } from "./refreshMcpMarketplace"
|
||||
import { restartMcpServer } from "./restartMcpServer"
|
||||
import { toggleMcpServer } from "./toggleMcpServer"
|
||||
import { toggleToolAutoApprove } from "./toggleToolAutoApprove"
|
||||
@@ -17,6 +18,7 @@ export function registerAllMethods(): void {
|
||||
registerMethod("addRemoteMcpServer", addRemoteMcpServer)
|
||||
registerMethod("deleteMcpServer", deleteMcpServer)
|
||||
registerMethod("downloadMcp", downloadMcp)
|
||||
registerMethod("refreshMcpMarketplace", refreshMcpMarketplace)
|
||||
registerMethod("restartMcpServer", restartMcpServer)
|
||||
registerMethod("toggleMcpServer", toggleMcpServer)
|
||||
registerMethod("toggleToolAutoApprove", toggleToolAutoApprove)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { EmptyRequest } from "../../../shared/proto/common"
|
||||
import type { McpMarketplaceCatalog } from "../../../shared/proto/mcp"
|
||||
import type { Controller } from "../index"
|
||||
|
||||
/**
|
||||
* RPC handler that silently refreshes the MCP marketplace catalog
|
||||
* @param controller Controller instance
|
||||
* @param _request Empty request
|
||||
* @returns MCP marketplace catalog
|
||||
*/
|
||||
export async function refreshMcpMarketplace(controller: Controller, _request: EmptyRequest): Promise<McpMarketplaceCatalog> {
|
||||
try {
|
||||
// Call the RPC variant which returns the result directly
|
||||
const catalog = await controller.silentlyRefreshMcpMarketplaceRPC()
|
||||
|
||||
if (catalog) {
|
||||
// Types are structurally identical, use direct type assertion
|
||||
return catalog as McpMarketplaceCatalog
|
||||
}
|
||||
|
||||
// Return empty catalog if nothing was fetched
|
||||
return { items: [] }
|
||||
} catch (error) {
|
||||
console.error("Failed to refresh MCP marketplace:", error)
|
||||
return { items: [] }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { resetState } from "./resetState"
|
||||
import { subscribeToState } from "./subscribeToState"
|
||||
import { toggleFavoriteModel } from "./toggleFavoriteModel"
|
||||
import { togglePlanActMode } from "./togglePlanActMode"
|
||||
import { updateTerminalConnectionTimeout } from "./updateTerminalConnectionTimeout"
|
||||
|
||||
// Streaming methods for this service
|
||||
export const streamingMethods = ["subscribeToState"]
|
||||
@@ -20,4 +21,5 @@ export function registerAllMethods(): void {
|
||||
registerMethod("subscribeToState", subscribeToState, { isStreaming: true })
|
||||
registerMethod("toggleFavoriteModel", toggleFavoriteModel)
|
||||
registerMethod("togglePlanActMode", togglePlanActMode)
|
||||
registerMethod("updateTerminalConnectionTimeout", updateTerminalConnectionTimeout)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Controller } from ".."
|
||||
import { Int64, Int64Request } from "../../../shared/proto/common"
|
||||
import { updateGlobalState } from "../../storage/state"
|
||||
|
||||
/**
|
||||
* Updates the terminal connection timeout setting
|
||||
* @param controller The controller instance
|
||||
* @param request The request containing the timeout value in milliseconds
|
||||
* @returns The updated timeout value
|
||||
*/
|
||||
export async function updateTerminalConnectionTimeout(controller: Controller, request: Int64Request): Promise<Int64> {
|
||||
try {
|
||||
const timeout = request.value
|
||||
|
||||
if (typeof timeout === "number" && !isNaN(timeout) && timeout > 0) {
|
||||
// Update the global state directly
|
||||
await updateGlobalState(controller.context, "shellIntegrationTimeout", timeout)
|
||||
return { value: timeout }
|
||||
} else {
|
||||
console.warn(`Invalid shell integration timeout value received: ${timeout}. Expected a positive number.`)
|
||||
throw new Error("Invalid timeout value. Expected a positive number.")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to update terminal connection timeout: ${error}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// AUTO-GENERATED FILE - DO NOT MODIFY DIRECTLY
|
||||
// Generated by proto/build-proto.js
|
||||
|
||||
import { createServiceRegistry, ServiceMethodHandler, StreamingMethodHandler } from "../grpc-service"
|
||||
import { StreamingResponseHandler } from "../grpc-handler"
|
||||
import { registerAllMethods } from "./methods"
|
||||
|
||||
// Create ui service registry
|
||||
const uiService = createServiceRegistry("ui")
|
||||
|
||||
// Export the method handler types and registration function
|
||||
export type UiMethodHandler = ServiceMethodHandler
|
||||
export type UiStreamingMethodHandler = StreamingMethodHandler
|
||||
export const registerMethod = uiService.registerMethod
|
||||
|
||||
// Export the request handlers
|
||||
export const handleUiServiceRequest = uiService.handleRequest
|
||||
export const handleUiServiceStreamingRequest = uiService.handleStreamingRequest
|
||||
export const isStreamingMethod = uiService.isStreamingMethod
|
||||
|
||||
// Register all ui methods
|
||||
registerAllMethods()
|
||||
@@ -0,0 +1,12 @@
|
||||
// AUTO-GENERATED FILE - DO NOT MODIFY DIRECTLY
|
||||
// Generated by proto/build-proto.js
|
||||
|
||||
// Import all method implementations
|
||||
import { registerMethod } from "./index"
|
||||
import { scrollToSettings } from "./scrollToSettings"
|
||||
|
||||
// Register all ui service methods
|
||||
export function registerAllMethods(): void {
|
||||
// Register each method with the registry
|
||||
registerMethod("scrollToSettings", scrollToSettings)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Controller } from ".."
|
||||
import { StringRequest } from "../../../shared/proto/common"
|
||||
|
||||
/**
|
||||
* Executes a scroll to settings action
|
||||
* @param controller The controller instance
|
||||
* @param request The request containing the ID of the settings section to scroll to
|
||||
* @returns An object with action and value fields for the UI to process
|
||||
*/
|
||||
export async function scrollToSettings(controller: Controller, request: StringRequest): Promise<Record<string, string>> {
|
||||
return {
|
||||
action: "scrollToSettings",
|
||||
value: request.value || "",
|
||||
}
|
||||
}
|
||||
@@ -149,6 +149,28 @@ export class WebviewProvider implements vscode.WebviewViewProvider {
|
||||
this.controller.clearTask()
|
||||
|
||||
this.outputChannel.appendLine("Webview view resolved")
|
||||
|
||||
// Set the title to include the keyboard shortcut
|
||||
if (this.view && "title" in this.view) {
|
||||
// Check if the view object has a title property
|
||||
const isMac = process.platform === "darwin"
|
||||
const shortcutDisplay = isMac ? " (⌘+')" : " (Ctrl+')"
|
||||
const baseTitle = this.context.extension.packageJSON.displayName || "Cline"
|
||||
const newTitleWithShortcut = `${baseTitle}${shortcutDisplay}`
|
||||
|
||||
const currentTitle = this.view.title
|
||||
|
||||
if (typeof currentTitle === "string") {
|
||||
if (!currentTitle.includes(shortcutDisplay)) {
|
||||
// Title exists and is a string, but doesn't have the shortcut
|
||||
this.view.title = newTitleWithShortcut
|
||||
}
|
||||
// If it includes shortcutDisplay, do nothing
|
||||
} else {
|
||||
// Title is undefined or not a string (e.g., for sidebar initially)
|
||||
this.view.title = newTitleWithShortcut
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+194
-31
@@ -28,7 +28,7 @@ let outputChannel: vscode.OutputChannel
|
||||
|
||||
// This method is called when your extension is activated
|
||||
// Your extension is activated the very first time the command is executed
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
outputChannel = vscode.window.createOutputChannel("Cline")
|
||||
context.subscriptions.push(outputChannel)
|
||||
|
||||
@@ -36,6 +36,9 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
Logger.initialize(outputChannel)
|
||||
Logger.log("Cline extension activated")
|
||||
|
||||
// Version checking for autoupdate notification
|
||||
const currentVersion = context.extension.packageJSON.version
|
||||
const previousVersion = context.globalState.get<string>("clineVersion")
|
||||
const sidebarWebview = new WebviewProvider(context, outputChannel)
|
||||
|
||||
// Initialize test mode and add disposables to context
|
||||
@@ -49,6 +52,29 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}),
|
||||
)
|
||||
|
||||
// Perform post-update actions if necessary
|
||||
try {
|
||||
if (!previousVersion || currentVersion !== previousVersion) {
|
||||
Logger.log(`Cline version changed: ${previousVersion} -> ${currentVersion}. First run or update detected.`)
|
||||
const lastShownPopupNotificationVersion = context.globalState.get<string>("clineLastPopupNotificationVersion")
|
||||
|
||||
if (currentVersion !== lastShownPopupNotificationVersion && previousVersion) {
|
||||
// Show VS Code popup notification as this version hasn't been notified yet without doing it for fresh installs
|
||||
const message = `Cline has been updated to v${currentVersion}`
|
||||
await vscode.commands.executeCommand("claude-dev.SidebarProvider.focus")
|
||||
await new Promise((resolve) => setTimeout(resolve, 200))
|
||||
vscode.window.showInformationMessage(message)
|
||||
// Record that we've shown the popup for this version.
|
||||
await context.globalState.update("clineLastPopupNotificationVersion", currentVersion)
|
||||
}
|
||||
// Always update the main version tracker for the next launch.
|
||||
await context.globalState.update("clineVersion", currentVersion)
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error(`Error during post-update actions: ${errorMessage}, Stack trace: ${error.stack}`)
|
||||
}
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("cline.plusButtonClicked", async (webview: any) => {
|
||||
const openChat = async (instance?: WebviewProvider) => {
|
||||
@@ -257,6 +283,8 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("cline.addToChat", async (range?: vscode.Range, diagnostics?: vscode.Diagnostic[]) => {
|
||||
await vscode.commands.executeCommand("cline.focusChatInput") // Ensure Cline is visible and input focused
|
||||
await pWaitFor(() => !!WebviewProvider.getVisibleInstance())
|
||||
const editor = vscode.window.activeTextEditor
|
||||
if (!editor) {
|
||||
return
|
||||
@@ -336,50 +364,100 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}),
|
||||
)
|
||||
|
||||
const CONTEXT_LINES_TO_EXPAND = 3
|
||||
const START_OF_LINE_CHAR_INDEX = 0
|
||||
const LINE_COUNT_ADJUSTMENT_FOR_ZERO_INDEXING = 1
|
||||
|
||||
// Register code action provider
|
||||
context.subscriptions.push(
|
||||
vscode.languages.registerCodeActionsProvider(
|
||||
"*",
|
||||
new (class implements vscode.CodeActionProvider {
|
||||
public static readonly providedCodeActionKinds = [vscode.CodeActionKind.QuickFix]
|
||||
public static readonly providedCodeActionKinds = [vscode.CodeActionKind.QuickFix, vscode.CodeActionKind.Refactor]
|
||||
|
||||
provideCodeActions(
|
||||
document: vscode.TextDocument,
|
||||
range: vscode.Range,
|
||||
context: vscode.CodeActionContext,
|
||||
): vscode.CodeAction[] {
|
||||
// Expand range to include surrounding 3 lines
|
||||
const expandedRange = new vscode.Range(
|
||||
Math.max(0, range.start.line - 3),
|
||||
0,
|
||||
Math.min(document.lineCount - 1, range.end.line + 3),
|
||||
document.lineAt(Math.min(document.lineCount - 1, range.end.line + 3)).text.length,
|
||||
)
|
||||
const actions: vscode.CodeAction[] = []
|
||||
const editor = vscode.window.activeTextEditor // Get active editor for selection check
|
||||
|
||||
// Expand range to include surrounding 3 lines or use selection if broader
|
||||
const selection = editor?.selection
|
||||
let expandedRange = range
|
||||
if (
|
||||
editor &&
|
||||
selection &&
|
||||
!selection.isEmpty &&
|
||||
selection.contains(range.start) &&
|
||||
selection.contains(range.end)
|
||||
) {
|
||||
expandedRange = selection
|
||||
} else {
|
||||
expandedRange = new vscode.Range(
|
||||
Math.max(0, range.start.line - CONTEXT_LINES_TO_EXPAND),
|
||||
START_OF_LINE_CHAR_INDEX,
|
||||
Math.min(
|
||||
document.lineCount - LINE_COUNT_ADJUSTMENT_FOR_ZERO_INDEXING,
|
||||
range.end.line + CONTEXT_LINES_TO_EXPAND,
|
||||
),
|
||||
document.lineAt(
|
||||
Math.min(
|
||||
document.lineCount - LINE_COUNT_ADJUSTMENT_FOR_ZERO_INDEXING,
|
||||
range.end.line + CONTEXT_LINES_TO_EXPAND,
|
||||
),
|
||||
).text.length,
|
||||
)
|
||||
}
|
||||
|
||||
// Add to Cline (Always available)
|
||||
const addAction = new vscode.CodeAction("Add to Cline", vscode.CodeActionKind.QuickFix)
|
||||
addAction.command = {
|
||||
command: "cline.addToChat",
|
||||
title: "Add to Cline",
|
||||
arguments: [expandedRange, context.diagnostics],
|
||||
}
|
||||
actions.push(addAction)
|
||||
|
||||
const fixAction = new vscode.CodeAction("Fix with Cline", vscode.CodeActionKind.QuickFix)
|
||||
fixAction.command = {
|
||||
command: "cline.fixWithCline",
|
||||
title: "Fix with Cline",
|
||||
arguments: [expandedRange, context.diagnostics],
|
||||
// Explain with Cline (Always available)
|
||||
const explainAction = new vscode.CodeAction("Explain with Cline", vscode.CodeActionKind.RefactorExtract) // Using a refactor kind
|
||||
explainAction.command = {
|
||||
command: "cline.explainCode",
|
||||
title: "Explain with Cline",
|
||||
arguments: [expandedRange],
|
||||
}
|
||||
actions.push(explainAction)
|
||||
|
||||
// Only show actions when there are errors
|
||||
// Improve with Cline (Always available)
|
||||
const improveAction = new vscode.CodeAction("Improve with Cline", vscode.CodeActionKind.RefactorRewrite) // Using a refactor kind
|
||||
improveAction.command = {
|
||||
command: "cline.improveCode",
|
||||
title: "Improve with Cline",
|
||||
arguments: [expandedRange],
|
||||
}
|
||||
actions.push(improveAction)
|
||||
|
||||
// Fix with Cline (Only if diagnostics exist)
|
||||
if (context.diagnostics.length > 0) {
|
||||
return [addAction, fixAction]
|
||||
} else {
|
||||
return []
|
||||
const fixAction = new vscode.CodeAction("Fix with Cline", vscode.CodeActionKind.QuickFix)
|
||||
fixAction.isPreferred = true
|
||||
fixAction.command = {
|
||||
command: "cline.fixWithCline",
|
||||
title: "Fix with Cline",
|
||||
arguments: [expandedRange, context.diagnostics],
|
||||
}
|
||||
actions.push(fixAction)
|
||||
}
|
||||
return actions
|
||||
}
|
||||
})(),
|
||||
{
|
||||
providedCodeActionKinds: [vscode.CodeActionKind.QuickFix],
|
||||
providedCodeActionKinds: [
|
||||
vscode.CodeActionKind.QuickFix,
|
||||
vscode.CodeActionKind.RefactorExtract,
|
||||
vscode.CodeActionKind.RefactorRewrite,
|
||||
],
|
||||
},
|
||||
),
|
||||
)
|
||||
@@ -406,21 +484,106 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}),
|
||||
)
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("cline.explainCode", async (range: vscode.Range) => {
|
||||
await vscode.commands.executeCommand("cline.focusChatInput") // Ensure Cline is visible and input focused
|
||||
await pWaitFor(() => !!WebviewProvider.getVisibleInstance())
|
||||
const editor = vscode.window.activeTextEditor
|
||||
if (!editor) {
|
||||
return
|
||||
}
|
||||
const selectedText = editor.document.getText(range)
|
||||
if (!selectedText.trim()) {
|
||||
vscode.window.showInformationMessage("Please select some code to explain.")
|
||||
return
|
||||
}
|
||||
const filePath = editor.document.uri.fsPath
|
||||
const visibleWebview = WebviewProvider.getVisibleInstance()
|
||||
const fileMention = visibleWebview?.controller.getFileMentionFromPath(filePath) || filePath
|
||||
const prompt = `Explain the following code from ${fileMention}:\n\`\`\`${editor.document.languageId}\n${selectedText}\n\`\`\``
|
||||
await visibleWebview?.controller.initTask(prompt)
|
||||
}),
|
||||
)
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("cline.improveCode", async (range: vscode.Range) => {
|
||||
await vscode.commands.executeCommand("cline.focusChatInput") // Ensure Cline is visible and input focused
|
||||
await pWaitFor(() => !!WebviewProvider.getVisibleInstance())
|
||||
const editor = vscode.window.activeTextEditor
|
||||
if (!editor) {
|
||||
return
|
||||
}
|
||||
const selectedText = editor.document.getText(range)
|
||||
if (!selectedText.trim()) {
|
||||
vscode.window.showInformationMessage("Please select some code to improve.")
|
||||
return
|
||||
}
|
||||
const filePath = editor.document.uri.fsPath
|
||||
const visibleWebview = WebviewProvider.getVisibleInstance()
|
||||
const fileMention = visibleWebview?.controller.getFileMentionFromPath(filePath) || filePath
|
||||
const prompt = `Improve the following code from ${fileMention} (e.g., suggest refactorings, optimizations, or better practices):\n\`\`\`${editor.document.languageId}\n${selectedText}\n\`\`\``
|
||||
await visibleWebview?.controller.initTask(prompt)
|
||||
}),
|
||||
)
|
||||
|
||||
// Register the focusChatInput command handler
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("cline.focusChatInput", () => {
|
||||
let visibleWebview = WebviewProvider.getVisibleInstance()
|
||||
if (!visibleWebview) {
|
||||
vscode.commands.executeCommand("claude-dev.SidebarProvider.focus")
|
||||
visibleWebview = WebviewProvider.getSidebarInstance()
|
||||
// showing the extension will call didBecomeVisible which focuses it already
|
||||
// but it doesn't focus if a tab is selected which focusChatInput accounts for
|
||||
}
|
||||
vscode.commands.registerCommand("cline.focusChatInput", async () => {
|
||||
let activeWebviewProvider: WebviewProvider | undefined = WebviewProvider.getVisibleInstance()
|
||||
|
||||
visibleWebview?.controller.postMessageToWebview({
|
||||
type: "action",
|
||||
action: "focusChatInput",
|
||||
})
|
||||
// If a tab is visible and active, ensure it's fully revealed (might be redundant but safe)
|
||||
if (activeWebviewProvider?.view && activeWebviewProvider.view.hasOwnProperty("reveal")) {
|
||||
const panelView = activeWebviewProvider.view as vscode.WebviewPanel
|
||||
panelView.reveal(panelView.viewColumn)
|
||||
} else if (!activeWebviewProvider) {
|
||||
// No webview is currently visible, try to activate the sidebar
|
||||
await vscode.commands.executeCommand("claude-dev.SidebarProvider.focus")
|
||||
await new Promise((resolve) => setTimeout(resolve, 200)) // Allow time for focus
|
||||
activeWebviewProvider = WebviewProvider.getSidebarInstance()
|
||||
|
||||
if (!activeWebviewProvider) {
|
||||
// Sidebar didn't become active (might be closed or not in current view container)
|
||||
// Check for existing tab panels
|
||||
const tabInstances = WebviewProvider.getTabInstances()
|
||||
if (tabInstances.length > 0) {
|
||||
const potentialTabInstance = tabInstances[tabInstances.length - 1] // Get the most recent one
|
||||
if (potentialTabInstance.view && potentialTabInstance.view.hasOwnProperty("reveal")) {
|
||||
const panelView = potentialTabInstance.view as vscode.WebviewPanel
|
||||
panelView.reveal(panelView.viewColumn)
|
||||
activeWebviewProvider = potentialTabInstance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!activeWebviewProvider) {
|
||||
// No existing Cline view found at all, open a new tab
|
||||
await vscode.commands.executeCommand("cline.openInNewTab")
|
||||
// After openInNewTab, a new webview is created. We need to get this new instance.
|
||||
// It might take a moment for it to register.
|
||||
await pWaitFor(
|
||||
() => {
|
||||
const visibleInstance = WebviewProvider.getVisibleInstance()
|
||||
// Ensure a boolean is returned
|
||||
return !!(visibleInstance?.view && visibleInstance.view.hasOwnProperty("reveal"))
|
||||
},
|
||||
{ timeout: 2000 },
|
||||
)
|
||||
activeWebviewProvider = WebviewProvider.getVisibleInstance()
|
||||
}
|
||||
}
|
||||
// At this point, activeWebviewProvider should be the one we want to send the message to.
|
||||
// It could still be undefined if opening a new tab failed or timed out.
|
||||
if (activeWebviewProvider) {
|
||||
activeWebviewProvider.controller.postMessageToWebview({
|
||||
type: "action",
|
||||
action: "focusChatInput",
|
||||
})
|
||||
} else {
|
||||
console.error("FocusChatInput: Could not find or activate a Cline webview to focus.")
|
||||
vscode.window.showErrorMessage(
|
||||
"Could not activate Cline view. Please try opening it manually from the Activity Bar.",
|
||||
)
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ export class BrowserSession {
|
||||
return stats
|
||||
}
|
||||
|
||||
async relaunchChromeDebugMode(controller: Controller) {
|
||||
async relaunchChromeDebugMode(controller: Controller): Promise<string> {
|
||||
try {
|
||||
const userDataDir = path.join(os.tmpdir(), "chrome-debug-profile")
|
||||
const installation = chromeLauncher.Launcher.getFirstInstallation()
|
||||
@@ -159,17 +159,9 @@ export class BrowserSession {
|
||||
throw new Error("Chrome was launched but debug port is not responding")
|
||||
}
|
||||
|
||||
controller?.postMessageToWebview({
|
||||
type: "browserRelaunchResult",
|
||||
success: true,
|
||||
text: `Browser successfully launched with debug mode\nUsing: ${installation}`,
|
||||
})
|
||||
return `Browser successfully launched with debug mode\nUsing: ${installation}`
|
||||
} catch (error) {
|
||||
controller?.postMessageToWebview({
|
||||
type: "browserRelaunchResult",
|
||||
success: false,
|
||||
text: `Failed to relaunch Chrome: ${error instanceof Error ? error.message : String(error)}`,
|
||||
})
|
||||
throw new Error(`Failed to relaunch Chrome: ${error instanceof Error ? error.message : globalThis.String(error)}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,11 +40,8 @@ export interface ExtensionMessage {
|
||||
| "totalTasksSize"
|
||||
| "addToInput"
|
||||
| "browserConnectionResult"
|
||||
| "scrollToSettings"
|
||||
| "browserRelaunchResult"
|
||||
| "fileSearchResults"
|
||||
| "grpc_response" // New type for gRPC responses
|
||||
| "setActiveQuote"
|
||||
text?: string
|
||||
action?:
|
||||
| "chatButtonClicked"
|
||||
|
||||
@@ -16,41 +16,31 @@ export interface WebviewMessage {
|
||||
| "reportBug"
|
||||
| "didShowAnnouncement"
|
||||
| "openInBrowser"
|
||||
| "openMention"
|
||||
| "showChatView"
|
||||
| "refreshClineRules"
|
||||
| "openMcpSettings"
|
||||
| "autoApprovalSettings"
|
||||
| "browserRelaunchResult"
|
||||
| "togglePlanActMode"
|
||||
| "openExtensionSettings"
|
||||
| "requestVsCodeLmModels"
|
||||
| "showAccountViewClicked"
|
||||
| "authStateChanged"
|
||||
| "authCallback"
|
||||
| "fetchMcpMarketplace"
|
||||
| "silentlyRefreshMcpMarketplace"
|
||||
| "searchCommits"
|
||||
| "fetchLatestMcpServersFromHub"
|
||||
| "telemetrySetting"
|
||||
| "openSettings"
|
||||
| "invoke"
|
||||
| "updateSettings"
|
||||
| "clearAllTaskHistory"
|
||||
| "fetchUserCreditsData"
|
||||
| "optionsResponse"
|
||||
| "requestTotalTasksSize"
|
||||
| "relaunchChromeDebugMode"
|
||||
| "scrollToSettings"
|
||||
| "searchFiles"
|
||||
| "grpc_request"
|
||||
| "grpc_request_cancel"
|
||||
| "toggleCursorRule"
|
||||
| "toggleWindsurfRule"
|
||||
| "toggleWorkflow"
|
||||
| "updateTerminalConnectionTimeout"
|
||||
| "setActiveQuote"
|
||||
|
||||
// | "relaunchChromeDebugMode"
|
||||
text?: string
|
||||
disabled?: boolean
|
||||
apiConfiguration?: ApiConfiguration
|
||||
|
||||
@@ -483,6 +483,19 @@ export const vertexModels = {
|
||||
outputPrice: 3.5,
|
||||
},
|
||||
},
|
||||
"gemini-2.5-flash-preview-05-20": {
|
||||
maxTokens: 65536,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsGlobalEndpoint: true,
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.6,
|
||||
thinkingConfig: {
|
||||
maxBudget: 24576,
|
||||
outputPrice: 3.5,
|
||||
},
|
||||
},
|
||||
"gemini-2.0-flash-thinking-exp-01-21": {
|
||||
maxTokens: 65_536,
|
||||
contextWindow: 1_048_576,
|
||||
@@ -601,6 +614,18 @@ export const geminiModels = {
|
||||
},
|
||||
],
|
||||
},
|
||||
"gemini-2.5-flash-preview-05-20": {
|
||||
maxTokens: 65536,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.6,
|
||||
thinkingConfig: {
|
||||
maxBudget: 24576,
|
||||
outputPrice: 3.5,
|
||||
},
|
||||
},
|
||||
"gemini-2.5-flash-preview-04-17": {
|
||||
maxTokens: 65536,
|
||||
contextWindow: 1_048_576,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
/* eslint-disable */
|
||||
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"
|
||||
import { Boolean, EmptyRequest, Metadata, StringRequest } from "./common"
|
||||
import { Boolean, EmptyRequest, Metadata, String, StringRequest } from "./common"
|
||||
|
||||
export const protobufPackage = "cline"
|
||||
|
||||
@@ -714,6 +714,14 @@ export const BrowserServiceDefinition = {
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
relaunchChromeDebugMode: {
|
||||
name: "relaunchChromeDebugMode",
|
||||
requestType: EmptyRequest,
|
||||
requestStream: false,
|
||||
responseType: String,
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
|
||||
@@ -10,6 +10,15 @@ import { Empty, EmptyRequest, Metadata, StringArray, StringRequest } from "./com
|
||||
|
||||
export const protobufPackage = "cline"
|
||||
|
||||
/** Request to toggle a Windsurf rule */
|
||||
export interface ToggleWindsurfRuleRequest {
|
||||
metadata?: Metadata | undefined
|
||||
/** Path to the rule file */
|
||||
rulePath: string
|
||||
/** Whether to enable or disable the rule */
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
/** Request to convert a list of URIs to relative paths */
|
||||
export interface RelativePathsRequest {
|
||||
metadata?: Metadata | undefined
|
||||
@@ -114,6 +123,108 @@ export interface ToggleClineRules {
|
||||
localClineRulesToggles?: ClineRulesToggles | undefined
|
||||
}
|
||||
|
||||
/** Request to toggle a Cursor rule */
|
||||
export interface ToggleCursorRuleRequest {
|
||||
metadata?: Metadata | undefined
|
||||
/** Path to the rule file */
|
||||
rulePath: string
|
||||
/** Whether to enable or disable the rule */
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
function createBaseToggleWindsurfRuleRequest(): ToggleWindsurfRuleRequest {
|
||||
return { metadata: undefined, rulePath: "", enabled: false }
|
||||
}
|
||||
|
||||
export const ToggleWindsurfRuleRequest: MessageFns<ToggleWindsurfRuleRequest> = {
|
||||
encode(message: ToggleWindsurfRuleRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.metadata !== undefined) {
|
||||
Metadata.encode(message.metadata, writer.uint32(10).fork()).join()
|
||||
}
|
||||
if (message.rulePath !== "") {
|
||||
writer.uint32(18).string(message.rulePath)
|
||||
}
|
||||
if (message.enabled !== false) {
|
||||
writer.uint32(24).bool(message.enabled)
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): ToggleWindsurfRuleRequest {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseToggleWindsurfRuleRequest()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
message.metadata = Metadata.decode(reader, reader.uint32())
|
||||
continue
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 18) {
|
||||
break
|
||||
}
|
||||
|
||||
message.rulePath = reader.string()
|
||||
continue
|
||||
}
|
||||
case 3: {
|
||||
if (tag !== 24) {
|
||||
break
|
||||
}
|
||||
|
||||
message.enabled = reader.bool()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): ToggleWindsurfRuleRequest {
|
||||
return {
|
||||
metadata: isSet(object.metadata) ? Metadata.fromJSON(object.metadata) : undefined,
|
||||
rulePath: isSet(object.rulePath) ? globalThis.String(object.rulePath) : "",
|
||||
enabled: isSet(object.enabled) ? globalThis.Boolean(object.enabled) : false,
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: ToggleWindsurfRuleRequest): unknown {
|
||||
const obj: any = {}
|
||||
if (message.metadata !== undefined) {
|
||||
obj.metadata = Metadata.toJSON(message.metadata)
|
||||
}
|
||||
if (message.rulePath !== "") {
|
||||
obj.rulePath = message.rulePath
|
||||
}
|
||||
if (message.enabled !== false) {
|
||||
obj.enabled = message.enabled
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<ToggleWindsurfRuleRequest>, I>>(base?: I): ToggleWindsurfRuleRequest {
|
||||
return ToggleWindsurfRuleRequest.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<ToggleWindsurfRuleRequest>, I>>(object: I): ToggleWindsurfRuleRequest {
|
||||
const message = createBaseToggleWindsurfRuleRequest()
|
||||
message.metadata =
|
||||
object.metadata !== undefined && object.metadata !== null ? Metadata.fromPartial(object.metadata) : undefined
|
||||
message.rulePath = object.rulePath ?? ""
|
||||
message.enabled = object.enabled ?? false
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseRelativePathsRequest(): RelativePathsRequest {
|
||||
return { metadata: undefined, uris: [] }
|
||||
}
|
||||
@@ -1277,6 +1388,99 @@ export const ToggleClineRules: MessageFns<ToggleClineRules> = {
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseToggleCursorRuleRequest(): ToggleCursorRuleRequest {
|
||||
return { metadata: undefined, rulePath: "", enabled: false }
|
||||
}
|
||||
|
||||
export const ToggleCursorRuleRequest: MessageFns<ToggleCursorRuleRequest> = {
|
||||
encode(message: ToggleCursorRuleRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.metadata !== undefined) {
|
||||
Metadata.encode(message.metadata, writer.uint32(10).fork()).join()
|
||||
}
|
||||
if (message.rulePath !== "") {
|
||||
writer.uint32(18).string(message.rulePath)
|
||||
}
|
||||
if (message.enabled !== false) {
|
||||
writer.uint32(24).bool(message.enabled)
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): ToggleCursorRuleRequest {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseToggleCursorRuleRequest()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
message.metadata = Metadata.decode(reader, reader.uint32())
|
||||
continue
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 18) {
|
||||
break
|
||||
}
|
||||
|
||||
message.rulePath = reader.string()
|
||||
continue
|
||||
}
|
||||
case 3: {
|
||||
if (tag !== 24) {
|
||||
break
|
||||
}
|
||||
|
||||
message.enabled = reader.bool()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): ToggleCursorRuleRequest {
|
||||
return {
|
||||
metadata: isSet(object.metadata) ? Metadata.fromJSON(object.metadata) : undefined,
|
||||
rulePath: isSet(object.rulePath) ? globalThis.String(object.rulePath) : "",
|
||||
enabled: isSet(object.enabled) ? globalThis.Boolean(object.enabled) : false,
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: ToggleCursorRuleRequest): unknown {
|
||||
const obj: any = {}
|
||||
if (message.metadata !== undefined) {
|
||||
obj.metadata = Metadata.toJSON(message.metadata)
|
||||
}
|
||||
if (message.rulePath !== "") {
|
||||
obj.rulePath = message.rulePath
|
||||
}
|
||||
if (message.enabled !== false) {
|
||||
obj.enabled = message.enabled
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<ToggleCursorRuleRequest>, I>>(base?: I): ToggleCursorRuleRequest {
|
||||
return ToggleCursorRuleRequest.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<ToggleCursorRuleRequest>, I>>(object: I): ToggleCursorRuleRequest {
|
||||
const message = createBaseToggleCursorRuleRequest()
|
||||
message.metadata =
|
||||
object.metadata !== undefined && object.metadata !== null ? Metadata.fromPartial(object.metadata) : undefined
|
||||
message.rulePath = object.rulePath ?? ""
|
||||
message.enabled = object.enabled ?? false
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
/** Service for file-related operations */
|
||||
export type FileServiceDefinition = typeof FileServiceDefinition
|
||||
export const FileServiceDefinition = {
|
||||
@@ -1310,6 +1514,15 @@ export const FileServiceDefinition = {
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
/** Opens a mention (file, path, git commit, problem, terminal, or URL) */
|
||||
openMention: {
|
||||
name: "openMention",
|
||||
requestType: StringRequest,
|
||||
requestStream: false,
|
||||
responseType: Empty,
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
/** Deletes a rule file from either global or workspace rules directory */
|
||||
deleteRuleFile: {
|
||||
name: "deleteRuleFile",
|
||||
@@ -1373,6 +1586,24 @@ export const FileServiceDefinition = {
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
/** Toggle a Cursor rule (enable or disable) */
|
||||
toggleCursorRule: {
|
||||
name: "toggleCursorRule",
|
||||
requestType: ToggleCursorRuleRequest,
|
||||
requestStream: false,
|
||||
responseType: ClineRulesToggles,
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
/** Toggle a Windsurf rule (enable or disable) */
|
||||
toggleWindsurfRule: {
|
||||
name: "toggleWindsurfRule",
|
||||
requestType: ToggleWindsurfRuleRequest,
|
||||
requestStream: false,
|
||||
responseType: ClineRulesToggles,
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
|
||||
+447
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
/* eslint-disable */
|
||||
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"
|
||||
import { Empty, Metadata, StringRequest } from "./common"
|
||||
import { Empty, EmptyRequest, Metadata, StringRequest } from "./common"
|
||||
|
||||
export const protobufPackage = "cline"
|
||||
|
||||
@@ -115,6 +115,31 @@ export interface McpServers {
|
||||
mcpServers: McpServer[]
|
||||
}
|
||||
|
||||
export interface McpMarketplaceItem {
|
||||
mcpId: string
|
||||
githubUrl: string
|
||||
name: string
|
||||
author: string
|
||||
description: string
|
||||
codiconIcon: string
|
||||
logoUrl: string
|
||||
category: string
|
||||
tags: string[]
|
||||
requiresApiKey: boolean
|
||||
readmeContent?: string | undefined
|
||||
llmsInstallationContent?: string | undefined
|
||||
isRecommended: boolean
|
||||
githubStars: number
|
||||
downloadCount: number
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
lastGithubSync: string
|
||||
}
|
||||
|
||||
export interface McpMarketplaceCatalog {
|
||||
items: McpMarketplaceItem[]
|
||||
}
|
||||
|
||||
function createBaseToggleMcpServerRequest(): ToggleMcpServerRequest {
|
||||
return { metadata: undefined, serverName: "", disabled: false }
|
||||
}
|
||||
@@ -1091,6 +1116,419 @@ export const McpServers: MessageFns<McpServers> = {
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseMcpMarketplaceItem(): McpMarketplaceItem {
|
||||
return {
|
||||
mcpId: "",
|
||||
githubUrl: "",
|
||||
name: "",
|
||||
author: "",
|
||||
description: "",
|
||||
codiconIcon: "",
|
||||
logoUrl: "",
|
||||
category: "",
|
||||
tags: [],
|
||||
requiresApiKey: false,
|
||||
readmeContent: undefined,
|
||||
llmsInstallationContent: undefined,
|
||||
isRecommended: false,
|
||||
githubStars: 0,
|
||||
downloadCount: 0,
|
||||
createdAt: "",
|
||||
updatedAt: "",
|
||||
lastGithubSync: "",
|
||||
}
|
||||
}
|
||||
|
||||
export const McpMarketplaceItem: MessageFns<McpMarketplaceItem> = {
|
||||
encode(message: McpMarketplaceItem, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.mcpId !== "") {
|
||||
writer.uint32(10).string(message.mcpId)
|
||||
}
|
||||
if (message.githubUrl !== "") {
|
||||
writer.uint32(18).string(message.githubUrl)
|
||||
}
|
||||
if (message.name !== "") {
|
||||
writer.uint32(26).string(message.name)
|
||||
}
|
||||
if (message.author !== "") {
|
||||
writer.uint32(34).string(message.author)
|
||||
}
|
||||
if (message.description !== "") {
|
||||
writer.uint32(42).string(message.description)
|
||||
}
|
||||
if (message.codiconIcon !== "") {
|
||||
writer.uint32(50).string(message.codiconIcon)
|
||||
}
|
||||
if (message.logoUrl !== "") {
|
||||
writer.uint32(58).string(message.logoUrl)
|
||||
}
|
||||
if (message.category !== "") {
|
||||
writer.uint32(66).string(message.category)
|
||||
}
|
||||
for (const v of message.tags) {
|
||||
writer.uint32(74).string(v!)
|
||||
}
|
||||
if (message.requiresApiKey !== false) {
|
||||
writer.uint32(80).bool(message.requiresApiKey)
|
||||
}
|
||||
if (message.readmeContent !== undefined) {
|
||||
writer.uint32(90).string(message.readmeContent)
|
||||
}
|
||||
if (message.llmsInstallationContent !== undefined) {
|
||||
writer.uint32(98).string(message.llmsInstallationContent)
|
||||
}
|
||||
if (message.isRecommended !== false) {
|
||||
writer.uint32(104).bool(message.isRecommended)
|
||||
}
|
||||
if (message.githubStars !== 0) {
|
||||
writer.uint32(112).int32(message.githubStars)
|
||||
}
|
||||
if (message.downloadCount !== 0) {
|
||||
writer.uint32(120).int32(message.downloadCount)
|
||||
}
|
||||
if (message.createdAt !== "") {
|
||||
writer.uint32(130).string(message.createdAt)
|
||||
}
|
||||
if (message.updatedAt !== "") {
|
||||
writer.uint32(138).string(message.updatedAt)
|
||||
}
|
||||
if (message.lastGithubSync !== "") {
|
||||
writer.uint32(146).string(message.lastGithubSync)
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): McpMarketplaceItem {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseMcpMarketplaceItem()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
message.mcpId = reader.string()
|
||||
continue
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 18) {
|
||||
break
|
||||
}
|
||||
|
||||
message.githubUrl = reader.string()
|
||||
continue
|
||||
}
|
||||
case 3: {
|
||||
if (tag !== 26) {
|
||||
break
|
||||
}
|
||||
|
||||
message.name = reader.string()
|
||||
continue
|
||||
}
|
||||
case 4: {
|
||||
if (tag !== 34) {
|
||||
break
|
||||
}
|
||||
|
||||
message.author = reader.string()
|
||||
continue
|
||||
}
|
||||
case 5: {
|
||||
if (tag !== 42) {
|
||||
break
|
||||
}
|
||||
|
||||
message.description = reader.string()
|
||||
continue
|
||||
}
|
||||
case 6: {
|
||||
if (tag !== 50) {
|
||||
break
|
||||
}
|
||||
|
||||
message.codiconIcon = reader.string()
|
||||
continue
|
||||
}
|
||||
case 7: {
|
||||
if (tag !== 58) {
|
||||
break
|
||||
}
|
||||
|
||||
message.logoUrl = reader.string()
|
||||
continue
|
||||
}
|
||||
case 8: {
|
||||
if (tag !== 66) {
|
||||
break
|
||||
}
|
||||
|
||||
message.category = reader.string()
|
||||
continue
|
||||
}
|
||||
case 9: {
|
||||
if (tag !== 74) {
|
||||
break
|
||||
}
|
||||
|
||||
message.tags.push(reader.string())
|
||||
continue
|
||||
}
|
||||
case 10: {
|
||||
if (tag !== 80) {
|
||||
break
|
||||
}
|
||||
|
||||
message.requiresApiKey = reader.bool()
|
||||
continue
|
||||
}
|
||||
case 11: {
|
||||
if (tag !== 90) {
|
||||
break
|
||||
}
|
||||
|
||||
message.readmeContent = reader.string()
|
||||
continue
|
||||
}
|
||||
case 12: {
|
||||
if (tag !== 98) {
|
||||
break
|
||||
}
|
||||
|
||||
message.llmsInstallationContent = reader.string()
|
||||
continue
|
||||
}
|
||||
case 13: {
|
||||
if (tag !== 104) {
|
||||
break
|
||||
}
|
||||
|
||||
message.isRecommended = reader.bool()
|
||||
continue
|
||||
}
|
||||
case 14: {
|
||||
if (tag !== 112) {
|
||||
break
|
||||
}
|
||||
|
||||
message.githubStars = reader.int32()
|
||||
continue
|
||||
}
|
||||
case 15: {
|
||||
if (tag !== 120) {
|
||||
break
|
||||
}
|
||||
|
||||
message.downloadCount = reader.int32()
|
||||
continue
|
||||
}
|
||||
case 16: {
|
||||
if (tag !== 130) {
|
||||
break
|
||||
}
|
||||
|
||||
message.createdAt = reader.string()
|
||||
continue
|
||||
}
|
||||
case 17: {
|
||||
if (tag !== 138) {
|
||||
break
|
||||
}
|
||||
|
||||
message.updatedAt = reader.string()
|
||||
continue
|
||||
}
|
||||
case 18: {
|
||||
if (tag !== 146) {
|
||||
break
|
||||
}
|
||||
|
||||
message.lastGithubSync = reader.string()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): McpMarketplaceItem {
|
||||
return {
|
||||
mcpId: isSet(object.mcpId) ? globalThis.String(object.mcpId) : "",
|
||||
githubUrl: isSet(object.githubUrl) ? globalThis.String(object.githubUrl) : "",
|
||||
name: isSet(object.name) ? globalThis.String(object.name) : "",
|
||||
author: isSet(object.author) ? globalThis.String(object.author) : "",
|
||||
description: isSet(object.description) ? globalThis.String(object.description) : "",
|
||||
codiconIcon: isSet(object.codiconIcon) ? globalThis.String(object.codiconIcon) : "",
|
||||
logoUrl: isSet(object.logoUrl) ? globalThis.String(object.logoUrl) : "",
|
||||
category: isSet(object.category) ? globalThis.String(object.category) : "",
|
||||
tags: globalThis.Array.isArray(object?.tags) ? object.tags.map((e: any) => globalThis.String(e)) : [],
|
||||
requiresApiKey: isSet(object.requiresApiKey) ? globalThis.Boolean(object.requiresApiKey) : false,
|
||||
readmeContent: isSet(object.readmeContent) ? globalThis.String(object.readmeContent) : undefined,
|
||||
llmsInstallationContent: isSet(object.llmsInstallationContent)
|
||||
? globalThis.String(object.llmsInstallationContent)
|
||||
: undefined,
|
||||
isRecommended: isSet(object.isRecommended) ? globalThis.Boolean(object.isRecommended) : false,
|
||||
githubStars: isSet(object.githubStars) ? globalThis.Number(object.githubStars) : 0,
|
||||
downloadCount: isSet(object.downloadCount) ? globalThis.Number(object.downloadCount) : 0,
|
||||
createdAt: isSet(object.createdAt) ? globalThis.String(object.createdAt) : "",
|
||||
updatedAt: isSet(object.updatedAt) ? globalThis.String(object.updatedAt) : "",
|
||||
lastGithubSync: isSet(object.lastGithubSync) ? globalThis.String(object.lastGithubSync) : "",
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: McpMarketplaceItem): unknown {
|
||||
const obj: any = {}
|
||||
if (message.mcpId !== "") {
|
||||
obj.mcpId = message.mcpId
|
||||
}
|
||||
if (message.githubUrl !== "") {
|
||||
obj.githubUrl = message.githubUrl
|
||||
}
|
||||
if (message.name !== "") {
|
||||
obj.name = message.name
|
||||
}
|
||||
if (message.author !== "") {
|
||||
obj.author = message.author
|
||||
}
|
||||
if (message.description !== "") {
|
||||
obj.description = message.description
|
||||
}
|
||||
if (message.codiconIcon !== "") {
|
||||
obj.codiconIcon = message.codiconIcon
|
||||
}
|
||||
if (message.logoUrl !== "") {
|
||||
obj.logoUrl = message.logoUrl
|
||||
}
|
||||
if (message.category !== "") {
|
||||
obj.category = message.category
|
||||
}
|
||||
if (message.tags?.length) {
|
||||
obj.tags = message.tags
|
||||
}
|
||||
if (message.requiresApiKey !== false) {
|
||||
obj.requiresApiKey = message.requiresApiKey
|
||||
}
|
||||
if (message.readmeContent !== undefined) {
|
||||
obj.readmeContent = message.readmeContent
|
||||
}
|
||||
if (message.llmsInstallationContent !== undefined) {
|
||||
obj.llmsInstallationContent = message.llmsInstallationContent
|
||||
}
|
||||
if (message.isRecommended !== false) {
|
||||
obj.isRecommended = message.isRecommended
|
||||
}
|
||||
if (message.githubStars !== 0) {
|
||||
obj.githubStars = Math.round(message.githubStars)
|
||||
}
|
||||
if (message.downloadCount !== 0) {
|
||||
obj.downloadCount = Math.round(message.downloadCount)
|
||||
}
|
||||
if (message.createdAt !== "") {
|
||||
obj.createdAt = message.createdAt
|
||||
}
|
||||
if (message.updatedAt !== "") {
|
||||
obj.updatedAt = message.updatedAt
|
||||
}
|
||||
if (message.lastGithubSync !== "") {
|
||||
obj.lastGithubSync = message.lastGithubSync
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<McpMarketplaceItem>, I>>(base?: I): McpMarketplaceItem {
|
||||
return McpMarketplaceItem.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<McpMarketplaceItem>, I>>(object: I): McpMarketplaceItem {
|
||||
const message = createBaseMcpMarketplaceItem()
|
||||
message.mcpId = object.mcpId ?? ""
|
||||
message.githubUrl = object.githubUrl ?? ""
|
||||
message.name = object.name ?? ""
|
||||
message.author = object.author ?? ""
|
||||
message.description = object.description ?? ""
|
||||
message.codiconIcon = object.codiconIcon ?? ""
|
||||
message.logoUrl = object.logoUrl ?? ""
|
||||
message.category = object.category ?? ""
|
||||
message.tags = object.tags?.map((e) => e) || []
|
||||
message.requiresApiKey = object.requiresApiKey ?? false
|
||||
message.readmeContent = object.readmeContent ?? undefined
|
||||
message.llmsInstallationContent = object.llmsInstallationContent ?? undefined
|
||||
message.isRecommended = object.isRecommended ?? false
|
||||
message.githubStars = object.githubStars ?? 0
|
||||
message.downloadCount = object.downloadCount ?? 0
|
||||
message.createdAt = object.createdAt ?? ""
|
||||
message.updatedAt = object.updatedAt ?? ""
|
||||
message.lastGithubSync = object.lastGithubSync ?? ""
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseMcpMarketplaceCatalog(): McpMarketplaceCatalog {
|
||||
return { items: [] }
|
||||
}
|
||||
|
||||
export const McpMarketplaceCatalog: MessageFns<McpMarketplaceCatalog> = {
|
||||
encode(message: McpMarketplaceCatalog, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
for (const v of message.items) {
|
||||
McpMarketplaceItem.encode(v!, writer.uint32(10).fork()).join()
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): McpMarketplaceCatalog {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseMcpMarketplaceCatalog()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
message.items.push(McpMarketplaceItem.decode(reader, reader.uint32()))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): McpMarketplaceCatalog {
|
||||
return {
|
||||
items: globalThis.Array.isArray(object?.items) ? object.items.map((e: any) => McpMarketplaceItem.fromJSON(e)) : [],
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: McpMarketplaceCatalog): unknown {
|
||||
const obj: any = {}
|
||||
if (message.items?.length) {
|
||||
obj.items = message.items.map((e) => McpMarketplaceItem.toJSON(e))
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<McpMarketplaceCatalog>, I>>(base?: I): McpMarketplaceCatalog {
|
||||
return McpMarketplaceCatalog.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<McpMarketplaceCatalog>, I>>(object: I): McpMarketplaceCatalog {
|
||||
const message = createBaseMcpMarketplaceCatalog()
|
||||
message.items = object.items?.map((e) => McpMarketplaceItem.fromPartial(e)) || []
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
export type McpServiceDefinition = typeof McpServiceDefinition
|
||||
export const McpServiceDefinition = {
|
||||
name: "McpService",
|
||||
@@ -1152,6 +1590,14 @@ export const McpServiceDefinition = {
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
refreshMcpMarketplace: {
|
||||
name: "refreshMcpMarketplace",
|
||||
requestType: EmptyRequest,
|
||||
requestStream: false,
|
||||
responseType: McpMarketplaceCatalog,
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
/* eslint-disable */
|
||||
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"
|
||||
import { Empty, EmptyRequest, Metadata, StringRequest } from "./common"
|
||||
import { Empty, EmptyRequest, Int64, Int64Request, Metadata, StringRequest } from "./common"
|
||||
|
||||
export const protobufPackage = "cline"
|
||||
|
||||
@@ -436,6 +436,14 @@ export const StateServiceDefinition = {
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
updateTerminalConnectionTimeout: {
|
||||
name: "updateTerminalConnectionTimeout",
|
||||
requestType: Int64Request,
|
||||
requestStream: false,
|
||||
responseType: Int64,
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-ts_proto v2.7.0
|
||||
// protoc v3.19.1
|
||||
// source: ui.proto
|
||||
|
||||
/* eslint-disable */
|
||||
import { Empty, StringRequest } from "./common"
|
||||
|
||||
export const protobufPackage = "cline"
|
||||
|
||||
/** UiService provides methods for managing UI interactions */
|
||||
export type UiServiceDefinition = typeof UiServiceDefinition
|
||||
export const UiServiceDefinition = {
|
||||
name: "UiService",
|
||||
fullName: "cline.UiService",
|
||||
methods: {
|
||||
/** Scrolls to a specific settings section in the settings view */
|
||||
scrollToSettings: {
|
||||
name: "scrollToSettings",
|
||||
requestType: StringRequest,
|
||||
requestStream: false,
|
||||
responseType: Empty,
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
} as const
|
||||
@@ -14,6 +14,7 @@ import { testBrowserConnection } from "../core/controller/browser/testBrowserCon
|
||||
import { discoverBrowser } from "../core/controller/browser/discoverBrowser"
|
||||
import { getDetectedChromePath } from "../core/controller/browser/getDetectedChromePath"
|
||||
import { updateBrowserSettings } from "../core/controller/browser/updateBrowserSettings"
|
||||
import { relaunchChromeDebugMode } from "../core/controller/browser/relaunchChromeDebugMode"
|
||||
|
||||
// Checkpoints Service
|
||||
import { checkpointDiff } from "../core/controller/checkpoints/checkpointDiff"
|
||||
@@ -23,6 +24,7 @@ import { checkpointRestore } from "../core/controller/checkpoints/checkpointRest
|
||||
import { copyToClipboard } from "../core/controller/file/copyToClipboard"
|
||||
import { openFile } from "../core/controller/file/openFile"
|
||||
import { openImage } from "../core/controller/file/openImage"
|
||||
import { openMention } from "../core/controller/file/openMention"
|
||||
import { deleteRuleFile } from "../core/controller/file/deleteRuleFile"
|
||||
import { createRuleFile } from "../core/controller/file/createRuleFile"
|
||||
import { searchCommits } from "../core/controller/file/searchCommits"
|
||||
@@ -30,6 +32,8 @@ import { selectImages } from "../core/controller/file/selectImages"
|
||||
import { getRelativePaths } from "../core/controller/file/getRelativePaths"
|
||||
import { searchFiles } from "../core/controller/file/searchFiles"
|
||||
import { toggleClineRule } from "../core/controller/file/toggleClineRule"
|
||||
import { toggleCursorRule } from "../core/controller/file/toggleCursorRule"
|
||||
import { toggleWindsurfRule } from "../core/controller/file/toggleWindsurfRule"
|
||||
|
||||
// Mcp Service
|
||||
import { toggleMcpServer } from "../core/controller/mcp/toggleMcpServer"
|
||||
@@ -39,6 +43,7 @@ import { downloadMcp } from "../core/controller/mcp/downloadMcp"
|
||||
import { restartMcpServer } from "../core/controller/mcp/restartMcpServer"
|
||||
import { deleteMcpServer } from "../core/controller/mcp/deleteMcpServer"
|
||||
import { toggleToolAutoApprove } from "../core/controller/mcp/toggleToolAutoApprove"
|
||||
import { refreshMcpMarketplace } from "../core/controller/mcp/refreshMcpMarketplace"
|
||||
|
||||
// Models Service
|
||||
import { getOllamaModels } from "../core/controller/models/getOllamaModels"
|
||||
@@ -58,6 +63,7 @@ import { subscribeToState } from "../core/controller/state/subscribeToState"
|
||||
import { toggleFavoriteModel } from "../core/controller/state/toggleFavoriteModel"
|
||||
import { resetState } from "../core/controller/state/resetState"
|
||||
import { togglePlanActMode } from "../core/controller/state/togglePlanActMode"
|
||||
import { updateTerminalConnectionTimeout } from "../core/controller/state/updateTerminalConnectionTimeout"
|
||||
|
||||
// Task Service
|
||||
import { cancelTask } from "../core/controller/task/cancelTask"
|
||||
@@ -73,6 +79,9 @@ import { askResponse } from "../core/controller/task/askResponse"
|
||||
import { taskFeedback } from "../core/controller/task/taskFeedback"
|
||||
import { taskCompletionViewChanges } from "../core/controller/task/taskCompletionViewChanges"
|
||||
|
||||
// Ui Service
|
||||
import { scrollToSettings } from "../core/controller/ui/scrollToSettings"
|
||||
|
||||
// Web Service
|
||||
import { checkIsImageUrl } from "../core/controller/web/checkIsImageUrl"
|
||||
import { fetchOpenGraphData } from "../core/controller/web/fetchOpenGraphData"
|
||||
@@ -97,6 +106,7 @@ export function addServices(
|
||||
discoverBrowser: wrapper(discoverBrowser, controller),
|
||||
getDetectedChromePath: wrapper(getDetectedChromePath, controller),
|
||||
updateBrowserSettings: wrapper(updateBrowserSettings, controller),
|
||||
relaunchChromeDebugMode: wrapper(relaunchChromeDebugMode, controller),
|
||||
})
|
||||
|
||||
// Checkpoints Service
|
||||
@@ -110,6 +120,7 @@ export function addServices(
|
||||
copyToClipboard: wrapper(copyToClipboard, controller),
|
||||
openFile: wrapper(openFile, controller),
|
||||
openImage: wrapper(openImage, controller),
|
||||
openMention: wrapper(openMention, controller),
|
||||
deleteRuleFile: wrapper(deleteRuleFile, controller),
|
||||
createRuleFile: wrapper(createRuleFile, controller),
|
||||
searchCommits: wrapper(searchCommits, controller),
|
||||
@@ -117,6 +128,8 @@ export function addServices(
|
||||
getRelativePaths: wrapper(getRelativePaths, controller),
|
||||
searchFiles: wrapper(searchFiles, controller),
|
||||
toggleClineRule: wrapper(toggleClineRule, controller),
|
||||
toggleCursorRule: wrapper(toggleCursorRule, controller),
|
||||
toggleWindsurfRule: wrapper(toggleWindsurfRule, controller),
|
||||
})
|
||||
|
||||
// Mcp Service
|
||||
@@ -128,6 +141,7 @@ export function addServices(
|
||||
restartMcpServer: wrapper(restartMcpServer, controller),
|
||||
deleteMcpServer: wrapper(deleteMcpServer, controller),
|
||||
toggleToolAutoApprove: wrapper(toggleToolAutoApprove, controller),
|
||||
refreshMcpMarketplace: wrapper(refreshMcpMarketplace, controller),
|
||||
})
|
||||
|
||||
// Models Service
|
||||
@@ -153,6 +167,7 @@ export function addServices(
|
||||
toggleFavoriteModel: wrapper(toggleFavoriteModel, controller),
|
||||
resetState: wrapper(resetState, controller),
|
||||
togglePlanActMode: wrapper(togglePlanActMode, controller),
|
||||
updateTerminalConnectionTimeout: wrapper(updateTerminalConnectionTimeout, controller),
|
||||
})
|
||||
|
||||
// Task Service
|
||||
@@ -171,6 +186,11 @@ export function addServices(
|
||||
taskCompletionViewChanges: wrapper(taskCompletionViewChanges, controller),
|
||||
})
|
||||
|
||||
// Ui Service
|
||||
server.addService(proto.cline.UiService.service, {
|
||||
scrollToSettings: wrapper(scrollToSettings, controller),
|
||||
})
|
||||
|
||||
// Web Service
|
||||
server.addService(proto.cline.WebService.service, {
|
||||
checkIsImageUrl: wrapper(checkIsImageUrl, controller),
|
||||
|
||||
@@ -4,7 +4,7 @@ import styled from "styled-components"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { vscode } from "@/utils/vscode"
|
||||
import { CODE_BLOCK_BG_COLOR } from "../common/CodeBlock"
|
||||
import { BrowserServiceClient } from "../../services/grpc-client"
|
||||
import { BrowserServiceClient, UiServiceClient } from "../../services/grpc-client"
|
||||
|
||||
interface ConnectionInfo {
|
||||
isConnected: boolean
|
||||
@@ -13,7 +13,7 @@ interface ConnectionInfo {
|
||||
}
|
||||
|
||||
export const BrowserSettingsMenu = () => {
|
||||
const { browserSettings } = useExtensionState()
|
||||
const { browserSettings, navigateToSettings } = useExtensionState()
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const [showInfoPopover, setShowInfoPopover] = useState(false)
|
||||
const [connectionInfo, setConnectionInfo] = useState<ConnectionInfo>({
|
||||
@@ -65,17 +65,16 @@ export const BrowserSettingsMenu = () => {
|
||||
}, [showInfoPopover])
|
||||
|
||||
const openBrowserSettings = () => {
|
||||
// First open the settings panel
|
||||
vscode.postMessage({
|
||||
type: "openSettings",
|
||||
})
|
||||
// First open the settings panel using direct navigation
|
||||
navigateToSettings()
|
||||
|
||||
// After a short delay, send a message to scroll to browser settings
|
||||
setTimeout(() => {
|
||||
vscode.postMessage({
|
||||
type: "scrollToSettings",
|
||||
text: "browser-settings-section",
|
||||
})
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await UiServiceClient.scrollToSettings({ value: "browser-settings-section" })
|
||||
} catch (error) {
|
||||
console.error("Error scrolling to browser settings:", error)
|
||||
}
|
||||
}, 300) // Give the settings panel time to open
|
||||
}
|
||||
|
||||
|
||||
@@ -966,7 +966,8 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
}
|
||||
setTimeout(() => {
|
||||
const newMode = chatSettings.mode === "plan" ? "act" : "plan"
|
||||
StateServiceClient.togglePlanActMode({
|
||||
vscode.postMessage({
|
||||
type: "togglePlanActMode",
|
||||
chatSettings: {
|
||||
mode: newMode,
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@ import Thumbnails from "@/components/common/Thumbnails"
|
||||
import { normalizeApiConfiguration } from "@/components/settings/ApiOptions"
|
||||
import { validateSlashCommand } from "@/utils/slash-commands"
|
||||
import TaskTimeline from "./TaskTimeline"
|
||||
import { TaskServiceClient } from "@/services/grpc-client"
|
||||
import { TaskServiceClient, FileServiceClient } from "@/services/grpc-client"
|
||||
import HeroTooltip from "@/components/common/HeroTooltip"
|
||||
|
||||
interface TaskHeaderProps {
|
||||
@@ -597,7 +597,7 @@ export const highlightMentions = (text: string, withShadow = true) => {
|
||||
key={index}
|
||||
className={withShadow ? "mention-context-highlight-with-shadow" : "mention-context-highlight"}
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => vscode.postMessage({ type: "openMention", text: part })}>
|
||||
onClick={() => FileServiceClient.openMention({ value: part })}>
|
||||
@{part}
|
||||
</span>
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
|
||||
import RulesToggleList from "./RulesToggleList"
|
||||
import Tooltip from "@/components/common/Tooltip"
|
||||
import styled from "styled-components"
|
||||
import { ClineRulesToggles, ToggleWindsurfRuleRequest } from "@shared/proto/file"
|
||||
|
||||
const ClineRulesToggleModal: React.FC = () => {
|
||||
const {
|
||||
@@ -18,6 +19,8 @@ const ClineRulesToggleModal: React.FC = () => {
|
||||
workflowToggles = {},
|
||||
setGlobalClineRulesToggles,
|
||||
setLocalClineRulesToggles,
|
||||
setLocalCursorRulesToggles,
|
||||
setLocalWindsurfRulesToggles,
|
||||
} = useExtensionState()
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
const buttonRef = useRef<HTMLDivElement>(null)
|
||||
@@ -77,19 +80,34 @@ const ClineRulesToggleModal: React.FC = () => {
|
||||
}
|
||||
|
||||
const toggleCursorRule = (rulePath: string, enabled: boolean) => {
|
||||
vscode.postMessage({
|
||||
type: "toggleCursorRule",
|
||||
FileServiceClient.toggleCursorRule({
|
||||
rulePath,
|
||||
enabled,
|
||||
})
|
||||
.then((response) => {
|
||||
// Update the local state with the response
|
||||
if (response.toggles) {
|
||||
setLocalCursorRulesToggles(response.toggles)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error toggling Cursor rule:", error)
|
||||
})
|
||||
}
|
||||
|
||||
const toggleWindsurfRule = (rulePath: string, enabled: boolean) => {
|
||||
vscode.postMessage({
|
||||
type: "toggleWindsurfRule",
|
||||
FileServiceClient.toggleWindsurfRule({
|
||||
rulePath,
|
||||
enabled,
|
||||
})
|
||||
} as ToggleWindsurfRuleRequest)
|
||||
.then((response: ClineRulesToggles) => {
|
||||
if (response.toggles) {
|
||||
setLocalWindsurfRulesToggles(response.toggles)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error toggling Windsurf rule:", error)
|
||||
})
|
||||
}
|
||||
|
||||
const toggleWorkflow = (workflowPath: string, enabled: boolean) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||
import { memo, useState } from "react"
|
||||
import styled from "styled-components"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { vscode } from "@/utils/vscode"
|
||||
import { TelemetrySetting } from "@shared/TelemetrySetting"
|
||||
|
||||
@@ -45,9 +46,11 @@ const ButtonContainer = styled.div`
|
||||
`
|
||||
|
||||
const TelemetryBanner = () => {
|
||||
const { navigateToSettings } = useExtensionState()
|
||||
|
||||
const handleOpenSettings = () => {
|
||||
handleClose()
|
||||
vscode.postMessage({ type: "openSettings" })
|
||||
navigateToSettings()
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useEffect, useState } from "react"
|
||||
import styled from "styled-components"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { vscode } from "@/utils/vscode"
|
||||
import { McpServiceClient } from "@/services/grpc-client"
|
||||
import AddRemoteServerForm from "./tabs/add-server/AddRemoteServerForm"
|
||||
import McpMarketplaceView from "./tabs/marketplace/McpMarketplaceView"
|
||||
import InstalledServersView from "./tabs/installed/InstalledServersView"
|
||||
@@ -28,9 +29,20 @@ const McpConfigurationView = ({ onDone, initialTab }: McpViewProps) => {
|
||||
}
|
||||
}, [mcpMarketplaceEnabled, activeTab])
|
||||
|
||||
// Get setter for MCP marketplace catalog from context
|
||||
const { setMcpMarketplaceCatalog } = useExtensionState()
|
||||
|
||||
useEffect(() => {
|
||||
if (mcpMarketplaceEnabled) {
|
||||
vscode.postMessage({ type: "silentlyRefreshMcpMarketplace" })
|
||||
McpServiceClient.refreshMcpMarketplace({})
|
||||
.then((response) => {
|
||||
// Types are structurally identical, use response directly
|
||||
setMcpMarketplaceCatalog(response)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error refreshing MCP marketplace:", error)
|
||||
})
|
||||
|
||||
vscode.postMessage({ type: "fetchLatestMcpServersFromHub" })
|
||||
}
|
||||
}, [mcpMarketplaceEnabled])
|
||||
|
||||
@@ -3,7 +3,6 @@ import { VSCodeButton, VSCodeCheckbox, VSCodeDropdown, VSCodeOption, VSCodeTextF
|
||||
import debounce from "debounce"
|
||||
import { BROWSER_VIEWPORT_PRESETS } from "../../../../src/shared/BrowserSettings"
|
||||
import { useExtensionState } from "../../context/ExtensionStateContext"
|
||||
import { vscode } from "../../utils/vscode"
|
||||
import styled from "styled-components"
|
||||
import { BrowserServiceClient } from "../../services/grpc-client"
|
||||
|
||||
@@ -60,19 +59,13 @@ export const BrowserSettingsSection: React.FC = () => {
|
||||
const [isBundled, setIsBundled] = useState(false)
|
||||
const [detectedChromePath, setDetectedChromePath] = useState<string | null>(null)
|
||||
|
||||
// Listen for browser connection test results and relaunch results
|
||||
// Listen for browser connection test results
|
||||
useEffect(() => {
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
const message = event.data
|
||||
if (message.type === "browserConnectionResult") {
|
||||
setConnectionStatus(message.success)
|
||||
setIsCheckingConnection(false)
|
||||
} else if (message.type === "browserRelaunchResult") {
|
||||
setRelaunchResult({
|
||||
success: message.success,
|
||||
message: message.text,
|
||||
})
|
||||
setDebugMode(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,9 +342,22 @@ export const BrowserSettingsSection: React.FC = () => {
|
||||
setRelaunchResult(null)
|
||||
// The connection status will be automatically updated by our polling
|
||||
|
||||
vscode.postMessage({
|
||||
type: "relaunchChromeDebugMode",
|
||||
})
|
||||
BrowserServiceClient.relaunchChromeDebugMode({})
|
||||
.then((result) => {
|
||||
setRelaunchResult({
|
||||
success: result.success,
|
||||
message: result.message,
|
||||
})
|
||||
setDebugMode(false)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error relaunching Chrome:", error)
|
||||
setRelaunchResult({
|
||||
success: false,
|
||||
message: `Error relaunching Chrome: ${error.message}`,
|
||||
})
|
||||
setDebugMode(false)
|
||||
})
|
||||
}
|
||||
|
||||
// Determine if we should show the relaunch button
|
||||
|
||||
@@ -115,7 +115,8 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
|
||||
switch (message.type) {
|
||||
case "didUpdateSettings":
|
||||
if (pendingTabChange) {
|
||||
StateServiceClient.togglePlanActMode({
|
||||
vscode.postMessage({
|
||||
type: "togglePlanActMode",
|
||||
chatSettings: {
|
||||
mode: pendingTabChange,
|
||||
},
|
||||
@@ -123,23 +124,25 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
|
||||
setPendingTabChange(null)
|
||||
}
|
||||
break
|
||||
case "scrollToSettings":
|
||||
setTimeout(() => {
|
||||
const elementId = message.text
|
||||
if (elementId) {
|
||||
const element = document.getElementById(elementId)
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: "smooth" })
|
||||
case "grpc_response":
|
||||
if (message.grpc_response?.message?.action === "scrollToSettings") {
|
||||
setTimeout(() => {
|
||||
const elementId = message.grpc_response?.message?.value
|
||||
if (elementId) {
|
||||
const element = document.getElementById(elementId)
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: "smooth" })
|
||||
|
||||
element.style.transition = "background-color 0.5s ease"
|
||||
element.style.backgroundColor = "var(--vscode-textPreformat-background)"
|
||||
element.style.transition = "background-color 0.5s ease"
|
||||
element.style.backgroundColor = "var(--vscode-textPreformat-background)"
|
||||
|
||||
setTimeout(() => {
|
||||
element.style.backgroundColor = "transparent"
|
||||
}, 1200)
|
||||
setTimeout(() => {
|
||||
element.style.backgroundColor = "transparent"
|
||||
}, 1200)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 300)
|
||||
}, 300)
|
||||
}
|
||||
break
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { useState } from "react"
|
||||
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { vscode } from "@/utils/vscode"
|
||||
import { StateServiceClient } from "@/services/grpc-client"
|
||||
import { Int64, Int64Request } from "@shared/proto/common"
|
||||
|
||||
export const TerminalSettingsSection: React.FC = () => {
|
||||
const { shellIntegrationTimeout, setShellIntegrationTimeout } = useExtensionState()
|
||||
@@ -26,11 +27,17 @@ export const TerminalSettingsSection: React.FC = () => {
|
||||
// Update local state
|
||||
setShellIntegrationTimeout(timeout)
|
||||
|
||||
// Send to extension
|
||||
vscode.postMessage({
|
||||
type: "updateTerminalConnectionTimeout",
|
||||
shellIntegrationTimeout: timeout,
|
||||
})
|
||||
// Send to extension using gRPC
|
||||
StateServiceClient.updateTerminalConnectionTimeout({
|
||||
value: timeout,
|
||||
} as Int64Request)
|
||||
.then((response: Int64) => {
|
||||
setShellIntegrationTimeout(response.value)
|
||||
setInputValue((response.value / 1000).toString())
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Failed to update terminal connection timeout:", error)
|
||||
})
|
||||
}
|
||||
|
||||
const handleInputBlur = () => {
|
||||
|
||||
@@ -53,6 +53,9 @@ interface ExtensionStateContextType extends ExtensionState {
|
||||
setMcpServers: (value: McpServer[]) => void
|
||||
setGlobalClineRulesToggles: (toggles: Record<string, boolean>) => void
|
||||
setLocalClineRulesToggles: (toggles: Record<string, boolean>) => void
|
||||
setLocalCursorRulesToggles: (toggles: Record<string, boolean>) => void
|
||||
setLocalWindsurfRulesToggles: (toggles: Record<string, boolean>) => void
|
||||
setMcpMarketplaceCatalog: (value: McpMarketplaceCatalog) => void
|
||||
|
||||
// Navigation state setters
|
||||
setShowMcp: (value: boolean) => void
|
||||
@@ -498,6 +501,7 @@ export const ExtensionStateContextProvider: React.FC<{
|
||||
shellIntegrationTimeout: value,
|
||||
})),
|
||||
setMcpServers: (mcpServers: McpServer[]) => setMcpServers(mcpServers),
|
||||
setMcpMarketplaceCatalog: (catalog: McpMarketplaceCatalog) => setMcpMarketplaceCatalog(catalog),
|
||||
setShowMcp,
|
||||
closeMcpView,
|
||||
setChatSettings: (value) => {
|
||||
@@ -526,6 +530,16 @@ export const ExtensionStateContextProvider: React.FC<{
|
||||
...prevState,
|
||||
localClineRulesToggles: toggles,
|
||||
})),
|
||||
setLocalCursorRulesToggles: (toggles) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
localCursorRulesToggles: toggles,
|
||||
})),
|
||||
setLocalWindsurfRulesToggles: (toggles) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
localWindsurfRulesToggles: toggles,
|
||||
})),
|
||||
setMcpTab,
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { TaskServiceDefinition } from "@shared/proto/task"
|
||||
import { WebServiceDefinition } from "@shared/proto/web"
|
||||
import { ModelsServiceDefinition } from "@shared/proto/models"
|
||||
import { SlashServiceDefinition } from "@shared/proto/slash"
|
||||
import { UiServiceDefinition } from "@shared/proto/ui"
|
||||
|
||||
const AccountServiceClient = createGrpcClient(AccountServiceDefinition)
|
||||
const BrowserServiceClient = createGrpcClient(BrowserServiceDefinition)
|
||||
@@ -23,6 +24,7 @@ const TaskServiceClient = createGrpcClient(TaskServiceDefinition)
|
||||
const WebServiceClient = createGrpcClient(WebServiceDefinition)
|
||||
const ModelsServiceClient = createGrpcClient(ModelsServiceDefinition)
|
||||
const SlashServiceClient = createGrpcClient(SlashServiceDefinition)
|
||||
const UiServiceClient = createGrpcClient(UiServiceDefinition)
|
||||
|
||||
export {
|
||||
AccountServiceClient,
|
||||
@@ -35,4 +37,5 @@ export {
|
||||
WebServiceClient,
|
||||
ModelsServiceClient,
|
||||
SlashServiceClient,
|
||||
UiServiceClient,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user