mirror of
https://github.com/cline/cline.git
synced 2026-09-04 11:44:01 +08:00
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d390b56f6 | |||
| 67f4caf2fe | |||
| 9b248ad6c2 | |||
| 45974ac925 | |||
| 2cedcc5a58 | |||
| 14a0c60550 | |||
| cdf368c21c | |||
| f3ae1340cf | |||
| 624fb8c8a1 | |||
| dbb5ac265d | |||
| 1fd137b684 | |||
| a718cc950e | |||
| cea93d9e98 | |||
| 346c1f7eff | |||
| 32f200e837 | |||
| 07a2daa827 | |||
| a22fc10a72 | |||
| 0c306121aa | |||
| 97139f713b | |||
| 77a877c6d3 | |||
| 627590ff2a | |||
| 6835870dee | |||
| a48c37ee82 | |||
| 579b1f1968 | |||
| 331da0f802 | |||
| 782ed7ff21 | |||
| c511b91a09 | |||
| efb6ae1529 | |||
| 58f80d4d16 | |||
| c3b556ddce | |||
| f16120fbfc | |||
| 02002860ca | |||
| b97e57fd4e | |||
| cd927ae279 | |||
| e2da226c10 | |||
| eae28f1cee | |||
| 47eacdc545 | |||
| b669dfbc7e | |||
| 9f192768bc | |||
| 8356e058c1 | |||
| 0870c65fa5 | |||
| 36c0192bd2 | |||
| 65a63952e3 | |||
| c6dbbdb43d | |||
| 1a66f64679 | |||
| debcbd537f | |||
| 6938809051 | |||
| b737911cdc | |||
| 1de02e9ab2 | |||
| 08d4240e70 | |||
| fe13ce8d6f | |||
| 7fe7605a85 | |||
| f0e352489f | |||
| aff78bda7c | |||
| c7c1d37379 | |||
| e6da7c7282 | |||
| 78c3c5eff2 | |||
| 6b243ee826 | |||
| 14a056ed3e | |||
| 086879d149 | |||
| 7a24c10188 | |||
| 6cf5fdadb9 |
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Put all the navigation state and message handling and navigation functions in the extension state context instead of the app.tsx
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
togglePlanActMode protobus migration
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
taskCompletionViewChanges protobus migration
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
copyToClipboard protobus migration
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
migrate accountLogoutClicked to protobus
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Migrate restartMcpServer to protobus
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Migrate the deleteMcpServer message to protobus
|
||||
@@ -0,0 +1,351 @@
|
||||
You have access to the `gh` terminal command. I already authenticated it for you. Please review it to use the PR that I asked you to review. You're already in the `cline` repo.
|
||||
|
||||
<detailed_sequence_of_steps>
|
||||
# GitHub PR Review Process - Detailed Sequence of Steps
|
||||
|
||||
## 1. Gather PR Information
|
||||
1. Get the PR title, description, and comments:
|
||||
```bash
|
||||
gh pr view <PR-number> --json title,body,comments
|
||||
```
|
||||
|
||||
2. Get the full diff of the PR:
|
||||
```bash
|
||||
gh pr diff <PR-number>
|
||||
```
|
||||
|
||||
## 2. Understand the Context
|
||||
1. Identify which files were modified in the PR:
|
||||
```bash
|
||||
gh pr view <PR-number> --json files
|
||||
```
|
||||
|
||||
2. Examine the original files in the main branch to understand the context:
|
||||
```xml
|
||||
<read_file>
|
||||
<path>path/to/file</path>
|
||||
</read_file>
|
||||
```
|
||||
|
||||
3. For specific sections of a file, you can use search_files:
|
||||
```xml
|
||||
<search_files>
|
||||
<path>path/to/directory</path>
|
||||
<regex>search term</regex>
|
||||
<file_pattern>*.ts</file_pattern>
|
||||
</search_files>
|
||||
```
|
||||
|
||||
## 3. Analyze the Changes
|
||||
1. For each modified file, understand:
|
||||
- What was changed
|
||||
- Why it was changed (based on PR description)
|
||||
- How it affects the codebase
|
||||
- Potential side effects
|
||||
|
||||
2. Look for:
|
||||
- Code quality issues
|
||||
- Potential bugs
|
||||
- Performance implications
|
||||
- Security concerns
|
||||
- Test coverage
|
||||
|
||||
## 4. Ask for User Confirmation
|
||||
1. Before making a decision, ask the user if you should approve the PR, providing your assessment and justification:
|
||||
```xml
|
||||
<ask_followup_question>
|
||||
<question>Based on my review of PR #<PR-number>, I recommend [approving/requesting changes]. Here's my justification:
|
||||
|
||||
[Detailed justification with key points about the PR quality, implementation, and any concerns]
|
||||
|
||||
Would you like me to proceed with this recommendation?</question>
|
||||
<options>["Yes, approve the PR", "Yes, request changes", "No, I'd like to discuss further"]</options>
|
||||
</ask_followup_question>
|
||||
```
|
||||
|
||||
## 5. Ask if User Wants a Comment Drafted
|
||||
1. After the user decides on approval/rejection, ask if they would like a comment drafted:
|
||||
```xml
|
||||
<ask_followup_question>
|
||||
<question>Would you like me to draft a comment for this PR that you can copy and paste?</question>
|
||||
<options>["Yes, please draft a comment", "No, I'll handle the comment myself"]</options>
|
||||
</ask_followup_question>
|
||||
```
|
||||
|
||||
2. If the user wants a comment drafted, provide a well-structured comment they can copy:
|
||||
```
|
||||
Thank you for this PR! Here's my assessment:
|
||||
|
||||
[Detailed assessment with key points about the PR quality, implementation, and any suggestions]
|
||||
|
||||
[Include specific feedback on code quality, functionality, and testing]
|
||||
```
|
||||
|
||||
## 6. Make a Decision
|
||||
1. Approve the PR if it meets quality standards:
|
||||
```bash
|
||||
# For single-line comments:
|
||||
gh pr review <PR-number> --approve --body "Your approval message"
|
||||
|
||||
# For multi-line comments with proper whitespace formatting:
|
||||
cat << EOF | gh pr review <PR-number> --approve --body-file -
|
||||
Thanks @username for this PR! The implementation looks good.
|
||||
|
||||
I particularly like how you've handled X and Y.
|
||||
|
||||
Great work!
|
||||
EOF
|
||||
```
|
||||
|
||||
2. Request changes if improvements are needed:
|
||||
```bash
|
||||
# For single-line comments:
|
||||
gh pr review <PR-number> --request-changes --body "Your feedback message"
|
||||
|
||||
# For multi-line comments with proper whitespace formatting:
|
||||
cat << EOF | gh pr review <PR-number> --request-changes --body-file -
|
||||
Thanks @username for this PR!
|
||||
|
||||
The implementation looks promising, but there are a few things to address:
|
||||
|
||||
1. Issue one
|
||||
2. Issue two
|
||||
|
||||
Please make these changes and we can merge this.
|
||||
EOF
|
||||
```
|
||||
|
||||
Note: The `cat << EOF | ... --body-file -` approach preserves all whitespace and formatting without requiring temporary files. The `-` parameter tells the command to read from standard input.
|
||||
</detailed_sequence_of_steps>
|
||||
|
||||
<example_review_process>
|
||||
# Example PR Review Process
|
||||
|
||||
Let's walk through a real example of reviewing PR #3627 which fixes the thinking mode calculation for Claude 3.7 models.
|
||||
|
||||
## Step 1: Gather PR Information
|
||||
|
||||
```bash
|
||||
# Get PR details
|
||||
gh pr view 3627 --json title,body,comments
|
||||
|
||||
# Get the full diff
|
||||
gh pr diff 3627
|
||||
```
|
||||
|
||||
## Step 2: Understand the Context
|
||||
|
||||
```xml
|
||||
# Examine the original files to understand what's being changed
|
||||
<read_file>
|
||||
<path>src/shared/api.ts</path>
|
||||
</read_file>
|
||||
|
||||
# Look at the ThinkingBudgetSlider component implementation
|
||||
<read_file>
|
||||
<path>webview-ui/src/components/settings/ThinkingBudgetSlider.tsx</path>
|
||||
</read_file>
|
||||
|
||||
# Check how thinking mode is currently handled in API providers
|
||||
<search_files>
|
||||
<path>src/api/providers</path>
|
||||
<regex>reasoningOn</regex>
|
||||
<file_pattern>*.ts</file_pattern>
|
||||
</search_files>
|
||||
```
|
||||
|
||||
## Step 3: Analyze the Changes
|
||||
|
||||
From the PR information and code examination, we can see that:
|
||||
|
||||
1. The PR fixes an issue with the thinking mode budget calculation for Claude 3.7 models
|
||||
2. Currently, the thinking budget is incorrectly calculated as 80% of maxTokens (8192), resulting in 6553 tokens
|
||||
3. Claude 3.7 actually supports a much larger thinking budget (up to 64000 tokens)
|
||||
4. The PR adds a `thinkingConfig` property with `maxBudget: 64000` to model definitions
|
||||
5. It updates API handlers to use this value when reasoning mode is enabled
|
||||
6. It enhances the slider component to calculate max values based on model-specific percentages
|
||||
7. Comprehensive tests were added to verify the calculations
|
||||
|
||||
## Step 4: Ask for User Confirmation
|
||||
|
||||
```xml
|
||||
<ask_followup_question>
|
||||
<question>Based on my review of PR #3627, I recommend approving this PR. Here's my justification:
|
||||
|
||||
1. The PR correctly fixes the thinking mode budget calculation for Claude 3.7 models
|
||||
2. It properly implements the thinkingConfig.maxBudget property (64000) for Claude 3.7 models
|
||||
3. It applies the appropriate percentage (50%) for the slider calculation
|
||||
4. The changes are well-tested with comprehensive unit tests
|
||||
5. The implementation is clean and follows the project's coding standards
|
||||
6. The PR includes helpful screenshots demonstrating the fix
|
||||
|
||||
Would you like me to proceed with approving this PR?</question>
|
||||
<options>["Yes, approve the PR", "No, I'd like to discuss further", "Let me review it myself first"]</options>
|
||||
</ask_followup_question>
|
||||
```
|
||||
|
||||
## Step 5: Ask if User Wants a Comment Drafted
|
||||
|
||||
```xml
|
||||
<ask_followup_question>
|
||||
<question>Would you like me to draft a comment for this PR that you can copy and paste?</question>
|
||||
<options>["Yes, please draft a comment", "No, I'll handle the comment myself"]</options>
|
||||
</ask_followup_question>
|
||||
```
|
||||
|
||||
## Step 6: Make a Decision
|
||||
|
||||
```bash
|
||||
# Option 1: Simple one-line comment
|
||||
gh pr review 3627 --approve --body "This PR looks good! It correctly fixes the thinking mode budget calculation for Claude 3.7 models."
|
||||
|
||||
# Option 2: Multi-line comment with proper whitespace formatting
|
||||
cat << EOF | gh pr review 3627 --approve --body-file -
|
||||
This PR looks good! It correctly fixes the thinking mode budget calculation for Claude 3.7 models.
|
||||
|
||||
I particularly like:
|
||||
1. The proper implementation of thinkingConfig.maxBudget property (64000)
|
||||
2. The appropriate percentage (50%) for the slider calculation
|
||||
3. The comprehensive unit tests
|
||||
4. The clean implementation that follows project coding standards
|
||||
|
||||
Great work!
|
||||
EOF
|
||||
```
|
||||
</example_review_process>
|
||||
|
||||
<common_gh_commands>
|
||||
# Common GitHub CLI Commands for PR Review
|
||||
|
||||
## Basic PR Commands
|
||||
```bash
|
||||
# List open PRs
|
||||
gh pr list
|
||||
|
||||
# View a specific PR
|
||||
gh pr view <PR-number>
|
||||
|
||||
# View PR with specific fields
|
||||
gh pr view <PR-number> --json title,body,comments,files,commits
|
||||
|
||||
# Check PR status
|
||||
gh pr status
|
||||
```
|
||||
|
||||
## Diff and File Commands
|
||||
```bash
|
||||
# Get the full diff of a PR
|
||||
gh pr diff <PR-number>
|
||||
|
||||
# List files changed in a PR
|
||||
gh pr view <PR-number> --json files
|
||||
|
||||
# Check out a PR locally
|
||||
gh pr checkout <PR-number>
|
||||
```
|
||||
|
||||
## Review Commands
|
||||
```bash
|
||||
# Approve a PR (single-line comment)
|
||||
gh pr review <PR-number> --approve --body "Your approval message"
|
||||
|
||||
# Approve a PR (multi-line comment with proper whitespace)
|
||||
cat << EOF | gh pr review <PR-number> --approve --body-file -
|
||||
Your multi-line
|
||||
approval message with
|
||||
|
||||
proper whitespace formatting
|
||||
EOF
|
||||
|
||||
# Request changes on a PR (single-line comment)
|
||||
gh pr review <PR-number> --request-changes --body "Your feedback message"
|
||||
|
||||
# Request changes on a PR (multi-line comment with proper whitespace)
|
||||
cat << EOF | gh pr review <PR-number> --request-changes --body-file -
|
||||
Your multi-line
|
||||
change request with
|
||||
|
||||
proper whitespace formatting
|
||||
EOF
|
||||
|
||||
# Add a comment review (without approval/rejection)
|
||||
gh pr review <PR-number> --comment --body "Your comment message"
|
||||
|
||||
# Add a comment review with proper whitespace
|
||||
cat << EOF | gh pr review <PR-number> --comment --body-file -
|
||||
Your multi-line
|
||||
comment with
|
||||
|
||||
proper whitespace formatting
|
||||
EOF
|
||||
```
|
||||
|
||||
## Additional Commands
|
||||
```bash
|
||||
# View PR checks status
|
||||
gh pr checks <PR-number>
|
||||
|
||||
# View PR commits
|
||||
gh pr view <PR-number> --json commits
|
||||
|
||||
# Merge a PR (if you have permission)
|
||||
gh pr merge <PR-number> --merge
|
||||
```
|
||||
</common_gh_commands>
|
||||
|
||||
<general_guidelines_for_commenting>
|
||||
When reviewing a PR, please talk normally and like a friendly reviwer. You should keep it short, and start out by thanking the author of the pr and @ mentioning them.
|
||||
|
||||
Whether or not you approve the PR, you should then give a quick summary of the changes without being too verbose or definitive, staying humble like that this is your understanding of the changes. Kind of how I'm talking to you right now.
|
||||
|
||||
If you have any suggestions, or things that need to be changed, request changes instead of approving the PR.
|
||||
|
||||
Leaving inline comments in code is good, but only do so if you have something specific to say about the code. And make sure you leave those comments first, and then request changes in the PR with a short comment explaining the overall theme of what you're asking them to change.
|
||||
</general_guidelines_for_commenting>
|
||||
|
||||
<example_comments_that_i_have_written_before>
|
||||
<brief_approve_comment>
|
||||
Looks good, though we should make this generic for all providers & models at some point
|
||||
</brief_approve_comment>
|
||||
<brief_approve_comment>
|
||||
Will this work for models that may not match across OR/Gemini? Like the thinking models?
|
||||
</brief_approve_comment>
|
||||
<approve_comment>
|
||||
This looks great! I like how you've handled the global endpoint support - adding it to the ModelInfo interface makes total sense since it's just another capability flag, similar to how we handle other model features.
|
||||
|
||||
The filtered model list approach is clean and will be easier to maintain than hardcoding which models work with global endpoints. And bumping the genai library was obviously needed for this to work.
|
||||
|
||||
Thanks for adding the docs about the limitations too - good for users to know they can't use context caches with global endpoints but might get fewer 429 errors.
|
||||
</approve_comment>
|
||||
<requesst_changes_comment>
|
||||
This is awesome. Thanks @scottsus.
|
||||
|
||||
My main concern though - does this work for all the possible VS Code themes? We struggled with this initially which is why it's not super styled currently. Please test and share screenshots with the different themes to make sure before we can merge
|
||||
</request_changes_comment>
|
||||
<request_changes_comment>
|
||||
Hey, the PR looks good overall but I'm concerned about removing those timeouts. Those were probably there for a reason - VSCode's UI can be finicky with timing.
|
||||
|
||||
Could you add back the timeouts after focusing the sidebar? Something like:
|
||||
|
||||
```typescript
|
||||
await vscode.commands.executeCommand("claude-dev.SidebarProvider.focus")
|
||||
await setTimeoutPromise(100) // Give UI time to update
|
||||
visibleWebview = WebviewProvider.getSidebarInstance()
|
||||
```
|
||||
</request_changes_comment>
|
||||
<request_changes_comment>
|
||||
Heya @alejandropta thanks for working on this!
|
||||
|
||||
A few notes:
|
||||
1 - Adding additional info to the environment variables is fairly problematic because env variables get appended to **every single message**. I don't think this is justifiable for a somewhat niche use case.
|
||||
2 - Adding this option to settings to include that could be an option, but we want our options to be simple and straightforward for new users
|
||||
3 - We're working on revisualizing the way our settings page is displayed/organized, and this could potentially be reconciled once that is in and our settings page is more clearly delineated.
|
||||
|
||||
So until the settings page is update, and this is added to settings in a way that's clean and doesn't confuse new users, I don't think we can merge this. Please bear with us.
|
||||
</request_changes_comment>
|
||||
<request_changes_comment>
|
||||
Also, don't forget to add a changeset since this fixes a user-facing bug.
|
||||
|
||||
The architectural change is solid - moving the focus logic to the command handlers makes sense. Just don't want to introduce subtle timing issues by removing those timeouts.
|
||||
</request_changes_comment>
|
||||
</example_comments_that_i_have_written_before>
|
||||
@@ -20,3 +20,11 @@ coverage
|
||||
!.github/scripts/coverage/
|
||||
|
||||
*evals.env
|
||||
|
||||
# Generated proto files
|
||||
src/shared/proto/*.ts
|
||||
src/core/controller/*/methods.ts
|
||||
src/core/controller/*/index.ts
|
||||
src/core/controller/grpc-service-config.ts
|
||||
webview-ui/src/services/grpc-client.ts
|
||||
src/standalone/server-setup.ts
|
||||
|
||||
@@ -1,5 +1,45 @@
|
||||
# Changelog
|
||||
|
||||
## [3.17.3]
|
||||
|
||||
- Fix diff edit errors with Claude 4 models
|
||||
|
||||
## [3.17.2]
|
||||
|
||||
- Add support for Claude 4 models (Sonnet 4 and Opus 4) in AWS Bedrock and Vertex AI providers
|
||||
- Add support for global workflows, allowing workflows to be shared across workspaces with local workflows taking precedence
|
||||
- Fix settings page z-index UI issues that caused display problems
|
||||
- Fix AWS Bedrock environment variable handling to properly restore process.env after API calls (Thanks @DaveFres!)
|
||||
|
||||
## [3.17.1]
|
||||
|
||||
- Add prompt caching for Claude 4 models on Cline and OpenRouter providers
|
||||
- Increase max tokens for Claude Opus 4 from 4096 to 8192
|
||||
|
||||
## [3.17.0]
|
||||
|
||||
- Add support for Anthropic Claude Sonnet 4 and Claude Opus 4 in both Anthropic and Vertex providers
|
||||
- Add integration with Nebius AI Studio as a new provider (Thanks @Aktsvigun!)
|
||||
- Add custom highlight and hotkey suggestion when the assistant prompts to switch to Act mode
|
||||
- Update settings page design, now split into tabs for easier navigation (Thanks Yellow Bat @dlab-anton, and Roo Team!)
|
||||
- Fix MCP Server configuration bug
|
||||
- Fix model listing for Requesty provider
|
||||
- Move all advanced settings to settings page
|
||||
|
||||
## [3.16.3]
|
||||
|
||||
- Add devstral-small-2505 to the Mistral model list, a new specialized coding model from Mistral AI (Thanks @BarreiroT!)
|
||||
- Add documentation links to rules & workflows UI
|
||||
- Add support for Streameable HTTP Transport for MCPs (Thanks @alejandropta!)
|
||||
- Improve error handling for Mistral SDK API
|
||||
|
||||
## [3.16.2]
|
||||
|
||||
- Add support for Gemini 2.5 Flash Preview 05-20 model to Vertex AI provider with massive 1M token context window (Thanks @omercelik!)
|
||||
- Add keyboard shortcut (Cmd+') to quickly focus Cline from anywhere in VS Code
|
||||
- Add lightbulb actions for selected text with options to "Add to Cline", "Explain with Cline", and "Improve with Cline"
|
||||
- Automatically focus Cline window after extension updates
|
||||
|
||||
## [3.16.1]
|
||||
|
||||
- Add Enable auto approve toggle switch, allowing users to easily turn auto-approve functionality on or off without losing their action settings
|
||||
|
||||
+27
-4
@@ -74,8 +74,24 @@
|
||||
{
|
||||
"group": "Features",
|
||||
"pages": [
|
||||
"features/auto-approve",
|
||||
"features/checkpoints",
|
||||
"features/cline-rules",
|
||||
"features/drag-and-drop",
|
||||
"features/plan-and-act",
|
||||
"features/slash-commands/workflows",
|
||||
"features/editing-messages",
|
||||
{
|
||||
"group": "@ Mentions",
|
||||
"pages": [
|
||||
"features/at-mentions/overview",
|
||||
"features/at-mentions/file-mentions",
|
||||
"features/at-mentions/terminal-mentions",
|
||||
"features/at-mentions/problem-mentions",
|
||||
"features/at-mentions/git-mentions",
|
||||
"features/at-mentions/url-mentions"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Slash Commands",
|
||||
"pages": [
|
||||
@@ -84,6 +100,16 @@
|
||||
"features/slash-commands/smol",
|
||||
"features/slash-commands/report-bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Commands & Shortcuts",
|
||||
"pages": [
|
||||
"features/commands-and-shortcuts/overview",
|
||||
"features/commands-and-shortcuts/code-commands",
|
||||
"features/commands-and-shortcuts/terminal-integration",
|
||||
"features/commands-and-shortcuts/git-integration",
|
||||
"features/commands-and-shortcuts/keyboard-shortcuts"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -91,11 +117,8 @@
|
||||
"group": "Exploring Cline's Tools",
|
||||
"pages": [
|
||||
"exploring-clines-tools/cline-tools-guide",
|
||||
"exploring-clines-tools/plan-and-act-modes-a-guide-to-effective-ai-development",
|
||||
"exploring-clines-tools/checkpoints",
|
||||
"exploring-clines-tools/new-task-tool",
|
||||
"exploring-clines-tools/remote-browser-support",
|
||||
"exploring-clines-tools/slash-commands"
|
||||
"exploring-clines-tools/remote-browser-support"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
---
|
||||
title: "Checkpoints and Messages"
|
||||
description: "When working with AI coding assistants, it's easy to lose control as they make rapid changes to your codebase. That's why we built Checkpoints - your safety net for experimenting confidently."
|
||||
---
|
||||
|
||||
Checkpoints automatically save snapshots of your workspace after each step in a task. This powerful feature lets you:
|
||||
|
||||
- Track and review changes made during a task
|
||||
- Roll back to any previous point if needed
|
||||
- Experiment confidently with auto-approve mode
|
||||
- Maintain full control over your workspace
|
||||
|
||||
### ⚙️ How Checkpoints Work
|
||||
|
||||
Cline creates a checkpoint after each tool use (file edits, commands, etc.). These checkpoints:
|
||||
|
||||
- Work alongside your Git workflow without interference
|
||||
- Maintain context between restores
|
||||
- Use a shadow Git repository to track changes
|
||||
|
||||
For example, if you're working on a feature and Cline makes multiple file changes, each change creates a checkpoint. This means you can review each modification and, if needed, roll back to any point without affecting your main Git repository.
|
||||
|
||||
#### Viewing Changes & Restoring to Checkpoint
|
||||
|
||||
After each tool use, you can:
|
||||
|
||||
1. Click the "Compare" button to see modified files
|
||||
2. Click the "Restore" button to open restore options
|
||||
|
||||
<Frame>
|
||||
<img
|
||||
src="https://storage.googleapis.com/cline_public_images/docs/assets/image%20(13).png"
|
||||
alt="Checkpoint comparison and restore options"
|
||||
/>
|
||||
</Frame>
|
||||
|
||||
#### Rolling Back
|
||||
|
||||
To restore to a previous point:
|
||||
|
||||
1. Click the "Restore" button next to any step
|
||||
2. Choose from three options:
|
||||
- **Restore Task and Workspace**: Reset both codebase and task to that point
|
||||
- **Restore Task Only**: Keep codebase changes but revert task context
|
||||
- **Restore Workspace Only**: Reset codebase while preserving task context
|
||||
|
||||
Example: If Cline makes changes you don't like while styling a component, you can use "Restore Workspace Only" to revert the code changes while keeping the conversation context, allowing you to try a different approach.
|
||||
|
||||
### 💡 Use Cases
|
||||
|
||||
Checkpoints let you be more experimental with Cline. While human coding is often methodical and iterative, AI can make substantial changes quickly. Checkpoints help you track these changes and revert if needed.
|
||||
|
||||
#### 1. Using Auto-Approve Mode
|
||||
|
||||
- Provides safety net for rapid iterations
|
||||
- Makes it easy to undo unexpected results
|
||||
|
||||
#### 2. Testing Different Approaches
|
||||
|
||||
- Try multiple solutions confidently
|
||||
- Compare different implementations
|
||||
- Quickly revert to working states
|
||||
- Ideal for exploring different design patterns or architectural approaches
|
||||
|
||||
<Frame caption="In this case, I didn't like the changes Cline made to my robot dog-walking website (still working on the robots) and I wanted to revert both the codebase and the task to before any changes were made so I could start fresh.">
|
||||
<img src="https://storage.googleapis.com/cline_public_images/docs/assets/checkpointsDemo.gif" alt="Checkpoint restore demo" />
|
||||
</Frame>
|
||||
|
||||
### ✨ Best Practices
|
||||
|
||||
1. Use checkpoints as safety nets when experimenting
|
||||
2. Leverage auto-approve mode more confidently, knowing you can always roll back
|
||||
3. Restore selectively based on needs:
|
||||
|
||||
- Use "Restore Task and Workspace" for a fresh start, reversing changes to files and the task conversation.
|
||||
- Use "Restore Task Only" to try different prompts, but leave all files as they exist
|
||||
- Use "Restore Workspace Only" to attempt different implementations, or prune context from the task
|
||||
|
||||
🛟 Checkpoints are your safety net when working with Cline, enabling you to experiment freely while maintaining full control over your codebase. Whether you're refactoring a complex component, trying different implementation approaches, or using auto-approve mode for rapid development, checkpoints ensure you can always review changes and roll back if needed.
|
||||
|
||||
#### 🗑️ Deleting Checkpoints
|
||||
|
||||
You can delete all checkpoints by using the **"Delete All History"** button in the task history menu. Note that this will also delete all tasks. Checkpoints are stored in VS Code's globalStorage.
|
||||
|
||||
---
|
||||
|
||||
## Editing Messages
|
||||
|
||||
Cline allows you to edit chat messages in a task after they've been submitted (with the exception of the message that started the task).
|
||||
|
||||
Perhaps you didn't get the results you wanted, thought of a better way to phrase your request, or need to add more information. Editing your message allows you to re-submit a request without starting over or restoring your files or workspace with checkpoints. There are two Restore options:
|
||||
|
||||
- **"Restore Chat"** restores just the task state and re-submits an API request to your provider with your edited message.
|
||||
|
||||
- **"Restore All"** restores both the task state and workspace state before re-submitting an API request. "Workspace state" refers to the condition of your workspace (files, content, etc.) at different points in the conversation.
|
||||
|
||||
**Interactive Editing:**
|
||||
|
||||
- Messages can be clicked to enter edit mode
|
||||
- Cline automatically selects all text when entering edit mode
|
||||
|
||||
**Keyboard Shortcuts:**
|
||||
|
||||
- Escape: Exit edit mode
|
||||
- Enter: Restore just the task
|
||||
- Cmd/Ctrl + Enter: Restore the task and workspace
|
||||
- Shift + Enter: Insert new line / line break
|
||||
|
||||
<Frame>
|
||||
<img
|
||||
src="https://storage.googleapis.com/cline_public_images/docs/assets/message-editing.png"
|
||||
alt="Message editing interface"
|
||||
/>
|
||||
</Frame>
|
||||
@@ -29,6 +29,11 @@ As a quick alternative to Cline suggesting the `newtask` tool or defining comple
|
||||
- **Action:** Cline will propose creating a new task, typically suggesting context based on the current session (similar to its default behavior when using the tool). You will still get the `ask_followup_question` prompt to confirm and potentially modify the context before the new task is created.
|
||||
- **Benefit:** Provides a fast, user-initiated way to leverage the `new_task` functionality for branching explorations or managing long sessions without waiting for Cline to suggest it.
|
||||
|
||||
<Note>
|
||||
For more details on using the `/newtask` slash command, see the [New Task Command](/features/slash-commands/new-task)
|
||||
documentation.
|
||||
</Note>
|
||||
|
||||
#### Default Behavior (Without `.clinerules`)
|
||||
|
||||
By default, without specific `.clinerules` dictating its behavior:
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
---
|
||||
title: "Slash Commands"
|
||||
---
|
||||
|
||||
#### Overview
|
||||
|
||||
Cline provides slash commands as a quick way to invoke specific tools or actions directly from the chat input, offering shortcuts for common operations. This page details the available slash commands and their usage.
|
||||
|
||||
#### /newtask
|
||||
|
||||
The `/newtask` slash command provides a fast, user-initiated way to leverage the `new_task` tool's functionality for branching explorations or managing long sessions without waiting for Cline to suggest it.
|
||||
|
||||
**Functionality:**
|
||||
|
||||
1. **Initiation:** Typing `/newtask` in the chat input signals Cline to prepare for starting a new task session.
|
||||
2. **Context Proposal:** Cline proposes creating a new task and typically suggests context to preload based on the current session (summarizing key aspects like current work, technical concepts, relevant files, problems solved, and next steps).
|
||||
3. **User Confirmation:** You will receive a confirmation prompt (via the `ask_followup_question` tool) displaying the proposed context. You can approve it directly or modify the context before the new task begins.
|
||||
4. **New Session:** Upon confirmation, Cline ends the current task session and immediately starts a new one, preloaded with the approved context.
|
||||
|
||||
**Benefit:** Allows you to cleanly branch your work or start a new phase while carrying over essential background information ("knowledge transfer") without manual copying or losing the thread of the previous session.
|
||||
|
||||
#### /smol (alias /compact)
|
||||
|
||||
The `/smol` slash command (with `/compact` as an alias) allows you to condense the chat history **within your current task**. This is useful when a conversation becomes very long, potentially impacting performance or making it harder for the model to maintain focus.
|
||||
|
||||
**Functionality:**
|
||||
|
||||
1. **Initiation:** Typing `/smol` or `/compact` tells Cline you want to condense the current chat history. You can optionally add instructions after the command to guide the summarization process (e.g., `/smol focus only on the database changes` or `/smol be concise, use bullet points`).
|
||||
2. **Summarization:** Cline analyzes the conversation history, considering any additional instructions provided, and generates a summary focusing on key elements: recent discussion points, important decisions, technical concepts, relevant files, problems solved, and planned next steps. Cline determines the appropriate length and detail for the summary. It retains the beginning and very recent parts of the chat while summarizing the middle sections.
|
||||
3. **User Confirmation:** Cline presents this generated summary to you via a confirmation prompt and asks if it accurately reflects the essential context.
|
||||
4. **Condensing:** If you approve the summary, Cline replaces the summarized middle portion of the chat history in its active context with the generated summary. This reduces the overall token count for subsequent interactions within the _same task_.
|
||||
5. **Feedback:** If you reject the summary or provide feedback, Cline will retain the original history and incorporate your feedback for future actions.
|
||||
|
||||
**Benefit:** Helps maintain focus and manage token usage during very long, continuous tasks (like deep debugging or extended feature development) without needing to start an entirely new task session. Allows user guidance on the summarization focus.
|
||||
|
||||
#### When to Use Which?
|
||||
|
||||
Choosing between `/newtask` and `/smol` depends on your goal:
|
||||
|
||||
- Use `/smol` (or `/compact`) when:
|
||||
- You want to continue the **same task**, but the chat history has become very long or costly.
|
||||
- You need to reduce token usage for upcoming interactions within the current workflow.
|
||||
- Example: Deep debugging session where you want to summarize previous steps before continuing.
|
||||
- Use `/newtask` when:
|
||||
- You have finished one phase of work and want to start a **fresh, related task**.
|
||||
- You want to branch your exploration while preserving key context from the previous session.
|
||||
- Example: Moving from developing Feature A to starting work on Feature B, carrying over relevant architectural decisions.
|
||||
|
||||
#### Why Manage Context?
|
||||
|
||||
While Cline supports large context windows, actively managing context using tools and commands like `/newtask` and `/smol` is often beneficial:
|
||||
|
||||
- **Performance:** Large language models can sometimes experience performance degradation or lose focus when context windows become extremely full (e.g., over 50-75% capacity, depending on the model). Condensing or resetting context can help maintain optimal performance.
|
||||
- **Relevance:** Summarizing or starting fresh ensures the most relevant information is prioritized in the context window.
|
||||
- **Cost:** Reducing the number of tokens sent to the model in each turn can help manage costs, especially with more expensive models.
|
||||
|
||||
Using `/newtask` and `/smol` provides you with direct control over the conversation context, allowing for more efficient and effective interaction with Cline.
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: "File Mentions"
|
||||
sidebarTitle: "File Mentions"
|
||||
---
|
||||
|
||||
File mentions let you pull any file from your workspace directly into your conversation with Cline. No more copying and pasting code snippets - just type `@/` and point to the file you need help with.
|
||||
|
||||
When you type `@/` in the chat, Cline shows your workspace files. Navigate through folders, select the file you want, and it's instantly available to Cline - complete with all imports, related functions, and surrounding context.
|
||||
|
||||
I use file mentions constantly when debugging. Instead of trying to figure out which parts of my code to copy over, I just reference the file directly:
|
||||
|
||||
```
|
||||
I'm getting this error when my form submits: @terminal
|
||||
|
||||
Here's my component: @/src/components/ContactForm.jsx
|
||||
|
||||
And the API endpoint: @/src/api/contact.js
|
||||
|
||||
What am I missing?
|
||||
```
|
||||
|
||||
This gives Cline everything it needs - the error message, the component code, and the API endpoint - all without me having to copy anything. Cline can see imports, dependencies, and all the surrounding context that might be causing the issue.
|
||||
|
||||
File mentions shine when you're dealing with complex bugs that span multiple files. Before, I'd have to carefully copy each relevant file, making sure I didn't miss anything important. Now I just reference each file with `@/` and Cline gets the complete picture.
|
||||
|
||||
Next time you're stuck on a problem, try using file mentions instead of copying code. You'll save time and get better answers because Cline has all the context it needs.
|
||||
|
||||
## How It Works Under the Hood
|
||||
|
||||
When you use a file mention in your message, here's what happens behind the scenes:
|
||||
|
||||
1. When you send your message, Cline detects the `@/path/to/file` pattern in your text
|
||||
2. The extension resolves the file path relative to your workspace root
|
||||
3. It checks if the file is binary (like an image) or text-based
|
||||
4. For text files, it reads the complete file content
|
||||
5. The file content is appended to your message in a structured format:
|
||||
```
|
||||
<file_content path="path/to/file">
|
||||
[Complete file content]
|
||||
</file_content>
|
||||
```
|
||||
6. This enhanced message with the embedded file content is sent to the AI
|
||||
7. The AI can now "see" the complete file content as if you had copied and pasted it
|
||||
|
||||
This seamless process happens automatically whenever you use a file mention, giving the AI full context without you having to manually copy anything.
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: "Folder Mentions"
|
||||
sidebarTitle: "Folder Mentions"
|
||||
---
|
||||
|
||||
Folder mentions let you bring entire directories into your conversation with Cline. Just type `@/` followed by a folder path ending with a slash, and Cline gets access to the folder structure and its contents.
|
||||
|
||||
When you type `@/` in chat, Cline shows your workspace files and folders. Navigate to the folder you want, make sure to include the trailing slash, and Cline will see the folder's structure and contents.
|
||||
|
||||
I use folder mentions when I need help understanding or refactoring a whole section of my codebase. Instead of referencing individual files one by one, I can just point to the entire directory:
|
||||
|
||||
```
|
||||
I'm trying to understand how the authentication flow works in my app.
|
||||
Can you explain the structure and relationships between the files in @/src/auth/?
|
||||
```
|
||||
|
||||
Cline can then see all the files in the auth directory, their contents, and how they relate to each other. This gives it the full context to explain complex interactions between multiple files.
|
||||
|
||||
Folder mentions are also perfect for getting help with project organization. When I'm unsure if my project structure makes sense, I'll ask Cline to review it:
|
||||
|
||||
```
|
||||
I'm setting up a new React project. Does this folder structure make sense? @/src/
|
||||
What would you change to make it more maintainable as the project grows?
|
||||
```
|
||||
|
||||
Next time you're working with multiple related files, try using folder mentions instead of referencing each file individually. You'll get more comprehensive help because Cline can see the bigger picture of how everything fits together.
|
||||
|
||||
## How It Works Under the Hood
|
||||
|
||||
When you use a folder mention in your message, here's what happens behind the scenes:
|
||||
|
||||
1. When you send your message, Cline detects the `@/path/to/folder/` pattern (with trailing slash) in your text
|
||||
2. The extension resolves the folder path relative to your workspace root
|
||||
3. It calls `fs.readdir()` to get a list of all files and subdirectories in that folder
|
||||
4. For each file in the directory, it checks if it's binary or text-based
|
||||
5. For text files, it extracts the complete content
|
||||
6. The folder structure and file contents are appended to your message in a structured format:
|
||||
|
||||
```
|
||||
<folder_content path="path/to/folder">
|
||||
├── file1.txt
|
||||
├── file2.js
|
||||
└── subfolder/
|
||||
|
||||
<file_content path="path/to/folder/file1.txt">
|
||||
[File content]
|
||||
</file_content>
|
||||
|
||||
<file_content path="path/to/folder/file2.js">
|
||||
[File content]
|
||||
</file_content>
|
||||
</folder_content>
|
||||
```
|
||||
|
||||
7. This enhanced message with the embedded folder structure and file contents is sent to the AI
|
||||
8. The AI can now "see" both the directory structure and the content of files within that directory
|
||||
|
||||
This process happens automatically whenever you use a folder mention, giving the AI a comprehensive view of your project structure and file contents.
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
title: "Git Mentions"
|
||||
sidebarTitle: "Git Mentions"
|
||||
---
|
||||
|
||||
Git mentions let you bring your repository's history and changes directly into your conversation with Cline. You can reference uncommitted changes with `@git-changes` or specific commits with `@[commit-hash]`.
|
||||
|
||||
When you type `@` in chat, you can select "Git Changes" from the menu or type `@git-changes` directly. For specific commits, type `@` followed by the commit hash (at least 7 characters). Cline will immediately see the git status, diffs, commit messages, and other relevant information.
|
||||
|
||||
I use git mentions constantly when I'm trying to understand code changes or troubleshoot issues introduced by recent commits. Instead of trying to copy and paste diffs or commit logs, I just ask:
|
||||
|
||||
```
|
||||
I think this commit broke our authentication flow: @a1b2c3d
|
||||
|
||||
Can you explain what changed and why it might be causing the issue?
|
||||
```
|
||||
|
||||
This gives Cline the complete commit information, including the commit message, author, date, and the full diff. Cline can then analyze exactly what changed and how it might affect other parts of the codebase.
|
||||
|
||||
The `@git-changes` mention is perfect when you're working on changes and want feedback before committing:
|
||||
|
||||
```
|
||||
Here are my current changes: @git-changes
|
||||
|
||||
I'm trying to implement a new feature for user profiles. Does my approach make sense?
|
||||
Are there any potential issues or improvements you'd suggest?
|
||||
```
|
||||
|
||||
This shows Cline all your uncommitted changes, including new files, modified files, and their diffs. Cline can then review your changes and provide feedback on your implementation.
|
||||
|
||||
Git mentions are especially powerful when combined with file mentions. When I'm investigating a bug, I'll often reference both:
|
||||
|
||||
```
|
||||
I think this commit introduced a bug: @a1b2c3d
|
||||
|
||||
Here's the current implementation: @/src/components/Auth.jsx
|
||||
|
||||
How can I fix the issue while preserving the intended functionality?
|
||||
```
|
||||
|
||||
Next time you're working with code changes or investigating issues, try using git mentions instead of manually describing or copying changes. You'll get more accurate help because Cline can see exactly what changed and in what context.
|
||||
|
||||
## How It Works Under the Hood
|
||||
|
||||
When you use git mentions in your message, here's what happens behind the scenes:
|
||||
|
||||
### For Git Changes (`@git-changes`)
|
||||
|
||||
1. When you send your message, Cline detects the `@git-changes` pattern in your text
|
||||
2. The extension runs git commands to get the current working state of your repository
|
||||
3. It captures the output of `git status` and `git diff` to see all uncommitted changes
|
||||
4. This information is appended to your message in a structured format:
|
||||
|
||||
```
|
||||
<git_working_state>
|
||||
On branch main
|
||||
Changes not staged for commit:
|
||||
modified: src/components/Button.jsx
|
||||
modified: src/styles/main.css
|
||||
|
||||
[Complete diff output with all changes]
|
||||
</git_working_state>
|
||||
```
|
||||
|
||||
### For Specific Commits (`@[commit-hash]`)
|
||||
|
||||
1. When you send your message, Cline detects the `@` followed by a commit hash pattern
|
||||
2. The extension runs `git show` and related commands to get information about that commit
|
||||
3. It retrieves the commit message, author, date, and the complete diff
|
||||
4. This information is appended to your message in a structured format:
|
||||
|
||||
```
|
||||
<git_commit hash="a1b2c3d">
|
||||
commit a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t
|
||||
Author: Developer Name <dev@example.com>
|
||||
Date: Mon May 20 14:30:45 2025 -0700
|
||||
|
||||
Fix authentication bug in login form
|
||||
|
||||
[Complete diff output showing all changes in the commit]
|
||||
</git_commit>
|
||||
```
|
||||
|
||||
This process happens automatically whenever you use git mentions, giving the AI complete visibility into your code changes without you having to copy and paste diffs or commit logs.
|
||||
@@ -0,0 +1,118 @@
|
||||
---
|
||||
title: "@ Mentions Overview"
|
||||
sidebarTitle: "Overview"
|
||||
---
|
||||
|
||||
@ mentions are one of Cline's most powerful features, letting you seamlessly bring external context into your conversations. Instead of copying and pasting code, error messages, or documentation, you can simply reference them with an @ symbol.
|
||||
|
||||
<Frame>
|
||||
<img src="https://storage.googleapis.com/cline_public_images/docs/assets/at-mentions.png" alt="@ Mentions Overview" />
|
||||
</Frame>
|
||||
|
||||
When you type `@` in the chat input, Cline shows a menu of available mention types. These mentions let you reference files, folders, problems, terminal output, git changes, and even web content directly in your conversations.
|
||||
|
||||
## Available @ Mentions
|
||||
|
||||
Cline supports several types of @ mentions, each designed to bring different kinds of context into your conversations:
|
||||
|
||||
<Columns cols={2}>
|
||||
<Card title="File Mentions" icon="file" href="/features/at-mentions/file-mentions">
|
||||
Reference any file in your workspace with `@/path/to/file`. Cline sees the complete file content, including imports, related
|
||||
functions, and surrounding context.
|
||||
</Card>
|
||||
|
||||
{" "}
|
||||
|
||||
<Card title="Folder Mentions" icon="folder" href="/features/at-mentions/folder-mentions">
|
||||
Reference entire directories with `@/path/to/folder/`. Cline sees the folder structure and all file contents, perfect for
|
||||
understanding complex interactions between multiple files.
|
||||
</Card>
|
||||
|
||||
{" "}
|
||||
|
||||
<Card title="Problem Mentions" icon="triangle-exclamation" href="/features/at-mentions/problem-mentions">
|
||||
Use `@problems` to show Cline all the errors and warnings in your workspace. Cline sees the complete list with file locations
|
||||
and error messages.
|
||||
</Card>
|
||||
|
||||
{" "}
|
||||
|
||||
<Card title="Terminal Mentions" icon="terminal" href="/features/at-mentions/terminal-mentions">
|
||||
Use `@terminal` to share your recent terminal output. Cline sees the complete output with formatting preserved, perfect for
|
||||
debugging build errors or test failures.
|
||||
</Card>
|
||||
|
||||
{" "}
|
||||
|
||||
<Card title="Git Mentions" icon="code-branch" href="/features/at-mentions/git-mentions">
|
||||
Reference uncommitted changes with `@git-changes` or specific commits with `@[commit-hash]`. Cline sees the complete diff,
|
||||
commit message, and other relevant information.
|
||||
</Card>
|
||||
|
||||
<Card title="URL Mentions" icon="globe" href="/features/at-mentions/url-mentions">
|
||||
Reference web content with `@https://example.com`. Cline fetches and sees the complete webpage content, perfect for
|
||||
referencing documentation or GitHub issues.
|
||||
</Card>
|
||||
</Columns>
|
||||
|
||||
## Why @ Mentions Matter
|
||||
|
||||
@ mentions transform how you interact with Cline by:
|
||||
|
||||
1. **Eliminating copy-paste**: No more copying and pasting code, error messages, or terminal output. Just reference them directly.
|
||||
|
||||
2. **Preserving context**: Cline sees the complete context, including imports, related functions, and surrounding code that might be relevant.
|
||||
|
||||
3. **Maintaining formatting**: Terminal output, error messages, and web content keep their formatting, making them easier to understand.
|
||||
|
||||
4. **Enabling complex workflows**: Combine multiple @ mentions to give Cline a complete picture of your problem:
|
||||
|
||||
```
|
||||
I'm getting these errors: @problems
|
||||
|
||||
Here's my component: @/src/components/Form.jsx
|
||||
And the API endpoint: @/src/api/users.js
|
||||
|
||||
The error happens when I submit: @terminal
|
||||
|
||||
I think this commit might have caused it: @a1b2c3d
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
To use @ mentions:
|
||||
|
||||
1. Type `@` in the chat input
|
||||
2. Select the type of mention from the menu or continue typing
|
||||
3. For files and folders, navigate through your workspace structure
|
||||
4. Send your message as usual
|
||||
|
||||
Cline will automatically process the mentions and include the referenced content in the context sent to the AI.
|
||||
|
||||
Try using @ mentions in your next conversation with Cline - you'll be amazed at how much more efficient and effective your interactions become when you can seamlessly bring in external context.
|
||||
|
||||
## How It Works Under the Hood
|
||||
|
||||
When you use @ mentions in your messages, there's a sophisticated process happening behind the scenes:
|
||||
|
||||
1. **Detection**: When you send a message, Cline scans the text for @ mention patterns using regular expressions
|
||||
2. **Processing**: For each detected mention, Cline:
|
||||
- Determines the mention type (file, folder, problems, terminal, git, URL)
|
||||
- Fetches the relevant content (file contents, terminal output, etc.)
|
||||
- Formats the content appropriately
|
||||
3. **Enhancement**: The original message is enhanced with structured data:
|
||||
|
||||
```
|
||||
Your original message with @/path/to/file
|
||||
|
||||
<file_content path="/path/to/file">
|
||||
[Complete file content]
|
||||
</file_content>
|
||||
```
|
||||
|
||||
4. **Context Inclusion**: This enhanced message with all the embedded content is sent to the AI model
|
||||
5. **Seamless Response**: The AI can now "see" all the referenced content as if you had manually copied and pasted it
|
||||
|
||||
This entire process happens automatically and seamlessly whenever you use @ mentions, giving the AI complete context without you having to manually copy anything.
|
||||
|
||||
Each type of @ mention has its own specific implementation details, which you can find in their respective documentation pages.
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
title: "Problem Mentions"
|
||||
sidebarTitle: "Problem Mentions"
|
||||
---
|
||||
|
||||
The problems mention gives Cline instant access to all the errors and warnings in your workspace. Just type `@problems` and Cline can see every diagnostic issue VSCode has detected.
|
||||
|
||||
When you type `@` in chat, select "Problems" from the menu or just type `@problems` directly. Cline will immediately see all the errors and warnings from your workspace, complete with file locations and error messages.
|
||||
|
||||
I use the problems mention constantly when I'm stuck on build errors or TypeScript issues. Instead of trying to describe the errors or copy them one by one, I just ask:
|
||||
|
||||
```
|
||||
I'm getting these TypeScript errors and I'm not sure how to fix them: @problems
|
||||
|
||||
Can you help me understand what's wrong and how to fix it?
|
||||
```
|
||||
|
||||
This gives Cline the complete list of errors with their exact locations and messages. Cline can then analyze the patterns across multiple errors and suggest comprehensive solutions.
|
||||
|
||||
The problems mention is especially powerful when combined with file mentions. When I'm dealing with complex type errors, I'll reference both:
|
||||
|
||||
```
|
||||
I'm getting these type errors: @problems
|
||||
|
||||
Here's my component: @/src/components/DataTable.tsx
|
||||
And the types file: @/src/types/api.ts
|
||||
|
||||
How can I fix these issues?
|
||||
```
|
||||
|
||||
This approach gives Cline everything it needs - the exact errors, the component code, and the type definitions - all without me having to copy anything manually.
|
||||
|
||||
Next time you're stuck on errors, try using `@problems` instead of copying error messages. You'll get more accurate help because Cline can see the complete error context and locations.
|
||||
|
||||
## How It Works Under the Hood
|
||||
|
||||
When you use the problems mention in your message, here's what happens behind the scenes:
|
||||
|
||||
1. When you send your message, Cline detects the `@problems` pattern in your text
|
||||
2. The extension calls VSCode's built-in `vscode.languages.getDiagnostics()` API to get all errors and warnings
|
||||
3. It formats these diagnostics into a structured text representation with file paths, line numbers, and error messages
|
||||
4. The formatted problems list is appended to your message in a structured format:
|
||||
```
|
||||
<workspace_diagnostics>
|
||||
/path/to/file.js:10:5 - error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
/path/to/file.js:15:3 - warning: This variable is never used.
|
||||
</workspace_diagnostics>
|
||||
```
|
||||
5. This enhanced message with the embedded diagnostics is sent to the AI
|
||||
6. The AI can now "see" all the errors and warnings in your workspace, complete with their locations and messages
|
||||
|
||||
This process happens automatically whenever you use the problems mention, giving the AI a comprehensive view of all the issues in your workspace without you having to copy them manually.
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
title: "Terminal Mentions"
|
||||
sidebarTitle: "Terminal Mentions"
|
||||
---
|
||||
|
||||
The terminal mention lets you bring your terminal output directly into your conversation with Cline. Just type `@terminal` and Cline can see the recent output from your terminal.
|
||||
|
||||
When you type `@` in chat, select "Terminal" from the menu or just type `@terminal` directly. Cline will immediately see the recent output from your active terminal, including error messages, build logs, or command results.
|
||||
|
||||
I use the terminal mention all the time when I'm dealing with build errors, test failures, or debugging output. Instead of trying to copy and paste terminal output (which often loses formatting), I just ask:
|
||||
|
||||
```
|
||||
I'm getting this error when running my tests: @terminal
|
||||
|
||||
What's causing this and how can I fix it?
|
||||
```
|
||||
|
||||
This gives Cline the complete terminal output with all its formatting intact. Cline can then analyze the error messages, stack traces, and surrounding context to provide more accurate help.
|
||||
|
||||
The terminal mention is especially powerful when combined with file mentions. When I'm debugging a failed API call, I'll reference both:
|
||||
|
||||
```
|
||||
I'm getting this error when calling my API: @terminal
|
||||
|
||||
Here's my API client code: @/src/api/client.js
|
||||
And the endpoint implementation: @/src/server/routes/users.js
|
||||
|
||||
What am I doing wrong?
|
||||
```
|
||||
|
||||
This approach gives Cline everything it needs - the exact error output, the client code, and the server implementation - all without me having to copy anything manually.
|
||||
|
||||
Next time you're running into issues with command output or build errors, try using `@terminal` instead of copying the output. You'll get more accurate help because Cline can see the complete terminal context with proper formatting.
|
||||
|
||||
## How It Works Under the Hood
|
||||
|
||||
When you use the terminal mention in your message, here's what happens behind the scenes:
|
||||
|
||||
1. When you send your message, Cline detects the `@terminal` pattern in your text
|
||||
2. The extension calls `getLatestTerminalOutput()` which accesses VSCode's terminal API
|
||||
3. It captures the recent output buffer from your active terminal
|
||||
4. The terminal output is appended to your message in a structured format:
|
||||
|
||||
```
|
||||
<terminal_output>
|
||||
$ npm run test
|
||||
> project@1.0.0 test
|
||||
> jest
|
||||
|
||||
FAIL src/components/__tests__/Button.test.js
|
||||
● Button component › renders correctly
|
||||
|
||||
[Complete terminal output with formatting preserved]
|
||||
</terminal_output>
|
||||
```
|
||||
|
||||
5. This enhanced message with the embedded terminal output is sent to the AI
|
||||
6. The AI can now "see" the complete terminal output with all formatting preserved
|
||||
|
||||
This process happens automatically whenever you use the terminal mention, giving the AI access to your command results, error messages, and other terminal output without you having to copy it manually.
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
title: "URL Mentions"
|
||||
sidebarTitle: "URL Mentions"
|
||||
---
|
||||
|
||||
URL mentions let you bring web content directly into your conversation with Cline. Just type `@` followed by any URL, and Cline can see the content of that webpage without you having to copy and paste anything.
|
||||
|
||||
When you type `@` in chat followed by a URL (like `@https://example.com`), Cline will fetch the content of that webpage and include it in the context. This works for documentation pages, GitHub issues, Stack Overflow questions, or any other web content you want to reference.
|
||||
|
||||
I use URL mentions constantly when I'm working with external APIs or libraries. Instead of trying to explain how an API works or copying documentation snippets, I just reference the docs directly:
|
||||
|
||||
```
|
||||
I'm trying to implement authentication with this API: @https://api.example.com/docs/auth
|
||||
|
||||
Can you help me write the code to get an access token based on these docs?
|
||||
```
|
||||
|
||||
This gives Cline the complete documentation page, so it can see all the authentication requirements, endpoints, parameters, and examples. Cline can then provide more accurate and comprehensive help based on the official documentation.
|
||||
|
||||
URL mentions are especially useful for referencing GitHub issues or discussions:
|
||||
|
||||
```
|
||||
I'm trying to fix this issue in our project: @https://github.com/our-org/our-repo/issues/123
|
||||
|
||||
Here's my current implementation: @/src/components/Feature.jsx
|
||||
|
||||
What changes do I need to make to address the issue?
|
||||
```
|
||||
|
||||
This shows Cline the complete GitHub issue, including the description, comments, and any code snippets or screenshots. Cline can then help you implement a solution that directly addresses the reported issue.
|
||||
|
||||
Next time you're working with external documentation or online resources, try using URL mentions instead of copying and pasting content. You'll get more accurate help because Cline can see the complete context of the webpage, including formatting, code examples, and surrounding information.
|
||||
|
||||
## How It Works Under the Hood
|
||||
|
||||
When you use a URL mention in your message, here's what happens behind the scenes:
|
||||
|
||||
1. When you send your message, Cline detects the `@http://...` or `@https://...` pattern in your text
|
||||
2. The extension launches a headless browser (Puppeteer) in the background
|
||||
3. It navigates to the URL and waits for the page to load completely
|
||||
4. The browser captures the page content, including text, formatting, and code examples
|
||||
5. The content is converted to a Markdown format that preserves the structure
|
||||
6. This content is appended to your message in a structured format:
|
||||
|
||||
```
|
||||
<url_content url="https://example.com/docs">
|
||||
# Example API Documentation
|
||||
|
||||
## Authentication
|
||||
|
||||
To authenticate with the API, you need to...
|
||||
|
||||
const token = await api.authenticate({
|
||||
username: 'user',
|
||||
password: 'pass'
|
||||
});
|
||||
|
||||
[Complete webpage content in Markdown format]
|
||||
</url_content>
|
||||
```
|
||||
|
||||
7. The browser is then closed to free up resources
|
||||
8. This enhanced message with the embedded webpage content is sent to the AI
|
||||
|
||||
This process happens automatically whenever you use a URL mention, giving the AI access to the complete content of the webpage without you having to copy and paste anything.
|
||||
@@ -0,0 +1,59 @@
|
||||
The Auto Approve menu lets you set fine-grained permissions on what you allow Cline to do in an automated way.
|
||||
|
||||
<Frame>
|
||||
<img src="https://storage.googleapis.com/cline_public_images/docs/assets/auto-approve.png" alt="Auto Approve" />
|
||||
</Frame>
|
||||
|
||||
## How it works
|
||||
|
||||
By default, Cline will ask for your permission before calling any tool, including reading or writing files.
|
||||
|
||||
If you want to allow Cline to do something without asking, you can set the Auto Approve permission for that tool.
|
||||
|
||||
## Permission Options
|
||||
|
||||
- **Read project files**
|
||||
|
||||
- Allows Cline to read files within your current workspace without asking
|
||||
- **Read all files**
|
||||
- Extends read permission to files outside your workspace (system files, config files, etc.)
|
||||
|
||||
- **Edit project files**
|
||||
|
||||
- Allows Cline to modify files within your current workspace without confirmation
|
||||
- **Edit all files**
|
||||
- Extends modification permission to files outside your workspace
|
||||
|
||||
- **Execute safe commands**
|
||||
|
||||
- Allows execution of terminal commands that the model deems non-destructive
|
||||
- **Execute all commands**
|
||||
- Permits execution of any terminal command without asking
|
||||
|
||||
- **Use the browser**
|
||||
|
||||
- Allows Cline to use the browser tool to fetch web content
|
||||
|
||||
- **Use MCP servers**
|
||||
|
||||
- Permits connection to and usage of MCP servers for extended functionality
|
||||
|
||||
- **Maximum requests**
|
||||
- Sets the number of consecutive automated actions Cline can take before requiring your input
|
||||
|
||||
## Best Practices
|
||||
|
||||
Personally, I like to keep auto-editing disabled because it gives me a chance to review changes every step of the way.
|
||||
|
||||
For most serious development workflows, I recommend starting with:
|
||||
|
||||
- Auto-approving read access to project files
|
||||
- Setting a reasonable maximum request limit (10-20)
|
||||
|
||||
This gives Cline enough freedom to explore your codebase without constant interruptions, while still requiring permission for edits or potentially destructive actions.
|
||||
|
||||
As you build more trust in Cline's capabilities with your specific projects, you can gradually increase the permissions to match your comfort level.
|
||||
|
||||
Remember that you can always adjust these settings as your needs change - tighten permissions for critical production work, or loosen them when prototyping and exploring.
|
||||
|
||||
You can even use the quick "star" actions to quickly toggle your auto-approved selections on and off as you go.
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: "Checkpoints"
|
||||
sidebarTitle: "Checkpoints"
|
||||
---
|
||||
|
||||
Checkpoints automatically save snapshots of your workspace after each step in a task. This feature lets you track changes, roll back when needed, and experiment confidently with your code.
|
||||
|
||||
## How Checkpoints Work
|
||||
|
||||
Cline creates a checkpoint after each tool use (file edits, commands, etc.). These checkpoints:
|
||||
|
||||
- Work alongside your Git workflow without interference
|
||||
- Maintain context between restores
|
||||
- Use a shadow Git repository to track changes
|
||||
|
||||
For example, if you're working on a feature and Cline makes multiple file changes, each change creates a checkpoint. This means you can review each modification and, if needed, roll back to any point without affecting your main Git repository.
|
||||
|
||||
## Viewing Changes & Restoring
|
||||
|
||||
After each tool use, you can:
|
||||
|
||||
1. Click the "Compare" button to see modified files
|
||||
2. Click the "Restore" button to open restore options
|
||||
|
||||
<Frame>
|
||||
<img
|
||||
src="https://storage.googleapis.com/cline_public_images/docs/assets/image%20(13).png"
|
||||
alt="Checkpoint comparison and restore options"
|
||||
/>
|
||||
</Frame>
|
||||
|
||||
## Restore Options
|
||||
|
||||
To restore to a previous point:
|
||||
|
||||
1. Click the "Restore" button next to any step
|
||||
2. Choose from three options:
|
||||
- **Restore Task and Workspace**: Reset both codebase and task to that point
|
||||
- **Restore Task Only**: Keep codebase changes but revert task context
|
||||
- **Restore Workspace Only**: Reset codebase while preserving task context
|
||||
|
||||
Example: If Cline makes changes you don't like while styling a component, you can use "Restore Workspace Only" to revert the code changes while keeping the conversation context, allowing you to try a different approach.
|
||||
|
||||
<Frame caption="Reverting both codebase and task to before any changes were made to start fresh">
|
||||
<img src="https://storage.googleapis.com/cline_public_images/docs/assets/checkpointsDemo.gif" alt="Checkpoint restore demo" />
|
||||
</Frame>
|
||||
|
||||
## Use Cases
|
||||
|
||||
Checkpoints let you be more experimental with Cline. While human coding is often methodical and iterative, AI can make substantial changes quickly. Checkpoints help you track these changes and revert if needed.
|
||||
|
||||
### Using Auto-Approve Mode
|
||||
|
||||
- Provides safety net for rapid iterations
|
||||
- Makes it easy to undo unexpected results
|
||||
|
||||
### Testing Different Approaches
|
||||
|
||||
- Try multiple solutions confidently
|
||||
- Compare different implementations
|
||||
- Quickly revert to working states
|
||||
- Ideal for exploring different design patterns or architectural approaches
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Use checkpoints as safety nets when experimenting
|
||||
2. Leverage auto-approve mode more confidently, knowing you can always roll back
|
||||
3. Restore selectively based on needs:
|
||||
- Use "Restore Task and Workspace" for a fresh start
|
||||
- Use "Restore Task Only" to try different prompts, but keep file changes
|
||||
- Use "Restore Workspace Only" to attempt different implementations while preserving conversation context
|
||||
|
||||
## Relationship with Message Editing
|
||||
|
||||
The [message editing feature](/features/editing-messages) uses checkpoints under the hood when you select the "Restore All" option. This allows you to not only edit and resubmit your message but also restore your workspace to the state it was in at that point in the conversation.
|
||||
|
||||
## Deleting Checkpoints
|
||||
|
||||
You can delete all checkpoints by using the **"Delete All History"** button in the task history menu. Note that this will also delete all tasks. Checkpoints are stored in VS Code's globalStorage.
|
||||
@@ -0,0 +1,129 @@
|
||||
---
|
||||
title: "Code Commands"
|
||||
sidebarTitle: "Code Commands"
|
||||
---
|
||||
|
||||
Cline's code commands bring AI assistance directly into your editor, letting you interact with your code without leaving your workflow. With a simple right-click, you can add code to Cline, and through the lightbulb menu, you can fix errors, get explanations, or improve your code.
|
||||
|
||||
## Available Code Commands
|
||||
|
||||
When you interact with code in your editor, you can access Cline commands in two ways:
|
||||
|
||||
### Right-Click Context Menu
|
||||
|
||||
When you right-click on selected code, you'll see:
|
||||
|
||||
<Frame>
|
||||
<img src="https://storage.googleapis.com/cline_public_images/docs/assets/code-commands.png" alt="Right Click Menu" />
|
||||
</Frame>
|
||||
|
||||
#### Add to Cline
|
||||
|
||||
The "Add to Cline" command sends your selected code to the Cline chat panel. This is perfect for:
|
||||
|
||||
- Asking questions about specific code snippets
|
||||
- Requesting improvements or optimizations
|
||||
- Getting explanations of complex logic
|
||||
|
||||
When you use this command, Cline automatically includes:
|
||||
|
||||
- The file path (as a file mention)
|
||||
- The selected code with proper formatting
|
||||
- The programming language for accurate syntax highlighting
|
||||
|
||||
### Lightbulb Menu (Code Actions)
|
||||
|
||||
When you see a lightbulb icon in your editor, click it to access these Cline commands:
|
||||
|
||||
<Frame>
|
||||
<img src="https://storage.googleapis.com/cline_public_images/docs/assets/lightbulb-actions.png" alt="Lightbulb Menu" />
|
||||
</Frame>
|
||||
|
||||
#### Fix with Cline
|
||||
|
||||
The "Fix with Cline" command appears in the lightbulb menu when your code has errors or warnings. This command:
|
||||
|
||||
1. Captures the selected code
|
||||
2. Identifies the errors or warnings from VSCode's diagnostics
|
||||
3. Sends both to Cline with a request to fix the issues
|
||||
4. Provides a solution that addresses the specific problems
|
||||
|
||||
This is incredibly useful for quickly resolving syntax errors, linter warnings, or type issues without having to manually describe the problem.
|
||||
|
||||
#### Explain with Cline
|
||||
|
||||
The "Explain with Cline" command helps you understand complex code. When you select code and use this command from the lightbulb menu, Cline:
|
||||
|
||||
1. Analyzes the selected code
|
||||
2. Provides a clear explanation of what the code does
|
||||
3. Breaks down complex logic into understandable parts
|
||||
4. Highlights important patterns or techniques used
|
||||
|
||||
#### Improve with Cline
|
||||
|
||||
The "Improve with Cline" command helps you enhance your code. When you select code and use this command from the lightbulb menu, Cline:
|
||||
|
||||
1. Analyzes the selected code for potential improvements
|
||||
2. Suggests optimizations, refactorings, or better practices
|
||||
3. Explains the reasoning behind the suggested changes
|
||||
4. Provides improved code that maintains the original functionality
|
||||
|
||||
## How to Use Code Commands
|
||||
|
||||
Using Cline's code commands is simple:
|
||||
|
||||
### For Right-Click Commands:
|
||||
|
||||
1. Select the code you want to work with
|
||||
2. Right-click to open the context menu
|
||||
3. Choose "Add to Cline"
|
||||
4. View the result in the Cline chat panel
|
||||
|
||||
### For Lightbulb Menu Commands:
|
||||
|
||||
1. Select the code you want to work with
|
||||
2. Look for the lightbulb icon that appears in the editor gutter
|
||||
3. Click the lightbulb to see available actions
|
||||
4. Choose the appropriate Cline command (Fix, Explain, or Improve)
|
||||
5. View the result in the Cline chat panel
|
||||
|
||||
After using any command, you can:
|
||||
|
||||
- Ask follow-up questions
|
||||
- Request modifications to the solution
|
||||
- Apply the changes back to your code
|
||||
|
||||
## How It Works Under the Hood
|
||||
|
||||
When you use a code command, here's what happens behind the scenes:
|
||||
|
||||
1. **Code Selection**: The extension captures your selected code and its context
|
||||
2. **Metadata Collection**: Cline gathers important metadata:
|
||||
|
||||
- File path and name
|
||||
- Programming language
|
||||
- Any associated diagnostics (errors/warnings)
|
||||
- Surrounding code context when relevant
|
||||
|
||||
3. **Command Processing**:
|
||||
|
||||
- For "Add to Cline," the code is formatted and sent to the chat panel
|
||||
- For "Fix with Cline," the code and diagnostics are analyzed and a fix is generated
|
||||
- For "Explain with Cline," the code is analyzed to provide a clear explanation
|
||||
- For "Improve with Cline," the code is analyzed for potential optimizations and improvements
|
||||
|
||||
4. **Integration with Chat**: The results appear in the Cline chat panel, where you can:
|
||||
- See the AI's response
|
||||
- Ask follow-up questions
|
||||
- Apply suggested changes
|
||||
|
||||
This seamless integration between your editor and Cline's AI capabilities makes it easy to get assistance without disrupting your coding flow.
|
||||
|
||||
## Tips for Effective Use
|
||||
|
||||
- **Select complete logical units**: When possible, select entire functions, classes, or modules to give Cline complete context
|
||||
- **Include imports**: For language-specific help, include relevant imports so Cline understands dependencies
|
||||
- **Combine with @ mentions**: For complex issues, use code commands along with file or problem mentions for more context
|
||||
- **Use keyboard shortcuts**: Speed up your workflow by [assigning keyboard shortcuts](/features/commands-and-shortcuts/keyboard-shortcuts) to common code commands
|
||||
|
||||
Next time you're struggling with a piece of code, try using Cline's code commands instead of switching to a separate chat interface. You'll be amazed at how much more efficient your workflow becomes when AI assistance is integrated directly into your editor.
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: "Generate Commit Message"
|
||||
sidebarTitle: "Generate Commit Message"
|
||||
---
|
||||
|
||||
Cline's Git integration brings AI assistance directly to your version control workflow. Generate commit messages without leaving your editor.
|
||||
|
||||
## Generate Commit Message
|
||||
|
||||
One of the most useful Git integrations is the ability to automatically generate meaningful commit messages:
|
||||
|
||||
<Frame>
|
||||
<img
|
||||
src="https://storage.googleapis.com/cline_public_images/docs/assets/generate-commit-message-with-cline.png"
|
||||
alt="Generate Commit Message with Cline"
|
||||
/>
|
||||
</Frame>
|
||||
|
||||
1. Make your changes and stage them in Git
|
||||
2. Click the robot icon in the Source Control view or run the "Generate Commit Message with Cline" command
|
||||
3. Cline analyzes your changes and generates a descriptive commit message
|
||||
4. The message is automatically inserted into the commit message input box
|
||||
|
||||
The generated commit messages:
|
||||
|
||||
- Start with a concise summary (50-72 characters)
|
||||
- Use imperative mood (e.g., "Add feature" not "Added feature")
|
||||
- Describe what was changed and why
|
||||
- Follow Git best practices
|
||||
|
||||
This feature saves time and ensures your commit history is consistent and informative.
|
||||
|
||||
<Tip>
|
||||
For information about using `@git-changes` and `@[commit-hash]` mentions in your chat messages, see the [Git
|
||||
Mentions](/features/at-mentions/git-mentions) documentation.
|
||||
</Tip>
|
||||
|
||||
## How It Works
|
||||
|
||||
When you use Cline's commit message generation feature, here's what happens behind the scenes:
|
||||
|
||||
1. Cline retrieves the current Git diff using `getWorkingState()`
|
||||
2. It formats this diff into a specialized prompt for the AI
|
||||
3. The AI analyzes the changes and generates an appropriate commit message
|
||||
4. The message is extracted and inserted into the Git commit message input box
|
||||
|
||||
This process uses your current Cline API configuration, so the quality of the generated messages matches your chosen AI model.
|
||||
|
||||
## Tips for Effective Use
|
||||
|
||||
- **Generate commit messages for complex changes**: The AI excels at summarizing multiple related changes into a coherent message.
|
||||
|
||||
- **Review and edit generated messages**: While the AI generates high-quality messages, it's always good practice to review and adjust them if needed.
|
||||
|
||||
- **Stage related changes together**: For the best results, stage related changes together so the AI can generate a cohesive message.
|
||||
|
||||
- **Use for consistent commit history**: Using the generate commit message feature helps maintain a consistent style across your commit history.
|
||||
|
||||
## How It Works Under the Hood
|
||||
|
||||
The commit message generation leverages VSCode's Git extension API to access repository information:
|
||||
|
||||
1. When you trigger the command:
|
||||
- Cline gets the current diff
|
||||
- It sends this to the AI with specific instructions for commit message formatting
|
||||
- It parses the AI's response
|
||||
- It accesses the Git extension API to set the commit message
|
||||
|
||||
This integration with Git makes it easy to generate high-quality commit messages without disrupting your workflow.
|
||||
|
||||
Next time you're struggling to write a good commit message, try using Cline's commit message generation. You'll save time and improve your version control workflow with AI assistance right where you need it.
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
title: "Keyboard Shortcuts"
|
||||
sidebarTitle: "Keyboard Shortcuts"
|
||||
---
|
||||
|
||||
Cline's keyboard shortcuts let you access AI assistance without taking your hands off the keyboard. Speed up your workflow by using hotkeys for common Cline actions.
|
||||
|
||||
## Default Keyboard Shortcuts
|
||||
|
||||
Cline comes with the following built-in keyboard shortcuts to streamline your workflow:
|
||||
|
||||
| Action | Windows/Linux | macOS | Condition | Description |
|
||||
| ----------------------- | ------------- | ------- | ---------------------------- | ----------------------------------------- |
|
||||
| Add to Cline | `Ctrl+'` | `Cmd+'` | When text is selected | Adds selected code to Cline chat |
|
||||
| Focus Chat Input | `Ctrl+'` | `Cmd+'` | When no text is selected | Focuses the Cline chat input field |
|
||||
| Generate Commit Message | (unset) | (unset) | When Git is the SCM provider | Available through the Source Control view |
|
||||
|
||||
## Available Commands for Custom Shortcuts
|
||||
|
||||
While Cline has only a few default keyboard shortcuts, you can assign your own shortcuts to any of these commands:
|
||||
|
||||
| Command ID | Description |
|
||||
| ---------------------------------------------------------------------------------------- | --------------------------------------------- |
|
||||
| [`cline.openInNewTab`](/features/commands-and-shortcuts/overview) | Opens Cline in a new editor tab |
|
||||
| [`cline.addToChat`](/features/commands-and-shortcuts/code-commands) | Adds selected code to Cline chat |
|
||||
| [`cline.addTerminalOutputToChat`](/features/commands-and-shortcuts/terminal-integration) | Adds terminal output to Cline |
|
||||
| `cline.focusChatInput` | Focuses the Cline chat input field |
|
||||
| [`cline.generateGitCommitMessage`](/features/commands-and-shortcuts/git-integration) | Generates a commit message for staged changes |
|
||||
| [`cline.explainCode`](/features/commands-and-shortcuts/code-commands) | Explains selected code |
|
||||
| [`cline.improveCode`](/features/commands-and-shortcuts/code-commands) | Suggests improvements for selected code |
|
||||
| [`cline.fixWithCline`](/features/commands-and-shortcuts/code-commands) | Fixes code with errors |
|
||||
| `claude-dev.SidebarProvider.focus` | Opens and focuses the Cline sidebar |
|
||||
|
||||
## Customizing Keyboard Shortcuts
|
||||
|
||||
You can customize Cline's keyboard shortcuts to match your preferences:
|
||||
|
||||
1. Open the Keyboard Shortcuts editor in VSCode:
|
||||
|
||||
- Press `Ctrl+K Ctrl+S` (Windows/Linux) or `Cmd+K Cmd+S` (macOS)
|
||||
- Or go to File > Preferences > Keyboard Shortcuts
|
||||
|
||||
2. Search for "Cline" to see all available commands
|
||||
|
||||
3. Click on the pencil icon next to any command to change its shortcut
|
||||
|
||||
4. Press the keys you want to assign to that command
|
||||
|
||||
5. Press Enter to save the new shortcut
|
||||
|
||||
## Suggested Custom Shortcuts
|
||||
|
||||
Here are some suggested shortcuts you might find useful:
|
||||
|
||||
| Action | Suggested Shortcut | Command ID | Description |
|
||||
| --------------------- | ------------------------------ | ----------------------------------------- | ----------------------------- |
|
||||
| Open Cline Sidebar | `Ctrl+Shift+C` / `Cmd+Shift+C` | `claude-dev.SidebarProvider.focus` | Opens the Cline sidebar panel |
|
||||
| New Task | `Alt+N` | `cline.plusButtonClicked` | Starts a new Cline task |
|
||||
| Add Terminal to Cline | `Alt+T` | `cline.addTerminalOutputToChat` | Adds terminal output to Cline |
|
||||
| Clear Current Task | `Alt+C` | (Requires custom keybinding to UI action) | Clears the current task |
|
||||
|
||||
## Keyboard-Only Workflow
|
||||
|
||||
With the right shortcuts, you can use Cline without ever touching the mouse:
|
||||
|
||||
1. Select code with keyboard navigation (`Shift+Arrow` keys)
|
||||
2. Send to Cline with `Ctrl+'` / `Cmd+'`
|
||||
3. Type your question and press Enter
|
||||
4. Review the response and apply suggestions
|
||||
|
||||
## Editor Integration Shortcuts
|
||||
|
||||
Cline's keyboard shortcuts integrate seamlessly with VSCode's built-in shortcuts:
|
||||
|
||||
- Use VSCode's selection shortcuts (`Ctrl+L` / `Cmd+L` to select line, etc.) before sending code to Cline
|
||||
- Combine with VSCode's split editor shortcuts to view code and Cline side by side
|
||||
- Use VSCode's terminal focus shortcut (`` Ctrl+` `` / `` Cmd+` ``) before capturing terminal output
|
||||
|
||||
## Tips for Effective Use
|
||||
|
||||
- **Learn the default shortcut first**: The `Ctrl+'` / `Cmd+'` shortcut is versatile - it adds selected code to chat when text is selected, or focuses the chat input when nothing is selected
|
||||
- **Create muscle memory**: Use keyboard shortcuts consistently to build habits
|
||||
- **Customize for your workflow**: Assign shortcuts to commands you use frequently
|
||||
- **Consider ergonomics**: Choose shortcuts that are comfortable for your keyboard layout
|
||||
|
||||
Keyboard shortcuts may seem like a small optimization, but they can significantly speed up your workflow when using Cline regularly. By keeping your hands on the keyboard, you maintain your coding flow while still getting AI assistance exactly when you need it.
|
||||
|
||||
## How to Find All Available Commands
|
||||
|
||||
To see all Cline commands that can be assigned shortcuts:
|
||||
|
||||
1. Open the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`)
|
||||
2. Type "Cline" to filter the list
|
||||
3. Browse the available commands
|
||||
|
||||
<Frame>
|
||||
<img
|
||||
src="https://storage.googleapis.com/cline_public_images/docs/assets/editor-integration.png"
|
||||
alt="Editor Integration Overview"
|
||||
/>
|
||||
</Frame>
|
||||
|
||||
This helps you discover features you might not have known about and assign shortcuts to the ones you use most frequently.
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
title: "Commands & Shortcuts Overview"
|
||||
sidebarTitle: "Overview"
|
||||
---
|
||||
|
||||
Cline integrates directly into VSCode's interface, letting you access AI assistance without disrupting your workflow. These integrations appear as commands in context menus, keyboard shortcuts, and quick fixes throughout the editor.
|
||||
|
||||
<Frame>
|
||||
<img
|
||||
src="https://storage.googleapis.com/cline_public_images/docs/assets/editor-integration.png"
|
||||
alt="Editor Integration Overview"
|
||||
/>
|
||||
</Frame>
|
||||
|
||||
### What are Editor Integrations?
|
||||
|
||||
Editor integrations are commands and shortcuts that let you use Cline right where you're working. Instead of switching to the Cline panel first, you can select code, right-click, and immediately send it to Cline for help.
|
||||
These integrations appear in different places throughout VSCode:
|
||||
|
||||
- In the editor context menu (right-click menu) - "Add to Cline"
|
||||
- In the terminal context menu - "Add to Cline"
|
||||
- In the Source Control view - "Generate Commit Message"
|
||||
- As keyboard shortcuts - Various Cline commands
|
||||
- As Quick Fix options (lightbulb menu) - "Fix with Cline", "Explain with Cline", "Improve with Cline"
|
||||
|
||||
### Available Editor Integrations
|
||||
|
||||
Cline offers several editor integrations, each designed to enhance different aspects of your development workflow:
|
||||
|
||||
<Columns cols={2}>
|
||||
<Card title="Code Commands" icon="code" href="/features/commands-and-shortcuts/code-commands">
|
||||
Right-click on code to add it to Cline, or use the lightbulb menu to fix errors, explain code, or improve it. Cline sees the complete code context, including imports and surrounding functions.
|
||||
</Card>
|
||||
|
||||
{" "}
|
||||
|
||||
<Card title="Terminal Integration" icon="terminal" href="/features/commands-and-shortcuts/terminal-integration">
|
||||
Add terminal output to Cline with a right-click or use `@terminal` mentions. Perfect for debugging build errors, test
|
||||
failures, or runtime issues.
|
||||
</Card>
|
||||
|
||||
{" "}
|
||||
|
||||
<Card title="Git Integration" icon="code-branch" href="/features/commands-and-shortcuts/git-integration">
|
||||
Generate commit messages, explain diffs, or analyze changes with Cline's Git integration. Cline understands your version
|
||||
control context.
|
||||
</Card>
|
||||
|
||||
{" "}
|
||||
|
||||
<Card title="Keyboard Shortcuts" icon="keyboard" href="/features/commands-and-shortcuts/keyboard-shortcuts">
|
||||
Speed up your workflow with keyboard shortcuts for common Cline actions. Quickly add code to chat, fix errors, or improve your code.
|
||||
</Card>
|
||||
</Columns>
|
||||
|
||||
### How They Work
|
||||
|
||||
When you use these commands, Cline:
|
||||
|
||||
- Captures the relevant context (selected code, file path, terminal output, etc.)
|
||||
- Focuses the Cline interface
|
||||
- Creates a conversation with the captured context
|
||||
- In some cases, automatically generates a suggested prompt
|
||||
|
||||
Behind the scenes, these commands use VSCode's extension API to register commands, access editor state, and control VSCode's interface.
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
title: "Terminal Integration"
|
||||
sidebarTitle: "Terminal Integration"
|
||||
---
|
||||
|
||||
Cline's terminal integration lets you bring your terminal output directly into your conversations with Cline. Instead of copying and pasting error messages or command results, you can send them to Cline with a simple right-click in the terminal.
|
||||
|
||||
<Frame>
|
||||
<img
|
||||
src="https://storage.googleapis.com/cline_public_images/docs/assets/terminal-integration.png"
|
||||
alt="Terminal Integration"
|
||||
/>
|
||||
</Frame>
|
||||
|
||||
## Right-Click Terminal Integration
|
||||
|
||||
When you're working in the VSCode terminal and see output you want to discuss with Cline:
|
||||
|
||||
1. Right-click in the terminal
|
||||
2. Select "Add to Cline" from the context menu
|
||||
3. The terminal output is immediately sent to the Cline chat panel
|
||||
|
||||
This is perfect for:
|
||||
|
||||
- Debugging build errors
|
||||
- Understanding test failures
|
||||
- Analyzing command output
|
||||
- Getting help with error messages
|
||||
|
||||
The right-click terminal integration is especially useful when you're already working in the terminal and encounter an issue.
|
||||
|
||||
Instead of switching context to the Cline chat panel and typing a description of the problem, you can send the terminal output directly to Cline with just a couple of clicks.
|
||||
|
||||
Alternatively, you can use the [`@terminal`](/features/at-mentions/terminal-mentions) mention to send the full terminal output to Cline.
|
||||
|
||||
<Tip>
|
||||
For information about using `@terminal` mentions in your chat messages, see the [Terminal
|
||||
Mentions](/features/at-mentions/terminal-mentions) documentation.
|
||||
</Tip>
|
||||
|
||||
## How Terminal Integration Works
|
||||
|
||||
When you use the right-click terminal integration, Cline:
|
||||
|
||||
1. Captures the terminal output with all formatting preserved
|
||||
2. Includes the complete context, including command history and results
|
||||
3. Formats it appropriately for the AI to understand
|
||||
4. Enables the AI to see exactly what you're seeing
|
||||
|
||||
This gives Cline the full context it needs to provide accurate help with terminal-related issues.
|
||||
|
||||
## Behind the Scenes
|
||||
|
||||
The terminal integration uses a clever technique to capture terminal output:
|
||||
|
||||
1. When you trigger the integration, Cline:
|
||||
|
||||
- Temporarily saves your current clipboard content
|
||||
- Selects all terminal content (or uses your existing selection)
|
||||
- Copies it to the clipboard
|
||||
- Reads the clipboard to get the terminal content
|
||||
- Restores your original clipboard content
|
||||
|
||||
2. The terminal content is then:
|
||||
- Formatted with proper syntax highlighting
|
||||
- Added to your message or sent as a new message
|
||||
- Enhanced with additional context when needed
|
||||
|
||||
This approach ensures that all terminal output, including colors and formatting, is accurately captured without affecting your clipboard.
|
||||
|
||||
## Tips for Effective Use
|
||||
|
||||
- **Use terminal integration for error messages**: When you encounter an error in the terminal, sending it to Cline often results in faster resolution than trying to describe the error.
|
||||
|
||||
- **Select specific output when needed**: By default, the integration captures all terminal content, but you can also select specific lines before right-clicking to focus on just the relevant output.
|
||||
|
||||
- **Combine with file mentions**: After sending terminal output to Cline, you can enhance your question by mentioning relevant files using the @ mentions feature.
|
||||
|
||||
- **Use for build and test output**: Terminal integration is particularly useful for understanding complex build errors or test failures that span multiple lines.
|
||||
|
||||
Next time you're staring at a cryptic error message in your terminal, try using Cline's terminal integration instead of copying and pasting. You'll get more accurate help because Cline can see the complete terminal context with proper formatting.
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: "Drag & Drop"
|
||||
sidebarTitle: "Drag & Drop"
|
||||
---
|
||||
|
||||
Dragging and dropping files into Cline is a quick way to add images, code, and other files to your conversations.
|
||||
|
||||
<Note>Due to VS Code quirks, to drag and drop files into the Cline chat input, you need to hold `Shift` while dragging.</Note>
|
||||
|
||||
Dragging and dropping workspace files into Cline will automatically create a [file mention](/features/at-mentions/file-mentions). This allows you to reference the file in your conversation without needing to type out the path.
|
||||
|
||||
### Supported File Types
|
||||
|
||||
Cline supports dragging external images from your file system, as well as files from your workspace.
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Editing Messages"
|
||||
sidebarTitle: "Editing Messages"
|
||||
---
|
||||
|
||||
Cline allows you to edit chat messages in a task after they've been submitted. This feature lets you refine your requests without starting a new task, helping you get better results with minimal disruption to your workflow.
|
||||
|
||||
## When to Edit Messages
|
||||
|
||||
You might want to edit a message when:
|
||||
|
||||
- You didn't get the results you wanted
|
||||
- You thought of a better way to phrase your request
|
||||
- You need to add more information or context
|
||||
- You made a typo or error in your original message
|
||||
|
||||
## How to Edit Messages
|
||||
|
||||
1. Click on any message in the conversation (except the initial task message)
|
||||
2. Edit the text as needed
|
||||
3. Use the restore options to resubmit your request
|
||||
|
||||
<Frame>
|
||||
<img
|
||||
src="https://storage.googleapis.com/cline_public_images/docs/assets/message-editing.png"
|
||||
alt="Message editing interface"
|
||||
/>
|
||||
</Frame>
|
||||
|
||||
## Restore Options
|
||||
|
||||
When you edit a message, you have two options for restoring:
|
||||
|
||||
### Restore Chat
|
||||
|
||||
The "Restore Chat" option:
|
||||
|
||||
- Restores just the task state
|
||||
- Re-submits an API request with your edited message
|
||||
- Preserves all file changes made up to that point
|
||||
- Is useful when you want to keep the current state of your workspace
|
||||
|
||||
### Restore All
|
||||
|
||||
The "Restore All" option:
|
||||
|
||||
- Restores both the task state and workspace state
|
||||
- Re-submits an API request with your edited message
|
||||
- Reverts your workspace to how it was at that point in the conversation
|
||||
- Uses [checkpoints](/features/checkpoints) under the hood to restore your workspace
|
||||
- Is useful when you want to try a completely different approach
|
||||
|
||||
## Keyboard Shortcuts
|
||||
|
||||
When editing a message, you can use these keyboard shortcuts:
|
||||
|
||||
- **Escape**: Exit edit mode without making changes
|
||||
- **Enter**: Restore just the task (equivalent to "Restore Chat")
|
||||
- **Cmd/Ctrl + Enter**: Restore the task and workspace (equivalent to "Restore All")
|
||||
- **Shift + Enter**: Insert a new line / line break in your message
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use message editing for minor adjustments to your requests
|
||||
- For major changes in direction, consider starting a new task
|
||||
- When using "Restore All," be aware that any file changes made after that message will be reverted
|
||||
- Edit messages closer to the beginning of a conversation to avoid losing significant progress
|
||||
+37
-26
@@ -1,9 +1,8 @@
|
||||
---
|
||||
title: "Plan & Act Modes: A Guide to Effective AI Development"
|
||||
title: "Plan & Act"
|
||||
sidebarTitle: "Plan & Act"
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Plan & Act modes represent Cline's approach to structured AI development, emphasizing thoughtful planning before implementation. This dual-mode system helps developers create more maintainable, accurate code while reducing iteration time.
|
||||
|
||||
<Frame>
|
||||
@@ -13,21 +12,23 @@ Plan & Act modes represent Cline's approach to structured AI development, emphas
|
||||
/>
|
||||
</Frame>
|
||||
|
||||
### Understanding the Modes
|
||||
#### Plan Mode: Think First
|
||||
|
||||
#### Plan Mode
|
||||
Plan mode is where you and Cline figure out what you're trying to build and how you'll build it. In this mode, Cline:
|
||||
|
||||
- Optimized for context gathering and strategy
|
||||
- Cannot make changes to your codebase
|
||||
- Focused on understanding requirements and creating implementation plans
|
||||
- Enables full file reading for comprehensive project understanding
|
||||
- Can read your entire codebase to understand the context
|
||||
- Won't make any changes to your files
|
||||
- Focuses on understanding requirements and creating a strategy
|
||||
- Helps identify potential issues before you write a single line of code
|
||||
|
||||
#### Act Mode
|
||||
#### Act Mode: Build It
|
||||
|
||||
- Streamlined for implementation based on established plans
|
||||
- Has access to all of Cline's building capabilities
|
||||
- Maintains context from the planning phase
|
||||
- Can execute changes to your codebase
|
||||
Once you've got a plan, you switch to Act mode. Now Cline:
|
||||
|
||||
- Has all the building capabilities at its disposal
|
||||
- Can make changes to your codebase
|
||||
- Still remembers everything from your planning session
|
||||
- Executes the strategy you worked out together
|
||||
|
||||
<Frame>
|
||||
<img src="https://storage.googleapis.com/cline_public_images/docs/assets/image%20(5).png" alt="Act mode capabilities" />
|
||||
@@ -35,6 +36,14 @@ Plan & Act modes represent Cline's approach to structured AI development, emphas
|
||||
|
||||
### Workflow Guide
|
||||
|
||||
When I'm working on a new feature or fixing a complex bug, here's what works for me:
|
||||
|
||||
1. I start in Plan mode and tell Cline what I want to build
|
||||
2. Cline helps me explore the codebase, looking at relevant files
|
||||
3. Together we figure out the best approach, considering edge cases and potential issues
|
||||
4. When I'm confident in our plan, I switch to Act mode
|
||||
5. Cline implements the solution based on our planning
|
||||
|
||||
#### 1. Start with Plan Mode
|
||||
|
||||
Begin every significant development task in Plan mode:
|
||||
@@ -108,24 +117,26 @@ Complex projects often require multiple plan-act cycles:
|
||||
|
||||
- Use Plan mode to explore edge cases before implementation
|
||||
- Switch back to Plan when encountering unexpected complexity
|
||||
- Leverage file reading to validate assumptions early
|
||||
- Leverage [file reading](/features/at-mentions/file-mentions) to validate assumptions early
|
||||
- Have Cline write markdown files of the plan for future reference
|
||||
|
||||
### Common Patterns
|
||||
|
||||
#### When to Use Plan Mode
|
||||
#### When to Use Each Mode
|
||||
|
||||
- Starting new features
|
||||
- Debugging complex issues
|
||||
- Architectural decisions
|
||||
- Requirements analysis
|
||||
I've found Plan mode works best when:
|
||||
|
||||
#### When to Use Act Mode
|
||||
- Starting something new where the approach isn't obvious
|
||||
- Debugging a tricky issue where I'm not sure what's wrong
|
||||
- Making architectural decisions that will affect multiple parts of the codebase
|
||||
- Trying to understand a complex workflow or feature
|
||||
|
||||
- Implementing agreed solutions
|
||||
- Making routine changes
|
||||
- Following established patterns
|
||||
- Executing test cases
|
||||
And Act mode is perfect for:
|
||||
|
||||
- Implementing a solution we've already planned out
|
||||
- Making routine changes where the approach is clear
|
||||
- Following established patterns in the codebase
|
||||
- Running tests and making minor adjustments
|
||||
|
||||
<Frame>
|
||||
<img src="https://storage.googleapis.com/cline_public_images/docs/assets/image%20(6).png" alt="Mode usage patterns" />
|
||||
@@ -142,4 +153,4 @@ Share your experiences and improvements:
|
||||
|
||||
---
|
||||
|
||||
Remember: The time invested in planning pays dividends in implementation quality and maintenance efficiency
|
||||
Remember: The time invested in planning pays dividends in implementation quality and maintenance efficiency.
|
||||
@@ -9,7 +9,7 @@ To invoke a workflow, type `/[workflow-name.md]` in the chat.
|
||||
|
||||
## How to Create and Use Workflows
|
||||
|
||||
Workflows live alongside Cline Rules. Creating one is straightforward:
|
||||
Workflows live alongside [Cline Rules](/features/cline-rules). Creating one is straightforward:
|
||||
|
||||
<Frame>
|
||||
<img src="https://storage.googleapis.com/cline_public_images/docs/assets/workflows.png" alt="Workflows tab in Cline" />
|
||||
@@ -22,9 +22,9 @@ Workflows live alongside Cline Rules. Creating one is straightforward:
|
||||
|
||||
The real power comes from how you structure your workflow files. You can:
|
||||
|
||||
- Leverage Cline's built-in tools like `ask_followup_question`, `read_file`, and `search_files`
|
||||
- Leverage Cline's [built-in tools](/exploring-clines-tools/cline-tools-guide) like `ask_followup_question`, `read_file`, `search_files`, and `new_task`
|
||||
- Use command-line tools you already have installed like `gh` or `docker`
|
||||
- Reference external MCP tool calls like Slack or Whatsapp
|
||||
- Reference external [MCP tool calls](/mcp/mcp-overview) like Slack or Whatsapp
|
||||
- Chain multiple actions together in a specific sequence
|
||||
|
||||
## Real-world Example
|
||||
@@ -133,13 +133,39 @@ You have access to the `gh` terminal command. I already authenticated it for you
|
||||
1. Approve the PR if it meets quality standards:
|
||||
|
||||
```bash
|
||||
# For single-line comments:
|
||||
gh pr review <PR-number> --approve --body "Your approval message"
|
||||
|
||||
# For multi-line comments with proper whitespace formatting:
|
||||
cat << EOF | gh pr review <PR-number> --approve --body-file -
|
||||
Thanks @username for this PR! The implementation looks good.
|
||||
|
||||
I particularly like how you've handled X and Y.
|
||||
|
||||
Great work!
|
||||
EOF
|
||||
```
|
||||
|
||||
2. Request changes if improvements are needed:
|
||||
|
||||
```bash
|
||||
# For single-line comments:
|
||||
gh pr review <PR-number> --request-changes --body "Your feedback message"
|
||||
|
||||
# For multi-line comments with proper whitespace formatting:
|
||||
cat << EOF | gh pr review <PR-number> --request-changes --body-file -
|
||||
Thanks @username for this PR!
|
||||
|
||||
The implementation looks promising, but there are a few things to address:
|
||||
|
||||
1. Issue one
|
||||
2. Issue two
|
||||
|
||||
Please make these changes and we can merge this.
|
||||
EOF
|
||||
```
|
||||
|
||||
Note: The `cat << EOF | ... --body-file -` approach preserves all whitespace and formatting without requiring temporary files. The `-` parameter tells the command to read from standard input.
|
||||
</detailed_sequence_of_steps>
|
||||
|
||||
<example_review_process>
|
||||
@@ -221,7 +247,21 @@ Would you like me to proceed with approving this PR?</question>
|
||||
## Step 6: Make a Decision
|
||||
|
||||
```bash
|
||||
gh pr review 3627 --approve --body "This PR looks good! It correctly fixes the thinking mode budget calculation for Claude 3.7 models by using the appropriate maxBudget value (64000) and applying the right percentage (50%) for the slider. The changes are well-tested and the implementation is clean."
|
||||
# Option 1: Simple one-line comment
|
||||
gh pr review 3627 --approve --body "This PR looks good! It correctly fixes the thinking mode budget calculation for Claude 3.7 models."
|
||||
|
||||
# Option 2: Multi-line comment with proper whitespace formatting
|
||||
cat << EOF | gh pr review 3627 --approve --body-file -
|
||||
This PR looks good! It correctly fixes the thinking mode budget calculation for Claude 3.7 models.
|
||||
|
||||
I particularly like:
|
||||
1. The proper implementation of thinkingConfig.maxBudget property (64000)
|
||||
2. The appropriate percentage (50%) for the slider calculation
|
||||
3. The comprehensive unit tests
|
||||
4. The clean implementation that follows project coding standards
|
||||
|
||||
Great work!
|
||||
EOF
|
||||
```
|
||||
|
||||
</example_review_process>
|
||||
@@ -262,14 +302,38 @@ gh pr checkout <PR-number>
|
||||
## Review Commands
|
||||
|
||||
```bash
|
||||
# Approve a PR
|
||||
# Approve a PR (single-line comment)
|
||||
gh pr review <PR-number> --approve --body "Your approval message"
|
||||
|
||||
# Request changes on a PR
|
||||
# Approve a PR (multi-line comment with proper whitespace)
|
||||
cat << EOF | gh pr review <PR-number> --approve --body-file -
|
||||
Your multi-line
|
||||
approval message with
|
||||
|
||||
proper whitespace formatting
|
||||
EOF
|
||||
|
||||
# Request changes on a PR (single-line comment)
|
||||
gh pr review <PR-number> --request-changes --body "Your feedback message"
|
||||
|
||||
# Request changes on a PR (multi-line comment with proper whitespace)
|
||||
cat << EOF | gh pr review <PR-number> --request-changes --body-file -
|
||||
Your multi-line
|
||||
change request with
|
||||
|
||||
proper whitespace formatting
|
||||
EOF
|
||||
|
||||
# Add a comment review (without approval/rejection)
|
||||
gh pr review <PR-number> --comment --body "Your comment message"
|
||||
|
||||
# Add a comment review with proper whitespace
|
||||
cat << EOF | gh pr review <PR-number> --comment --body-file -
|
||||
Your multi-line
|
||||
comment with
|
||||
|
||||
proper whitespace formatting
|
||||
EOF
|
||||
```
|
||||
|
||||
## Additional Commands
|
||||
@@ -286,6 +350,64 @@ gh pr merge <PR-number> --merge
|
||||
```
|
||||
|
||||
</common_gh_commands>
|
||||
|
||||
<general_guidelines_for_commenting>
|
||||
When reviewing a PR, please talk normally and like a friendly reviwer. You should keep it short, and start out by thanking the author of the pr and @ mentioning them.
|
||||
|
||||
Whether or not you approve the PR, you should then give a quick summary of the changes without being too verbose or definitive, staying humble like that this is your understanding of the changes. Kind of how I'm talking to you right now.
|
||||
|
||||
If you have any suggestions, or things that need to be changed, request changes instead of approving the PR.
|
||||
|
||||
Leaving inline comments in code is good, but only do so if you have something specific to say about the code. And make sure you leave those comments first, and then request changes in the PR with a short comment explaining the overall theme of what you're asking them to change.
|
||||
</general_guidelines_for_commenting>
|
||||
|
||||
<example_comments_that_i_have_written_before>
|
||||
<brief_approve_comment>
|
||||
Looks good, though we should make this generic for all providers & models at some point
|
||||
</brief_approve_comment>
|
||||
<brief_approve_comment>
|
||||
Will this work for models that may not match across OR/Gemini? Like the thinking models?
|
||||
</brief_approve_comment>
|
||||
<approve_comment>
|
||||
This looks great! I like how you've handled the global endpoint support - adding it to the ModelInfo interface makes total sense since it's just another capability flag, similar to how we handle other model features.
|
||||
|
||||
The filtered model list approach is clean and will be easier to maintain than hardcoding which models work with global endpoints. And bumping the genai library was obviously needed for this to work.
|
||||
|
||||
Thanks for adding the docs about the limitations too - good for users to know they can't use context caches with global endpoints but might get fewer 429 errors.
|
||||
</approve_comment>
|
||||
<requesst_changes_comment>
|
||||
This is awesome. Thanks @scottsus.
|
||||
|
||||
My main concern though - does this work for all the possible VS Code themes? We struggled with this initially which is why it's not super styled currently. Please test and share screenshots with the different themes to make sure before we can merge
|
||||
</request_changes_comment>
|
||||
<request_changes_comment>
|
||||
Hey, the PR looks good overall but I'm concerned about removing those timeouts. Those were probably there for a reason - VSCode's UI can be finicky with timing.
|
||||
|
||||
Could you add back the timeouts after focusing the sidebar? Something like:
|
||||
|
||||
```typescript
|
||||
await vscode.commands.executeCommand("claude-dev.SidebarProvider.focus")
|
||||
await setTimeoutPromise(100) // Give UI time to update
|
||||
visibleWebview = WebviewProvider.getSidebarInstance()
|
||||
```
|
||||
|
||||
</request_changes_comment>
|
||||
<request_changes_comment>
|
||||
Heya @alejandropta thanks for working on this!
|
||||
|
||||
A few notes:
|
||||
1 - Adding additional info to the environment variables is fairly problematic because env variables get appended to **every single message**. I don't think this is justifiable for a somewhat niche use case.
|
||||
2 - Adding this option to settings to include that could be an option, but we want our options to be simple and straightforward for new users
|
||||
3 - We're working on revisualizing the way our settings page is displayed/organized, and this could potentially be reconciled once that is in and our settings page is more clearly delineated.
|
||||
|
||||
So until the settings page is update, and this is added to settings in a way that's clean and doesn't confuse new users, I don't think we can merge this. Please bear with us.
|
||||
</request_changes_comment>
|
||||
<request_changes_comment>
|
||||
Also, don't forget to add a changeset since this fixes a user-facing bug.
|
||||
|
||||
The architectural change is solid - moving the focus logic to the command handlers makes sense. Just don't want to introduce subtle timing issues by removing those timeouts.
|
||||
</request_changes_comment>
|
||||
</example_comments_that_i_have_written_before>
|
||||
````
|
||||
|
||||
When I get a new PR to review, I used to manually gather context: checking the PR description, examining the diff, looking at surrounding files, and finally forming an opinion. Now I just:
|
||||
@@ -294,7 +416,7 @@ When I get a new PR to review, I used to manually gather context: checking the P
|
||||
2. Paste in the PR number
|
||||
3. Let Cline handle everything else
|
||||
|
||||
My workflow uses the `gh` command-line tool to:
|
||||
My workflow uses the `gh` command-line tool and Cline's built in `ask_followup_question` to:
|
||||
|
||||
- Pull the PR description and comments
|
||||
- Examine the diff
|
||||
|
||||
@@ -134,14 +134,6 @@ const baseConfig = {
|
||||
aliasResolverPlugin,
|
||||
/* add to the end of plugins array */
|
||||
esbuildProblemMatcherPlugin,
|
||||
{
|
||||
name: "alias-plugin",
|
||||
setup(build) {
|
||||
build.onResolve({ filter: /^pkce-challenge$/ }, (args) => {
|
||||
return { path: require.resolve("pkce-challenge/dist/index.browser.js") }
|
||||
})
|
||||
},
|
||||
},
|
||||
],
|
||||
format: "cjs",
|
||||
sourcesContent: false,
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
التقى Cline، مساعد الذكاء الاصطناعي الذي يمكنه استخدام **سطر الأوامر** و **محرر النصوص** الخاص بك.
|
||||
|
||||
بفضل [قدرات Claude 3.7 Sonnet على التعليمات البرمجية الوكيلة](https://www.anthropic.com/claude/sonnet)، يمكن لـ Cline التعامل مع مهام تطوير البرامج المعقدة خطوة بخطوة. مع الأدوات التي تسمح له بإنشاء وتعديل الملفات، واستكشاف المشاريع الكبيرة، واستخدام المتصفح، وتنفيذ أوامر الطرفية (بعد منحك الإذن)، يمكنه مساعدتك بطرق تتجاوز إكمال الكود أو الدعم الفني. يمكن لـ Cline أيضًا استخدام بروتوكول سياق النموذج (MCP) لإنشاء أدوات جديدة وتوسيع قدراته الخاصة. في حين تعمل النصوص البرمجية الآلية المستقلة تقليديًا في بيئات محاصرة، توفر هذه الإضافة واجهة رسومية لموافقة المستخدم على كل تغيير في الملف وأمر طرفية، مما يوفر طريقة آمنة وسهلة الاستخدام لاستكشاف إمكانات الذكاء الاصطناعي الوكيل.
|
||||
بفضل [قدرات Claude 4 Sonnet على التعليمات البرمجية الوكيلة](https://www.anthropic.com/claude/sonnet)، يمكن لـ Cline التعامل مع مهام تطوير البرامج المعقدة خطوة بخطوة. مع الأدوات التي تسمح له بإنشاء وتعديل الملفات، واستكشاف المشاريع الكبيرة، واستخدام المتصفح، وتنفيذ أوامر الطرفية (بعد منحك الإذن)، يمكنه مساعدتك بطرق تتجاوز إكمال الكود أو الدعم الفني. يمكن لـ Cline أيضًا استخدام بروتوكول سياق النموذج (MCP) لإنشاء أدوات جديدة وتوسيع قدراته الخاصة. في حين تعمل النصوص البرمجية الآلية المستقلة تقليديًا في بيئات محاصرة، توفر هذه الإضافة واجهة رسومية لموافقة المستخدم على كل تغيير في الملف وأمر طرفية، مما يوفر طريقة آمنة وسهلة الاستخدام لاستكشاف إمكانات الذكاء الاصطناعي الوكيل.
|
||||
|
||||
1. أدخل مهمتك وأضف الصور لتحويل المحاكاة إلى تطبيقات وظيفية أو إصلاح الأخطاء مع لقطات الشاشة.
|
||||
2. يبدأ Cline بتحليل هيكل الملفات الخاصة بك وشجرة التعريف المصدرية، وإجراء عمليات بحث regex، وقراءة الملفات ذات الصلة للاطلاع على المشاريع الحالية. من خلال إدارة المعلومات التي يتم إضافتها إلى السياق بعناية، يمكن لـ Cline تقديم مساعدة قيمة حتى للمشاريع الكبيرة والمعقدة دون إرهاق نافذة السياق.
|
||||
@@ -87,7 +87,7 @@
|
||||
|
||||
### استخدم المتصفح
|
||||
|
||||
مع قدرة [استخدام الكمبيوتر](https://www.anthropic.com/news/3-5-models-and-computer-use) الجديدة لـ Claude 3.5 Sonnet، يمكن لـ Cline إطلاق متصفح، والنقر على العناصر، وكتابة النص، والتمرير، والتقاط لقطات الشاشة وسجلات وحدة التحكم في كل خطوة. يسمح له هذا بالتصحيح التفاعلي، واختبار نهاية إلى نهاية، وحتى الاستخدام العام للويب! يمنحه هذا الاستقلالية لإصلاح الأخطاء البصرية وأخطاء وقت التشغيل دون الحاجة إلى نسخ ولصق سجلات الأخطاء بنفسك.
|
||||
مع قدرة [استخدام الكمبيوتر](https://www.anthropic.com/news/3-5-models-and-computer-use) الجديدة لـ Claude 4 Sonnet، يمكن لـ Cline إطلاق متصفح، والنقر على العناصر، وكتابة النص، والتمرير، والتقاط لقطات الشاشة وسجلات وحدة التحكم في كل خطوة. يسمح له هذا بالتصحيح التفاعلي، واختبار نهاية إلى نهاية، وحتى الاستخدام العام للويب! يمنحه هذا الاستقلالية لإصلاح الأخطاء البصرية وأخطاء وقت التشغيل دون الحاجة إلى نسخ ولصق سجلات الأخطاء بنفسك.
|
||||
|
||||
حاول طلب من Cline "اختبار التطبيق"، وشاهده يشغل أمرًا مثل `npm run dev`، ويطلق خادم التطوير المحلي في متصفح، ويجري سلسلة من الاختبارات للتأكد من أن كل شيء يعمل. [شاهد عرضًا توضيحيًا هنا.](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
Lernen Sie Cline kennen, einen KI-Assistenten, der Ihre **CLI** u**N**d **E**ditor nutzen kann.
|
||||
|
||||
Dank der [agentischen Codierungsfähigkeiten von Claude 3.7 Sonnet](https://www.anthropic.com/claude/sonnet) kann Cline komplexe Softwareentwicklungsaufgaben Schritt für Schritt bewältigen. Mit Werkzeugen, die ihm das Erstellen und Bearbeiten von Dateien, das Erkunden großer Projekte, die Nutzung des Browsers und das Ausführen von Terminalbefehlen (nach Ihrer Genehmigung) ermöglichen, kann er Ihnen auf eine Weise helfen, die über die Codevervollständigung oder technischen Support hinausgeht. Cline kann sogar das Model Context Protocol (MCP) verwenden, um neue Werkzeuge zu erstellen und seine eigenen Fähigkeiten zu erweitern. Während autonome KI-Skripte traditionell in sandboxed Umgebungen laufen, bietet diese Erweiterung eine Mensch-in-der-Schleife-GUI, um jede Dateiänderung und jeden Terminalbefehl zu genehmigen, was eine sichere und zugängliche Möglichkeit bietet, das Potenzial agentischer KI zu erkunden.
|
||||
Dank der [agentischen Codierungsfähigkeiten von Claude 4 Sonnet](https://www.anthropic.com/claude/sonnet) kann Cline komplexe Softwareentwicklungsaufgaben Schritt für Schritt bewältigen. Mit Werkzeugen, die ihm das Erstellen und Bearbeiten von Dateien, das Erkunden großer Projekte, die Nutzung des Browsers und das Ausführen von Terminalbefehlen (nach Ihrer Genehmigung) ermöglichen, kann er Ihnen auf eine Weise helfen, die über die Codevervollständigung oder technischen Support hinausgeht. Cline kann sogar das Model Context Protocol (MCP) verwenden, um neue Werkzeuge zu erstellen und seine eigenen Fähigkeiten zu erweitern. Während autonome KI-Skripte traditionell in sandboxed Umgebungen laufen, bietet diese Erweiterung eine Mensch-in-der-Schleife-GUI, um jede Dateiänderung und jeden Terminalbefehl zu genehmigen, was eine sichere und zugängliche Möglichkeit bietet, das Potenzial agentischer KI zu erkunden.
|
||||
|
||||
1. Geben Sie Ihre Aufgabe ein und fügen Sie Bilder hinzu, um Mockups in funktionale Apps zu konvertieren oder Fehler mit Screenshots zu beheben.
|
||||
2. Cline beginnt mit der Analyse Ihrer Dateistruktur und Quellcode-ASTs, führt Regex-Suchen durch und liest relevante Dateien, um sich in bestehenden Projekten zurechtzufinden. Durch sorgfältiges Management der hinzugefügten Informationen kann Cline wertvolle Unterstützung auch bei großen, komplexen Projekten bieten, ohne das Kontextfenster zu überladen.
|
||||
@@ -83,7 +83,7 @@ Alle von Cline vorgenommenen Änderungen werden in der Timeline Ihrer Datei aufg
|
||||
|
||||
### Den Browser verwenden
|
||||
|
||||
Mit der neuen [Computer Use](https://www.anthropic.com/news/3-5-models-and-computer-use) Fähigkeit von Claude 3.5 Sonnet kann Cline einen Browser starten, Elemente anklicken, Text eingeben und scrollen, dabei Screenshots und Konsolenprotokolle bei jedem Schritt erfassen. Dies ermöglicht interaktives Debugging, End-to-End-Tests und sogar allgemeine Webnutzung! Dies gibt ihm die Autonomie, visuelle Fehler und Laufzeitprobleme zu beheben, ohne dass Sie selbst Fehlerprotokolle kopieren und einfügen müssen.
|
||||
Mit der neuen [Computer Use](https://www.anthropic.com/news/3-5-models-and-computer-use) Fähigkeit von Claude 4 Sonnet kann Cline einen Browser starten, Elemente anklicken, Text eingeben und scrollen, dabei Screenshots und Konsolenprotokolle bei jedem Schritt erfassen. Dies ermöglicht interaktives Debugging, End-to-End-Tests und sogar allgemeine Webnutzung! Dies gibt ihm die Autonomie, visuelle Fehler und Laufzeitprobleme zu beheben, ohne dass Sie selbst Fehlerprotokolle kopieren und einfügen müssen.
|
||||
|
||||
Versuchen Sie, Cline zu bitten, "die App zu testen", und sehen Sie zu, wie er einen Befehl wie `npm run dev` ausführt, Ihren lokal laufenden Dev-Server in einem Browser startet und eine Reihe von Tests durchführt, um zu bestätigen, dass alles funktioniert. [Sehen Sie sich hier eine Demo an.](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
Conozca a Cline, un asistente de IA que puede usar su **CLI** y **E**ditor.
|
||||
|
||||
Gracias a las [habilidades de codificación agencial de Claude 3.7 Sonnet](https://www.anthropic.com/claude/sonnet), Cline puede abordar tareas complejas de desarrollo de software paso a paso. Con herramientas que le permiten crear y editar archivos, explorar grandes proyectos, usar el navegador y ejecutar comandos de terminal (con su aprobación), puede ayudarle de una manera que va más allá de la autocompletación de código o el soporte técnico. Cline incluso puede usar el Model Context Protocol (MCP) para crear nuevas herramientas y expandir sus propias capacidades. Mientras que los scripts de IA autónomos tradicionalmente se ejecutan en entornos aislados, esta extensión ofrece una GUI con un humano en el bucle para aprobar cada cambio de archivo y comando de terminal, proporcionando una forma segura y accesible de explorar el potencial de la IA agencial.
|
||||
Gracias a las [habilidades de codificación agencial de Claude 4 Sonnet](https://www.anthropic.com/claude/sonnet), Cline puede abordar tareas complejas de desarrollo de software paso a paso. Con herramientas que le permiten crear y editar archivos, explorar grandes proyectos, usar el navegador y ejecutar comandos de terminal (con su aprobación), puede ayudarle de una manera que va más allá de la autocompletación de código o el soporte técnico. Cline incluso puede usar el Model Context Protocol (MCP) para crear nuevas herramientas y expandir sus propias capacidades. Mientras que los scripts de IA autónomos tradicionalmente se ejecutan en entornos aislados, esta extensión ofrece una GUI con un humano en el bucle para aprobar cada cambio de archivo y comando de terminal, proporcionando una forma segura y accesible de explorar el potencial de la IA agencial.
|
||||
|
||||
1. Ingrese su tarea y agregue imágenes para convertir maquetas en aplicaciones funcionales o solucionar errores con capturas de pantalla.
|
||||
2. Cline comenzará analizando su estructura de archivos y ASTs de código fuente, realizando búsquedas Regex y leyendo archivos relevantes para orientarse en proyectos existentes. Al gestionar cuidadosamente la información agregada, Cline puede proporcionar asistencia valiosa incluso en proyectos grandes y complejos sin sobrecargar la ventana de contexto.
|
||||
@@ -83,7 +83,7 @@ Todos los cambios realizados por Cline se registran en la línea de tiempo de su
|
||||
|
||||
### Usar el navegador
|
||||
|
||||
Con la nueva [habilidad de uso de computadora](https://www.anthropic.com/news/3-5-models-and-computer-use) de Claude 3.5 Sonnet, Cline puede iniciar un navegador, hacer clic en elementos, escribir texto y desplazarse, capturando capturas de pantalla y registros de consola. Esto permite la depuración interactiva, pruebas de extremo a extremo e incluso el uso general de la web. Esto le da la autonomía para solucionar errores visuales y problemas de tiempo de ejecución sin que tenga que copiar y pegar registros de errores.
|
||||
Con la nueva [habilidad de uso de computadora](https://www.anthropic.com/news/3-5-models-and-computer-use) de Claude 4 Sonnet, Cline puede iniciar un navegador, hacer clic en elementos, escribir texto y desplazarse, capturando capturas de pantalla y registros de consola. Esto permite la depuración interactiva, pruebas de extremo a extremo e incluso el uso general de la web. Esto le da la autonomía para solucionar errores visuales y problemas de tiempo de ejecución sin que tenga que copiar y pegar registros de errores.
|
||||
|
||||
Intente pedirle a Cline que "pruebe la aplicación" y observe cómo ejecuta un comando como `npm run dev`, inicia su servidor de desarrollo local en un navegador y realiza una serie de pruebas para confirmar que todo funciona. [Vea una demostración aquí.](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
Clineは、**CLI**と**エディター**を使用できるAIアシスタントです。
|
||||
|
||||
[Claude 3.7 Sonnetのエージェント的コーディング機能](https://www.anthropic.com/claude/sonnet)のおかげで、Clineは複雑なソフトウェア開発タスクをステップバイステップで処理できます。ファイルの作成と編集、大規模プロジェクトの探索、ブラウザの使用、ターミナルコマンドの実行(許可後)などのツールを使用して、コード補完や技術サポートを超えた支援を提供します。Clineは、Model Context Protocol (MCP)を使用して新しいツールを作成し、自身の機能を拡張することもできます。自律的なAIスクリプトは通常サンドボックス環境で実行されますが、この拡張機能はファイル変更やターミナルコマンドを承認するための人間インターフェースを提供し、エージェント的AIの可能性を安全かつアクセスしやすい方法で探求できます。
|
||||
[Claude 4 Sonnetのエージェント的コーディング機能](https://www.anthropic.com/claude/sonnet)のおかげで、Clineは複雑なソフトウェア開発タスクをステップバイステップで処理できます。ファイルの作成と編集、大規模プロジェクトの探索、ブラウザの使用、ターミナルコマンドの実行(許可後)などのツールを使用して、コード補完や技術サポートを超えた支援を提供します。Clineは、Model Context Protocol (MCP)を使用して新しいツールを作成し、自身の機能を拡張することもできます。自律的なAIスクリプトは通常サンドボックス環境で実行されますが、この拡張機能はファイル変更やターミナルコマンドを承認するための人間インターフェースを提供し、エージェント的AIの可能性を安全かつアクセスしやすい方法で探求できます。
|
||||
|
||||
1. タスクを入力し、モックアップを機能するアプリに変換したり、スクリーンショットでバグを修正したりします。
|
||||
2. Clineは、ファイル構造とソースコードASTの分析、正規表現検索の実行、関連ファイルの読み取りから始め、既存プロジェクトに精通します。コンテキストに追加される情報を慎重に管理することで、大規模で複雑なプロジェクトでもコンテキストウィンドウを圧倒することなく貴重な支援を提供できます。
|
||||
@@ -83,7 +83,7 @@ Clineによるすべての変更はファイルのタイムラインに記録さ
|
||||
|
||||
### ブラウザの使用
|
||||
|
||||
Claude 3.5 Sonnetの新しい[コンピュータ使用](https://www.anthropic.com/news/3-5-models-and-computer-use)機能により、Clineはブラウザを起動し、要素をクリック、テキストを入力、スクロールし、各ステップでスクリーンショットとコンソールログをキャプチャできます。これにより、インタラクティブなデバッグ、エンドツーエンドテスト、さらには一般的なウェブ使用が可能になります。これにより、エラーログを手動でコピー&ペーストすることなく、視覚的なバグやランタイムの問題を自律的に修正できます。
|
||||
Claude 4 Sonnetの新しい[コンピュータ使用](https://www.anthropic.com/news/3-5-models-and-computer-use)機能により、Clineはブラウザを起動し、要素をクリック、テキストを入力、スクロールし、各ステップでスクリーンショットとコンソールログをキャプチャできます。これにより、インタラクティブなデバッグ、エンドツーエンドテスト、さらには一般的なウェブ使用が可能になります。これにより、エラーログを手動でコピー&ペーストすることなく、視覚的なバグやランタイムの問題を自律的に修正できます。
|
||||
|
||||
Clineに「アプリをテストして」と頼んでみてください。彼は`npm run dev`のようなコマンドを実行し、ローカルで実行中の開発サーバーをブラウザで起動し、一連のテストを実行してすべてが正常に動作することを確認します。[デモはこちら。](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
Cline을 만나보세요, **CLI** 및 **에디터**를 활용할 수 있는 AI 어시스턴트입니다.
|
||||
|
||||
[Claude 3.7 Sonnet의 에이전트형 코딩 기능](https://www.anthropic.com/claude/sonnet) 덕분에, Cline은 복잡한 소프트웨어 개발 작업을 단계별로 처리할 수 있습니다. 파일 생성과 편집, 대규모 프로젝트 탐색, 브라우저 사용, 터미널 명령 실행(권한 허가 필요) 등의 도구를 사용하여 단순 코드 완성이나 기술 지원을 넘어서는 도움을 제공합니다. Cline은 Model Context Protocol(MCP)를 사용하여 새로운 도구를 만들고 자신의 기능을 확장할 수도 있습니다. 자율적인 AI 스크립트는 일반적으로 샌드박스 환경에서 실행되지만, 이 확장 프로그램은 모든 파일 변경 및 터미널 명령을 승인할 수 있는 사람이 개입가능한 GUI를 제공하여, 에이전트형 AI의 잠재력을 보다 안전하고 쉽게 탐색할 수 있도록 합니다.
|
||||
[Claude 4 Sonnet의 에이전트형 코딩 기능](https://www.anthropic.com/claude/sonnet) 덕분에, Cline은 복잡한 소프트웨어 개발 작업을 단계별로 처리할 수 있습니다. 파일 생성과 편집, 대규모 프로젝트 탐색, 브라우저 사용, 터미널 명령 실행(권한 허가 필요) 등의 도구를 사용하여 단순 코드 완성이나 기술 지원을 넘어서는 도움을 제공합니다. Cline은 Model Context Protocol(MCP)를 사용하여 새로운 도구를 만들고 자신의 기능을 확장할 수도 있습니다. 자율적인 AI 스크립트는 일반적으로 샌드박스 환경에서 실행되지만, 이 확장 프로그램은 모든 파일 변경 및 터미널 명령을 승인할 수 있는 사람이 개입가능한 GUI를 제공하여, 에이전트형 AI의 잠재력을 보다 안전하고 쉽게 탐색할 수 있도록 합니다.
|
||||
|
||||
1. 작업을 입력하고, 목업을 기능하는 앱으로 변환하거나 스크린샷으로 버그를 수정합니다.
|
||||
2. Cline은 파일 구조와 소스코드 AST의 분석, 정규식 검색 실행, 관련 파일 읽기부터 시작하여 기존 프로젝트를 파악합니다. 또한, 어떤 정보를 컨텍스트에 추가할지를 신중하게 관리하여, 대규모 복잡한 프로젝트에서도 컨텍스트 윈도우를 과부하시키지 않으면서도 효과적인 지원을 제공합니다.
|
||||
@@ -78,7 +78,7 @@ Cline에 의한 모든 변경은 파일의 타임라인에 기록되어 필요
|
||||
|
||||
### 브라우저 사용
|
||||
|
||||
Claude 3.5 Sonnet의 새로운 [컴퓨터 사용](https://www.anthropic.com/news/3-5-models-and-computer-use) 기능으로 인해, Cline은 브라우저를 실행하고 요소를 클릭하고 텍스트를 입력하고 스크롤하며 각 단계에서 스크린샷과 콘솔 로그를 캡처할 수 있습니다. 이를 통해 인터랙티브한 디버깅, 엔드투엔드 테스트, 심지어 일반적인 웹 탐색까지 가능해집니다. 이로 인해 오류 로그를 수동으로 복사 & 붙여넣기 할 필요 없이 시각적 버그나 런타임 문제를 자율적으로 수정할 수 있습니다.
|
||||
Claude 4 Sonnet의 새로운 [컴퓨터 사용](https://www.anthropic.com/news/3-5-models-and-computer-use) 기능으로 인해, Cline은 브라우저를 실행하고 요소를 클릭하고 텍스트를 입력하고 스크롤하며 각 단계에서 스크린샷과 콘솔 로그를 캡처할 수 있습니다. 이를 통해 인터랙티브한 디버깅, 엔드투엔드 테스트, 심지어 일반적인 웹 탐색까지 가능해집니다. 이로 인해 오류 로그를 수동으로 복사 & 붙여넣기 할 필요 없이 시각적 버그나 런타임 문제를 자율적으로 수정할 수 있습니다.
|
||||
|
||||
Cline에게 "앱을 테스트해줘"라고 요청하면, `npm run dev`와 같은 명령을 실행하고 로컬에서 실행 중인 개발 서버를 브라우저에서 실행하여 일련의 테스트를 수행하고 모든 것이 정상적으로 작동하는지 확인합니다. [데모는 여기를 참조하세요.](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
Conheça o Cline: um assistente de IA que pode usar seu **CLI** e **Editor**.
|
||||
|
||||
Graças às [habilidades avançadas do Claude 3.7 Sonnet](https://www.anthropic.com/claude/sonnet), o Cline pode lidar com tarefas complexas de desenvolvimento de software passo a passo. Com ferramentas que permitem criar e editar arquivos, explorar grandes projetos, usar o navegador e executar comandos no terminal (com sua aprovação), ele pode ajudar você de maneiras que vão além da inclusão de código ou suporte técnico. O Cline pode é capaz inclusive de usar o Model Context Protocol (MCP) para criar novas ferramentas e expandir seus próprios recursos. Embora os scripts de IA autônomas tradicionalmente sejam executados em ambientes isolados, esta extensão oferece uma GUI com um humano no circuito para aprovar cada alteração de arquivo e comando de terminal, fornecendo uma maneira segura e acessível de explorar todo o potencial da IA.
|
||||
Graças às [habilidades avançadas do Claude 4 Sonnet](https://www.anthropic.com/claude/sonnet), o Cline pode lidar com tarefas complexas de desenvolvimento de software passo a passo. Com ferramentas que permitem criar e editar arquivos, explorar grandes projetos, usar o navegador e executar comandos no terminal (com sua aprovação), ele pode ajudar você de maneiras que vão além da inclusão de código ou suporte técnico. O Cline pode é capaz inclusive de usar o Model Context Protocol (MCP) para criar novas ferramentas e expandir seus próprios recursos. Embora os scripts de IA autônomas tradicionalmente sejam executados em ambientes isolados, esta extensão oferece uma GUI com um humano no circuito para aprovar cada alteração de arquivo e comando de terminal, fornecendo uma maneira segura e acessível de explorar todo o potencial da IA.
|
||||
|
||||
1. Insira sua tarefa e adicione imagens para transformar mockups em aplicativos funcionais ou corrigir erros através de capturas de tela.
|
||||
|
||||
@@ -83,7 +83,7 @@ Todas as alterações feitas pelo Cline são registradas na Linha do tempo do ar
|
||||
|
||||
### Uso do navegador
|
||||
|
||||
Com a nova habilidade de [uso de computador](https://www.anthropic.com/news/3-5-models-and-computer-use) do Claude Sonnet 3.5, Cline pode abrir um navegador, clicar em elementos, digitar texto e rolar, capturando a tela e logs de console. Isso permite depurar de maneira interativa, testes end-to-end e até mesmo uso geral da web. Isso lhe dá autonomia para solucionar erros visuais e problemas em tempo de execução sem precisar copiar e colar logs dos erros.
|
||||
Com a nova habilidade de [uso de computador](https://www.anthropic.com/news/3-5-models-and-computer-use) do Claude Sonnet 4, Cline pode abrir um navegador, clicar em elementos, digitar texto e rolar, capturando a tela e logs de console. Isso permite depurar de maneira interativa, testes end-to-end e até mesmo uso geral da web. Isso lhe dá autonomia para solucionar erros visuais e problemas em tempo de execução sem precisar copiar e colar logs dos erros.
|
||||
|
||||
Tente pedir a Cline para "testar o aplicativo" e observe enquanto o Cline executa um comando como `npm run dev`, inicia seu servidor de desenvolvimento local em um navegador e executa uma série de testes para confirmar se tudo funciona. [Veja uma demonstração aqui.](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
认识 Cline —— 一个可以使用你的 **终端** 和 **编辑器** 的 AI 助手。
|
||||
|
||||
得益于 [Claude 3.7 Sonnet 的代理式编码能力](https://www.anthropic.com/claude/sonnet),Cline 能够逐步处理复杂的软件开发任务。借助于一系列工具,他可以创建和编辑文件、浏览大型项目、使用浏览器,并在你授权后执行终端命令,从而在代码补全或技术支持之外提供更深入的帮助。Cline 甚至还能使用 Model Context Protocol(MCP)来创建新工具,并扩展自身的能力。虽然传统的自动化 AI 脚本通常运行在沙盒环境中,但这个扩展提供了一个人类参与审核的图形界面(GUI),用于审批每一次文件变更和终端命令,从而为探索代理式 AI 的潜力提供了一种安全且易于使用的方式。
|
||||
得益于 [Claude 4 Sonnet 的代理式编码能力](https://www.anthropic.com/claude/sonnet),Cline 能够逐步处理复杂的软件开发任务。借助于一系列工具,他可以创建和编辑文件、浏览大型项目、使用浏览器,并在你授权后执行终端命令,从而在代码补全或技术支持之外提供更深入的帮助。Cline 甚至还能使用 Model Context Protocol(MCP)来创建新工具,并扩展自身的能力。虽然传统的自动化 AI 脚本通常运行在沙盒环境中,但这个扩展提供了一个人类参与审核的图形界面(GUI),用于审批每一次文件变更和终端命令,从而为探索代理式 AI 的潜力提供了一种安全且易于使用的方式。
|
||||
|
||||
1. 输入你的任务,并添加图片,以将界面原型(mockup)转换为功能应用,或通过截图修复 bug。
|
||||
2. Cline 会从分析你的文件结构和源代码的抽象语法树(AST)开始,同时执行正则搜索并读取相关文件,以便尽快熟悉项目上下文。通过精细地管理上下文中引入的信息,即使面对大型复杂项目,Cline 也能在不超出上下文窗口限制的前提下提供有效协助。
|
||||
@@ -83,7 +83,7 @@ Cline 所做的所有更改都会记录在你的文件时间轴中,提供了
|
||||
|
||||
### 使用浏览器
|
||||
|
||||
借助 Claude 3.5 Sonnet 的新 [计算机使用](https://www.anthropic.com/news/3-5-models-and-computer-use) 功能,Cline 可以启动浏览器,点击元素,输入文本和滚动,在每一步捕获截图和控制台日志。这允许进行交互式调试、端到端测试,甚至是一般的网页使用!这使他能够自主修复视觉错误和运行时问题,而无需你亲自操作和复制粘贴错误日志。
|
||||
借助 Claude 4 Sonnet 的新 [计算机使用](https://www.anthropic.com/news/3-5-models-and-computer-use) 功能,Cline 可以启动浏览器,点击元素,输入文本和滚动,在每一步捕获截图和控制台日志。这允许进行交互式调试、端到端测试,甚至是一般的网页使用!这使他能够自主修复视觉错误和运行时问题,而无需你亲自操作和复制粘贴错误日志。
|
||||
|
||||
试试让 Cline “测试应用程序”,看看他如何运行 `npm run dev` 命令,在浏览器中启动你本地运行的开发服务器,并执行一系列测试以确认一切正常。[在这里查看演示。](https://x.com/sdrzn/status/1850880547825823989)
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
認識 Cline,一個可以使用您的**命令列介面** (CLI) 和**程式編輯器** (Editor) 的 AI 助理。
|
||||
|
||||
感謝 [Claude 3.7 Sonnet 的代理式程式設計能力](https://www.anthropic.com/claude/sonnet),Cline 能夠逐步處理複雜的軟體開發任務。透過能讓他建立和編輯檔案、探索大型專案、使用瀏覽器,以及執行終端機指令(在您授權後)的工具,從而在程式碼補全或技術支援之外提供更深入的協助。Cline 甚至能使用模型上下文協定(Model Context Protocol,MCP)來建立新工具並擴展自己的功能。雖然自主 AI 腳本傳統上會在沙箱環境中執行,但這個擴充套件提供了人機互動的圖形介面,讓您可以核准每個檔案變更和終端機指令,提供一個安全且容易使用的方式來探索代理式 AI 的潛力。
|
||||
感謝 [Claude 4 Sonnet 的代理式程式設計能力](https://www.anthropic.com/claude/sonnet),Cline 能夠逐步處理複雜的軟體開發任務。透過能讓他建立和編輯檔案、探索大型專案、使用瀏覽器,以及執行終端機指令(在您授權後)的工具,從而在程式碼補全或技術支援之外提供更深入的協助。Cline 甚至能使用模型上下文協定(Model Context Protocol,MCP)來建立新工具並擴展自己的功能。雖然自主 AI 腳本傳統上會在沙箱環境中執行,但這個擴充套件提供了人機互動的圖形介面,讓您可以核准每個檔案變更和終端機指令,提供一個安全且容易使用的方式來探索代理式 AI 的潛力。
|
||||
|
||||
1. 輸入您的任務,並可以加入圖片來將設計稿轉換成功能性應用程式,或使用截圖來修正錯誤。
|
||||
2. Cline 會先分析您的檔案結構和程式碼 AST、執行正規表達式搜尋,並讀取相關檔案,以便在現有專案中快速掌握狀況。透過仔細管理加入上下文的資訊,Cline 可以在不超過上下文視窗的情況下,為大型且複雜的專案提供有價值的協助。
|
||||
@@ -84,7 +84,7 @@ Cline 可以直接在您的編輯器中建立和編輯檔案,並顯示變更
|
||||
|
||||
### 使用瀏覽器
|
||||
|
||||
透過 Claude 3.5 Sonnet 的新[電腦使用](https://www.anthropic.com/news/3-5-models-and-computer-use)功能,Cline 可以啟動瀏覽器、點選元素、輸入文字和捲動,在每個步驟擷取螢幕截圖和主控台記錄。這讓互動式除錯、端對端測試,甚至一般網頁使用成為可能!這讓他能獨立修正視覺問題和執行時錯誤,而不需要您手動複製錯誤記錄。
|
||||
透過 Claude 4 Sonnet 的新[電腦使用](https://www.anthropic.com/news/3-5-models-and-computer-use)功能,Cline 可以啟動瀏覽器、點選元素、輸入文字和捲動,在每個步驟擷取螢幕截圖和主控台記錄。這讓互動式除錯、端對端測試,甚至一般網頁使用成為可能!這讓他能獨立修正視覺問題和執行時錯誤,而不需要您手動複製錯誤記錄。
|
||||
|
||||
試著請 Cline 「測試應用程式」,觀察他如何執行 `npm run dev`、在瀏覽器中啟動您的本機開發伺服器,並執行一系列測試來確認一切正常運作。[點此觀看示範](https://x.com/sdrzn/status/1850880547825823989)。
|
||||
|
||||
@@ -108,10 +108,13 @@ Cline 可以直接在您的編輯器中建立和編輯檔案,並顯示變更
|
||||
|
||||
### 新增上下文
|
||||
|
||||
**`@url`:**貼上網址讓擴充套件擷取並轉換為 Markdown,當您想給 Cline 最新文件時很有用
|
||||
**`@problems`:**新增工作區的錯誤和警告(「問題」面板)給 Cline 修正
|
||||
**`@file`:**新增檔案內容,讓您不必浪費 API 請求來核准讀取檔案(+ 輸入以搜尋檔案)
|
||||
**`@folder`:**一次新增整個資料夾的檔案,讓您的工作流程更快速
|
||||
**`@url`**:貼上網址讓擴充套件擷取並轉換為 Markdown,當您想給 Cline 最新文件時很有用
|
||||
|
||||
**`@problems`**:新增工作區的錯誤和警告(「問題」面板)給 Cline 修正
|
||||
|
||||
**`@file`**:新增檔案內容,讓您不必浪費 API 請求來核准讀取檔案(+ 輸入以搜尋檔案)
|
||||
|
||||
**`@folder`**:一次新增整個資料夾的檔案,讓您的工作流程更快速
|
||||
|
||||
<!-- 透明像素用於浮動圖片後的換行 -->
|
||||
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
|
||||
|
||||
Generated
+20
-20
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "claude-dev",
|
||||
"version": "3.16.0",
|
||||
"version": "3.17.2",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "claude-dev",
|
||||
"version": "3.16.0",
|
||||
"version": "3.17.2",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/bedrock-sdk": "^0.12.4",
|
||||
@@ -19,7 +19,7 @@
|
||||
"@grpc/grpc-js": "^1.9.15",
|
||||
"@grpc/reflection": "^1.0.4",
|
||||
"@mistralai/mistralai": "^1.5.0",
|
||||
"@modelcontextprotocol/sdk": "^1.7.0",
|
||||
"@modelcontextprotocol/sdk": "^1.11.1",
|
||||
"@opentelemetry/api": "^1.4.1",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "^0.39.1",
|
||||
"@opentelemetry/resources": "^1.30.1",
|
||||
@@ -7600,17 +7600,17 @@
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/@modelcontextprotocol/sdk": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.7.0.tgz",
|
||||
"integrity": "sha512-IYPe/FLpvF3IZrd/f5p5ffmWhMc3aEMuM2wGJASDqC2Ge7qatVCdbfPx3n/5xFeb19xN0j/911M2AaFuircsWA==",
|
||||
"license": "MIT",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.1.tgz",
|
||||
"integrity": "sha512-9LfmxKTb1v+vUS1/emSk1f5ePmTLkb9Le9AxOB5T0XM59EUumwcS45z05h7aiZx3GI0Bl7mjb3FMEglYj+acuQ==",
|
||||
"dependencies": {
|
||||
"content-type": "^1.0.5",
|
||||
"cors": "^2.8.5",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"eventsource": "^3.0.2",
|
||||
"express": "^5.0.1",
|
||||
"express-rate-limit": "^7.5.0",
|
||||
"pkce-challenge": "^4.1.0",
|
||||
"pkce-challenge": "^5.0.0",
|
||||
"raw-body": "^3.0.0",
|
||||
"zod": "^3.23.8",
|
||||
"zod-to-json-schema": "^3.24.1"
|
||||
@@ -21465,10 +21465,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pkce-challenge": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-4.1.0.tgz",
|
||||
"integrity": "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==",
|
||||
"license": "MIT",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz",
|
||||
"integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==",
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
@@ -31509,16 +31508,17 @@
|
||||
"integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="
|
||||
},
|
||||
"@modelcontextprotocol/sdk": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.7.0.tgz",
|
||||
"integrity": "sha512-IYPe/FLpvF3IZrd/f5p5ffmWhMc3aEMuM2wGJASDqC2Ge7qatVCdbfPx3n/5xFeb19xN0j/911M2AaFuircsWA==",
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.1.tgz",
|
||||
"integrity": "sha512-9LfmxKTb1v+vUS1/emSk1f5ePmTLkb9Le9AxOB5T0XM59EUumwcS45z05h7aiZx3GI0Bl7mjb3FMEglYj+acuQ==",
|
||||
"requires": {
|
||||
"content-type": "^1.0.5",
|
||||
"cors": "^2.8.5",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"eventsource": "^3.0.2",
|
||||
"express": "^5.0.1",
|
||||
"express-rate-limit": "^7.5.0",
|
||||
"pkce-challenge": "^4.1.0",
|
||||
"pkce-challenge": "^5.0.0",
|
||||
"raw-body": "^3.0.0",
|
||||
"zod": "^3.23.8",
|
||||
"zod-to-json-schema": "^3.24.1"
|
||||
@@ -41248,9 +41248,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"pkce-challenge": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-4.1.0.tgz",
|
||||
"integrity": "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz",
|
||||
"integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ=="
|
||||
},
|
||||
"pony-cause": {
|
||||
"version": "1.1.1",
|
||||
@@ -44188,4 +44188,4 @@
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+38
-7
@@ -2,7 +2,7 @@
|
||||
"name": "claude-dev",
|
||||
"displayName": "Cline",
|
||||
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
|
||||
"version": "3.16.1",
|
||||
"version": "3.17.3",
|
||||
"icon": "assets/icons/icon.png",
|
||||
"engines": {
|
||||
"vscode": "^1.84.0"
|
||||
@@ -50,8 +50,21 @@
|
||||
"activitybar": [
|
||||
{
|
||||
"id": "claude-dev-ActivityBar",
|
||||
"title": "Cline",
|
||||
"icon": "assets/icons/icon.svg"
|
||||
"title": "Cline (⌘+')",
|
||||
"icon": "assets/icons/icon.svg",
|
||||
"when": "isMac"
|
||||
},
|
||||
{
|
||||
"id": "claude-dev-ActivityBar",
|
||||
"title": "Cline (Ctrl+')",
|
||||
"icon": "assets/icons/icon.svg",
|
||||
"when": "isWindows"
|
||||
},
|
||||
{
|
||||
"id": "claude-dev-ActivityBar",
|
||||
"title": "Cline (Ctrl+')",
|
||||
"icon": "assets/icons/icon.svg",
|
||||
"when": "isLinux || !isMac && !isWindows"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -126,6 +139,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 +163,14 @@
|
||||
{
|
||||
"command": "cline.generateGitCommitMessage",
|
||||
"when": "scmProvider == git"
|
||||
},
|
||||
{
|
||||
"command": "cline.focusChatInput",
|
||||
"key": "cmd+'",
|
||||
"mac": "cmd+'",
|
||||
"win": "ctrl+'",
|
||||
"linux": "ctrl+'",
|
||||
"when": "!editorHasSelection"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
@@ -242,18 +273,18 @@
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run package",
|
||||
"compile": "npm run check-types && npm run lint && node esbuild.js",
|
||||
"compile-standalone": "npm run protos && npm run check-types && npm run lint && node esbuild.js --standalone",
|
||||
"compile-standalone": "npm run check-types && npm run lint && node esbuild.js --standalone",
|
||||
"postcompile-standalone": "node scripts/package-standalone.mjs",
|
||||
"watch": "npm-run-all -p watch:*",
|
||||
"watch:esbuild": "node esbuild.js --watch",
|
||||
"watch:tsc": "tsc --noEmit --watch --project tsconfig.json",
|
||||
"package": "npm run build:webview && npm run check-types && npm run lint && node esbuild.js --production",
|
||||
"package": "npm run check-types && npm run build:webview && npm run lint && node esbuild.js --production",
|
||||
"protos": "node proto/build-proto.js && node scripts/generate-server-setup.mjs",
|
||||
"postprotos": "prettier src/shared/proto src/core/controller webview-ui/src/services src/standalone/server-setup.ts --write --log-level silent",
|
||||
"compile-tests": "node ./scripts/build-tests.js",
|
||||
"watch-tests": "tsc -p . -w --outDir out",
|
||||
"pretest": "npm run compile-tests && npm run compile && npm run lint",
|
||||
"check-types": "tsc --noEmit",
|
||||
"check-types": "npm run protos && tsc --noEmit",
|
||||
"lint": "eslint src --ext ts && eslint webview-ui/src --ext ts",
|
||||
"format": "prettier . --check",
|
||||
"format:fix": "prettier . --write",
|
||||
@@ -323,7 +354,7 @@
|
||||
"@grpc/grpc-js": "^1.9.15",
|
||||
"@grpc/reflection": "^1.0.4",
|
||||
"@mistralai/mistralai": "^1.5.0",
|
||||
"@modelcontextprotocol/sdk": "^1.7.0",
|
||||
"@modelcontextprotocol/sdk": "^1.11.1",
|
||||
"@opentelemetry/api": "^1.4.1",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "^0.39.1",
|
||||
"@opentelemetry/resources": "^1.30.1",
|
||||
|
||||
@@ -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);
|
||||
@@ -34,6 +37,35 @@ service FileService {
|
||||
|
||||
// Search for files in the workspace with fuzzy matching
|
||||
rpc searchFiles(FileSearchRequest) returns (FileSearchResults);
|
||||
|
||||
// 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);
|
||||
|
||||
// Refreshes all rule toggles (Cline, External, and Workflows)
|
||||
rpc refreshRules(EmptyRequest) returns (RefreshedRules);
|
||||
}
|
||||
|
||||
// Response for refreshRules operation
|
||||
message RefreshedRules {
|
||||
ClineRulesToggles global_cline_rules_toggles = 1;
|
||||
ClineRulesToggles local_cline_rules_toggles = 2;
|
||||
ClineRulesToggles local_cursor_rules_toggles = 3;
|
||||
ClineRulesToggles local_windsurf_rules_toggles = 4;
|
||||
ClineRulesToggles local_workflow_toggles = 5;
|
||||
ClineRulesToggles global_workflow_toggles = 6;
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -97,3 +129,29 @@ message RuleFile {
|
||||
string display_name = 2; // Filename for display purposes
|
||||
bool already_exists = 3; // For createRuleFile, indicates if file already existed
|
||||
}
|
||||
|
||||
// Request to toggle a Cline rule
|
||||
message ToggleClineRuleRequest {
|
||||
Metadata metadata = 1;
|
||||
bool is_global = 2; // Whether this is a global rule or workspace rule
|
||||
string rule_path = 3; // Path to the rule file
|
||||
bool enabled = 4; // Whether to enable or disable the rule
|
||||
}
|
||||
|
||||
// Maps from filepath to enabled/disabled status, matching app's ClineRulesToggles type
|
||||
message ClineRulesToggles {
|
||||
map<string, bool> toggles = 1;
|
||||
}
|
||||
|
||||
// Response for toggleClineRule operation
|
||||
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
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ service McpService {
|
||||
rpc downloadMcp(StringRequest) returns (Empty);
|
||||
rpc restartMcpServer(StringRequest) returns (McpServers);
|
||||
rpc deleteMcpServer(StringRequest) returns (McpServers);
|
||||
rpc toggleToolAutoApprove(ToggleToolAutoApproveRequest) returns (McpServers);
|
||||
rpc refreshMcpMarketplace(EmptyRequest) returns (McpMarketplaceCatalog);
|
||||
}
|
||||
|
||||
message ToggleMcpServerRequest {
|
||||
@@ -33,6 +35,13 @@ message AddRemoteMcpServerRequest {
|
||||
string server_url = 3;
|
||||
}
|
||||
|
||||
message ToggleToolAutoApproveRequest {
|
||||
Metadata metadata = 1;
|
||||
string server_name = 2;
|
||||
repeated string tool_names = 3;
|
||||
bool auto_approve = 4;
|
||||
}
|
||||
|
||||
message McpTool {
|
||||
string name = 1;
|
||||
optional string description = 2;
|
||||
@@ -77,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,8 @@ service StateService {
|
||||
rpc toggleFavoriteModel(StringRequest) returns (Empty);
|
||||
rpc resetState(EmptyRequest) returns (Empty);
|
||||
rpc togglePlanActMode(TogglePlanActModeRequest) returns (Empty);
|
||||
rpc updateTerminalConnectionTimeout(Int64Request) returns (Int64);
|
||||
rpc updateAutoApprovalSettings(AutoApprovalSettingsRequest) returns (Empty);
|
||||
}
|
||||
|
||||
message State {
|
||||
@@ -36,3 +38,26 @@ message ChatContent {
|
||||
optional string message = 1;
|
||||
repeated string images = 2;
|
||||
}
|
||||
|
||||
// Message for auto approval settings
|
||||
message AutoApprovalSettingsRequest {
|
||||
Metadata metadata = 1;
|
||||
|
||||
message Actions {
|
||||
bool read_files = 1;
|
||||
bool read_files_externally = 2;
|
||||
bool edit_files = 3;
|
||||
bool edit_files_externally = 4;
|
||||
bool execute_safe_commands = 5;
|
||||
bool execute_all_commands = 6;
|
||||
bool use_browser = 7;
|
||||
bool use_mcp = 8;
|
||||
}
|
||||
|
||||
int32 version = 2;
|
||||
bool enabled = 3;
|
||||
Actions actions = 4;
|
||||
int32 max_requests = 5;
|
||||
bool enable_notifications = 6;
|
||||
repeated string favorites = 7;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
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);
|
||||
|
||||
// Marks the current announcement as shown and returns whether an announcement should still be shown
|
||||
rpc onDidShowAnnouncement(EmptyRequest) returns (Boolean);
|
||||
}
|
||||
@@ -3,7 +3,8 @@ set -eu
|
||||
|
||||
DIR=${1:-src/}
|
||||
DEST_DIR=dist-standalone
|
||||
DEST=dist-standalone/vscode-uses.txt
|
||||
SDK_DEST=$DEST_DIR/vscode-sdk-uses.txt
|
||||
CSS_DEST=$DEST_DIR/vscode-css-uses.txt
|
||||
mkdir -p $DEST_DIR
|
||||
|
||||
{
|
||||
@@ -11,8 +12,16 @@ git grep -h 'vscode\.' $DIR |
|
||||
grep -Ev '//.*vscode' | # remove commented out code
|
||||
sed 's|.*vscode\.|vscode.|'| # remove everything before vscode.
|
||||
sed 's/[^a-zA-Z0-9_.].*$//' | # remove everything after last identifier
|
||||
sort | uniq > $DEST
|
||||
sort | uniq > $SDK_DEST
|
||||
}
|
||||
echo Wrote uses of the vscode SDK to $(realpath $SDK_DEST)
|
||||
|
||||
echo Done, wrote uses of the vscode SDK to $(realpath $DEST)
|
||||
{
|
||||
grep -rh -- --vscode- webview-ui/build/ |
|
||||
sed 's/--vscode/\n--vscode/g' | # One var per line
|
||||
grep -- --vscode | # Remove lines that don't have vars.
|
||||
sed 's/[),"\\].*$//' | # remove from the end of the var name to the end of the line.
|
||||
sort | uniq > $CSS_DEST
|
||||
}
|
||||
echo Wrote vscode vars used to $(realpath $CSS_DEST)
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ApiStream, ApiStreamUsageChunk } from "./transform/stream"
|
||||
import { DeepSeekHandler } from "./providers/deepseek"
|
||||
import { RequestyHandler } from "./providers/requesty"
|
||||
import { TogetherHandler } from "./providers/together"
|
||||
import { NebiusHandler } from "./providers/nebius"
|
||||
import { QwenHandler } from "./providers/qwen"
|
||||
import { MistralHandler } from "./providers/mistral"
|
||||
import { DoubaoHandler } from "./providers/doubao"
|
||||
@@ -75,6 +76,8 @@ export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
|
||||
return new ClineHandler(options)
|
||||
case "litellm":
|
||||
return new LiteLlmHandler(options)
|
||||
case "nebius":
|
||||
return new NebiusHandler(options)
|
||||
case "asksage":
|
||||
return new AskSageHandler(options)
|
||||
case "xai":
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import "should"
|
||||
import { AwsBedrockHandler } from "../bedrock"
|
||||
import { ApiHandlerOptions } from "@shared/api"
|
||||
|
||||
describe("AwsBedrockHandler", () => {
|
||||
describe("withTempEnv", () => {
|
||||
// Store original env vars for cleanup
|
||||
const originalEnv: Record<string, string | undefined> = {}
|
||||
|
||||
beforeEach(() => {
|
||||
// Store original values before each test
|
||||
originalEnv.TEST_VAR = process.env.TEST_VAR
|
||||
originalEnv.ANOTHER_VAR = process.env.ANOTHER_VAR
|
||||
originalEnv.VAR1 = process.env.VAR1
|
||||
originalEnv.VAR2 = process.env.VAR2
|
||||
originalEnv.VAR3 = process.env.VAR3
|
||||
originalEnv.UNDEFINED_VAR = process.env.UNDEFINED_VAR
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
// Restore original values after each test
|
||||
Object.entries(originalEnv).forEach(([key, value]) => {
|
||||
if (value === undefined) {
|
||||
delete process.env[key]
|
||||
} else {
|
||||
process.env[key] = value
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it("should restore original environment variables after operation", async () => {
|
||||
// Set initial environment
|
||||
process.env.TEST_VAR = "original"
|
||||
process.env.ANOTHER_VAR = "another"
|
||||
|
||||
// Store original values
|
||||
const originalTestVar = process.env.TEST_VAR
|
||||
const originalAnotherVar = process.env.ANOTHER_VAR
|
||||
|
||||
await AwsBedrockHandler["withTempEnv"](
|
||||
() => {
|
||||
process.env.TEST_VAR = "modified"
|
||||
delete process.env.ANOTHER_VAR
|
||||
},
|
||||
async () => {
|
||||
// Verify environment is modified
|
||||
process.env.TEST_VAR!.should.equal("modified")
|
||||
should.not.exist(process.env.ANOTHER_VAR)
|
||||
return "test"
|
||||
},
|
||||
)
|
||||
|
||||
// Verify environment is restored
|
||||
process.env.TEST_VAR!.should.equal(originalTestVar)
|
||||
process.env.ANOTHER_VAR!.should.equal(originalAnotherVar)
|
||||
})
|
||||
|
||||
it("should handle undefined environment variables", async () => {
|
||||
await AwsBedrockHandler["withTempEnv"](
|
||||
() => {
|
||||
delete process.env.UNDEFINED_VAR
|
||||
},
|
||||
async () => {
|
||||
should.not.exist(process.env.UNDEFINED_VAR)
|
||||
return "test"
|
||||
},
|
||||
)
|
||||
|
||||
// Verify undefined variable is not present
|
||||
should.not.exist(process.env.UNDEFINED_VAR)
|
||||
})
|
||||
|
||||
it("should handle errors and still restore environment", async () => {
|
||||
// Set initial environment
|
||||
process.env.TEST_VAR = "original"
|
||||
|
||||
try {
|
||||
await AwsBedrockHandler["withTempEnv"](
|
||||
() => {
|
||||
process.env.TEST_VAR = "modified"
|
||||
},
|
||||
async () => {
|
||||
throw new Error("Test error")
|
||||
},
|
||||
)
|
||||
should.fail(null, null, "Expected error was not thrown", "throw")
|
||||
} catch (error) {
|
||||
;(error as Error).message.should.equal("Test error")
|
||||
}
|
||||
|
||||
// Verify environment is restored even after error
|
||||
process.env.TEST_VAR!.should.equal("original")
|
||||
})
|
||||
|
||||
it("should handle multiple environment variable changes", async () => {
|
||||
// Set initial environment
|
||||
process.env.VAR1 = "original1"
|
||||
process.env.VAR2 = "original2"
|
||||
process.env.VAR3 = "original3"
|
||||
|
||||
// Store original values
|
||||
const originalVar1 = process.env.VAR1
|
||||
const originalVar2 = process.env.VAR2
|
||||
const originalVar3 = process.env.VAR3
|
||||
|
||||
await AwsBedrockHandler["withTempEnv"](
|
||||
() => {
|
||||
process.env.VAR1 = "modified1"
|
||||
process.env.VAR2 = "modified2"
|
||||
delete process.env.VAR3
|
||||
},
|
||||
async () => {
|
||||
// Verify environment is modified
|
||||
process.env.VAR1!.should.equal("modified1")
|
||||
process.env.VAR2!.should.equal("modified2")
|
||||
should.not.exist(process.env.VAR3)
|
||||
return "test"
|
||||
},
|
||||
)
|
||||
|
||||
// Verify environment is restored
|
||||
process.env.VAR1!.should.equal(originalVar1)
|
||||
process.env.VAR2!.should.equal(originalVar2)
|
||||
process.env.VAR3!.should.equal(originalVar3)
|
||||
})
|
||||
|
||||
it("should work with AWS_PROFILE", async () => {
|
||||
process.env["AWS_PROFILE"] = "test-profile"
|
||||
|
||||
const preAWSProfile = process.env["AWS_PROFILE"]
|
||||
|
||||
await AwsBedrockHandler["withTempEnv"](
|
||||
() => {
|
||||
delete process.env["AWS_PROFILE"]
|
||||
},
|
||||
async () => {
|
||||
should.not.exist(process.env["AWS_PROFILE"])
|
||||
return "test"
|
||||
},
|
||||
)
|
||||
|
||||
process.env["AWS_PROFILE"]!.should.equal(preAWSProfile)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -24,13 +24,15 @@ export class AnthropicHandler implements ApiHandler {
|
||||
const modelId = model.id
|
||||
|
||||
const budget_tokens = this.options.thinkingBudgetTokens || 0
|
||||
const reasoningOn = modelId.includes("3-7") && budget_tokens !== 0 ? true : false
|
||||
const reasoningOn = (modelId.includes("3-7") || modelId.includes("4-")) && budget_tokens !== 0 ? true : false
|
||||
|
||||
switch (modelId) {
|
||||
// 'latest' alias does not support cache_control
|
||||
case "claude-sonnet-4-20250514":
|
||||
case "claude-3-7-sonnet-20250219":
|
||||
case "claude-3-5-sonnet-20241022":
|
||||
case "claude-3-5-haiku-20241022":
|
||||
case "claude-opus-4-20250514":
|
||||
case "claude-3-opus-20240229":
|
||||
case "claude-3-haiku-20240307": {
|
||||
/*
|
||||
@@ -96,6 +98,8 @@ export class AnthropicHandler implements ApiHandler {
|
||||
// https://github.com/anthropics/anthropic-sdk-typescript?tab=readme-ov-file#default-headers
|
||||
// https://github.com/anthropics/anthropic-sdk-typescript/commit/c920b77fc67bd839bfeb6716ceab9d7c9bbe7393
|
||||
switch (modelId) {
|
||||
case "claude-sonnet-4-20250514":
|
||||
case "claude-opus-4-20250514":
|
||||
case "claude-3-7-sonnet-20250219":
|
||||
case "claude-3-5-sonnet-20241022":
|
||||
case "claude-3-5-haiku-20241022":
|
||||
|
||||
@@ -47,7 +47,11 @@ export class AwsBedrockHandler implements ApiHandler {
|
||||
}
|
||||
|
||||
const budget_tokens = this.options.thinkingBudgetTokens || 0
|
||||
const reasoningOn = baseModelId.includes("3-7") && budget_tokens !== 0 ? true : false
|
||||
const reasoningOn =
|
||||
(baseModelId.includes("3-7") || baseModelId.includes("sonnet-4") || baseModelId.includes("opus-4")) &&
|
||||
budget_tokens !== 0
|
||||
? true
|
||||
: false
|
||||
|
||||
// Get model info and message indices for caching
|
||||
const userMsgIndices = messages.reduce((acc, msg, index) => (msg.role === "user" ? [...acc, index] : acc), [] as number[])
|
||||
@@ -58,56 +62,62 @@ export class AwsBedrockHandler implements ApiHandler {
|
||||
// initialization, and allowing for session renewal if necessary as well
|
||||
const client = await this.getAnthropicClient()
|
||||
|
||||
// AWS SDK prioritizes AWS_PROFILE over AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY pair
|
||||
// If this is set as an env variable already (ie. from ~/.zshrc) it will override credentials configured by Cline
|
||||
const previousEnv = process.env
|
||||
delete process.env["AWS_PROFILE"]
|
||||
const stream = await client.messages.create({
|
||||
model: modelId,
|
||||
max_tokens: model.info.maxTokens || 8192,
|
||||
thinking: reasoningOn ? { type: "enabled", budget_tokens: budget_tokens } : undefined,
|
||||
temperature: reasoningOn ? undefined : 0,
|
||||
system: [
|
||||
{
|
||||
text: systemPrompt,
|
||||
type: "text",
|
||||
...(this.options.awsBedrockUsePromptCache === true && {
|
||||
cache_control: { type: "ephemeral" },
|
||||
}),
|
||||
},
|
||||
],
|
||||
messages: messages.map((message, index) => {
|
||||
if (index === lastUserMsgIndex || index === secondLastMsgUserIndex) {
|
||||
return {
|
||||
...message,
|
||||
content:
|
||||
typeof message.content === "string"
|
||||
? [
|
||||
{
|
||||
type: "text",
|
||||
text: message.content,
|
||||
...(this.options.awsBedrockUsePromptCache === true && {
|
||||
cache_control: { type: "ephemeral" },
|
||||
}),
|
||||
},
|
||||
]
|
||||
: message.content.map((content, contentIndex) =>
|
||||
contentIndex === message.content.length - 1
|
||||
? {
|
||||
...content,
|
||||
// Use withTempEnv to ensure environment variables are properly restored
|
||||
const stream = await AwsBedrockHandler.withTempEnv(
|
||||
() => {
|
||||
// AWS SDK prioritizes AWS_PROFILE over AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY pair
|
||||
// If this is set as an env variable already (ie. from ~/.zshrc) it will override credentials configured by Cline
|
||||
// Temporarily remove AWS_PROFILE to ensure our credentials are used
|
||||
delete process.env["AWS_PROFILE"]
|
||||
},
|
||||
async () => {
|
||||
return await client.messages.create({
|
||||
model: modelId,
|
||||
max_tokens: model.info.maxTokens || 8192,
|
||||
thinking: reasoningOn ? { type: "enabled", budget_tokens: budget_tokens } : undefined,
|
||||
temperature: reasoningOn ? undefined : 0,
|
||||
system: [
|
||||
{
|
||||
text: systemPrompt,
|
||||
type: "text",
|
||||
...(this.options.awsBedrockUsePromptCache === true && {
|
||||
cache_control: { type: "ephemeral" },
|
||||
}),
|
||||
},
|
||||
],
|
||||
messages: messages.map((message, index) => {
|
||||
if (index === lastUserMsgIndex || index === secondLastMsgUserIndex) {
|
||||
return {
|
||||
...message,
|
||||
content:
|
||||
typeof message.content === "string"
|
||||
? [
|
||||
{
|
||||
type: "text",
|
||||
text: message.content,
|
||||
...(this.options.awsBedrockUsePromptCache === true && {
|
||||
cache_control: { type: "ephemeral" },
|
||||
}),
|
||||
}
|
||||
: content,
|
||||
),
|
||||
}
|
||||
}
|
||||
return message
|
||||
}),
|
||||
stream: true,
|
||||
})
|
||||
process.env = previousEnv
|
||||
},
|
||||
]
|
||||
: message.content.map((content, contentIndex) =>
|
||||
contentIndex === message.content.length - 1
|
||||
? {
|
||||
...content,
|
||||
...(this.options.awsBedrockUsePromptCache === true && {
|
||||
cache_control: { type: "ephemeral" },
|
||||
}),
|
||||
}
|
||||
: content,
|
||||
),
|
||||
}
|
||||
}
|
||||
return message
|
||||
}),
|
||||
stream: true,
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
for await (const chunk of stream) {
|
||||
switch (chunk.type) {
|
||||
@@ -297,13 +307,23 @@ export class AwsBedrockHandler implements ApiHandler {
|
||||
}
|
||||
|
||||
private static async withTempEnv<R>(updateEnv: () => void, fn: () => Promise<R>): Promise<R> {
|
||||
const previousEnv = { ...process.env }
|
||||
const previousEnv = Object.assign({}, process.env)
|
||||
|
||||
try {
|
||||
updateEnv()
|
||||
return await fn()
|
||||
} finally {
|
||||
process.env = previousEnv
|
||||
// Restore the previous environment
|
||||
// First clear any new variables that might have been added
|
||||
for (const key in process.env) {
|
||||
if (!(key in previousEnv)) {
|
||||
delete process.env[key]
|
||||
}
|
||||
}
|
||||
// Then restore all previous values
|
||||
for (const key in previousEnv) {
|
||||
process.env[key] = previousEnv[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,13 +19,23 @@ export class MistralHandler implements ApiHandler {
|
||||
|
||||
@withRetry()
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const stream = await this.client.chat.stream({
|
||||
model: this.getModel().id,
|
||||
// max_completion_tokens: this.getModel().info.maxTokens,
|
||||
temperature: 0,
|
||||
messages: [{ role: "system", content: systemPrompt }, ...convertToMistralMessages(messages)],
|
||||
stream: true,
|
||||
})
|
||||
const stream = await this.client.chat
|
||||
.stream({
|
||||
model: this.getModel().id,
|
||||
// max_completion_tokens: this.getModel().info.maxTokens,
|
||||
temperature: 0,
|
||||
messages: [{ role: "system", content: systemPrompt }, ...convertToMistralMessages(messages)],
|
||||
stream: true,
|
||||
})
|
||||
.catch((err) => {
|
||||
// The Mistal SDK uses statusCode instead of status
|
||||
// However, if they introduce status for something, I don't want to override it
|
||||
if ("statusCode" in err && !("status" in err)) {
|
||||
err.status = err.statusCode
|
||||
}
|
||||
|
||||
throw err
|
||||
})
|
||||
|
||||
for await (const chunk of stream) {
|
||||
const delta = chunk.data.choices[0]?.delta
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import OpenAI from "openai"
|
||||
import { withRetry } from "../retry"
|
||||
import { ApiHandler } from "../index"
|
||||
import { convertToOpenAiMessages } from "../transform/openai-format"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
import { convertToR1Format } from "../transform/r1-format"
|
||||
import { nebiusDefaultModelId, nebiusModels, type ModelInfo, type ApiHandlerOptions, type NebiusModelId } from "../../shared/api"
|
||||
|
||||
export class NebiusHandler implements ApiHandler {
|
||||
private client: OpenAI
|
||||
|
||||
constructor(private readonly options: ApiHandlerOptions) {
|
||||
this.client = new OpenAI({
|
||||
baseURL: "https://api.studio.nebius.ai/v1",
|
||||
apiKey: this.options.nebiusApiKey,
|
||||
})
|
||||
}
|
||||
|
||||
@withRetry()
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const model = this.getModel()
|
||||
|
||||
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = model.id.includes("DeepSeek-R1")
|
||||
? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
|
||||
: [{ role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages)]
|
||||
|
||||
const stream = await this.client.chat.completions.create({
|
||||
model: model.id,
|
||||
messages: openAiMessages,
|
||||
temperature: 0,
|
||||
stream: true,
|
||||
stream_options: { include_usage: true },
|
||||
})
|
||||
for await (const chunk of stream) {
|
||||
const delta = chunk.choices[0]?.delta
|
||||
if (delta?.content) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: delta.content,
|
||||
}
|
||||
}
|
||||
|
||||
if (delta && "reasoning_content" in delta && delta.reasoning_content) {
|
||||
yield {
|
||||
type: "reasoning",
|
||||
reasoning: (delta.reasoning_content as string | undefined) || "",
|
||||
}
|
||||
}
|
||||
|
||||
if (chunk.usage) {
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: chunk.usage.prompt_tokens || 0,
|
||||
outputTokens: chunk.usage.completion_tokens || 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): { id: string; info: ModelInfo } {
|
||||
const modelId = this.options.apiModelId
|
||||
|
||||
if (modelId !== undefined && modelId in nebiusModels) {
|
||||
return { id: modelId, info: nebiusModels[modelId as NebiusModelId] }
|
||||
}
|
||||
return { id: nebiusDefaultModelId, info: nebiusModels[nebiusDefaultModelId] }
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,16 @@ import { convertToOpenAiMessages } from "@api/transform/openai-format"
|
||||
import { calculateApiCostOpenAI } from "@utils/cost"
|
||||
import { ApiStream } from "@api/transform/stream"
|
||||
|
||||
// Requesty usage includes an extra field for Anthropic use cases.
|
||||
// Safely cast the prompt token details section to the appropriate structure.
|
||||
interface RequestyUsage extends OpenAI.CompletionUsage {
|
||||
prompt_tokens_details?: {
|
||||
caching_tokens?: number
|
||||
cached_tokens?: number
|
||||
}
|
||||
total_cost?: number
|
||||
}
|
||||
|
||||
export class RequestyHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: OpenAI
|
||||
@@ -41,7 +51,10 @@ export class RequestyHandler implements ApiHandler {
|
||||
thinkingBudget > 0
|
||||
? { thinking: { type: "enabled", budget_tokens: thinkingBudget } }
|
||||
: { thinking: { type: "disabled" } }
|
||||
const thinkingArgs = model.id.includes("claude-3-7-sonnet") ? thinking : {}
|
||||
const thinkingArgs =
|
||||
model.id.includes("claude-3-7-sonnet") || model.id.includes("claude-sonnet-4") || model.id.includes("claude-opus-4")
|
||||
? thinking
|
||||
: {}
|
||||
|
||||
// @ts-ignore-next-line
|
||||
const stream = await this.client.chat.completions.create({
|
||||
@@ -55,6 +68,8 @@ export class RequestyHandler implements ApiHandler {
|
||||
...thinkingArgs,
|
||||
})
|
||||
|
||||
let lastUsage: any = undefined
|
||||
|
||||
for await (const chunk of stream) {
|
||||
const delta = chunk.choices[0]?.delta
|
||||
if (delta?.content) {
|
||||
@@ -71,32 +86,26 @@ export class RequestyHandler implements ApiHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// Requesty usage includes an extra field for Anthropic use cases.
|
||||
// Safely cast the prompt token details section to the appropriate structure.
|
||||
interface RequestyUsage extends OpenAI.CompletionUsage {
|
||||
prompt_tokens_details?: {
|
||||
caching_tokens?: number
|
||||
cached_tokens?: number
|
||||
}
|
||||
total_cost?: number
|
||||
}
|
||||
|
||||
if (chunk.usage) {
|
||||
const usage = chunk.usage as RequestyUsage
|
||||
const inputTokens = usage.prompt_tokens || 0
|
||||
const outputTokens = usage.completion_tokens || 0
|
||||
const cacheWriteTokens = usage.prompt_tokens_details?.caching_tokens || undefined
|
||||
const cacheReadTokens = usage.prompt_tokens_details?.cached_tokens || undefined
|
||||
const totalCost = calculateApiCostOpenAI(model.info, inputTokens, outputTokens, cacheWriteTokens, cacheReadTokens)
|
||||
lastUsage = chunk.usage
|
||||
}
|
||||
}
|
||||
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: inputTokens,
|
||||
outputTokens: outputTokens,
|
||||
cacheWriteTokens: cacheWriteTokens,
|
||||
cacheReadTokens: cacheReadTokens,
|
||||
totalCost: totalCost,
|
||||
}
|
||||
if (lastUsage) {
|
||||
const usage = lastUsage as RequestyUsage
|
||||
const inputTokens = usage.prompt_tokens || 0
|
||||
const outputTokens = usage.completion_tokens || 0
|
||||
const cacheWriteTokens = usage.prompt_tokens_details?.caching_tokens || undefined
|
||||
const cacheReadTokens = usage.prompt_tokens_details?.cached_tokens || undefined
|
||||
const totalCost = calculateApiCostOpenAI(model.info, inputTokens, outputTokens, cacheWriteTokens, cacheReadTokens)
|
||||
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: inputTokens,
|
||||
outputTokens: outputTokens,
|
||||
cacheWriteTokens: cacheWriteTokens,
|
||||
cacheReadTokens: cacheReadTokens,
|
||||
totalCost: totalCost,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,10 +41,15 @@ export class VertexHandler implements ApiHandler {
|
||||
|
||||
// Claude implementation
|
||||
let budget_tokens = this.options.thinkingBudgetTokens || 0
|
||||
const reasoningOn = modelId.includes("3-7") && budget_tokens !== 0 ? true : false
|
||||
const reasoningOn =
|
||||
(modelId.includes("3-7") || modelId.includes("sonnet-4") || modelId.includes("opus-4")) && budget_tokens !== 0
|
||||
? true
|
||||
: false
|
||||
let stream
|
||||
|
||||
switch (modelId) {
|
||||
case "claude-sonnet-4@20250514":
|
||||
case "claude-opus-4@20250514":
|
||||
case "claude-3-7-sonnet@20250219":
|
||||
case "claude-3-5-sonnet-v2@20241022":
|
||||
case "claude-3-5-sonnet@20240620":
|
||||
|
||||
@@ -23,6 +23,8 @@ export async function createOpenRouterStream(
|
||||
// this was initially specifically for claude models (some models may 'support prompt caching' automatically without this)
|
||||
// handles direct model.id match logic
|
||||
switch (model.id) {
|
||||
case "anthropic/claude-sonnet-4":
|
||||
case "anthropic/claude-opus-4":
|
||||
case "anthropic/claude-3.7-sonnet":
|
||||
case "anthropic/claude-3.7-sonnet:beta":
|
||||
case "anthropic/claude-3.7-sonnet:thinking":
|
||||
@@ -79,6 +81,8 @@ export async function createOpenRouterStream(
|
||||
// (models usually default to max tokens allowed)
|
||||
let maxTokens: number | undefined
|
||||
switch (model.id) {
|
||||
case "anthropic/claude-sonnet-4":
|
||||
case "anthropic/claude-opus-4":
|
||||
case "anthropic/claude-3.7-sonnet":
|
||||
case "anthropic/claude-3.7-sonnet:beta":
|
||||
case "anthropic/claude-3.7-sonnet:thinking":
|
||||
@@ -112,6 +116,8 @@ export async function createOpenRouterStream(
|
||||
|
||||
let reasoning: { max_tokens: number } | undefined = undefined
|
||||
switch (model.id) {
|
||||
case "anthropic/claude-sonnet-4":
|
||||
case "anthropic/claude-opus-4":
|
||||
case "anthropic/claude-3.7-sonnet":
|
||||
case "anthropic/claude-3.7-sonnet:beta":
|
||||
case "anthropic/claude-3.7-sonnet:thinking":
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { fileExistsAtPath, isDirectory, readDirectory } from "@utils/fs"
|
||||
import { ensureRulesDirectoryExists, GlobalFileNames } from "@core/storage/disk"
|
||||
import { ensureRulesDirectoryExists, ensureWorkflowsDirectoryExists, GlobalFileNames } from "@core/storage/disk"
|
||||
import { getGlobalState, getWorkspaceState, updateGlobalState, updateWorkspaceState } from "@core/storage/state"
|
||||
import * as path from "path"
|
||||
import fs from "fs/promises"
|
||||
@@ -172,9 +172,13 @@ export const createRuleFile = async (isGlobal: boolean, filename: string, cwd: s
|
||||
try {
|
||||
let filePath: string
|
||||
if (isGlobal) {
|
||||
// global means its implicitly clinerules
|
||||
const globalClineRulesFilePath = await ensureRulesDirectoryExists()
|
||||
filePath = path.join(globalClineRulesFilePath, filename)
|
||||
if (type === "workflow") {
|
||||
const globalClineWorkflowFilePath = await ensureWorkflowsDirectoryExists()
|
||||
filePath = path.join(globalClineWorkflowFilePath, filename)
|
||||
} else {
|
||||
const globalClineRulesFilePath = await ensureRulesDirectoryExists()
|
||||
filePath = path.join(globalClineRulesFilePath, filename)
|
||||
}
|
||||
} else {
|
||||
const localClineRulesFilePath = path.resolve(cwd, GlobalFileNames.clineRules)
|
||||
|
||||
@@ -243,9 +247,15 @@ export async function deleteRuleFile(
|
||||
|
||||
// Update the appropriate toggles
|
||||
if (isGlobal) {
|
||||
const toggles = ((await getGlobalState(context, "globalClineRulesToggles")) as ClineRulesToggles) || {}
|
||||
delete toggles[rulePath]
|
||||
await updateGlobalState(context, "globalClineRulesToggles", toggles)
|
||||
if (type === "workflow") {
|
||||
const toggles = ((await getGlobalState(context, "globalWorkflowToggles")) as ClineRulesToggles) || {}
|
||||
delete toggles[rulePath]
|
||||
await updateGlobalState(context, "globalWorkflowToggles", toggles)
|
||||
} else {
|
||||
const toggles = ((await getGlobalState(context, "globalClineRulesToggles")) as ClineRulesToggles) || {}
|
||||
delete toggles[rulePath]
|
||||
await updateGlobalState(context, "globalClineRulesToggles", toggles)
|
||||
}
|
||||
} else {
|
||||
if (type === "workflow") {
|
||||
const toggles = ((await getWorkspaceState(context, "workflowToggles")) as ClineRulesToggles) || {}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import path from "path"
|
||||
import { GlobalFileNames } from "@core/storage/disk"
|
||||
import { GlobalFileNames, ensureWorkflowsDirectoryExists } from "@core/storage/disk"
|
||||
import { ClineRulesToggles } from "@shared/cline-rules"
|
||||
import { getWorkspaceState, updateWorkspaceState } from "@core/storage/state"
|
||||
import { getWorkspaceState, updateWorkspaceState, getGlobalState, updateGlobalState } from "@core/storage/state"
|
||||
import * as vscode from "vscode"
|
||||
import { synchronizeRuleToggles } from "@core/context/instructions/user-instructions/rule-helpers"
|
||||
|
||||
@@ -11,10 +11,23 @@ import { synchronizeRuleToggles } from "@core/context/instructions/user-instruct
|
||||
export async function refreshWorkflowToggles(
|
||||
context: vscode.ExtensionContext,
|
||||
workingDirectory: string,
|
||||
): Promise<ClineRulesToggles> {
|
||||
): Promise<{
|
||||
globalWorkflowToggles: ClineRulesToggles
|
||||
localWorkflowToggles: ClineRulesToggles
|
||||
}> {
|
||||
// Global workflows
|
||||
const globalWorkflowToggles = ((await getGlobalState(context, "globalWorkflowToggles")) as ClineRulesToggles) || {}
|
||||
const globalClineWorkflowsFilePath = await ensureWorkflowsDirectoryExists()
|
||||
const updatedGlobalWorkflowToggles = await synchronizeRuleToggles(globalClineWorkflowsFilePath, globalWorkflowToggles)
|
||||
await updateGlobalState(context, "globalWorkflowToggles", updatedGlobalWorkflowToggles)
|
||||
|
||||
const workflowRulesToggles = ((await getWorkspaceState(context, "workflowToggles")) as ClineRulesToggles) || {}
|
||||
const workflowsDirPath = path.resolve(workingDirectory, GlobalFileNames.workflows)
|
||||
const updatedWorkflowToggles = await synchronizeRuleToggles(workflowsDirPath, workflowRulesToggles)
|
||||
await updateWorkspaceState(context, "workflowToggles", updatedWorkflowToggles)
|
||||
return updatedWorkflowToggles
|
||||
|
||||
return {
|
||||
globalWorkflowToggles: updatedGlobalWorkflowToggles,
|
||||
localWorkflowToggles: updatedWorkflowToggles,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,9 +9,14 @@ import { deleteRuleFile } from "./deleteRuleFile"
|
||||
import { getRelativePaths } from "./getRelativePaths"
|
||||
import { openFile } from "./openFile"
|
||||
import { openImage } from "./openImage"
|
||||
import { openMention } from "./openMention"
|
||||
import { refreshRules } from "./refreshRules"
|
||||
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 {
|
||||
@@ -22,7 +27,12 @@ export function registerAllMethods(): void {
|
||||
registerMethod("getRelativePaths", getRelativePaths)
|
||||
registerMethod("openFile", openFile)
|
||||
registerMethod("openImage", openImage)
|
||||
registerMethod("openMention", openMention)
|
||||
registerMethod("refreshRules", refreshRules)
|
||||
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,33 @@
|
||||
import { EmptyRequest } from "@shared/proto/common"
|
||||
import { RefreshedRules } from "@shared/proto/file"
|
||||
import type { Controller } from "../index"
|
||||
import { refreshClineRulesToggles } from "@core/context/instructions/user-instructions/cline-rules"
|
||||
import { refreshExternalRulesToggles } from "@core/context/instructions/user-instructions/external-rules"
|
||||
import { refreshWorkflowToggles } from "@core/context/instructions/user-instructions/workflows"
|
||||
import { cwd } from "@core/task"
|
||||
|
||||
/**
|
||||
* Refreshes all rule toggles (Cline, External, and Workflows)
|
||||
* @param controller The controller instance
|
||||
* @param _request The empty request
|
||||
* @returns RefreshedRules containing updated toggles for all rule types
|
||||
*/
|
||||
export async function refreshRules(controller: Controller, _request: EmptyRequest): Promise<RefreshedRules> {
|
||||
try {
|
||||
const { globalToggles, localToggles } = await refreshClineRulesToggles(controller.context, cwd)
|
||||
const { cursorLocalToggles, windsurfLocalToggles } = await refreshExternalRulesToggles(controller.context, cwd)
|
||||
const { localWorkflowToggles, globalWorkflowToggles } = await refreshWorkflowToggles(controller.context, cwd)
|
||||
|
||||
return {
|
||||
globalClineRulesToggles: { toggles: globalToggles },
|
||||
localClineRulesToggles: { toggles: localToggles },
|
||||
localCursorRulesToggles: { toggles: cursorLocalToggles },
|
||||
localWindsurfRulesToggles: { toggles: windsurfLocalToggles },
|
||||
localWorkflowToggles: { toggles: localWorkflowToggles },
|
||||
globalWorkflowToggles: { toggles: globalWorkflowToggles },
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to refresh rules:", error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { ToggleClineRuleRequest, ClineRulesToggles, ToggleClineRules } from "../../../shared/proto/file"
|
||||
import type { Controller } from "../index"
|
||||
import { getGlobalState, getWorkspaceState, updateGlobalState, updateWorkspaceState } from "../../../core/storage/state"
|
||||
import { ClineRulesToggles as AppClineRulesToggles } from "@shared/cline-rules"
|
||||
|
||||
/**
|
||||
* Toggles a Cline rule (enable or disable)
|
||||
* @param controller The controller instance
|
||||
* @param request The toggle request
|
||||
* @returns The updated Cline rule toggles
|
||||
*/
|
||||
export async function toggleClineRule(controller: Controller, request: ToggleClineRuleRequest): Promise<ToggleClineRules> {
|
||||
const { isGlobal, rulePath, enabled } = request
|
||||
|
||||
if (!rulePath || typeof enabled !== "boolean" || typeof isGlobal !== "boolean") {
|
||||
console.error("toggleClineRule: Missing or invalid parameters", {
|
||||
rulePath,
|
||||
isGlobal: typeof isGlobal === "boolean" ? isGlobal : `Invalid: ${typeof isGlobal}`,
|
||||
enabled: typeof enabled === "boolean" ? enabled : `Invalid: ${typeof enabled}`,
|
||||
})
|
||||
throw new Error("Missing or invalid parameters for toggleClineRule")
|
||||
}
|
||||
|
||||
// This is the same core logic as in the original handler
|
||||
if (isGlobal) {
|
||||
const toggles = ((await getGlobalState(controller.context, "globalClineRulesToggles")) as AppClineRulesToggles) || {}
|
||||
toggles[rulePath] = enabled
|
||||
await updateGlobalState(controller.context, "globalClineRulesToggles", toggles)
|
||||
} else {
|
||||
const toggles = ((await getWorkspaceState(controller.context, "localClineRulesToggles")) as AppClineRulesToggles) || {}
|
||||
toggles[rulePath] = enabled
|
||||
await updateWorkspaceState(controller.context, "localClineRulesToggles", toggles)
|
||||
}
|
||||
|
||||
// Get the current state to return in the response
|
||||
const globalToggles = ((await getGlobalState(controller.context, "globalClineRulesToggles")) as AppClineRulesToggles) || {}
|
||||
const localToggles = ((await getWorkspaceState(controller.context, "localClineRulesToggles")) as AppClineRulesToggles) || {}
|
||||
|
||||
return {
|
||||
globalClineRulesToggles: { toggles: globalToggles },
|
||||
localClineRulesToggles: { toggles: localToggles },
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
+73
-141
@@ -32,8 +32,12 @@ 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 {
|
||||
ensureMcpServersDirectoryExists,
|
||||
ensureSettingsDirectoryExists,
|
||||
GlobalFileNames,
|
||||
ensureWorkflowsDirectoryExists,
|
||||
} from "../storage/disk"
|
||||
import {
|
||||
getAllExtensionState,
|
||||
getGlobalState,
|
||||
@@ -66,7 +70,7 @@ export class Controller {
|
||||
workspaceTracker: WorkspaceTracker
|
||||
mcpHub: McpHub
|
||||
accountService: ClineAccountService
|
||||
private latestAnnouncementId = "may-16-2025_16:11:00" // update to some unique identifier when we add a new announcement
|
||||
latestAnnouncementId = "may-22-2025_16:11:00" // update to some unique identifier when we add a new announcement
|
||||
|
||||
constructor(
|
||||
readonly context: vscode.ExtensionContext,
|
||||
@@ -292,20 +296,6 @@ export class Controller {
|
||||
}
|
||||
await this.postStateToWebview()
|
||||
break
|
||||
case "autoApprovalSettings":
|
||||
if (message.autoApprovalSettings) {
|
||||
const currentSettings = (await getAllExtensionState(this.context)).autoApprovalSettings
|
||||
const incomingVersion = message.autoApprovalSettings.version ?? 1
|
||||
const currentVersion = currentSettings?.version ?? 1
|
||||
if (incomingVersion > currentVersion) {
|
||||
await updateGlobalState(this.context, "autoApprovalSettings", message.autoApprovalSettings)
|
||||
if (this.task) {
|
||||
this.task.autoApprovalSettings = message.autoApprovalSettings
|
||||
}
|
||||
await this.postStateToWebview()
|
||||
}
|
||||
}
|
||||
break
|
||||
case "optionsResponse":
|
||||
await this.postMessageToWebview({
|
||||
type: "invoke",
|
||||
@@ -313,29 +303,11 @@ 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()
|
||||
break
|
||||
case "refreshClineRules":
|
||||
await refreshClineRulesToggles(this.context, cwd)
|
||||
await refreshExternalRulesToggles(this.context, cwd)
|
||||
await refreshWorkflowToggles(this.context, cwd)
|
||||
await this.postStateToWebview()
|
||||
break
|
||||
case "openInBrowser":
|
||||
if (message.url) {
|
||||
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 +327,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,78 +362,21 @@ export class Controller {
|
||||
|
||||
// break
|
||||
// }
|
||||
case "toggleToolAutoApprove": {
|
||||
try {
|
||||
await this.mcpHub?.toggleToolAutoApprove(message.serverName!, message.toolNames!, message.autoApprove!)
|
||||
} catch (error) {
|
||||
if (message.toolNames?.length === 1) {
|
||||
console.error(
|
||||
`Failed to toggle auto-approve for server ${message.serverName} with tool ${message.toolNames[0]}:`,
|
||||
error,
|
||||
)
|
||||
} else {
|
||||
console.error(`Failed to toggle auto-approve tools for server ${message.serverName}:`, error)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
case "toggleClineRule": {
|
||||
const { isGlobal, rulePath, enabled } = message
|
||||
if (rulePath && typeof enabled === "boolean" && typeof isGlobal === "boolean") {
|
||||
if (isGlobal) {
|
||||
const toggles =
|
||||
((await getGlobalState(this.context, "globalClineRulesToggles")) as ClineRulesToggles) || {}
|
||||
toggles[rulePath] = enabled
|
||||
await updateGlobalState(this.context, "globalClineRulesToggles", toggles)
|
||||
} else {
|
||||
const toggles =
|
||||
((await getWorkspaceState(this.context, "localClineRulesToggles")) as ClineRulesToggles) || {}
|
||||
toggles[rulePath] = enabled
|
||||
await updateWorkspaceState(this.context, "localClineRulesToggles", toggles)
|
||||
}
|
||||
await this.postStateToWebview()
|
||||
} else {
|
||||
console.error("toggleClineRule: Missing or invalid parameters", {
|
||||
rulePath,
|
||||
isGlobal: typeof isGlobal === "boolean" ? isGlobal : `Invalid: ${typeof isGlobal}`,
|
||||
enabled: typeof enabled === "boolean" ? enabled : `Invalid: ${typeof enabled}`,
|
||||
})
|
||||
}
|
||||
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") {
|
||||
const toggles = ((await getWorkspaceState(this.context, "workflowToggles")) as ClineRulesToggles) || {}
|
||||
toggles[workflowPath] = enabled
|
||||
await updateWorkspaceState(this.context, "workflowToggles", toggles)
|
||||
await this.postStateToWebview()
|
||||
const { workflowPath, enabled, isGlobal } = message
|
||||
if (workflowPath && typeof enabled === "boolean" && typeof isGlobal === "boolean") {
|
||||
if (isGlobal) {
|
||||
const globalWorkflowToggles =
|
||||
((await getGlobalState(this.context, "globalWorkflowToggles")) as ClineRulesToggles) || {}
|
||||
globalWorkflowToggles[workflowPath] = enabled
|
||||
await updateGlobalState(this.context, "globalWorkflowToggles", globalWorkflowToggles)
|
||||
await this.postStateToWebview()
|
||||
} else {
|
||||
const toggles = ((await getWorkspaceState(this.context, "workflowToggles")) as ClineRulesToggles) || {}
|
||||
toggles[workflowPath] = enabled
|
||||
await updateWorkspaceState(this.context, "workflowToggles", toggles)
|
||||
await this.postStateToWebview()
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -496,20 +407,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)
|
||||
@@ -593,21 +490,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)
|
||||
}
|
||||
@@ -923,6 +805,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)
|
||||
@@ -937,6 +853,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
|
||||
@@ -1319,6 +1249,7 @@ export class Controller {
|
||||
planActSeparateModelsSetting,
|
||||
enableCheckpointsSetting,
|
||||
globalClineRulesToggles,
|
||||
globalWorkflowToggles,
|
||||
shellIntegrationTimeout,
|
||||
isNewUser,
|
||||
} = await getAllExtensionState(this.context)
|
||||
@@ -1332,7 +1263,7 @@ export class Controller {
|
||||
const localCursorRulesToggles =
|
||||
((await getWorkspaceState(this.context, "localCursorRulesToggles")) as ClineRulesToggles) || {}
|
||||
|
||||
const workflowToggles = ((await getWorkspaceState(this.context, "workflowToggles")) as ClineRulesToggles) || {}
|
||||
const localWorkflowToggles = ((await getWorkspaceState(this.context, "workflowToggles")) as ClineRulesToggles) || {}
|
||||
|
||||
return {
|
||||
version: this.context.extension?.packageJSON?.version ?? "",
|
||||
@@ -1361,7 +1292,8 @@ export class Controller {
|
||||
localClineRulesToggles: localClineRulesToggles || {},
|
||||
localWindsurfRulesToggles: localWindsurfRulesToggles || {},
|
||||
localCursorRulesToggles: localCursorRulesToggles || {},
|
||||
workflowToggles: workflowToggles || {},
|
||||
localWorkflowToggles: localWorkflowToggles || {},
|
||||
globalWorkflowToggles: globalWorkflowToggles || {},
|
||||
shellIntegrationTimeout,
|
||||
isNewUser,
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ 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"
|
||||
import { updateMcpTimeout } from "./updateMcpTimeout"
|
||||
|
||||
// Register all mcp service methods
|
||||
@@ -16,7 +18,9 @@ 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)
|
||||
registerMethod("updateMcpTimeout", updateMcpTimeout)
|
||||
}
|
||||
|
||||
@@ -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: [] }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { ToggleToolAutoApproveRequest, McpServers } from "@shared/proto/mcp"
|
||||
import type { Controller } from "../index"
|
||||
import { convertMcpServersToProtoMcpServers } from "@shared/proto-conversions/mcp/mcp-server-conversion"
|
||||
|
||||
/**
|
||||
* Toggles auto-approve setting for MCP server tools
|
||||
* @param controller The controller instance
|
||||
* @param request The toggle tool auto-approve request
|
||||
* @returns Updated list of MCP servers
|
||||
*/
|
||||
export async function toggleToolAutoApprove(controller: Controller, request: ToggleToolAutoApproveRequest): Promise<McpServers> {
|
||||
try {
|
||||
// Call the RPC variant that returns the servers directly
|
||||
const mcpServers =
|
||||
(await controller.mcpHub?.toggleToolAutoApproveRPC(request.serverName, request.toolNames, request.autoApprove)) || []
|
||||
|
||||
// Convert application types to proto types
|
||||
return { mcpServers: convertMcpServersToProtoMcpServers(mcpServers) }
|
||||
} catch (error) {
|
||||
console.error(`Failed to toggle tool auto-approve for ${request.serverName}:`, error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,8 @@ export async function refreshOpenRouterModels(
|
||||
}
|
||||
|
||||
switch (rawModel.id) {
|
||||
case "anthropic/claude-sonnet-4":
|
||||
case "anthropic/claude-opus-4":
|
||||
case "anthropic/claude-3-7-sonnet":
|
||||
case "anthropic/claude-3-7-sonnet:beta":
|
||||
case "anthropic/claude-3.7-sonnet":
|
||||
|
||||
@@ -44,6 +44,11 @@ export async function refreshRequestyModels(
|
||||
models[model.id] = modelInfo
|
||||
}
|
||||
console.log("Requesty models fetched", models)
|
||||
|
||||
controller.postMessageToWebview({
|
||||
type: "requestyModels",
|
||||
requestyModels: models,
|
||||
})
|
||||
} else {
|
||||
console.error("Invalid response from Requesty API")
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import { resetState } from "./resetState"
|
||||
import { subscribeToState } from "./subscribeToState"
|
||||
import { toggleFavoriteModel } from "./toggleFavoriteModel"
|
||||
import { togglePlanActMode } from "./togglePlanActMode"
|
||||
import { updateAutoApprovalSettings } from "./updateAutoApprovalSettings"
|
||||
import { updateTerminalConnectionTimeout } from "./updateTerminalConnectionTimeout"
|
||||
|
||||
// Streaming methods for this service
|
||||
export const streamingMethods = ["subscribeToState"]
|
||||
@@ -20,4 +22,6 @@ export function registerAllMethods(): void {
|
||||
registerMethod("subscribeToState", subscribeToState, { isStreaming: true })
|
||||
registerMethod("toggleFavoriteModel", toggleFavoriteModel)
|
||||
registerMethod("togglePlanActMode", togglePlanActMode)
|
||||
registerMethod("updateAutoApprovalSettings", updateAutoApprovalSettings)
|
||||
registerMethod("updateTerminalConnectionTimeout", updateTerminalConnectionTimeout)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Controller } from ".."
|
||||
import { AutoApprovalSettingsRequest } from "../../../shared/proto/state"
|
||||
import { Empty } from "../../../shared/proto/common"
|
||||
import { convertProtoToAutoApprovalSettings } from "../../../shared/proto-conversions/models/auto-approval-settings-conversion"
|
||||
import { updateGlobalState } from "../../../core/storage/state"
|
||||
|
||||
/**
|
||||
* Updates the auto approval settings
|
||||
* @param controller The controller instance
|
||||
* @param request The auto approval settings request
|
||||
* @returns Empty response
|
||||
*/
|
||||
export async function updateAutoApprovalSettings(controller: Controller, request: AutoApprovalSettingsRequest): Promise<Empty> {
|
||||
const currentSettings = (await controller.getStateToPostToWebview()).autoApprovalSettings
|
||||
const incomingVersion = request.version
|
||||
const currentVersion = currentSettings?.version ?? 1
|
||||
|
||||
// Only update if incoming version is higher
|
||||
if (incomingVersion > currentVersion) {
|
||||
const settings = convertProtoToAutoApprovalSettings(request)
|
||||
|
||||
await updateGlobalState(controller.context, "autoApprovalSettings", settings)
|
||||
|
||||
if (controller.task) {
|
||||
controller.task.autoApprovalSettings = settings
|
||||
}
|
||||
|
||||
await controller.postStateToWebview()
|
||||
}
|
||||
|
||||
return Empty.create()
|
||||
}
|
||||
@@ -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,14 @@
|
||||
// AUTO-GENERATED FILE - DO NOT MODIFY DIRECTLY
|
||||
// Generated by proto/build-proto.js
|
||||
|
||||
// Import all method implementations
|
||||
import { registerMethod } from "./index"
|
||||
import { onDidShowAnnouncement } from "./onDidShowAnnouncement"
|
||||
import { scrollToSettings } from "./scrollToSettings"
|
||||
|
||||
// Register all ui service methods
|
||||
export function registerAllMethods(): void {
|
||||
// Register each method with the registry
|
||||
registerMethod("onDidShowAnnouncement", onDidShowAnnouncement)
|
||||
registerMethod("scrollToSettings", scrollToSettings)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { EmptyRequest, Boolean } from "../../../shared/proto/common"
|
||||
import type { Controller } from "../index"
|
||||
import { getGlobalState, updateGlobalState } from "../../storage/state"
|
||||
|
||||
/**
|
||||
* Marks the current announcement as shown and returns the updated shouldShowAnnouncement value
|
||||
*
|
||||
* @param controller The controller instance
|
||||
* @param _request The empty request (not used)
|
||||
* @returns Boolean indicating whether an announcement should be shown
|
||||
*/
|
||||
export async function onDidShowAnnouncement(controller: Controller, _request: EmptyRequest): Promise<Boolean> {
|
||||
try {
|
||||
// Update the lastShownAnnouncementId to the current latestAnnouncementId
|
||||
await updateGlobalState(controller.context, "lastShownAnnouncementId", controller.latestAnnouncementId)
|
||||
|
||||
// Get the updated lastShownAnnouncementId value after the update
|
||||
const lastShownAnnouncementId = await getGlobalState(controller.context, "lastShownAnnouncementId")
|
||||
|
||||
// Calculate the new shouldShowAnnouncement value
|
||||
// This replicates the same logic used in getStateToPostToWebview()
|
||||
const shouldShowAnnouncement = lastShownAnnouncementId !== controller.latestAnnouncementId
|
||||
|
||||
return { value: shouldShowAnnouncement }
|
||||
} catch (error) {
|
||||
console.error("Failed to acknowledge announcement:", error)
|
||||
return { value: false }
|
||||
}
|
||||
}
|
||||
@@ -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 || "",
|
||||
}
|
||||
}
|
||||
@@ -604,6 +604,7 @@ RULES
|
||||
- Before executing commands, check the "Actively Running Terminals" section in environment_details. If present, consider how these active processes might impact your task. For example, if a local development server is already running, you wouldn't need to start it again. If no active terminals are listed, proceed with command execution as normal.
|
||||
- When using the replace_in_file tool, you must include complete lines in your SEARCH blocks, not partial lines. The system requires exact line matches and cannot match partial lines. For example, if you want to match a line containing "const x = 5;", your SEARCH block must include the entire line, not just "x = 5" or other fragments.
|
||||
- When using the replace_in_file tool, if you use multiple SEARCH/REPLACE blocks, list them in the order they appear in the file. For example if you need to make changes to both line 10 and line 50, first include the SEARCH/REPLACE block for line 10, followed by the SEARCH/REPLACE block for line 50.
|
||||
- When using the replace_in_file tool, Do NOT add extra characters to the markers (e.g., <<<<<<< SEARCH> is INVALID). Do NOT forget to use the closing >>>>>>> REPLACE marker. Do NOT modify the marker format in any way. Malformed XML will cause complete tool failure and break the entire editing process.
|
||||
- It is critical you wait for the user's response after each tool use, in order to confirm the success of the tool use. For example, if asked to make a todo app, you would create a file, wait for the user's response it was created successfully, then create another file if needed, wait for the user's response it was created successfully, etc.${
|
||||
supportsBrowserUse
|
||||
? " Then if you want to test your work, you might use browser_action to launch the site, wait for the user's response confirming the site was launched along with a screenshot, then perhaps e.g., click a button to test functionality if needed, wait for the user's response confirming the button was clicked along with a screenshot of the new state, before finally closing the browser."
|
||||
|
||||
@@ -8,7 +8,8 @@ import fs from "fs/promises"
|
||||
*/
|
||||
export async function parseSlashCommands(
|
||||
text: string,
|
||||
workflowToggles: ClineRulesToggles,
|
||||
localWorkflowToggles: ClineRulesToggles,
|
||||
globalWorkflowToggles: ClineRulesToggles,
|
||||
): Promise<{ processedText: string; needsClinerulesFileCheck: boolean }> {
|
||||
const SUPPORTED_DEFAULT_COMMANDS = ["newtask", "smol", "compact", "newrule", "reportbug"]
|
||||
|
||||
@@ -58,18 +59,29 @@ export async function parseSlashCommands(
|
||||
return { processedText: processedText, needsClinerulesFileCheck: commandName === "newrule" ? true : false }
|
||||
}
|
||||
|
||||
// in practice we want to minimize this work, so we only do it if theres a possible match
|
||||
const enabledWorkflows = Object.entries(workflowToggles)
|
||||
const globalWorkflows = Object.entries(globalWorkflowToggles)
|
||||
.filter(([_, enabled]) => enabled)
|
||||
.map(([filePath, _]) => {
|
||||
const fileName = filePath.replace(/^.*[/\\]/, "")
|
||||
|
||||
return {
|
||||
fullPath: filePath,
|
||||
fileName: fileName,
|
||||
}
|
||||
})
|
||||
|
||||
const localWorkflows = Object.entries(localWorkflowToggles)
|
||||
.filter(([_, enabled]) => enabled)
|
||||
.map(([filePath, _]) => {
|
||||
const fileName = filePath.replace(/^.*[/\\]/, "")
|
||||
return {
|
||||
fullPath: filePath,
|
||||
fileName: fileName,
|
||||
}
|
||||
})
|
||||
|
||||
// local workflows have precedence over global workflows
|
||||
const enabledWorkflows = [...localWorkflows, ...globalWorkflows]
|
||||
|
||||
// Then check if the command matches any enabled workflow filename
|
||||
const matchingWorkflow = enabledWorkflows.find((workflow) => workflow.fileName === commandName)
|
||||
|
||||
|
||||
@@ -76,6 +76,17 @@ export async function ensureRulesDirectoryExists(): Promise<string> {
|
||||
return clineRulesDir
|
||||
}
|
||||
|
||||
export async function ensureWorkflowsDirectoryExists(): Promise<string> {
|
||||
const userDocumentsPath = await getDocumentsPath()
|
||||
const clineWorkflowsDir = path.join(userDocumentsPath, "Cline", "Workflows")
|
||||
try {
|
||||
await fs.mkdir(clineWorkflowsDir, { recursive: true })
|
||||
} catch (error) {
|
||||
return path.join(os.homedir(), "Documents", "Cline", "Workflows") // in case creating a directory in documents fails for whatever reason (e.g. permissions) - this is fine because we will fail gracefully with a path that does not exist
|
||||
}
|
||||
return clineWorkflowsDir
|
||||
}
|
||||
|
||||
export async function ensureMcpServersDirectoryExists(): Promise<string> {
|
||||
const userDocumentsPath = await getDocumentsPath()
|
||||
const mcpServersDir = path.join(userDocumentsPath, "Cline", "MCP")
|
||||
|
||||
@@ -19,6 +19,7 @@ export type SecretKey =
|
||||
| "authNonce"
|
||||
| "asksageApiKey"
|
||||
| "xaiApiKey"
|
||||
| "nebiusApiKey"
|
||||
| "sambanovaApiKey"
|
||||
|
||||
export type GlobalStateKey =
|
||||
@@ -54,6 +55,7 @@ export type GlobalStateKey =
|
||||
| "openRouterProviderSorting"
|
||||
| "autoApprovalSettings"
|
||||
| "globalClineRulesToggles"
|
||||
| "globalWorkflowToggles"
|
||||
| "browserSettings"
|
||||
| "chatSettings"
|
||||
| "vsCodeLmModelSelector"
|
||||
|
||||
@@ -155,6 +155,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
thinkingBudgetTokens,
|
||||
reasoningEffort,
|
||||
sambanovaApiKey,
|
||||
nebiusApiKey,
|
||||
planActSeparateModelsSettingRaw,
|
||||
favoritedModelIds,
|
||||
globalClineRulesToggles,
|
||||
@@ -162,6 +163,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
shellIntegrationTimeout,
|
||||
enableCheckpointsSettingRaw,
|
||||
mcpMarketplaceEnabledRaw,
|
||||
globalWorkflowToggles,
|
||||
] = await Promise.all([
|
||||
getGlobalState(context, "isNewUser") as Promise<boolean | undefined>,
|
||||
getGlobalState(context, "apiProvider") as Promise<ApiProvider | undefined>,
|
||||
@@ -242,6 +244,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
getGlobalState(context, "thinkingBudgetTokens") as Promise<number | undefined>,
|
||||
getGlobalState(context, "reasoningEffort") as Promise<string | undefined>,
|
||||
getSecret(context, "sambanovaApiKey") as Promise<string | undefined>,
|
||||
getSecret(context, "nebiusApiKey") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planActSeparateModelsSetting") as Promise<boolean | undefined>,
|
||||
getGlobalState(context, "favoritedModelIds") as Promise<string[] | undefined>,
|
||||
getGlobalState(context, "globalClineRulesToggles") as Promise<ClineRulesToggles | undefined>,
|
||||
@@ -249,6 +252,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
getGlobalState(context, "shellIntegrationTimeout") as Promise<number | undefined>,
|
||||
getGlobalState(context, "enableCheckpointsSetting") as Promise<boolean | undefined>,
|
||||
getGlobalState(context, "mcpMarketplaceEnabled") as Promise<boolean | undefined>,
|
||||
getGlobalState(context, "globalWorkflowToggles") as Promise<ClineRulesToggles | undefined>,
|
||||
fetch,
|
||||
])
|
||||
|
||||
@@ -353,6 +357,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
asksageApiUrl,
|
||||
xaiApiKey,
|
||||
sambanovaApiKey,
|
||||
nebiusApiKey,
|
||||
favoritedModelIds,
|
||||
requestTimeoutMs,
|
||||
},
|
||||
@@ -382,6 +387,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
planActSeparateModelsSetting,
|
||||
enableCheckpointsSetting: enableCheckpointsSetting,
|
||||
shellIntegrationTimeout: shellIntegrationTimeout || 4000,
|
||||
globalWorkflowToggles: globalWorkflowToggles || {},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +451,7 @@ export async function updateApiConfiguration(context: vscode.ExtensionContext, a
|
||||
reasoningEffort,
|
||||
clineApiKey,
|
||||
sambanovaApiKey,
|
||||
nebiusApiKey,
|
||||
favoritedModelIds,
|
||||
} = apiConfiguration
|
||||
await updateGlobalState(context, "apiProvider", apiProvider)
|
||||
@@ -505,6 +512,7 @@ export async function updateApiConfiguration(context: vscode.ExtensionContext, a
|
||||
await updateGlobalState(context, "reasoningEffort", reasoningEffort)
|
||||
await storeSecret(context, "clineApiKey", clineApiKey)
|
||||
await storeSecret(context, "sambanovaApiKey", sambanovaApiKey)
|
||||
await storeSecret(context, "nebiusApiKey", nebiusApiKey)
|
||||
await updateGlobalState(context, "favoritedModelIds", favoritedModelIds)
|
||||
await updateGlobalState(context, "requestTimeoutMs", apiConfiguration.requestTimeoutMs)
|
||||
}
|
||||
@@ -534,6 +542,7 @@ export async function resetExtensionState(context: vscode.ExtensionContext) {
|
||||
"asksageApiKey",
|
||||
"xaiApiKey",
|
||||
"sambanovaApiKey",
|
||||
"nebiusApiKey",
|
||||
]
|
||||
for (const key of secretKeys) {
|
||||
await storeSecret(context, key, undefined)
|
||||
|
||||
@@ -4117,7 +4117,7 @@ export class Task {
|
||||
// Track if we need to check clinerulesFile
|
||||
let needsClinerulesFileCheck = false
|
||||
|
||||
const workflowToggles = await refreshWorkflowToggles(this.getContext(), cwd)
|
||||
const { localWorkflowToggles, globalWorkflowToggles } = await refreshWorkflowToggles(this.getContext(), cwd)
|
||||
|
||||
const processUserContent = async () => {
|
||||
// This is a temporary solution to dynamically load context mentions from tool results. It checks for the presence of tags that indicate that the tool was rejected and feedback was provided (see formatToolDeniedFeedback, attemptCompletion, executeCommand, and consecutiveMistakeCount >= 3) or "<answer>" (see askFollowupQuestion), we place all user generated content in these tags so they can effectively be used as markers for when we should parse mentions). However if we allow multiple tools responses in the future, we will need to parse mentions specifically within the user content tags.
|
||||
@@ -4143,7 +4143,8 @@ export class Task {
|
||||
// when parsing slash commands, we still want to allow the user to provide their desired context
|
||||
const { processedText, needsClinerulesFileCheck: needsCheck } = await parseSlashCommands(
|
||||
parsedText,
|
||||
workflowToggles,
|
||||
localWorkflowToggles,
|
||||
globalWorkflowToggles,
|
||||
)
|
||||
|
||||
if (needsCheck) {
|
||||
|
||||
@@ -149,6 +149,8 @@ export class WebviewProvider implements vscode.WebviewViewProvider {
|
||||
this.controller.clearTask()
|
||||
|
||||
this.outputChannel.appendLine("Webview view resolved")
|
||||
|
||||
// Title setting logic removed to allow VSCode to use the container title primarily.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+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)}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import { arePathsEqual } from "@utils/path"
|
||||
import { secondsToMs } from "@utils/time"
|
||||
import { GlobalFileNames } from "@core/storage/disk"
|
||||
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
|
||||
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
|
||||
import { ExtensionMessage } from "@shared/ExtensionMessage"
|
||||
|
||||
// Default timeout for internal MCP data requests in milliseconds; is not the same as the user facing timeout stored as DEFAULT_MCP_TIMEOUT_SECONDS
|
||||
@@ -38,10 +39,10 @@ const DEFAULT_REQUEST_TIMEOUT_MS = 5000
|
||||
export type McpConnection = {
|
||||
server: McpServer
|
||||
client: Client
|
||||
transport: StdioClientTransport | SSEClientTransport
|
||||
transport: StdioClientTransport | SSEClientTransport | StreamableHTTPClientTransport
|
||||
}
|
||||
|
||||
export type McpTransportType = "stdio" | "sse"
|
||||
export type McpTransportType = "stdio" | "sse" | "http"
|
||||
|
||||
export type McpServerConfig = z.infer<typeof ServerConfigSchema>
|
||||
|
||||
@@ -69,7 +70,15 @@ const StdioConfigSchema = BaseConfigSchema.extend({
|
||||
transportType: "stdio" as const,
|
||||
}))
|
||||
|
||||
const ServerConfigSchema = z.union([StdioConfigSchema, SseConfigSchema])
|
||||
const StreamableHTTPConfigSchema = BaseConfigSchema.extend({
|
||||
transportType: z.literal("http"),
|
||||
url: z.string().url(),
|
||||
}).transform((config) => ({
|
||||
...config,
|
||||
transportType: "http" as const,
|
||||
}))
|
||||
|
||||
const ServerConfigSchema = z.union([StdioConfigSchema, SseConfigSchema, StreamableHTTPConfigSchema])
|
||||
|
||||
const McpSettingsSchema = z.object({
|
||||
mcpServers: z.record(ServerConfigSchema),
|
||||
@@ -183,7 +192,7 @@ export class McpHub {
|
||||
|
||||
private async connectToServerRPC(
|
||||
name: string,
|
||||
config: z.infer<typeof StdioConfigSchema> | z.infer<typeof SseConfigSchema>,
|
||||
config: z.infer<typeof StdioConfigSchema> | z.infer<typeof SseConfigSchema> | z.infer<typeof StreamableHTTPConfigSchema>,
|
||||
): Promise<void> {
|
||||
// Remove existing connection if it exists (should never happen, the connection should be deleted beforehand)
|
||||
this.connections = this.connections.filter((conn) => conn.server.name !== name)
|
||||
@@ -200,10 +209,12 @@ export class McpHub {
|
||||
},
|
||||
)
|
||||
|
||||
let transport: StdioClientTransport | SSEClientTransport
|
||||
let transport: StdioClientTransport | SSEClientTransport | StreamableHTTPClientTransport
|
||||
|
||||
if (config.transportType === "sse") {
|
||||
transport = new SSEClientTransport(new URL(config.url), {})
|
||||
} else if (config.transportType === "http") {
|
||||
transport = new StreamableHTTPClientTransport(new URL(config.url), {})
|
||||
} else {
|
||||
transport = new StdioClientTransport({
|
||||
command: config.command,
|
||||
@@ -297,7 +308,7 @@ export class McpHub {
|
||||
|
||||
private async connectToServer(
|
||||
name: string,
|
||||
config: z.infer<typeof StdioConfigSchema> | z.infer<typeof SseConfigSchema>,
|
||||
config: z.infer<typeof StdioConfigSchema> | z.infer<typeof SseConfigSchema> | z.infer<typeof StreamableHTTPConfigSchema>,
|
||||
): Promise<void> {
|
||||
// Remove existing connection if it exists (should never happen, the connection should be deleted beforehand)
|
||||
this.connections = this.connections.filter((conn) => conn.server.name !== name)
|
||||
@@ -314,10 +325,12 @@ export class McpHub {
|
||||
},
|
||||
)
|
||||
|
||||
let transport: StdioClientTransport | SSEClientTransport
|
||||
let transport: StdioClientTransport | SSEClientTransport | StreamableHTTPClientTransport
|
||||
|
||||
if (config.transportType === "sse") {
|
||||
transport = new SSEClientTransport(new URL(config.url), {})
|
||||
} else if (config.transportType === "http") {
|
||||
transport = new StreamableHTTPClientTransport(new URL(config.url), {})
|
||||
} else {
|
||||
transport = new StdioClientTransport({
|
||||
command: config.command,
|
||||
@@ -778,7 +791,7 @@ export class McpHub {
|
||||
console.error(`Failed to parse timeout configuration for server ${serverName}: ${error}`)
|
||||
}
|
||||
|
||||
return await connection.client.request(
|
||||
const result = await connection.client.request(
|
||||
{
|
||||
method: "tools/call",
|
||||
params: {
|
||||
@@ -791,6 +804,63 @@ export class McpHub {
|
||||
timeout,
|
||||
},
|
||||
)
|
||||
|
||||
return {
|
||||
...result,
|
||||
content: result.content ?? [],
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RPC variant of toggleToolAutoApprove that returns the updated servers instead of notifying the webview
|
||||
* @param serverName The name of the MCP server
|
||||
* @param toolNames Array of tool names to toggle auto-approve for
|
||||
* @param shouldAllow Whether to enable or disable auto-approve
|
||||
* @returns Array of updated MCP servers
|
||||
*/
|
||||
async toggleToolAutoApproveRPC(serverName: string, toolNames: string[], shouldAllow: boolean): Promise<McpServer[]> {
|
||||
try {
|
||||
const settingsPath = await this.getMcpSettingsFilePath()
|
||||
const content = await fs.readFile(settingsPath, "utf-8")
|
||||
const config = JSON.parse(content)
|
||||
|
||||
// Initialize autoApprove if it doesn't exist
|
||||
if (!config.mcpServers[serverName].autoApprove) {
|
||||
config.mcpServers[serverName].autoApprove = []
|
||||
}
|
||||
|
||||
const autoApprove = config.mcpServers[serverName].autoApprove
|
||||
for (const toolName of toolNames) {
|
||||
const toolIndex = autoApprove.indexOf(toolName)
|
||||
|
||||
if (shouldAllow && toolIndex === -1) {
|
||||
// Add tool to autoApprove list
|
||||
autoApprove.push(toolName)
|
||||
} else if (!shouldAllow && toolIndex !== -1) {
|
||||
// Remove tool from autoApprove list
|
||||
autoApprove.splice(toolIndex, 1)
|
||||
}
|
||||
}
|
||||
|
||||
await fs.writeFile(settingsPath, JSON.stringify(config, null, 2))
|
||||
|
||||
// Update the tools list to reflect the change
|
||||
const connection = this.connections.find((conn) => conn.server.name === serverName)
|
||||
if (connection && connection.server.tools) {
|
||||
// Update the autoApprove property of each tool in the in-memory server object
|
||||
connection.server.tools = connection.server.tools.map((tool) => ({
|
||||
...tool,
|
||||
autoApprove: autoApprove.includes(tool.name),
|
||||
}))
|
||||
}
|
||||
|
||||
// Return sorted servers without notifying webview
|
||||
const serverOrder = Object.keys(config.mcpServers || {})
|
||||
return this.getSortedMcpServers(serverOrder)
|
||||
} catch (error) {
|
||||
console.error("Failed to update autoApprove settings:", error)
|
||||
throw error // Re-throw to ensure the error is properly handled
|
||||
}
|
||||
}
|
||||
|
||||
async toggleToolAutoApprove(serverName: string, toolNames: string[], shouldAllow: boolean): Promise<void> {
|
||||
|
||||
@@ -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"
|
||||
@@ -143,7 +140,8 @@ export interface ExtensionState {
|
||||
vscMachineId: string
|
||||
globalClineRulesToggles: ClineRulesToggles
|
||||
localClineRulesToggles: ClineRulesToggles
|
||||
workflowToggles: ClineRulesToggles
|
||||
localWorkflowToggles: ClineRulesToggles
|
||||
globalWorkflowToggles: ClineRulesToggles
|
||||
localCursorRulesToggles: ClineRulesToggles
|
||||
localWindsurfRulesToggles: ClineRulesToggles
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ApiConfiguration } from "./api"
|
||||
import { AutoApprovalSettings } from "./AutoApprovalSettings"
|
||||
import { BrowserSettings } from "./BrowserSettings"
|
||||
import { ChatSettings } from "./ChatSettings"
|
||||
import { UserInfo } from "./UserInfo"
|
||||
@@ -14,53 +13,35 @@ export interface WebviewMessage {
|
||||
| "newTask"
|
||||
| "condense"
|
||||
| "reportBug"
|
||||
| "didShowAnnouncement"
|
||||
| "openInBrowser"
|
||||
| "openMention"
|
||||
| "showChatView"
|
||||
| "refreshClineRules"
|
||||
| "openMcpSettings"
|
||||
| "autoApprovalSettings"
|
||||
| "browserRelaunchResult"
|
||||
| "openExtensionSettings"
|
||||
| "requestVsCodeLmModels"
|
||||
| "toggleToolAutoApprove"
|
||||
| "showAccountViewClicked"
|
||||
| "authStateChanged"
|
||||
| "authCallback"
|
||||
| "fetchMcpMarketplace"
|
||||
| "silentlyRefreshMcpMarketplace"
|
||||
| "searchCommits"
|
||||
| "fetchLatestMcpServersFromHub"
|
||||
| "telemetrySetting"
|
||||
| "openSettings"
|
||||
| "invoke"
|
||||
| "updateSettings"
|
||||
| "clearAllTaskHistory"
|
||||
| "fetchUserCreditsData"
|
||||
| "optionsResponse"
|
||||
| "requestTotalTasksSize"
|
||||
| "relaunchChromeDebugMode"
|
||||
| "scrollToSettings"
|
||||
| "searchFiles"
|
||||
| "grpc_request"
|
||||
| "grpc_request_cancel"
|
||||
| "toggleClineRule"
|
||||
| "toggleCursorRule"
|
||||
| "toggleWindsurfRule"
|
||||
| "toggleWorkflow"
|
||||
| "deleteClineRule"
|
||||
| "updateTerminalConnectionTimeout"
|
||||
| "setActiveQuote"
|
||||
|
||||
// | "relaunchChromeDebugMode"
|
||||
text?: string
|
||||
disabled?: boolean
|
||||
apiConfiguration?: ApiConfiguration
|
||||
images?: string[]
|
||||
bool?: boolean
|
||||
number?: number
|
||||
autoApprovalSettings?: AutoApprovalSettings
|
||||
browserSettings?: BrowserSettings
|
||||
chatSettings?: ChatSettings
|
||||
chatContent?: ChatContent
|
||||
|
||||
+189
-6
@@ -19,6 +19,7 @@ export type ApiProvider =
|
||||
| "vscode-lm"
|
||||
| "cline"
|
||||
| "litellm"
|
||||
| "nebius"
|
||||
| "fireworks"
|
||||
| "asksage"
|
||||
| "xai"
|
||||
@@ -81,6 +82,7 @@ export interface ApiHandlerOptions {
|
||||
azureApiVersion?: string
|
||||
vsCodeLmModelSelector?: LanguageModelChatSelector
|
||||
qwenApiLine?: string
|
||||
nebiusApiKey?: string
|
||||
asksageApiUrl?: string
|
||||
asksageApiKey?: string
|
||||
xaiApiKey?: string
|
||||
@@ -136,8 +138,29 @@ export interface OpenAiCompatibleModelInfo extends ModelInfo {
|
||||
// Anthropic
|
||||
// https://docs.anthropic.com/en/docs/about-claude/models // prices updated 2025-01-02
|
||||
export type AnthropicModelId = keyof typeof anthropicModels
|
||||
export const anthropicDefaultModelId: AnthropicModelId = "claude-3-7-sonnet-20250219"
|
||||
export const anthropicDefaultModelId: AnthropicModelId = "claude-sonnet-4-20250514"
|
||||
export const anthropicModels = {
|
||||
"claude-sonnet-4-20250514": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
cacheReadsPrice: 0.3,
|
||||
},
|
||||
"claude-opus-4-20250514": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 15.0,
|
||||
outputPrice: 75.0,
|
||||
cacheWritesPrice: 18.75,
|
||||
cacheReadsPrice: 1.5,
|
||||
},
|
||||
"claude-3-7-sonnet-20250219": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 200_000,
|
||||
@@ -195,8 +218,28 @@ export const anthropicModels = {
|
||||
// AWS Bedrock
|
||||
// https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference.html
|
||||
export type BedrockModelId = keyof typeof bedrockModels
|
||||
export const bedrockDefaultModelId: BedrockModelId = "anthropic.claude-3-7-sonnet-20250219-v1:0"
|
||||
export const bedrockDefaultModelId: BedrockModelId = "anthropic.claude-sonnet-4-20250514-v1:0"
|
||||
export const bedrockModels = {
|
||||
"anthropic.claude-sonnet-4-20250514-v1:0": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
cacheReadsPrice: 0.3,
|
||||
},
|
||||
"anthropic.claude-opus-4-20250514-v1:0": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 15.0,
|
||||
outputPrice: 75.0,
|
||||
cacheWritesPrice: 18.75,
|
||||
cacheReadsPrice: 1.5,
|
||||
},
|
||||
"amazon.nova-premier-v1:0": {
|
||||
maxTokens: 10_000,
|
||||
contextWindow: 1_000_000,
|
||||
@@ -315,7 +358,7 @@ export const bedrockModels = {
|
||||
|
||||
// OpenRouter
|
||||
// https://openrouter.ai/models?order=newest&supported_parameters=tools
|
||||
export const openRouterDefaultModelId = "anthropic/claude-3.7-sonnet" // will always exist in openRouterModels
|
||||
export const openRouterDefaultModelId = "anthropic/claude-sonnet-4" // will always exist in openRouterModels
|
||||
export const openRouterDefaultModelInfo: ModelInfo = {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 200_000,
|
||||
@@ -327,14 +370,34 @@ export const openRouterDefaultModelInfo: ModelInfo = {
|
||||
cacheWritesPrice: 3.75,
|
||||
cacheReadsPrice: 0.3,
|
||||
description:
|
||||
"Claude 3.7 Sonnet is an advanced large language model with improved reasoning, coding, and problem-solving capabilities. It introduces a hybrid reasoning approach, allowing users to choose between rapid responses and extended, step-by-step processing for complex tasks. The model demonstrates notable improvements in coding, particularly in front-end development and full-stack updates, and excels in agentic workflows, where it can autonomously navigate multi-step processes. \n\nClaude 3.7 Sonnet maintains performance parity with its predecessor in standard mode while offering an extended reasoning mode for enhanced accuracy in math, coding, and instruction-following tasks.\n\nRead more at the [blog post here](https://www.anthropic.com/news/claude-3-7-sonnet)",
|
||||
"Claude 4 Sonnet is an advanced large language model with improved reasoning, coding, and problem-solving capabilities. It introduces a hybrid reasoning approach, allowing users to choose between rapid responses and extended, step-by-step processing for complex tasks. The model demonstrates notable improvements in coding, particularly in front-end development and full-stack updates, and excels in agentic workflows, where it can autonomously navigate multi-step processes. \n\nClaude 4 Sonnet maintains performance parity with its predecessor in standard mode while offering an extended reasoning mode for enhanced accuracy in math, coding, and instruction-following tasks.\n\nRead more at the [blog post here](https://www.anthropic.com/news/claude-4)",
|
||||
}
|
||||
// Vertex AI
|
||||
// https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-claude
|
||||
// https://cloud.google.com/vertex-ai/generative-ai/pricing#partner-models
|
||||
export type VertexModelId = keyof typeof vertexModels
|
||||
export const vertexDefaultModelId: VertexModelId = "claude-3-7-sonnet@20250219"
|
||||
export const vertexDefaultModelId: VertexModelId = "claude-sonnet-4@20250514"
|
||||
export const vertexModels = {
|
||||
"claude-sonnet-4@20250514": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
cacheReadsPrice: 0.3,
|
||||
},
|
||||
"claude-opus-4@20250514": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 15.0,
|
||||
outputPrice: 75.0,
|
||||
cacheWritesPrice: 18.75,
|
||||
cacheReadsPrice: 1.5,
|
||||
},
|
||||
"claude-3-7-sonnet@20250219": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 200_000,
|
||||
@@ -483,6 +546,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 +677,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,
|
||||
@@ -1367,7 +1455,7 @@ export const doubaoModels = {
|
||||
// Mistral
|
||||
// https://docs.mistral.ai/getting-started/models/models_overview/
|
||||
export type MistralModelId = keyof typeof mistralModels
|
||||
export const mistralDefaultModelId: MistralModelId = "codestral-2501"
|
||||
export const mistralDefaultModelId: MistralModelId = "devstral-small-2505"
|
||||
export const mistralModels = {
|
||||
"mistral-large-2411": {
|
||||
maxTokens: 131_000,
|
||||
@@ -1457,6 +1545,14 @@ export const mistralModels = {
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 0.9,
|
||||
},
|
||||
"devstral-small-2505": {
|
||||
maxTokens: 128_000,
|
||||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.3,
|
||||
},
|
||||
} as const satisfies Record<string, ModelInfo>
|
||||
|
||||
// LiteLLM
|
||||
@@ -1527,6 +1623,93 @@ export const askSageModels = {
|
||||
},
|
||||
}
|
||||
|
||||
// Nebius AI Studio
|
||||
// https://docs.nebius.com/studio/inference/models
|
||||
export const nebiusModels = {
|
||||
"deepseek-ai/DeepSeek-V3": {
|
||||
maxTokens: 32_000,
|
||||
contextWindow: 96_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.5,
|
||||
outputPrice: 1.5,
|
||||
},
|
||||
"deepseek-ai/DeepSeek-V3-0324-fast": {
|
||||
maxTokens: 128_000,
|
||||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 2,
|
||||
outputPrice: 6,
|
||||
},
|
||||
"deepseek-ai/DeepSeek-R1": {
|
||||
maxTokens: 32_000,
|
||||
contextWindow: 96_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.8,
|
||||
outputPrice: 2.4,
|
||||
},
|
||||
"deepseek-ai/DeepSeek-R1-fast": {
|
||||
maxTokens: 32_000,
|
||||
contextWindow: 96_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 2,
|
||||
outputPrice: 6,
|
||||
},
|
||||
"meta-llama/Llama-3.3-70B-Instruct-fast": {
|
||||
maxTokens: 32_000,
|
||||
contextWindow: 96_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.25,
|
||||
outputPrice: 0.75,
|
||||
},
|
||||
"Qwen/Qwen2.5-32B-Instruct-fast": {
|
||||
maxTokens: 8_192,
|
||||
contextWindow: 32_768,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.13,
|
||||
outputPrice: 0.4,
|
||||
},
|
||||
"Qwen/Qwen2.5-Coder-32B-Instruct-fast": {
|
||||
maxTokens: 128_000,
|
||||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.3,
|
||||
},
|
||||
"Qwen/Qwen3-4B-fast": {
|
||||
maxTokens: 32_000,
|
||||
contextWindow: 41_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.08,
|
||||
outputPrice: 0.24,
|
||||
},
|
||||
"Qwen/Qwen3-30B-A3B-fast": {
|
||||
maxTokens: 32_000,
|
||||
contextWindow: 41_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 0.9,
|
||||
},
|
||||
"Qwen/Qwen3-235B-A22B": {
|
||||
maxTokens: 32_000,
|
||||
contextWindow: 41_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.2,
|
||||
outputPrice: 0.6,
|
||||
},
|
||||
} as const satisfies Record<string, ModelInfo>
|
||||
export type NebiusModelId = keyof typeof nebiusModels
|
||||
export const nebiusDefaultModelId = "Qwen/Qwen2.5-32B-Instruct-fast" satisfies NebiusModelId
|
||||
|
||||
// X AI
|
||||
// https://docs.x.ai/docs/api-reference
|
||||
export type XAIModelId = keyof typeof xaiModels
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { AutoApprovalSettings } from "../../AutoApprovalSettings"
|
||||
import { AutoApprovalSettingsRequest } from "../../proto/state"
|
||||
|
||||
// Converts domain AutoApprovalSettings to proto AutoApprovalSettingsRequest
|
||||
export function convertAutoApprovalSettingsToProto(settings: AutoApprovalSettings): AutoApprovalSettingsRequest {
|
||||
return {
|
||||
metadata: {},
|
||||
version: settings.version,
|
||||
enabled: settings.enabled,
|
||||
actions: {
|
||||
readFiles: settings.actions.readFiles || false,
|
||||
readFilesExternally: settings.actions.readFilesExternally || false,
|
||||
editFiles: settings.actions.editFiles || false,
|
||||
editFilesExternally: settings.actions.editFilesExternally || false,
|
||||
executeSafeCommands: settings.actions.executeSafeCommands || false,
|
||||
executeAllCommands: settings.actions.executeAllCommands || false,
|
||||
useBrowser: settings.actions.useBrowser || false,
|
||||
useMcp: settings.actions.useMcp || false,
|
||||
},
|
||||
maxRequests: settings.maxRequests || 20,
|
||||
enableNotifications: settings.enableNotifications || false,
|
||||
favorites: settings.favorites || [],
|
||||
}
|
||||
}
|
||||
|
||||
// Converts proto AutoApprovalSettingsRequest to domain AutoApprovalSettings
|
||||
export function convertProtoToAutoApprovalSettings(protoSettings: AutoApprovalSettingsRequest): AutoApprovalSettings {
|
||||
return {
|
||||
version: protoSettings.version,
|
||||
enabled: protoSettings.enabled,
|
||||
actions: {
|
||||
readFiles: protoSettings.actions?.readFiles || false,
|
||||
readFilesExternally: protoSettings.actions?.readFilesExternally || false,
|
||||
editFiles: protoSettings.actions?.editFiles || false,
|
||||
editFilesExternally: protoSettings.actions?.editFilesExternally || false,
|
||||
executeSafeCommands: protoSettings.actions?.executeSafeCommands || false,
|
||||
executeAllCommands: protoSettings.actions?.executeAllCommands || false,
|
||||
useBrowser: protoSettings.actions?.useBrowser || false,
|
||||
useMcp: protoSettings.actions?.useMcp || false,
|
||||
},
|
||||
maxRequests: protoSettings.maxRequests || 20,
|
||||
enableNotifications: protoSettings.enableNotifications || false,
|
||||
favorites: protoSettings.favorites || [],
|
||||
}
|
||||
}
|
||||
@@ -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,24 @@ import { Empty, EmptyRequest, Metadata, StringArray, StringRequest } from "./com
|
||||
|
||||
export const protobufPackage = "cline"
|
||||
|
||||
/** Response for refreshRules operation */
|
||||
export interface RefreshedRules {
|
||||
globalClineRulesToggles?: ClineRulesToggles | undefined
|
||||
localClineRulesToggles?: ClineRulesToggles | undefined
|
||||
localCursorRulesToggles?: ClineRulesToggles | undefined
|
||||
localWindsurfRulesToggles?: ClineRulesToggles | undefined
|
||||
workflowToggles?: ClineRulesToggles | undefined
|
||||
}
|
||||
|
||||
/** 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
|
||||
@@ -87,6 +105,288 @@ export interface RuleFile {
|
||||
alreadyExists: boolean
|
||||
}
|
||||
|
||||
/** Request to toggle a Cline rule */
|
||||
export interface ToggleClineRuleRequest {
|
||||
metadata?: Metadata | undefined
|
||||
/** Whether this is a global rule or workspace rule */
|
||||
isGlobal: boolean
|
||||
/** Path to the rule file */
|
||||
rulePath: string
|
||||
/** Whether to enable or disable the rule */
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
/** Maps from filepath to enabled/disabled status, matching app's ClineRulesToggles type */
|
||||
export interface ClineRulesToggles {
|
||||
toggles: { [key: string]: boolean }
|
||||
}
|
||||
|
||||
export interface ClineRulesToggles_TogglesEntry {
|
||||
key: string
|
||||
value: boolean
|
||||
}
|
||||
|
||||
/** Response for toggleClineRule operation */
|
||||
export interface ToggleClineRules {
|
||||
globalClineRulesToggles?: ClineRulesToggles | undefined
|
||||
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 createBaseRefreshedRules(): RefreshedRules {
|
||||
return {
|
||||
globalClineRulesToggles: undefined,
|
||||
localClineRulesToggles: undefined,
|
||||
localCursorRulesToggles: undefined,
|
||||
localWindsurfRulesToggles: undefined,
|
||||
workflowToggles: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
export const RefreshedRules: MessageFns<RefreshedRules> = {
|
||||
encode(message: RefreshedRules, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.globalClineRulesToggles !== undefined) {
|
||||
ClineRulesToggles.encode(message.globalClineRulesToggles, writer.uint32(10).fork()).join()
|
||||
}
|
||||
if (message.localClineRulesToggles !== undefined) {
|
||||
ClineRulesToggles.encode(message.localClineRulesToggles, writer.uint32(18).fork()).join()
|
||||
}
|
||||
if (message.localCursorRulesToggles !== undefined) {
|
||||
ClineRulesToggles.encode(message.localCursorRulesToggles, writer.uint32(26).fork()).join()
|
||||
}
|
||||
if (message.localWindsurfRulesToggles !== undefined) {
|
||||
ClineRulesToggles.encode(message.localWindsurfRulesToggles, writer.uint32(34).fork()).join()
|
||||
}
|
||||
if (message.workflowToggles !== undefined) {
|
||||
ClineRulesToggles.encode(message.workflowToggles, writer.uint32(42).fork()).join()
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): RefreshedRules {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseRefreshedRules()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
message.globalClineRulesToggles = ClineRulesToggles.decode(reader, reader.uint32())
|
||||
continue
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 18) {
|
||||
break
|
||||
}
|
||||
|
||||
message.localClineRulesToggles = ClineRulesToggles.decode(reader, reader.uint32())
|
||||
continue
|
||||
}
|
||||
case 3: {
|
||||
if (tag !== 26) {
|
||||
break
|
||||
}
|
||||
|
||||
message.localCursorRulesToggles = ClineRulesToggles.decode(reader, reader.uint32())
|
||||
continue
|
||||
}
|
||||
case 4: {
|
||||
if (tag !== 34) {
|
||||
break
|
||||
}
|
||||
|
||||
message.localWindsurfRulesToggles = ClineRulesToggles.decode(reader, reader.uint32())
|
||||
continue
|
||||
}
|
||||
case 5: {
|
||||
if (tag !== 42) {
|
||||
break
|
||||
}
|
||||
|
||||
message.workflowToggles = ClineRulesToggles.decode(reader, reader.uint32())
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): RefreshedRules {
|
||||
return {
|
||||
globalClineRulesToggles: isSet(object.globalClineRulesToggles)
|
||||
? ClineRulesToggles.fromJSON(object.globalClineRulesToggles)
|
||||
: undefined,
|
||||
localClineRulesToggles: isSet(object.localClineRulesToggles)
|
||||
? ClineRulesToggles.fromJSON(object.localClineRulesToggles)
|
||||
: undefined,
|
||||
localCursorRulesToggles: isSet(object.localCursorRulesToggles)
|
||||
? ClineRulesToggles.fromJSON(object.localCursorRulesToggles)
|
||||
: undefined,
|
||||
localWindsurfRulesToggles: isSet(object.localWindsurfRulesToggles)
|
||||
? ClineRulesToggles.fromJSON(object.localWindsurfRulesToggles)
|
||||
: undefined,
|
||||
workflowToggles: isSet(object.workflowToggles) ? ClineRulesToggles.fromJSON(object.workflowToggles) : undefined,
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: RefreshedRules): unknown {
|
||||
const obj: any = {}
|
||||
if (message.globalClineRulesToggles !== undefined) {
|
||||
obj.globalClineRulesToggles = ClineRulesToggles.toJSON(message.globalClineRulesToggles)
|
||||
}
|
||||
if (message.localClineRulesToggles !== undefined) {
|
||||
obj.localClineRulesToggles = ClineRulesToggles.toJSON(message.localClineRulesToggles)
|
||||
}
|
||||
if (message.localCursorRulesToggles !== undefined) {
|
||||
obj.localCursorRulesToggles = ClineRulesToggles.toJSON(message.localCursorRulesToggles)
|
||||
}
|
||||
if (message.localWindsurfRulesToggles !== undefined) {
|
||||
obj.localWindsurfRulesToggles = ClineRulesToggles.toJSON(message.localWindsurfRulesToggles)
|
||||
}
|
||||
if (message.workflowToggles !== undefined) {
|
||||
obj.workflowToggles = ClineRulesToggles.toJSON(message.workflowToggles)
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<RefreshedRules>, I>>(base?: I): RefreshedRules {
|
||||
return RefreshedRules.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<RefreshedRules>, I>>(object: I): RefreshedRules {
|
||||
const message = createBaseRefreshedRules()
|
||||
message.globalClineRulesToggles =
|
||||
object.globalClineRulesToggles !== undefined && object.globalClineRulesToggles !== null
|
||||
? ClineRulesToggles.fromPartial(object.globalClineRulesToggles)
|
||||
: undefined
|
||||
message.localClineRulesToggles =
|
||||
object.localClineRulesToggles !== undefined && object.localClineRulesToggles !== null
|
||||
? ClineRulesToggles.fromPartial(object.localClineRulesToggles)
|
||||
: undefined
|
||||
message.localCursorRulesToggles =
|
||||
object.localCursorRulesToggles !== undefined && object.localCursorRulesToggles !== null
|
||||
? ClineRulesToggles.fromPartial(object.localCursorRulesToggles)
|
||||
: undefined
|
||||
message.localWindsurfRulesToggles =
|
||||
object.localWindsurfRulesToggles !== undefined && object.localWindsurfRulesToggles !== null
|
||||
? ClineRulesToggles.fromPartial(object.localWindsurfRulesToggles)
|
||||
: undefined
|
||||
message.workflowToggles =
|
||||
object.workflowToggles !== undefined && object.workflowToggles !== null
|
||||
? ClineRulesToggles.fromPartial(object.workflowToggles)
|
||||
: undefined
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
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: [] }
|
||||
}
|
||||
@@ -900,6 +1200,449 @@ export const RuleFile: MessageFns<RuleFile> = {
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseToggleClineRuleRequest(): ToggleClineRuleRequest {
|
||||
return { metadata: undefined, isGlobal: false, rulePath: "", enabled: false }
|
||||
}
|
||||
|
||||
export const ToggleClineRuleRequest: MessageFns<ToggleClineRuleRequest> = {
|
||||
encode(message: ToggleClineRuleRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.metadata !== undefined) {
|
||||
Metadata.encode(message.metadata, writer.uint32(10).fork()).join()
|
||||
}
|
||||
if (message.isGlobal !== false) {
|
||||
writer.uint32(16).bool(message.isGlobal)
|
||||
}
|
||||
if (message.rulePath !== "") {
|
||||
writer.uint32(26).string(message.rulePath)
|
||||
}
|
||||
if (message.enabled !== false) {
|
||||
writer.uint32(32).bool(message.enabled)
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): ToggleClineRuleRequest {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseToggleClineRuleRequest()
|
||||
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 !== 16) {
|
||||
break
|
||||
}
|
||||
|
||||
message.isGlobal = reader.bool()
|
||||
continue
|
||||
}
|
||||
case 3: {
|
||||
if (tag !== 26) {
|
||||
break
|
||||
}
|
||||
|
||||
message.rulePath = reader.string()
|
||||
continue
|
||||
}
|
||||
case 4: {
|
||||
if (tag !== 32) {
|
||||
break
|
||||
}
|
||||
|
||||
message.enabled = reader.bool()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): ToggleClineRuleRequest {
|
||||
return {
|
||||
metadata: isSet(object.metadata) ? Metadata.fromJSON(object.metadata) : undefined,
|
||||
isGlobal: isSet(object.isGlobal) ? globalThis.Boolean(object.isGlobal) : false,
|
||||
rulePath: isSet(object.rulePath) ? globalThis.String(object.rulePath) : "",
|
||||
enabled: isSet(object.enabled) ? globalThis.Boolean(object.enabled) : false,
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: ToggleClineRuleRequest): unknown {
|
||||
const obj: any = {}
|
||||
if (message.metadata !== undefined) {
|
||||
obj.metadata = Metadata.toJSON(message.metadata)
|
||||
}
|
||||
if (message.isGlobal !== false) {
|
||||
obj.isGlobal = message.isGlobal
|
||||
}
|
||||
if (message.rulePath !== "") {
|
||||
obj.rulePath = message.rulePath
|
||||
}
|
||||
if (message.enabled !== false) {
|
||||
obj.enabled = message.enabled
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<ToggleClineRuleRequest>, I>>(base?: I): ToggleClineRuleRequest {
|
||||
return ToggleClineRuleRequest.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<ToggleClineRuleRequest>, I>>(object: I): ToggleClineRuleRequest {
|
||||
const message = createBaseToggleClineRuleRequest()
|
||||
message.metadata =
|
||||
object.metadata !== undefined && object.metadata !== null ? Metadata.fromPartial(object.metadata) : undefined
|
||||
message.isGlobal = object.isGlobal ?? false
|
||||
message.rulePath = object.rulePath ?? ""
|
||||
message.enabled = object.enabled ?? false
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseClineRulesToggles(): ClineRulesToggles {
|
||||
return { toggles: {} }
|
||||
}
|
||||
|
||||
export const ClineRulesToggles: MessageFns<ClineRulesToggles> = {
|
||||
encode(message: ClineRulesToggles, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
Object.entries(message.toggles).forEach(([key, value]) => {
|
||||
ClineRulesToggles_TogglesEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join()
|
||||
})
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): ClineRulesToggles {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseClineRulesToggles()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
const entry1 = ClineRulesToggles_TogglesEntry.decode(reader, reader.uint32())
|
||||
if (entry1.value !== undefined) {
|
||||
message.toggles[entry1.key] = entry1.value
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): ClineRulesToggles {
|
||||
return {
|
||||
toggles: isObject(object.toggles)
|
||||
? Object.entries(object.toggles).reduce<{ [key: string]: boolean }>((acc, [key, value]) => {
|
||||
acc[key] = Boolean(value)
|
||||
return acc
|
||||
}, {})
|
||||
: {},
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: ClineRulesToggles): unknown {
|
||||
const obj: any = {}
|
||||
if (message.toggles) {
|
||||
const entries = Object.entries(message.toggles)
|
||||
if (entries.length > 0) {
|
||||
obj.toggles = {}
|
||||
entries.forEach(([k, v]) => {
|
||||
obj.toggles[k] = v
|
||||
})
|
||||
}
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<ClineRulesToggles>, I>>(base?: I): ClineRulesToggles {
|
||||
return ClineRulesToggles.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<ClineRulesToggles>, I>>(object: I): ClineRulesToggles {
|
||||
const message = createBaseClineRulesToggles()
|
||||
message.toggles = Object.entries(object.toggles ?? {}).reduce<{ [key: string]: boolean }>((acc, [key, value]) => {
|
||||
if (value !== undefined) {
|
||||
acc[key] = globalThis.Boolean(value)
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseClineRulesToggles_TogglesEntry(): ClineRulesToggles_TogglesEntry {
|
||||
return { key: "", value: false }
|
||||
}
|
||||
|
||||
export const ClineRulesToggles_TogglesEntry: MessageFns<ClineRulesToggles_TogglesEntry> = {
|
||||
encode(message: ClineRulesToggles_TogglesEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.key !== "") {
|
||||
writer.uint32(10).string(message.key)
|
||||
}
|
||||
if (message.value !== false) {
|
||||
writer.uint32(16).bool(message.value)
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): ClineRulesToggles_TogglesEntry {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseClineRulesToggles_TogglesEntry()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
message.key = reader.string()
|
||||
continue
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 16) {
|
||||
break
|
||||
}
|
||||
|
||||
message.value = reader.bool()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): ClineRulesToggles_TogglesEntry {
|
||||
return {
|
||||
key: isSet(object.key) ? globalThis.String(object.key) : "",
|
||||
value: isSet(object.value) ? globalThis.Boolean(object.value) : false,
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: ClineRulesToggles_TogglesEntry): unknown {
|
||||
const obj: any = {}
|
||||
if (message.key !== "") {
|
||||
obj.key = message.key
|
||||
}
|
||||
if (message.value !== false) {
|
||||
obj.value = message.value
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<ClineRulesToggles_TogglesEntry>, I>>(base?: I): ClineRulesToggles_TogglesEntry {
|
||||
return ClineRulesToggles_TogglesEntry.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<ClineRulesToggles_TogglesEntry>, I>>(object: I): ClineRulesToggles_TogglesEntry {
|
||||
const message = createBaseClineRulesToggles_TogglesEntry()
|
||||
message.key = object.key ?? ""
|
||||
message.value = object.value ?? false
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseToggleClineRules(): ToggleClineRules {
|
||||
return { globalClineRulesToggles: undefined, localClineRulesToggles: undefined }
|
||||
}
|
||||
|
||||
export const ToggleClineRules: MessageFns<ToggleClineRules> = {
|
||||
encode(message: ToggleClineRules, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.globalClineRulesToggles !== undefined) {
|
||||
ClineRulesToggles.encode(message.globalClineRulesToggles, writer.uint32(10).fork()).join()
|
||||
}
|
||||
if (message.localClineRulesToggles !== undefined) {
|
||||
ClineRulesToggles.encode(message.localClineRulesToggles, writer.uint32(18).fork()).join()
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): ToggleClineRules {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseToggleClineRules()
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32()
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break
|
||||
}
|
||||
|
||||
message.globalClineRulesToggles = ClineRulesToggles.decode(reader, reader.uint32())
|
||||
continue
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 18) {
|
||||
break
|
||||
}
|
||||
|
||||
message.localClineRulesToggles = ClineRulesToggles.decode(reader, reader.uint32())
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): ToggleClineRules {
|
||||
return {
|
||||
globalClineRulesToggles: isSet(object.globalClineRulesToggles)
|
||||
? ClineRulesToggles.fromJSON(object.globalClineRulesToggles)
|
||||
: undefined,
|
||||
localClineRulesToggles: isSet(object.localClineRulesToggles)
|
||||
? ClineRulesToggles.fromJSON(object.localClineRulesToggles)
|
||||
: undefined,
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: ToggleClineRules): unknown {
|
||||
const obj: any = {}
|
||||
if (message.globalClineRulesToggles !== undefined) {
|
||||
obj.globalClineRulesToggles = ClineRulesToggles.toJSON(message.globalClineRulesToggles)
|
||||
}
|
||||
if (message.localClineRulesToggles !== undefined) {
|
||||
obj.localClineRulesToggles = ClineRulesToggles.toJSON(message.localClineRulesToggles)
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<ToggleClineRules>, I>>(base?: I): ToggleClineRules {
|
||||
return ToggleClineRules.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<ToggleClineRules>, I>>(object: I): ToggleClineRules {
|
||||
const message = createBaseToggleClineRules()
|
||||
message.globalClineRulesToggles =
|
||||
object.globalClineRulesToggles !== undefined && object.globalClineRulesToggles !== null
|
||||
? ClineRulesToggles.fromPartial(object.globalClineRulesToggles)
|
||||
: undefined
|
||||
message.localClineRulesToggles =
|
||||
object.localClineRulesToggles !== undefined && object.localClineRulesToggles !== null
|
||||
? ClineRulesToggles.fromPartial(object.localClineRulesToggles)
|
||||
: undefined
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
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 = {
|
||||
@@ -933,6 +1676,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",
|
||||
@@ -987,6 +1739,42 @@ export const FileServiceDefinition = {
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
/** Toggle a Cline rule (enable or disable) */
|
||||
toggleClineRule: {
|
||||
name: "toggleClineRule",
|
||||
requestType: ToggleClineRuleRequest,
|
||||
requestStream: false,
|
||||
responseType: ToggleClineRules,
|
||||
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: {},
|
||||
},
|
||||
/** Refreshes all rule toggles (Cline, External, and Workflows) */
|
||||
refreshRules: {
|
||||
name: "refreshRules",
|
||||
requestType: EmptyRequest,
|
||||
requestStream: false,
|
||||
responseType: RefreshedRules,
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
@@ -1007,6 +1795,10 @@ export type Exact<P, I extends P> = P extends Builtin
|
||||
? P
|
||||
: P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never }
|
||||
|
||||
function isObject(value: any): boolean {
|
||||
return typeof value === "object" && value !== null
|
||||
}
|
||||
|
||||
function isSet(value: any): boolean {
|
||||
return value !== null && value !== undefined
|
||||
}
|
||||
|
||||
+571
-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"
|
||||
|
||||
@@ -71,6 +71,13 @@ export interface AddRemoteMcpServerRequest {
|
||||
serverUrl: string
|
||||
}
|
||||
|
||||
export interface ToggleToolAutoApproveRequest {
|
||||
metadata?: Metadata | undefined
|
||||
serverName: string
|
||||
toolNames: string[]
|
||||
autoApprove: boolean
|
||||
}
|
||||
|
||||
export interface McpTool {
|
||||
name: string
|
||||
description?: string | undefined
|
||||
@@ -108,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 }
|
||||
}
|
||||
@@ -387,6 +419,115 @@ export const AddRemoteMcpServerRequest: MessageFns<AddRemoteMcpServerRequest> =
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseToggleToolAutoApproveRequest(): ToggleToolAutoApproveRequest {
|
||||
return { metadata: undefined, serverName: "", toolNames: [], autoApprove: false }
|
||||
}
|
||||
|
||||
export const ToggleToolAutoApproveRequest: MessageFns<ToggleToolAutoApproveRequest> = {
|
||||
encode(message: ToggleToolAutoApproveRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.metadata !== undefined) {
|
||||
Metadata.encode(message.metadata, writer.uint32(10).fork()).join()
|
||||
}
|
||||
if (message.serverName !== "") {
|
||||
writer.uint32(18).string(message.serverName)
|
||||
}
|
||||
for (const v of message.toolNames) {
|
||||
writer.uint32(26).string(v!)
|
||||
}
|
||||
if (message.autoApprove !== false) {
|
||||
writer.uint32(32).bool(message.autoApprove)
|
||||
}
|
||||
return writer
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): ToggleToolAutoApproveRequest {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
|
||||
let end = length === undefined ? reader.len : reader.pos + length
|
||||
const message = createBaseToggleToolAutoApproveRequest()
|
||||
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.serverName = reader.string()
|
||||
continue
|
||||
}
|
||||
case 3: {
|
||||
if (tag !== 26) {
|
||||
break
|
||||
}
|
||||
|
||||
message.toolNames.push(reader.string())
|
||||
continue
|
||||
}
|
||||
case 4: {
|
||||
if (tag !== 32) {
|
||||
break
|
||||
}
|
||||
|
||||
message.autoApprove = reader.bool()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break
|
||||
}
|
||||
reader.skip(tag & 7)
|
||||
}
|
||||
return message
|
||||
},
|
||||
|
||||
fromJSON(object: any): ToggleToolAutoApproveRequest {
|
||||
return {
|
||||
metadata: isSet(object.metadata) ? Metadata.fromJSON(object.metadata) : undefined,
|
||||
serverName: isSet(object.serverName) ? globalThis.String(object.serverName) : "",
|
||||
toolNames: globalThis.Array.isArray(object?.toolNames) ? object.toolNames.map((e: any) => globalThis.String(e)) : [],
|
||||
autoApprove: isSet(object.autoApprove) ? globalThis.Boolean(object.autoApprove) : false,
|
||||
}
|
||||
},
|
||||
|
||||
toJSON(message: ToggleToolAutoApproveRequest): unknown {
|
||||
const obj: any = {}
|
||||
if (message.metadata !== undefined) {
|
||||
obj.metadata = Metadata.toJSON(message.metadata)
|
||||
}
|
||||
if (message.serverName !== "") {
|
||||
obj.serverName = message.serverName
|
||||
}
|
||||
if (message.toolNames?.length) {
|
||||
obj.toolNames = message.toolNames
|
||||
}
|
||||
if (message.autoApprove !== false) {
|
||||
obj.autoApprove = message.autoApprove
|
||||
}
|
||||
return obj
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<ToggleToolAutoApproveRequest>, I>>(base?: I): ToggleToolAutoApproveRequest {
|
||||
return ToggleToolAutoApproveRequest.fromPartial(base ?? ({} as any))
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<ToggleToolAutoApproveRequest>, I>>(object: I): ToggleToolAutoApproveRequest {
|
||||
const message = createBaseToggleToolAutoApproveRequest()
|
||||
message.metadata =
|
||||
object.metadata !== undefined && object.metadata !== null ? Metadata.fromPartial(object.metadata) : undefined
|
||||
message.serverName = object.serverName ?? ""
|
||||
message.toolNames = object.toolNames?.map((e) => e) || []
|
||||
message.autoApprove = object.autoApprove ?? false
|
||||
return message
|
||||
},
|
||||
}
|
||||
|
||||
function createBaseMcpTool(): McpTool {
|
||||
return { name: "", description: undefined, inputSchema: undefined, autoApprove: undefined }
|
||||
}
|
||||
@@ -975,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",
|
||||
@@ -1028,6 +1582,22 @@ export const McpServiceDefinition = {
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
toggleToolAutoApprove: {
|
||||
name: "toggleToolAutoApprove",
|
||||
requestType: ToggleToolAutoApproveRequest,
|
||||
requestStream: false,
|
||||
responseType: McpServers,
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
refreshMcpMarketplace: {
|
||||
name: "refreshMcpMarketplace",
|
||||
requestType: EmptyRequest,
|
||||
requestStream: false,
|
||||
responseType: McpMarketplaceCatalog,
|
||||
responseStream: false,
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user