Compare commits

..

2 Commits

Author SHA1 Message Date
abeatrix 6f07dcd53b changeset 2025-07-16 23:51:14 -07:00
abeatrix 3abc882dde Handle auth state changes in all extension windows
Addresses an issue where authentication state changes (login/logout) were not being properly propagated across all extension windows.

The `onDidChange` event handler for `clineAccountId` secret now checks if the secret was added/updated (login) or removed (logout).

- If the secret exists, `restoreRefreshTokenAndRetrieveAuthInfo` is called to restore auth info (login from another window).
- If the secret is removed, `handleDeauth` is called to handle logout for all windows.

This ensures that all extension windows are kept in sync with the current authentication state.
2025-07-16 23:48:10 -07:00
1084 changed files with 83651 additions and 97728 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
Improve the Claude Code error messages
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
Handle auth state changes in all extension windows
+1 -1
View File
@@ -716,7 +716,7 @@ The Controller class manages MCP servers through the McpHub service:
class Controller {
mcpHub?: McpHub
constructor(context: vscode.ExtensionContext, webviewProvider: WebviewProvider) {
constructor(context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel, webviewProvider: WebviewProvider) {
this.mcpHub = new McpHub(this)
}
+21 -7
View File
@@ -6,14 +6,28 @@ Analyze the current branch's changes against main to provide informed insights a
## Step 1: Gather Git Information
<important>Do not return any text or conversation other than what is necessary to run these commands</important>
**Run the following command to get the latest changes (bash):**
```bash
B=$(for c in main master origin/main origin/master; do git rev-parse --verify -q "$c" >/dev/null && echo "$c" && break; done); B=${B:-HEAD}; r(){ git branch --show-current; printf "=== STATUS ===\n"; git status --porcelain | cat; printf "=== COMMIT MESSAGES ===\n"; git log "$B"..HEAD --oneline | cat; printf "=== CHANGED FILES ===\n"; git diff "$B" --name-only | cat; printf "=== FULL DIFF ===\n"; git diff "$B" | cat; }; L=$(r | wc -l); if [ "$L" -gt 500 ]; then r > cline-git-analysis.temp && echo "::OUTPUT_FILE=cline-git-analysis.temp"; else r; fi
```
**First, check the expected output size:**
```shell
(git branch --show-current && echo "=== STATUS ===" && git status --porcelain | cat && echo "=== COMMIT MESSAGES ===" && git log main..HEAD --oneline | cat && echo "=== CHANGED FILES ===" && git diff main --name-only | cat && echo "=== FULL DIFF ===" && git diff main | cat) | wc -l
```
```powershell
$B=$null;foreach($c in 'main','master','origin/main','origin/master'){git rev-parse --verify -q $c *> $null;if($LASTEXITCODE -eq 0){$B=$c;break}};if(-not $B){$B='HEAD'};function r([string]$b){git rev-parse --abbrev-ref HEAD; '=== STATUS ==='; git status --porcelain | cat; '=== COMMIT MESSAGES ==='; git log "$b"..HEAD --oneline | cat; '=== CHANGED FILES ==='; git diff "$b" --name-only | cat; '=== FULL DIFF ==='; git diff "$b" | cat};$out=r $B|Out-String;$lines=($out -split "`r?`n").Count;if($lines -gt 500){$out|Set-Content -NoNewline cline-git-analysis.temp; '::OUTPUT_FILE=cline-git-analysis.temp'}else{$out}
```
**If the expected line count is greater than 500 lines, use the file-based approach:**
```shell
git branch --show-current > cline-git-analysis.temp && echo "=== STATUS ===" >> cline-git-analysis.temp && git status --porcelain >> cline-git-analysis.temp && echo "=== COMMIT MESSAGES ===" >> cline-git-analysis.temp && git log main..HEAD --oneline >> cline-git-analysis.temp && echo "=== CHANGED FILES ===" >> cline-git-analysis.temp && git diff main --name-only >> cline-git-analysis.temp && echo "=== FULL DIFF ===" >> cline-git-analysis.temp && git diff main >> cline-git-analysis.temp
```
Then, read the file using the read_file tool. After you have read the file but before you proceed with subsequent steps, delete it:
```shell
rm cline-git-analysis.temp
```
**If the expected line count is 500 lines or fewer, use the direct approach:**
```shell
git branch --show-current && echo "=== STATUS ===" && git status --porcelain | cat && echo "=== COMMIT MESSAGES ===" && git log main..HEAD --oneline | cat && echo "=== CHANGED FILES ===" && git diff main --name-only | cat && echo "=== FULL DIFF ===" && git diff main | cat
```
<important>If using the direct approach, pipe outputs through `cat` to avoid interactive terminals. If the user's shell is not bash/zsh, adjust the command and chaining
syntax accordingly.</important>
## Step 2: Silent, Structured Analysis Phase
- Analyze all git output without providing commentary or narration
-3
View File
@@ -219,9 +219,6 @@ EOF
## Basic PR Commands
```bash
# Get current PR number
gh pr view --json number -q .number
# List open PRs
gh pr list
+6
View File
@@ -0,0 +1,6 @@
[codespell]
# Ref: https://github.com/codespell-project/codespell#using-a-config-file
skip = .git*,*.svg,package-lock.json,*.css,.codespellrc,locales
check-hidden = true
ignore-regex = (\b(optIn|isTaller)\b|https://\S+)
# ignore-words-list =
+35
View File
@@ -0,0 +1,35 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
},
"plugins": ["@typescript-eslint", "eslint-rules"],
"rules": {
"@typescript-eslint/naming-convention": [
"warn",
{
"selector": "import",
"format": ["camelCase", "PascalCase"]
}
],
"@typescript-eslint/semi": "off",
"curly": "warn",
"eqeqeq": "warn",
"no-throw-literal": "warn",
"semi": "off",
"react-hooks/exhaustive-deps": "off",
"eslint-rules/no-protobuf-object-literals": "error",
"eslint-rules/no-grpc-client-object-literals": "error",
"eslint-rules/no-direct-vscode-api": "warn",
"no-restricted-syntax": [
"error",
{
"selector": "VariableDeclarator[id.type=\"ObjectPattern\"][init.object.name=\"process\"][init.property.name=\"env\"]",
"message": "Use process.env.VARIABLE_NAME directly instead of destructuring"
}
]
},
"ignorePatterns": ["out", "dist", "**/*.d.ts"]
}
+1 -3
View File
@@ -1,3 +1 @@
/docs/
/.github/ @saoudrizwan @garoth @sjf
/README.md @saoudrizwan @nickbaumann98
* @saoudrizwan @ocasta181 @NightTrek @pashpashpash @dcbartlett @saito-sv @Garoth
+67 -66
View File
@@ -1,69 +1,70 @@
name: 🐛 Bug Report
description: File a bug report
labels: ['bug']
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
**Important:** All bug reports must be reproducible using Claude Sonnet 4.5. Cline uses complex prompts so less capable models may not work as expected.
- type: dropdown
id: plugin-type
attributes:
label: Plugin Type
description: Which plugin are you reporting a bug for?
options:
- VSCode Extension
- JetBrains Plugin
default: 0
validations:
required: true
- type: input
id: cline-version
attributes:
label: Cline Version
description: What version of Cline are you using? (You can find this at the bottom of the Settings view)
placeholder: 'e.g., 1.2.3'
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
description: How do you trigger this bug? Please walk us through it step by step.
value: |
1.
2.
3.
validations:
required: false
- type: input
id: provider-model
attributes:
label: Provider/Model
description: What provider and model were you using when the issue occurred?
placeholder: 'e.g., cline:anthropic/claude-sonnet-4.5, gemini:gemini-2.5-pro-exp-03-25'
validations:
required: false
- type: textarea
id: system-info
attributes:
label: System Information
description: What operating system and hardware are you using?
placeholder: |
Operating System: Windows 11, macOS Sonoma, Ubuntu 22.04, etc.
Hardware: CPU, GPU, RAM specifications if relevant
e.g.,
OS: Windows 11
CPU: Intel Core i7-11700K
GPU: NVIDIA GeForce RTX 3070
RAM: 32GB DDR4
validations:
required: false
- type: markdown
attributes:
value: |
**Important:** All bug reports must be reproducible using Claude 3.5 Sonnet. Cline uses complex prompts so less capable models may not work as expected.
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
description: How do you trigger this bug? Please walk us through it step by step.
value: |
1.
2.
3.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant API REQUEST output
description: Please copy and paste any relevant output. This will be automatically formatted into code, so no need for backticks.
render: shell
- type: input
id: provider-model
attributes:
label: Provider/Model
description: What provider and model were you using when the issue occurred?
placeholder: "e.g., cline:anthropic/claude-3.7-sonnet, gemini:gemini-2.5-pro-exp-03-25"
validations:
required: true
- type: input
id: operating-system
attributes:
label: Operating System
description: What operating system are you using?
placeholder: "e.g., Windows 11, macOS Sonoma, Ubuntu 22.04"
validations:
required: true
- type: textarea
id: system-info
attributes:
label: System Info
description: What system information is relevant to the issue?
placeholder: "e.g., CPU: Intel Core i7-11700K, GPU: NVIDIA GeForce RTX 3070, RAM: 32GB DDR4"
validations:
required: true
- type: input
id: cline-version
attributes:
label: Cline Version
description: What version of Cline are you using? (You can find this at the bottom of the Settings view)
placeholder: "e.g., 1.2.3"
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Add any other context about the problem here, such as screenshots or related issues.
@@ -0,0 +1,116 @@
name: 💡 Feature Proposal & Contribution
description: Propose a new feature or improvement, and optionally offer to implement feature as a contributor
labels: ["proposal"]
body:
- type: markdown
attributes:
value: |
**Feature Proposal & Contribution for Cline**
Thank you for proposing a feature or improvement for Cline! This template helps us understand the problem, evaluate the solution, and coordinate implementation.
**For detailed proposals:** Please provide comprehensive information to enable fast prioritization and discussion.
**For contribution offers:** You can indicate your willingness to implement the feature yourself.
Before submitting:
- Search existing [Issues](https://github.com/cline/cline/issues) and [Discussions](https://github.com/cline/cline/discussions) to avoid duplicates
- Read the [Contributing Guide](https://github.com/cline/cline/blob/main/CONTRIBUTING.md) if you plan to contribute
- Don't start implementation until the proposal is reviewed and approved
- type: textarea
id: problem-description
attributes:
label: What problem does this solve?
description: |
Describe the problem clearly from a user's point of view. Focus on why this matters, who it affects, and when it occurs.
✅ Good examples:
- "LLM provider returns 400 error when nearing the context window instead of truncating"
- "Submit button is invisible in dark mode"
- "Users can't easily share their Cline configurations with team members"
❌ Avoid vague descriptions:
- "Performance is bad"
- "UI needs work"
Your description should include:
- Who is affected?
- When does it happen?
- What's the current vs expected behavior?
- What is the impact?
placeholder: Be specific about the problem, who it affects, and the impact.
validations:
required: true
- type: textarea
id: proposed-solution
attributes:
label: What's the proposed solution?
description: |
Describe how the problem should be solved. Be specific about UX, system behavior, and any flows that would change.
✅ Good examples:
- "Add error handling immediately after attempting to create the llm stream and retry after manually truncating"
- "Update button styling to ensure contrast in all themes"
- "Add export/import functionality in settings with JSON format"
❌ Avoid vague solutions:
- "Improve performance"
- "Fix the bug"
Your solution should include:
- What exactly will change?
- How will users interact with it?
- What's the expected outcome?
placeholder: Describe the proposed changes and how they solve the problem.
validations:
required: false
- type: dropdown
id: contribution-intent
attributes:
label: Are you interested in implementing this?
description: Let us know if you'd like to contribute to this feature
options:
- "No, just proposing the idea"
- "Yes, I'd like to implement this myself"
- "Yes, I'd like to collaborate with others"
- "Maybe, depending on complexity and guidance"
validations:
required: false
- type: textarea
id: implementation-approach
attributes:
label: Implementation approach (if contributing)
description: |
**Only fill this out if you selected "Yes" above.**
How do you plan to implement this? Include:
- High-level technical approach
- Files/components that would be affected
- Any new dependencies required
- Potential challenges or considerations you've identified
This helps us provide better guidance and ensures alignment before you start coding.
placeholder: "My implementation approach would be..."
- type: checkboxes
id: checklist
attributes:
label: Proposal checklist
options:
- label: I've checked for existing issues or related proposals
required: true
- label: I understand this needs review before implementation can start
required: true
- type: checkboxes
id: contribution-checklist
attributes:
label: Contribution checklist (if contributing)
description: Only check these if you plan to contribute
options:
- label: I've read the [Contributing Guide](https://github.com/cline/cline/blob/main/CONTRIBUTING.md)
- label: I'm willing to make changes based on feedback
- label: I understand the code review process and requirements
+5 -4
View File
@@ -2,14 +2,15 @@
Thank you for contributing to Cline!
⚠️ Important: Before submitting this PR, please ensure you have:
- For feature requests: Created a discussion in our Feature Requests discussions board https://github.com/cline/cline/discussions/categories/feature-requests and received approval from core maintainers before implementation
- For all changes: Link the associated issue/discussion in the "Related Issue" section below
- Opened an issue and discussed your proposed changes with the community / contributors
- Received approval from a core Cline contributor prior to proceeding with the implementation
- Link the associated issue in the "Related Issue" section
Limited exceptions:
Small bug fixes, typo corrections, minor wording improvements, or simple type fixes that don't change functionality may be submitted directly without prior discussion.
Small bug fixes, typo corrections, minor wording improvements, or simple type fixes that don't change functionality may be submitted directly.
Why this requirement?
We deeply appreciate all community contributions - they are essential to Cline's success! To ensure the best use of everyone's time and maintain project direction, we use our Feature Requests discussions board to gauge community interest and validate feature ideas before implementation begins. This helps us focus development efforts on features that will benefit the most users.
We deeply appreciate all community contributions - they are the core reason we're able to operate successfully and keep innovating! We welcome community input and want to make it as easy as possible for people to submit quality work. This process helps our core maintainers review new ideas faster and saves contributor time by ensuring you have the go-ahead before spending time on implementation.
-->
### Related Issue
+28
View File
@@ -0,0 +1,28 @@
# Codespell configuration is within .codespellrc
---
name: Codespell
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
codespell:
if: false
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Annotate locations with typos
uses: codespell-project/codespell-problem-matcher@v1
- name: Codespell
uses: codespell-project/actions-codespell@v2
with:
only_warn: 1
+6 -26
View File
@@ -56,29 +56,6 @@ jobs:
path: webview-ui/node_modules
key: ${{ runner.os }}-npm-webview-${{ hashFiles('webview-ui/package-lock.json') }}
# Cache VS Code installation
- name: Cache VS Code
uses: actions/cache@v4
id: vscode-cache
with:
path: .vscode-test
key: vscode-${{ runner.os }}-stable-${{ hashFiles('.vscode-test.mjs', 'package.json') }}
restore-keys: |
vscode-${{ runner.os }}-stable-
# Cache Playwright browsers
- name: Cache Playwright browsers
uses: actions/cache@v4
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
~/Library/Caches/ms-playwright
~/AppData/Local/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
restore-keys: |
playwright-browsers-${{ runner.os }}-
- name: Install root dependencies
if: steps.root-cache.outputs.cache-hit != 'true'
run: npm ci
@@ -91,14 +68,17 @@ jobs:
if: matrix.runner == 'ubuntu'
run: sudo apt-get update && sudo apt-get install -y xvfb
# Run optimized E2E tests (eliminates redundant builds)
# Build the extension before running tests
- name: Build Tests and Extension
run: npm run pretest
- name: Run E2E tests - Linux
if: matrix.runner == 'ubuntu'
run: xvfb-run -a npm run test:e2e:optimal
run: xvfb-run -a npm run test:e2e
- name: Run E2E tests - Non-Linux
if: matrix.runner != 'ubuntu'
run: npm run test:e2e:optimal
run: npm run test:e2e
- uses: actions/upload-artifact@v4
if: ${{ failure() }}
-75
View File
@@ -1,75 +0,0 @@
name: "Publish Nightly Release"
on:
schedule:
- cron: '0 12 * * *' # 4 AM PST (UTC-8) = 12 UTC
workflow_dispatch:
permissions:
contents: write
packages: write
checks: write
pull-requests: write
jobs:
test:
uses: ./.github/workflows/test.yml
publish:
needs: test
name: Publish Cline (Nightly) Extension
if: github.repository == 'cline/cline'
runs-on: ubuntu-latest
environment: PublishNightly
steps:
- uses: actions/checkout@v4
- name: Check for recent commits
run: |
if [ $(git rev-list --count HEAD --since="24 hours ago") -eq 0 ]; then
echo "No commits in last 24 hours, exiting"
exit 0
fi
echo "Found recent commits, proceeding with build"
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"
# Cache root dependencies - only reuse if package-lock.json exactly matches
- name: Cache root dependencies
uses: actions/cache@v4
id: root-cache
with:
path: node_modules
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
# Cache webview-ui dependencies - only reuse if package-lock.json exactly matches
- name: Cache webview-ui dependencies
uses: actions/cache@v4
id: webview-cache
with:
path: webview-ui/node_modules
key: ${{ runner.os }}-npm-webview-${{ hashFiles('webview-ui/package-lock.json') }}
- name: Install root dependencies
if: steps.root-cache.outputs.cache-hit != 'true'
run: npm ci --include=optional
- name: Install webview-ui dependencies
if: steps.webview-cache.outputs.cache-hit != 'true'
run: cd webview-ui && npm ci --include=optional
- name: Install Publishing Tools
run: npm install -g @vscode/vsce ovsx
- name: Publish Extension as Pre-release
env:
VSCE_PAT: ${{ secrets.VSCE_PAT }}
OVSX_PAT: ${{ secrets.OVSX_PAT }}
TELEMETRY_SERVICE_API_KEY: ${{ secrets.TELEMETRY_SERVICE_API_KEY }}
ERROR_SERVICE_API_KEY: ${{ secrets.ERROR_SERVICE_API_KEY }}
CLINE_ENVIRONMENT: production
run: npm run publish:marketplace:nightly
+1 -4
View File
@@ -94,12 +94,9 @@ jobs:
env:
VSCE_PAT: ${{ secrets.VSCE_PAT }}
OVSX_PAT: ${{ secrets.OVSX_PAT }}
CLINE_ENVIRONMENT: production
TELEMETRY_SERVICE_API_KEY: ${{ secrets.TELEMETRY_SERVICE_API_KEY }}
ERROR_SERVICE_API_KEY: ${{ secrets.ERROR_SERVICE_API_KEY }}
run: |
# Required to generate the .vsix
vsce package --allow-package-secrets sendgrid --out "cline-${{ steps.get_version.outputs.version }}.vsix"
vsce package --out "cline-${{ steps.get_version.outputs.version }}.vsix"
if [ "${{ github.event.inputs.release-type }}" = "pre-release" ]; then
npm run publish:marketplace:prerelease
+113 -154
View File
@@ -1,9 +1,6 @@
name: Tests
on:
push:
branches:
- main
workflow_dispatch:
pull_request:
branches:
@@ -17,45 +14,7 @@ permissions:
pull-requests: write # Needed to add comments/annotations to PRs
jobs:
quality-checks:
runs-on: ubuntu-latest
name: Quality Checks
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: 22
- name: Cache root dependencies
uses: actions/cache@v4
id: root-cache
with:
path: node_modules
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
- name: Cache webview-ui dependencies
uses: actions/cache@v4
id: webview-cache
with:
path: webview-ui/node_modules
key: ${{ runner.os }}-npm-webview-${{ hashFiles('webview-ui/package-lock.json') }}
- name: Install root dependencies
if: steps.root-cache.outputs.cache-hit != 'true'
run: npm ci
- name: Install webview-ui dependencies
if: steps.webview-cache.outputs.cache-hit != 'true'
run: cd webview-ui && npm ci
- name: Run Quality Checks (Parallel)
run: npm run ci:check-all
test:
needs: quality-checks
strategy:
fail-fast: false
matrix:
@@ -74,6 +33,18 @@ jobs:
with:
node-version: 22
# Setup Python for coverage script
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install requests
# Cache root dependencies - only reuse if package-lock.json exactly matches
- name: Cache root dependencies
uses: actions/cache@v4
id: root-cache
@@ -81,6 +52,7 @@ jobs:
path: node_modules
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
# Cache webview-ui dependencies - only reuse if package-lock.json exactly matches
- name: Cache webview-ui dependencies
uses: actions/cache@v4
id: webview-cache
@@ -96,60 +68,61 @@ jobs:
if: steps.webview-cache.outputs.cache-hit != 'true'
run: cd webview-ui && npm ci
- name: Install xvfb on Linux
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y xvfb
- name: Install local modules on windows
if: runner.os == 'Windows' && steps.root-cache.outputs.cache-hit == 'true'
run: |
npm install eslint-plugin-eslint-rules
cd webview-ui/ && npm install eslint-plugin-eslint-rules
- name: Set up NPM on Windows
if: runner.os == 'Windows'
run: |
npm config set script-shell "C:\\Program Files\\Git\\bin\\bash.exe"
# Build the extension and tests (without redundant checks)
- name: Type Check
run: npm run check-types
- name: ESLint Check
run: npm run lint
- name: Prettier / Format Check
run: npm run format
# Build the extension before running tests
- name: Build Tests and Extension
run: npm run ci:build
run: npm run pretest
- name: Unit Tests with coverage - Linux
id: unit_tests_linux
# Unit Tests disabled due to module system conflicts between backend and webview-ui
# - name: Unit Tests
# run: npm run test:unit
# Run extension tests with coverage
- name: Extension Tests with Coverage
id: extension_coverage
continue-on-error: true
if: runner.os == 'Linux'
run: |
npx nyc --nycrc-path .nycrc.unit.json --reporter=lcov npm run test:unit
- name: Unit Tests - Non-Linux
id: unit_tests_non_linux
continue-on-error: true
if: runner.os != 'Linux'
run: |
npm run test:unit
- name: Extension Integration Tests - Linux
id: integration_tests_linux
continue-on-error: true
if: runner.os == 'Linux'
run: xvfb-run -a npm run test:coverage
- name: Extension Integration Tests - Non-Linux
id: integration_tests_non_linux
continue-on-error: true
if: runner.os != 'Linux'
run: npm run test:integration
node ./scripts/test-ci.js > extension_coverage.txt 2>&1
# Default the encoding to UTF-8 - It's not the default on Windows
PYTHONUTF8=1 PYTHONPATH=.github/scripts python -m coverage_check extract-coverage extension_coverage.txt --type=extension --github-output --verbose
# Run webview tests with coverage
- name: Webview Tests with Coverage
id: webview_tests
id: webview_coverage
continue-on-error: true
run: |
cd webview-ui
npm run test:coverage
- name: Check Test Results
if: always()
run: |
failed=""
[[ "${{ steps.unit_tests_linux.outcome }}" == "failure" && "${{ runner.os }}" == "Linux" ]] && failed="$failed unit_tests_linux"
[[ "${{ steps.unit_tests_non_linux.outcome }}" == "failure" && "${{ runner.os }}" != "Linux" ]] && failed="$failed unit_tests_non_linux"
[[ "${{ steps.integration_tests_linux.outcome }}" == "failure" && "${{ runner.os }}" == "Linux" ]] && failed="$failed integration_tests_linux"
[[ "${{ steps.integration_tests_non_linux.outcome }}" == "failure" && "${{ runner.os }}" != "Linux" ]] && failed="$failed integration_tests_non_linux"
[[ "${{ steps.webview_tests.outcome }}" == "failure" ]] && failed="$failed webview_tests"
[[ -n "$failed" ]] && { echo "❌ The following test suites failed:$failed"; exit 1; }
echo "✅ All tests passed"
# Ensure coverage dependency is installed
npm install --no-save @vitest/coverage-v8
npm run test:coverage > webview_coverage.txt 2>&1
cd ..
# Default the encoding to UTF-8 - It's not the default on Windows
PYTHONUTF8=1 PYTHONPATH=.github/scripts python -m coverage_check extract-coverage webview-ui/webview_coverage.txt --type=webview --github-output --verbose
# Save coverage reports as artifacts (workflow-scoped)
- name: Save Coverage Reports
uses: actions/upload-artifact@v4
# Only upload artifacts on Linux - We only need coverage from one OS
@@ -157,21 +130,54 @@ jobs:
with:
name: pr-coverage-reports
path: |
coverage-unit/lcov.info
webview-ui/coverage/lcov.info
extension_coverage.txt
webview-ui/webview_coverage.txt
retention-period: workflow # Artifacts are automatically deleted when the workflow completes
test-platform-integration:
needs: quality-checks
# Set the check as failed if any of the tests failed
- name: Print test results and check for failures
run: |
echo "Extension Tests Result: ${{ steps.extension_coverage.outcome }}"
cat extension_coverage.txt
echo "Webview Tests Result: ${{ steps.webview_coverage.outcome }}"
cat webview-ui/webview_coverage.txt
# Check if any of the test steps failed
# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#steps-context
if [ "${{ steps.extension_coverage.outcome }}" != "success" ] || [ "${{ steps.webview_coverage.outcome }}" != "success" ]; then
echo "Tests failed."
exit 1
fi
coverage:
needs: test
runs-on: ubuntu-latest
# Only run on PRs to main branch
if: github.event_name == 'pull_request' && github.base_ref == 'main'
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for accurate comparison
# Setup Python for coverage script
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install requests
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: 22
# Cache root dependencies - only reuse if package-lock.json exactly matches
- name: Cache root dependencies
uses: actions/cache@v4
id: root-cache
@@ -179,6 +185,7 @@ jobs:
path: node_modules
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
# Cache webview-ui dependencies - only reuse if package-lock.json exactly matches
- name: Cache webview-ui dependencies
uses: actions/cache@v4
id: webview-cache
@@ -186,14 +193,6 @@ jobs:
path: webview-ui/node_modules
key: ${{ runner.os }}-npm-webview-${{ hashFiles('webview-ui/package-lock.json') }}
# Cache testing-platform dependencies
- name: Cache testing-platform dependencies
uses: actions/cache@v4
id: testing-platform-cache
with:
path: testing-platform/node_modules
key: ${{ runner.os }}-npm-testing-platform-${{ hashFiles('testing-platform/package-lock.json') }}
- name: Install root dependencies
if: steps.root-cache.outputs.cache-hit != 'true'
run: npm ci
@@ -202,70 +201,30 @@ jobs:
if: steps.webview-cache.outputs.cache-hit != 'true'
run: cd webview-ui && npm ci
- name: Compile standalone
run: npm run compile-standalone
# Build the extension before running tests
- name: Build Extension
run: npm run compile
- name: Install testing platform dependencies
if: steps.testing-platform-cache.outputs.cache-hit != 'true'
run: cd testing-platform && npm ci
- name: Running testing platform integration spec tests
continue-on-error: true
timeout-minutes: 7
# Temporarily wrapping the test command to always return a neutral exit code.
# This prevents the job from showing as failed and avoids distracting developers
# until the integration tests are ready to be enforced.
run: |
npm run test:tp-orchestrator -- tests/specs/ --count=1 --coverage || true
- name: Save Coverage Reports
uses: actions/upload-artifact@v4
with:
name: test-platform-integration-core-coverage
path: coverage/**/lcov.info
qlty:
needs: [test, test-platform-integration]
runs-on: ubuntu-latest
# Run on PRs to main, pushes to main, and manual dispatches
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download unit tests coverage reports
# Download coverage artifacts from test job
- name: Download Coverage Reports
uses: actions/download-artifact@v4
with:
name: pr-coverage-reports
path: .
path: . # Download to root directory to match expected paths
- name: Upload core unit tests coverage to Qlty
uses: qltysh/qlty-action/coverage@v2
with:
token: ${{ secrets.QLTY_COVERAGE_TOKEN }}
# we can merge multiple files if necessary
files: |
coverage-unit/lcov.info
tag: unit:core
# Process coverage workflow
- name: Process coverage workflow
id: coverage
run: |
# Extract PR number from GITHUB_REF
PR_NUMBER=$(echo "$GITHUB_REF" | sed -e 's/refs\/pull\///' -e 's/\/merge//')
- name: Upload webview-ui unit tests coverage to Qlty
uses: qltysh/qlty-action/coverage@v2
with:
token: ${{ secrets.QLTY_COVERAGE_TOKEN }}
# we can merge multiple files if necessary
files: |
webview-ui/coverage/lcov.info
tag: unit:webview-ui
add-prefix: webview-ui/
- name: Download test platform integration core coverage artifact
uses: actions/download-artifact@v4
with:
name: test-platform-integration-core-coverage
path: integration-core-coverage-reports
- name: Upload core integration tests coverage to Qlty
uses: qltysh/qlty-action/coverage@v2
with:
token: ${{ secrets.QLTY_COVERAGE_TOKEN }}
files: integration-core-coverage-reports/**/lcov.info
tag: integration:core
# Run the coverage workflow from root directory
PYTHONPATH=.github/scripts python -m coverage_check process-workflow \
--base-branch ${{ github.base_ref }} \
--pr-number $PR_NUMBER \
--repo $GITHUB_REPOSITORY \
--token ${{ secrets.GITHUB_TOKEN }} \
--verbose
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -1,53 +0,0 @@
name: Trigger Jetbrains Plugin <-> Cline Tests
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
concurrency:
group: jetbrains-trigger-${{ github.event.number }}
cancel-in-progress: true
jobs:
trigger-integration-test:
name: Run Tests
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App Token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: 1998650
private-key: ${{ secrets.CLINE_JETBRAINS_WORKFLOW_KEY }}
owner: cline
repositories: intellij-plugin
- name: Trigger IntelliJ Plugin Integration Test
run: |
curl -X POST \
-H "Authorization: Bearer ${{ steps.app-token.outputs.token }}" \
-H "Accept: application/vnd.github.v3+json" \
-H "User-Agent: cline-pr-trigger" \
-H "Content-Type: application/json" \
https://api.github.com/repos/cline/intellij-plugin/dispatches \
-d @- <<EOF
{
"event_type": "cline-pr-check",
"client_payload": {
"pr_number": "${{ github.event.number }}",
"branch_name": "${{ github.head_ref }}",
"action": "${{ github.event.action }}",
"sha": "${{ github.event.pull_request.head.sha }}",
"pr_title": ${{ toJSON(github.event.pull_request.title) }},
"pr_url": "${{ github.event.pull_request.html_url }}"
}
}
EOF
- name: Log trigger details
run: |
echo "Triggered IntelliJ Plugin integration test for:"
echo " PR #${{ github.event.number }}: ${{ github.event.pull_request.title }}"
echo " Branch: ${{ github.head_ref }}"
echo " Action: ${{ github.event.action }}"
echo " SHA: ${{ github.event.pull_request.head.sha }}"
+12 -10
View File
@@ -15,25 +15,27 @@ pnpm-lock.yaml
.venv
.actrc
webview-ui/src/**/*.js
webview-ui/src/**/*.js.map
# Ignore coverage directories and files
coverage
coverage-unit
.nyc_output
# But don't ignore the coverage scripts in .github/scripts/
!.github/scripts/coverage/
*evals.env
## Generated files ##
# Generated files
src/generated/
src/shared/proto/
# Core
src/core/controller/*/methods.ts
src/core/controller/*/index.ts
src/core/controller/grpc-service-config.ts
# Shared
src/shared/proto/*.ts
src/shared/proto/host/*.ts
# Webview
webview-ui/src/services/grpc-client.ts
# Host bridge
src/hosts/vscode/client/host-grpc-client.ts
src/standalone/server-setup.ts
# E2E Tests
test-results
## CLI pre-release ##
/cli
Regular → Executable
+17 -1
View File
@@ -1 +1,17 @@
lint-staged
echo "Running pre-commit checks..."
# Run ESLint
echo "Running ESLint..."
npm run lint || {
echo "❌ ESLint check failed. Please fix the errors and try committing again."
exit 1
}
# Run Prettier
echo "Running Prettier..."
npx lint-staged --verbose || {
echo "❌ Prettier failed. Please fix the errors and try committing again."
exit 1
}
echo "✅ All checks passed!"
+4 -13
View File
@@ -1,15 +1,6 @@
{
"extension": [
"ts"
],
"spec": [
"src/**/__tests__/*.ts"
],
"require": [
"ts-node/register",
"source-map-support/register",
"./src/test/requires.ts"
],
"recursive": true,
"exit": true
"extension": ["ts"],
"spec": ["src/**/__tests__/*.ts", "eslint-rules/__tests__/**/*.test.ts"],
"require": ["ts-node/register", "source-map-support/register", "./src/test/requires.ts"],
"recursive": true
}
-48
View File
@@ -1,48 +0,0 @@
{
"all": true,
"check-coverage": false,
"reporter": [
"text",
"lcov"
],
"include": [
"src/**/*.ts"
],
"exclude": [
"**/*.d.ts",
"**/*.{test,spec}.{js,jsx,ts,tsx,mjs,cjs}",
"**/__tests__/**",
"**/test/**",
"**/tests/**",
"**/.nyc_output/**",
"**/.vscode-test/**",
"**/tests-results/**",
"src/test/**",
"src/generated/**",
"**/node_modules/**",
"**/dist/**",
"**/out/**",
"**/build/**",
"**/coverage/**",
"**/coverage-unit/**",
"**/proto/**",
"**/*.{config,setup}.{js,ts,mjs,cjs}",
"**/vite-env.d.ts",
"**/*.{css,scss,sass,less,styl}",
"**/*.{svg,png,jpg,jpeg,gif,ico}",
"**/*.{json,yaml,yml}"
],
"extension": [
".ts",
".js"
],
"cache": true,
"sourceMap": true,
"instrument": true,
"report-dir": "./coverage-unit"
}
+8
View File
@@ -0,0 +1,8 @@
dist/
node_modules
webview-ui/build/
*.md
package-lock.json
src/core/prompts/system.ts
src/core/prompts/model_prompts/claude4.ts
evals/
+8
View File
@@ -0,0 +1,8 @@
{
"tabWidth": 4,
"useTabs": true,
"printWidth": 130,
"semi": false,
"bracketSameLine": true,
"endOfLine": "lf"
}
+2 -2
View File
@@ -2,9 +2,9 @@
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"dbaeumer.vscode-eslint",
"connor4312.esbuild-problem-matchers",
"ms-vscode.extension-test-runner",
"bradlc.vscode-tailwindcss",
"biomejs.biome"
"bradlc.vscode-tailwindcss"
]
}
+19 -119
View File
@@ -6,63 +6,15 @@
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension (production)",
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--disable-workspace-trust",
"--disable-extensions", // Avoid conflicts with installed extensions
"${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"args": ["--extensionDevelopmentPath=${workspaceFolder}", "--disable-workspace-trust", "${workspaceFolder}"],
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
"preLaunchTask": "${defaultBuildTask}",
"env": {
"IS_DEV": "true",
"DEV_WORKSPACE_FOLDER": "${workspaceFolder}",
"CLINE_ENVIRONMENT": "production"
}
},
{
"name": "Run Extension (staging)",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--disable-workspace-trust",
"--disable-extensions", // Avoid conflicts with installed extensions
"${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}",
"env": {
"IS_DEV": "true",
"DEV_WORKSPACE_FOLDER": "${workspaceFolder}",
"CLINE_ENVIRONMENT": "staging"
}
},
{
"name": "Run Extension (local)",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--disable-workspace-trust",
"--disable-extensions", // Avoid conflicts with installed extensions
"${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}",
"env": {
"IS_DEV": "true",
"DEV_WORKSPACE_FOLDER": "${workspaceFolder}",
"CLINE_ENVIRONMENT": "local"
"DEV_WORKSPACE_FOLDER": "${workspaceFolder}"
}
},
{
@@ -74,91 +26,39 @@
"--user-data-dir=${workspaceFolder}/dist/tmp/user",
"--profile-temp",
"--sync=off",
"--disable-extensions", // Avoid conflicts with installed extensions
"--disable-extensions",
"--extensionDevelopmentPath=${workspaceFolder}",
"${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
"preLaunchTask": "clean-tmp-user",
"internalConsoleOptions": "openOnSessionStart",
"postDebugTask": "stop",
"env": {
"IS_DEV": "true",
"TEMP_PROFILE": "true",
"DEV_WORKSPACE_FOLDER": "${workspaceFolder}",
"CLINE_ENVIRONMENT": "production"
"DEV_WORKSPACE_FOLDER": "${workspaceFolder}"
}
},
{
"type": "node",
"request": "launch",
"name": "Debug Test Standalone Core Api Server (test:sca-server)",
"skipFiles": [
"<node_internals>/**"
],
"name": "Run Standalone Service",
"skipFiles": ["<node_internals>/**"],
"sourceMaps": true,
"resolveSourceMapLocations": [
"${workspaceFolder}/**",
"!**/node_modules/**"
],
"cwd": "${workspaceFolder}",
"outFiles": [
"${workspaceFolder}/dist/**/*.js",
"${workspaceFolder}/dist-standalone/**/*.js"
],
"resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"],
"cwd": "${workspaceFolder}/dist-standalone",
"outFiles": ["${workspaceFolder}/dist-standalone/**/*.js"],
"preLaunchTask": "compile-standalone",
"runtimeExecutable": "npx",
"runtimeArgs": [
"tsx"
],
"program": "scripts/test-standalone-core-api-server.ts",
"env": {
"PROTOBUS_PORT": "26040",
"HOSTBRIDGE_PORT": "26041",
"WORKSPACE_DIR": "${workspaceFolder}",
"E2E_TEST": "true",
"CLINE_ENVIRONMENT": "local"
// Turns on grpc debug log.
//"GRPC_TRACE": "all",
//"GRPC_VERBOSITY": "DEBUG",
"NODE_PATH": "${workspaceFolder}/dist-standalone/node_modules",
"HOST_BRIDGE_ADDRESS": "localhost:50052"
},
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},
{
"type": "node",
"request": "launch",
"name": "Debug Current Test File",
"skipFiles": [
"<node_internals>/**"
],
"sourceMaps": true,
"resolveSourceMapLocations": [
"${workspaceFolder}/**",
"!**/node_modules/**"
],
"cwd": "${workspaceFolder}",
"runtimeExecutable": "npx",
"runtimeArgs": [
"mocha"
],
"args": [
"--require",
"ts-node/register",
"--require",
"source-map-support/register",
"--require",
"./src/test/requires.ts",
"--exit",
"${file}"
],
"env": {
"TS_NODE_PROJECT": "./tsconfig.unit-test.json",
"NODE_ENV": "test",
"IS_DEV": "true",
"CLINE_ENVIRONMENT": "local"
},
"console": "integratedTerminal",
"internalConsoleOptions": "openOnSessionStart"
"program": "standalone.js"
}
]
}
+2 -20
View File
@@ -6,26 +6,8 @@
},
"search.exclude": {
"out": true, // set this to false to include "out" folder in search results
"dist": true, // set this to false to include "dist" folder in search results,
"node_modules": true,
"dist-standalone": true
"dist": true // set this to false to include "dist" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off",
"typescript.preferences.quoteStyle": "double",
// Protobuf settings
"protoc": {
"options": [
"--proto_path=proto"
]
},
// Enable Lint and format using Biome
"biome.enabled": true,
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"source.fixAll.biome": "explicit",
"source.removeUnused.biome": "always",
"source.removeUnusedImports": "always",
"source.organizeImports.biome": "always"
}
"typescript.tsc.autoDetect": "off"
}
+10 -36
View File
@@ -30,13 +30,7 @@
},
{
"label": "watch",
"dependsOn": [
"npm: protos",
"npm: build:webview",
"npm: dev:webview",
"npm: watch:tsc",
"npm: watch:esbuild"
],
"dependsOn": ["npm: protos", "npm: build:webview", "npm: dev:webview", "npm: watch:tsc", "npm: watch:esbuild"],
"presentation": {
"reveal": "always"
},
@@ -66,9 +60,7 @@
"problemMatcher": [],
"isBackground": true,
"label": "npm: build:webview",
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"group": "watch",
"reveal": "always"
@@ -86,9 +78,7 @@
"problemMatcher": [],
"isBackground": true,
"label": "npm: build:webview:test",
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"group": "watch",
"reveal": "always"
@@ -123,9 +113,7 @@
],
"isBackground": true,
"label": "npm: dev:webview",
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"group": "watch",
"reveal": "always"
@@ -161,9 +149,7 @@
},
"isBackground": true,
"label": "npm: watch:esbuild",
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"group": "watch",
"reveal": "always"
@@ -199,9 +185,7 @@
},
"isBackground": true,
"label": "npm: watch:esbuild:test",
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"group": "watch",
"reveal": "always"
@@ -220,9 +204,7 @@
"problemMatcher": "$tsc-watch",
"isBackground": true,
"label": "npm: watch:tsc",
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"group": "watch",
"reveal": "always"
@@ -233,9 +215,7 @@
"script": "watch-tests",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"reveal": "always",
"group": "watchers"
@@ -244,11 +224,7 @@
},
{
"label": "tasks: watch-tests",
"dependsOn": [
"npm: protos",
"npm: watch",
"npm: watch-tests"
],
"dependsOn": ["npm: protos", "npm: watch", "npm: watch-tests"],
"problemMatcher": []
},
{
@@ -259,9 +235,7 @@
{
"label": "clean-tmp-user",
"type": "shell",
"dependsOn": [
"watch"
],
"dependsOn": ["watch"],
"command": "rm -rf ${workspaceFolder}/dist/tmp/user && mkdir -p ${workspaceFolder}/dist/tmp/user"
}
],
+1 -7
View File
@@ -61,12 +61,6 @@ old_docs/**
!assets/icons/**
# Ignore E2E build files
e2e-build.mjs
e2e-build.js
e2e.vsix
test-results/
# Ignore Storybook files
**/*.stories.tsx
*storybook.log
storybook-static
**/StorybookDecorator.tsx
+549 -883
View File
File diff suppressed because it is too large Load Diff
+10 -36
View File
@@ -14,11 +14,14 @@ Bug reports help make Cline better for everyone! Before creating a new issue, pl
## Before Contributing
All contributions must begin with a GitHub Issue, unless the change is for small bug fixes, typo corrections, minor wording improvements, or simple type fixes that don't change functionality.
**For features and contributions**:
- First check the [Feature Requests discussions board](https://github.com/cline/cline/discussions/categories/feature-requests) for similar ideas
- If your idea is new, create a new feature request
- Wait for approval from core maintainers before starting implementation
- Once approved, feel free to begin working on a PR with the help of our community!
- **Check existing issues**: Search [GitHub Issues](https://github.com/cline/cline/issues).
- **Create an issue**: Use appropriate templates:
- **Contributions:** Use the "Contribution Request" template to propose what you'd like to work on.
- **Bugs:** "Bug Report" template for reporting issues.
- **Features:** "Detailed Feature Proposal" template for suggesting new features.
- **Wait for approval**: A core Cline contributor must approve your contribution request before you start implementation.
- **Claim issues**: Once approved, the issue will be assigned to you.
**PRs without approved issues may be closed.**
@@ -74,6 +77,7 @@ We also welcome contributions to our [documentation](https://github.com/cline/cl
4. Testing
- Run `npm run test` to run tests locally.
- Before submitting PR, run `npm run format:fix` to format your code
- Run `npm run test:ci` to run tests locally
### Extension
@@ -146,7 +150,7 @@ Anyone can contribute code to Cline, but we ask that you follow these guidelines
- Run `npm run lint` to check code style
- Run `npm run format` to automatically format code
- All PRs must pass CI checks which include both linting and formatting
- Address any warnings or errors from linter before submitting
- Address any ESLint warnings or errors before submitting
- Follow TypeScript best practices and maintain type safety
3. **Testing**
@@ -156,36 +160,6 @@ Anyone can contribute code to Cline, but we ask that you follow these guidelines
- Update existing tests if your changes affect them
- Include both unit tests and integration tests where appropriate
**End-to-End (E2E) Testing**
Cline includes comprehensive E2E tests using Playwright that simulate real user interactions with the extension in VS Code:
- **Running E2E tests:**
```bash
npm run test:e2e # Build and run all E2E tests
npm run e2e # Run tests without rebuilding
npm run test:e2e -- --debug # Run with interactive debugger
```
- **Writing E2E tests:**
- Tests are located in `src/test/e2e/`
- Use the `e2e` fixture for single-root workspace tests
- Use `e2eMultiRoot` fixture for multi-root workspace tests
- Follow existing patterns in `auth.test.ts`, `chat.test.ts`, `diff.test.ts`, and `editor.test.ts`
- See `src/test/e2e/README.md` for detailed documentation
- **Debug mode features:**
- Interactive Playwright Inspector for step-by-step debugging
- Record new interactions and generate test code automatically
- Visual VS Code instance for manual testing
- Element inspection and selector validation
- **Test environment:**
- Automated VS Code setup with Cline extension loaded
- Mock API server for backend testing
- Temporary workspaces with test fixtures
- Video recording for failed tests
4. **Version Management with Changesets**
- Create a changeset for any user-facing changes using `npm run changeset`
+3 -3
View File
@@ -30,9 +30,9 @@ English | <a href="https://github.com/cline/cline/blob/main/locales/es/README.md
</table>
</div>
Meet Cline, an AI assistant that can use your **CLI** a**N**d **E**ditor.
Meet Cline (pronounced /klaɪn/, like "Klein"), an AI assistant that can use your **CLI** a**N**d **E**ditor.
Thanks to [Claude Sonnet's agentic coding capabilities](https://www.anthropic.com/claude/sonnet), Cline can handle complex software development tasks step-by-step. With tools that let him create & edit files, explore large projects, use the browser, and execute terminal commands (after you grant permission), he can assist you in ways that go beyond code completion or tech support. Cline can even use the Model Context Protocol (MCP) to create new tools and extend his own capabilities. While autonomous AI scripts traditionally run in sandboxed environments, this extension provides a human-in-the-loop GUI to approve every file change and terminal command, providing a safe and accessible way to explore the potential of agentic AI.
Thanks to [Claude 3.7 Sonnet's agentic coding capabilities](https://www.anthropic.com/claude/sonnet), Cline can handle complex software development tasks step-by-step. With tools that let him create & edit files, explore large projects, use the browser, and execute terminal commands (after you grant permission), he can assist you in ways that go beyond code completion or tech support. Cline can even use the Model Context Protocol (MCP) to create new tools and extend his own capabilities. While autonomous AI scripts traditionally run in sandboxed environments, this extension provides a human-in-the-loop GUI to approve every file change and terminal command, providing a safe and accessible way to explore the potential of agentic AI.
1. Enter your task and add images to convert mockups into functional apps or fix bugs with screenshots.
2. Cline starts by analyzing your file structure & source code ASTs, running regex searches, and reading relevant files to get up to speed in existing projects. By carefully managing what information is added to context, Cline can provide valuable assistance even for large, complex projects without overwhelming the context window.
@@ -87,7 +87,7 @@ All changes made by Cline are recorded in your file's Timeline, providing an eas
### Use the Browser
With Claude Sonnet's new [Computer Use](https://www.anthropic.com/news/3-5-models-and-computer-use) capability, Cline can launch a browser, click elements, type text, and scroll, capturing screenshots and console logs at each step. This allows for interactive debugging, end-to-end testing, and even general web use! This gives him autonomy to fixing visual bugs and runtime issues without you needing to handhold and copy-pasting error logs yourself.
With Claude 3.5 Sonnet's new [Computer Use](https://www.anthropic.com/news/3-5-models-and-computer-use) capability, Cline can launch a browser, click elements, type text, and scroll, capturing screenshots and console logs at each step. This allows for interactive debugging, end-to-end testing, and even general web use! This gives him autonomy to fixing visual bugs and runtime issues without you needing to handhold and copy-pasting error logs yourself.
Try asking Cline to "test the app", and watch as he runs a command like `npm run dev`, launches your locally running dev server in a browser, and performs a series of tests to confirm that everything works. [See a demo here.](https://x.com/sdrzn/status/1850880547825823989)
-166
View File
@@ -1,166 +0,0 @@
{
"$schema": "https://biomejs.dev/schemas/2.1.4/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true,
"defaultBranch": "main"
},
"assist": {
"enabled": true,
"actions": {
"source": {
"organizeImports": "on",
"useSortedAttributes": "on"
}
}
},
"linter": {
"enabled": true,
"domains": {
"react": "recommended"
},
// Ideally we would want to turn on all the rules that are currently off,
// keeping them off currently to make sure only changes on the migrations
// are included in the initial PR before we apply the format and lint changes.
// TODO: turn on all rules that are currently off if applicable.
// TODO: Remove --diagnostic-level=error from CI commands.
"rules": {
"recommended": true,
"correctness": {
"useExhaustiveDependencies": "off",
"noUndeclaredVariables": "off",
"noEmptyPattern": "off",
"useJsxKeyInIterable": "off",
"noInnerDeclarations": "off",
"useHookAtTopLevel": "off",
"useYield": "off",
"noConstructorReturn": "off",
"noInvalidPositionAtImportRule": "off",
"noSwitchDeclarations": "off",
"noUnusedImports": "error"
},
"a11y": "off",
"style": {
"useNodejsImportProtocol": "off",
"useImportType": "off",
"useBlockStatements": "warn",
"useNamingConvention": "off",
"useThrowOnlyError": "info",
"useConsistentArrayType": "off",
"noParameterAssign": "off",
"useAsConstAssertion": "off",
"useDefaultParameterLast": "off",
"noNonNullAssertion": "off",
"useEnumInitializers": "off",
"useSelfClosingElements": "off",
"useSingleVarDeclarator": "off",
"useNumberNamespace": "off",
"noInferrableTypes": "off",
"useTemplate": "off",
"noUselessElse": "off"
},
"suspicious": {
"noDoubleEquals": "warn",
"noImplicitAnyLet": "info",
"noThenProperty": "off",
"noAsyncPromiseExecutor": "off",
"noImportAssign": "off",
"noExplicitAny": "off",
"noControlCharactersInRegex": "off",
"noShadowRestrictedNames": "off",
"noArrayIndexKey": "info",
"noAssignInExpressions": "warn"
},
"complexity": {
"noUselessConstructor": "off",
"useOptionalChain": "off",
"noBannedTypes": "off",
"useLiteralKeys": "off",
"noUselessCatch": "off",
"noUselessSwitchCase": "off",
"noStaticOnlyClass": "off"
},
"security": {
"noDangerouslySetInnerHtml": "warn"
}
}
},
"formatter": {
"enabled": true,
"indentStyle": "tab",
"indentWidth": 4,
"lineWidth": 130,
"lineEnding": "lf",
"formatWithErrors": true
},
"javascript": {
"formatter": {
"semicolons": "asNeeded",
"arrowParentheses": "always",
"bracketSameLine": true,
"bracketSpacing": true,
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"trailingCommas": "all"
}
},
"json": {
"formatter": {
"trailingCommas": "none",
"expand": "always"
}
},
"files": {
"includes": [
"**",
"!**/dist/**",
"!**/dist-*/**",
"!**/out/**",
"!**/evals/**",
"!**/playwright/**",
"!**/test-results/**",
"!**/node_modules/**",
"!**/webview-ui/build/**",
"!**/generated/**",
"!**/proto/**",
"!**/tests/specs/**"
]
},
"plugins": [
"src/dev/grit/process-env.grit"
],
"overrides": [
{
"includes": [
"**",
"!**/hosts/vscode/**",
"!**/test/**",
"!**/*.test.ts",
"!src/dev/**",
"!src/extension.ts",
"!src/integrations/git/commit-message-generator.ts",
"!src/integrations/terminal/**",
"!src/core/controller/ui/openWalkthrough.ts"
],
"plugins": [
"src/dev/grit/vscode-api.grit"
]
},
{
"includes": [
"**",
"!src/core/storage/state-migrations.ts",
"!src/core/storage/FileContextTracker.ts",
"!src/core/context/context-tracking/FileContextTracker.ts",
"!src/common.ts",
"!src/services/logging/distinctId.ts",
"!src/core/storage/utils/state-helpers.ts",
"!src/extension.ts"
],
"plugins": [
"src/dev/grit/use-cache-service.grit"
]
}
]
}
+1
View File
@@ -9,6 +9,7 @@ lint:
except: # Add exceptions for current patterns that contradict STANDARD settings
- RPC_PASCAL_CASE # rpcs are camel case (start with lowercase)
- PACKAGE_DIRECTORY_MATCH # the protos in the cline package are not in a dir named cline.
- RPC_REQUEST_RESPONSE_UNIQUE # request messages are not unique.
- RPC_REQUEST_STANDARD_NAME # request messages dont all end with Request
- RPC_RESPONSE_STANDARD_NAME # response messages dont all end with Response
+31 -84
View File
@@ -25,15 +25,15 @@
},
"styling": {
"eyebrows": "breadcrumbs",
"codeblocks": "system",
"css": "styles.css"
"codeblocks": "system"
},
"appearance": {
"default": "system",
"strict": false
},
"fonts": {
"family": "Roboto"
"family": "Roboto",
"weight": 400
},
"navbar": {
"links": [
@@ -57,30 +57,29 @@
{
"group": "Getting Started",
"pages": [
"getting-started/what-is-cline",
"getting-started/for-new-coders",
"getting-started/installing-cline",
"getting-started/installing-dev-essentials",
"getting-started/model-selection-guide",
"getting-started/task-management",
"getting-started/understanding-context-management",
{
"group": "For New Coders",
"pages": [
"getting-started/for-new-coders",
"getting-started/installing-dev-essentials"
]
}
"getting-started/what-is-cline"
]
},
{
"group": "Improving Your Prompting Skills",
"pages": [
"prompting/prompt-engineering-guide",
"prompting/cline-memory-bank"
]
"pages": ["prompting/prompt-engineering-guide", "prompting/cline-memory-bank"]
},
{
"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": [
@@ -92,10 +91,15 @@
"features/at-mentions/url-mentions"
]
},
"features/auto-approve",
"features/auto-compact",
"features/checkpoints",
"features/cline-rules",
{
"group": "Slash Commands",
"pages": [
"features/slash-commands/new-task",
"features/slash-commands/new-rule",
"features/slash-commands/smol",
"features/slash-commands/report-bug"
]
},
{
"group": "Commands & Shortcuts",
"pages": [
@@ -105,31 +109,7 @@
"features/commands-and-shortcuts/git-integration",
"features/commands-and-shortcuts/keyboard-shortcuts"
]
},
{
"group": "Customization",
"pages": [
"features/customization/opening-cline-in-sidebar",
"features/customization/disable-terminal-pagers"
]
},
"features/dictation",
"features/drag-and-drop",
"features/editing-messages",
"features/focus-chain",
"features/plan-and-act",
{
"group": "Slash Commands",
"pages": [
"features/slash-commands/new-task",
"features/slash-commands/new-rule",
"features/slash-commands/smol",
"features/slash-commands/report-bug",
"features/slash-commands/deep-planning"
]
},
"features/slash-commands/workflows",
"features/yolo-mode"
}
]
},
{
@@ -166,33 +146,20 @@
"pages": [
"provider-config/anthropic",
"provider-config/claude-code",
{
"group": "AWS Bedrock",
"pages": [
"provider-config/aws-bedrock/api-key",
"provider-config/aws-bedrock/iam-credentials",
"provider-config/aws-bedrock/cli-profile"
]
},
"provider-config/aws-bedrock-with-apikey-authentication",
"provider-config/aws-bedrock-with-credentials-authentication",
"provider-config/aws-bedrock-with-profile-authentication",
"provider-config/gcp-vertex-ai",
"provider-config/litellm-and-cline-using-codestral",
"provider-config/vscode-language-model-api",
"provider-config/xai-grok",
"provider-config/mistral-ai",
"provider-config/deepseek",
"provider-config/groq",
"provider-config/cerebras",
"provider-config/doubao",
"provider-config/fireworks",
"provider-config/zai",
"provider-config/ollama",
"provider-config/openai",
"provider-config/openai-compatible",
"provider-config/openrouter",
"provider-config/sap-aicore",
"provider-config/vercel-ai-gateway",
"provider-config/requesty",
"provider-config/baseten"
"provider-config/requesty"
]
},
{
@@ -205,16 +172,11 @@
},
{
"group": "Troubleshooting",
"pages": [
"troubleshooting/terminal-quick-fixes",
"troubleshooting/terminal-integration-guide"
]
"pages": ["troubleshooting/terminal-quick-fixes", "troubleshooting/terminal-integration-guide"]
},
{
"group": "More Info",
"pages": [
"more-info/telemetry"
]
"pages": ["more-info/telemetry"]
}
]
},
@@ -225,25 +187,10 @@
"discord": "https://discord.gg/cline"
}
},
"anchors": [
{
"name": "What is Cline",
"icon": "house",
"url": "getting-started/what-is-cline"
}
],
"redirects": [
{
"source": "/getting-started/installing-cline-jetbrains",
"destination": "/getting-started/installing-cline"
}
],
"search": {
"prompt": "Search Cline documentation..."
},
"contextual": {
"options": [
"copy"
]
"options": ["copy"]
}
}
@@ -56,7 +56,7 @@ Cline is your AI assistant that can:
## Available Tools
For the most up-to-date implementation details, you can view the full source code in the [Cline repository](https://github.com/cline/cline/blob/main/src/core/prompts/system-prompt/tools).
For the most up-to-date implementation details, you can view the full source code in the [Cline repository](https://github.com/cline/cline/blob/main/src/core/Cline.ts).
Cline has access to the following tools for various tasks:
-75
View File
@@ -1,75 +0,0 @@
---
title: "Automatic Context Summarization"
sidebarTitle: "Auto Compact"
---
When your conversation approaches the model's context window limit, Cline automatically summarizes it to free up space and keep working.
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/condensing.png"
alt="Auto-compact feature condensing conversation context"
/>
</Frame>
## How It Works
Cline monitors token usage during your conversation. When you're getting close to the limit, he:
1. Creates a comprehensive summary of everything that's happened
2. Preserves all the technical details, code changes, and decisions
3. Replaces the conversation history with the summary
4. Continues exactly where he left off
You'll see a summarization tool call when this happens, showing the total cost like any other api call in the chat view.
## Why This Matters
Previously, Cline would truncate older messages when hitting context limits. This meant losing important context from earlier in the conversation.
Now with summarization:
- All technical decisions and code patterns are preserved
- File changes and project context remain intact
- Cline remembers everything he's done
- You can work on much larger projects without interruption
<Tip>
Context Summarization synergizes beautifully with [Focus Chain](/features/focus-chain). When Focus Chain is enabled, todo lists persist across summarizations. This means Cline can work on long-horizon tasks that span multiple context windows while staying on track with the todo list guiding him through each reset.
</Tip>
## Technical Details
The summarization happens through your configured API provider using the same model you're already using. It leverages prompt caching to minimize costs.
1. Cline uses a [summarization prompt](https://github.com/cline/cline/blob/main/src/core/prompts/contextManagement.ts) to request a summary of the conversation.
2. Once the summary is generated, Cline replaces the conversation history with a [continuation prompt](https://github.com/cline/cline/blob/main/src/core/prompts/contextManagement.ts#L69) that asks Cline to keep working and provides the summary as context.
Different models have different context window thresholds for when auto-summarization kicks in. You can see how thresholds are determined in [context-window-utils.ts](https://github.com/cline/cline/blob/main/src/core/context/context-management/context-window-utils.ts).
## Cost Considerations
Summarization leverages your existing prompt cache from the conversation, so it costs about the same as any other tool call.
Since most input tokens are already cached, you're primarily paying for the summary generation (output tokens), making it very cost-effective.
## Restoring Context with Checkpoints
You can use [checkpoints](/features/checkpoints) to restore your task state from before a summarization occurred. This means you never truly lose context - you can always roll back to previous versions of your conversation.
<Note>
Editing a message before a summarization tool call will work similarly to a checkpoint, allowing you to restore the conversation to that point.
</Note>
## Next Generation Model Support
Auto Compact uses advanced LLM-based summarization which we've found works significantly better for next-generation models. We currently support this feature for the following models:
- **Claude 4 series**
- **Gemini 2.5 series**
- **GPT-5**
- **Grok 4**
<Note>
When using other models, Cline automatically falls back to the standard rule-based context truncation method, even if Auto Compact is enabled in settings.
</Note>
+1 -13
View File
@@ -11,19 +11,7 @@ You can create a rule by clicking the `+` button in the Rules tab. This will ope
Once you save the file:
- Your rule will be stored in the `.clinerules/` directory in your project (if it's a Workspace Rule)
- Or in the Global Rules directory (if it's a Global Rule):
### Global Rules Directory Location
The location of your Global Rules directory depends on your operating system:
| Operating System | Default Location | Notes |
|------------------|------------------|-------|
| **Windows** | `Documents\Cline\Rules` | Uses system Documents folder |
| **macOS** | `~/Documents/Cline/Rules` | Uses user Documents folder |
| **Linux/WSL** | `~/Documents/Cline/Rules` | May fall back to `~/Cline/Rules` on some systems |
> **Note for Linux/WSL users**: If you don't find your global rules in `~/Documents/Cline/Rules`, check `~/Cline/Rules` as the location may vary depending on your system configuration and whether the Documents directory exists.
- Or in the `Documents/Cline/Rules` directory (if it's a Global Rule).
You can also have Cline create a rule for you by using the [`/newrule` slash command](/features/slash-commands/new-rule) in the chat.
@@ -21,6 +21,7 @@ While Cline has only a few default keyboard shortcuts, you can assign your own s
| 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 |
@@ -1,79 +0,0 @@
---
title: "Disable Terminal Pagers During Cline Sessions"
description: "Make CLI output non-interactive when Cline runs commands by detecting the CLINE_ACTIVE environment variable and disabling pagers like less."
---
Many CLI tools (like Git) use a pager such as `less` for interactive, scrollable output. When Cline runs commands in your terminal, that interactivity gets in the way — the pager can pause on the first page and block progress. You can configure your shell so that when a terminal is spawned by Cline, pagers are disabled and output streams through normally.
## How it works
Cline sets an environment variable for terminals it opens to run commands:
- `CLINE_ACTIVE` — non-empty when the shell is running under Cline
You can detect this variable in your shell startup file and adjust environment variables or aliases only for Cline-run sessions. This keeps your normal interactive terminals unchanged.
## Quick setup (Zsh/Bash)
Add the following to your `~/.zshrc`, `~/.bashrc`, or `~/.bash_profile`:
```bash
# Disable pagers when the terminal is launched by Cline
if [[ -n "$CLINE_ACTIVE" ]]; then
export PAGER=cat
export GIT_PAGER=cat
export SYSTEMD_PAGER=cat
export LESS="-FRX"
fi
```
<Note>
- `PAGER=cat` ensures generic pager-aware tools print directly to stdout
- `GIT_PAGER=cat` prevents Git from invoking `less`
- `SYSTEMD_PAGER=cat` disables paging in systemd tools (if present)
- `LESS="-FRX"` makes `less` behave more like streaming output if a tool still calls it
</Note>
This configuration only applies when `CLINE_ACTIVE` is set, so your normal terminals keep their usual interactive behavior.
## Verify
- Open a task in Cline that runs terminal commands and check:
- `echo "$CLINE_ACTIVE"` prints a non-empty value
- `git log` or other long outputs should stream without pausing
- If changes don't take effect:
- Make sure you updated the correct startup file for your shell
- Restart VS Code/Cursor so integrated terminals reload your shell config
- Confirm your terminal profile sources your `~/.zshrc` or `~/.bashrc`
## Optional tweaks
- Prefer command-line options when you don't want to rely on env vars:
```bash
# One-off usage (no aliases)
git --no-pager log -n 50 --decorate --oneline
systemctl --no-pager status nginx
journalctl --no-pager -u nginx -n 200
less -FRX README.md
```
- You can also override paging via shell aliases scoped to Cline sessions using options rather than env vars:
```bash
if [[ -n "$CLINE_ACTIVE" ]]; then
# Make 'less' non-interactive by default
alias less='less -FRX'
# Disable paging for common tools via CLI flags
alias git='command git --no-pager'
alias systemctl='command systemctl --no-pager'
alias journalctl='command journalctl --no-pager'
fi
```
- If you prefer environment variables, many CLIs also respect a generic or tool-specific pager variable:
- Git: `GIT_PAGER=cat`
- Systemd: `SYSTEMD_PAGER=cat`
- Man pages: `MANPAGER=cat` (not typically needed for Cline-driven commands)
- Aliases affect the current interactive shell, while environment variables propagate to child processes. Choose the approach that best fits your workflow.
@@ -1,60 +0,0 @@
---
title: "Opening Cline in the Right Sidebar"
description: "Learn how to open Cline in the right sidebar in VS Code and Cursor"
---
By default, when you first install Cline, it appears in VS Code's left sidebar alongside your file explorer and other extensions. However, for a better coding experience, we recommend moving Cline to the right sidebar. This allows you to keep your project files visible in the left sidebar while chatting with Cline on the right, giving you full visibility of your codebase as Cline works on your project.
## VS Code
To open Cline in the right sidebar:
<Steps>
<Step title="Align Extension View">
Make sure your extension view is aligned vertically to the left
</Step>
<Step title="Open Right Side View">
Click the button that opens the right side panel in VS Code (typically used to open GitHub Copilot chat). Optionally use the `Option + CMD/Ctrl + B` shortcut.
</Step>
<Step title="Drag Cline Icon">
Drag the Cline icon over to the nav panel at the top of that right view
</Step>
</Steps>
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/vscode_right_view.gif"
alt="VS Code Right Sidebar Setup"
/>
</Frame>
## Cursor
To open Cline in the right sidebar:
<Steps>
<Step title="Align Extensions">
Cursor uses a horizontal activity bar by default to optimize space for the AI chat interface ([see here for details](https://cursor.com/docs/configuration/migrations/vscode#activity-bar-orientation)). To switch to vertical:
1. Open the Command Palette (`CMD/Ctrl + Shift + P`)
2. Search for "Preferences: Open Settings (UI)"
3. Search for `workbench.activityBar.orientation`
4. Set the value to `vertical`
5. Restart Cursor for the changes to take effect
</Step>
<Step title="Open Agent Panel">
Click the Cursor cube icon button that opens Cursor's agent (right side view panel)
</Step>
<Step title="Drag to Three Dots">
Drag the Cline icon directly onto the three dots button - it doesn't work if you just drag it to the top, it has to be the three dots
</Step>
</Steps>
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/cursor-side-bar.gif"
alt="Cursor Right Sidebar Setup"
/>
</Frame>
Once set up, Cline will load on the right side and you can use it as normal.
-149
View File
@@ -1,149 +0,0 @@
---
title: "Dictation"
description: "Communicate with Cline using your voice for faster, more natural AI collaboration"
---
Dictation transforms how you work with AI. Instead of typing out complex thoughts, you speak naturally and share your complete intent. This isn't just about speed - though voice is faster - it's about unlocking the kind of fluid collaboration that typing can't match.
## Why Voice Changes Everything
When you type, you edit yourself. You simplify complex ideas, skip context, and lose nuance. When you speak, you share everything on your mind - the full problem, the constraints, the edge cases you're worried about.
Use Dictation constantly in [Plan mode](/features/plan-and-act) for rapid back-and-forth discussions. Instead of typing careful, structured prompts, think about a problem. Cline asks clarifying questions, respond immediately, and iterate until having a solid plan.
The friction of typing was holding back real collaboration. Voice removes that friction.
## Getting Started
**Enable Dictation:**
1. Go to Settings → Features → Dictation
2. Toggle "Enable Dictation" on
3. Sign into your Cline account when prompted
4. Install FFmpeg if you haven't already (Cline will guide you)
Once enabled, you'll see a microphone button in the chat input area.
**Using Dictation:**
- Click the microphone button to start recording
- Speak naturally
- Click again to stop recording
- Wait for transcription to appear in the chat
<Tip>
Dictation works with any AI model you've configured. The transcription happens through Cline's service, but your conversation continues with whatever model you're using.
</Tip>
## System Requirements
Dictation uses FFmpeg to capture your voice across all platforms:
- **macOS**: FFmpeg (via Homebrew: `brew install ffmpeg`)
- **Linux**: FFmpeg (via apt: `sudo apt-get install ffmpeg`)
- **Windows**: FFmpeg (via winget: `winget install Gyan.FFmpeg`)
If you don't have FFmpeg installed, Cline will automatically detect this and prompt you to install it with a single click.
## Where Dictation Shines
### Plan Mode Conversations
Dictation is perfect for [Plan mode](/features/plan-and-act) discussions. Instead of carefully crafting prompts, you can:
- Dictate your entire problem context in one go
- Respond to Cline's questions immediately
- Iterate on ideas without typing friction
- Think out loud while Cline listens
Start a planning session by speaking for 2-3 minutes straight, explaining the full context of what you're trying to build, the constraints you're working with, and the specific challenges you're facing.
### Complex Problem Explanation
Some problems are hard to type out. When you're dealing with:
- Multi-step workflows with edge cases
- Integration challenges across multiple systems
- Performance issues with specific reproduction steps
- UI/UX problems that need detailed context
Speaking lets you explain the full situation naturally, including all the "oh, and also..." details that matter.
### Code Review and Debugging
When reviewing code or explaining bugs, voice lets you walk through your thought process:
- "This function looks fine, but I'm worried about what happens when..."
- "The issue might be in this section, or possibly this other area..."
- "I tried X and Y, but neither worked because..."
You can share your complete debugging journey instead of just the final question.
## Technical Requirements
**System Requirements:**
- FFmpeg installed on your system
- Active internet connection
- Cline account with transcription credits
**Audio Quality:**
- Records in WebM format with Opus codec
- Mono audio at 16kHz sample rate
- Optimized for voice recognition
**Privacy:**
- Audio recorded locally on your machine
- Only audio files sent for transcription
- No audio stored after transcription
- Temporary files automatically cleaned up
## Cost and Credits
Voice transcription costs $0.006 per minute through your Cline account. For most users, this works out to pennies per session.
A typical 5-minute planning conversation costs about 3 cents. Even heavy voice users rarely spend more than a few dollars per month.
<Note>
Pricing is experimental and may change as we refine the service.
</Note>
## Best Practices
**Speak Naturally**
Don't try to speak like you type. Use your normal conversational tone and don't worry about perfect grammar.
**Give Context First**
Start with the big picture, then drill down into specifics. "I'm building a React app that needs to handle real-time data, and I'm running into performance issues with the WebSocket connection..."
**Use Voice for Exploration**
Dictation is perfect for exploratory conversations where you're not sure exactly what you need. Start talking through the problem and let the conversation evolve.
**Combine with Text**
You don't have to use voice for everything. Use voice for complex explanations and context, then switch to text for quick follow-ups or code snippets.
## Troubleshooting
**Microphone Not Working**
- Check your IDE permissions for microphone access
- Ensure FFmpeg is properly installed
- Try refreshing VSCode/your editor
**Poor Transcription Quality**
- Speak clearly and at normal volume
- Reduce background noise if possible
- Check your microphone settings
**Connection Issues**
- Verify internet connection
- Check if firewall is blocking Cline's servers
- Try signing out and back into your Cline account
**Authentication Issues**
- Sign out and back into your Cline account if you see authentication errors
- Check that your account has sufficient transcription credits
- Verify your internet connection is stable
**Audio Recording Issues**
- Ensure FFmpeg is properly installed and accessible
- Check that your browser/IDE has microphone permissions
- Try restarting your editor if audio capture fails
## The Future of AI Collaboration
When you can speak your thoughts as fast as you think them, you stop self-editing. You share the full context, the edge cases, the "what if" scenarios that matter. This leads to better solutions and fewer back-and-forth clarifications.
+1 -19
View File
@@ -5,28 +5,10 @@ sidebarTitle: "Drag & Drop"
Dragging and dropping files into Cline is a quick way to add images, code, and other files to your conversations.
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/dran-n-drop.gif"
alt="Dragging and dropping files into Cline chat"
/>
</Frame>
<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.
### Dragging from Finder/File Explorer
You can drag files directly from your system's file manager into Cline:
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/drag-n-drop-finder.gif"
alt="Dragging files from Finder into Cline"
/>
</Frame>
### Supported File Types
Cline supports dragging external images, pdfs, csv, excel, and other text files from your file system, as well as files from your workspace.
Cline supports dragging external images from your file system, as well as files from your workspace.
-303
View File
@@ -1,303 +0,0 @@
---
title: "Focus Chain"
sidebarTitle: "Focus Chain"
---
Focus Chain is a task management enhancement feature in Cline that provides automatic todo list management with real-time progress tracking throughout your tasks.
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/2dos.gif"
alt="Focus Chain todo list management with real-time progress tracking"
/>
</Frame>
This enables Cline to work on long-horizon tasks, seamlessly managing the context sent to LLMs, and keeping Cline on track across many context window resets.
<Tip>
Focus Chain works particularly well with Cline's [Deep Planning slash command](/features/slash-commands/deep-planning), providing seamless progress tracking for implementation tasks created through the [planning process](/features/plan-and-act).
</Tip>
## Key Features
### Automatic Todo List Generation
Cline analyzes your task and automatically creates a comprehensive todo list with:
- Clear, actionable items in markdown checklist format
- Logical breakdown of complex tasks into manageable steps
- Real-time updates as work progresses
### User-Editable Todo Lists
Todo lists are stored as editable markdown files:
- Direct editing through your preferred markdown editor
- Automatic detection of changes you make
- Seamless integration back into Cline's workflow
- Quick access through the edit button in the task header
### Visual Progress Tracking
The task header displays clear progress indicators:
- **Step counters** showing current progress (e.g., "3/8")
- **Completed items** clearly marked with checkmarks
- **Current work** highlighted with indicators
- **Expandable view** to see the full todo list
### Smart Reminder System
Configurable reminders ensure todo lists stay current:
- Default reminder every 6 messages (customizable 1-100)
- Automatic prompts when switching from Plan Mode to Act Mode
- User-triggered updates when todo lists are manually edited
## Getting Started
<Steps>
<Step title="Open Cline Settings">
- Click the gear icon in the Cline sidebar
- Navigate to the "Features" section
</Step>
<Step title="Enable Focus Chain">
- Check "Enable Focus Chain"
- Optionally adjust "Remind Cline Interval" (default: 6 messages)
</Step>
<Step title="Start a New Task">
- Begin a new task
- Cline will automatically start creating and managing todo lists
</Step>
</Steps>
| Setting | Default | Range | Description |
|---------|---------|-------|-------------|
| Enable Focus Chain | Disabled | On/Off | Enables enhanced task progress tracking |
| Remind Cline Interval | 6 | 1-100 messages | How often Cline updates the todo list |
## Usage Examples
#### 1. Task Initiation
When you start a new task with Focus Chain enabled:
``` markdown User Request
User: "Create a user authentication system for my React app"
Cline: [Analyzes request and creates todo list]
```
#### 2. Todo List Created
Cline creates a comprehensive plan for the task, stored in a markdown file:
```markdown Todo List Created
- [ ] Set up project structure
- [ ] Install authentication dependencies
- [ ] Create user registration component
- [ ] Implement login functionality
- [ ] Add password validation
- [ ] Set up user database schema
- [ ] Write authentication tests
- [ ] Deploy to staging environment
```
#### 3. Progress Tracking
As Cline works, the task header shows real-time progress:
```markdown Todo List Header
[3/8] Implement login functionality ⌄
```
Click to expand and see the full list:
```markdown Full Todo List
✓ Set up project structure
✓ Install authentication dependencies
✓ Create user registration component
○ Implement login functionality ← Currently working
○ Add password validation
○ Set up user database schema
○ Write authentication tests
○ Deploy to staging environment
```
#### 4. User Editing
Need to tweak the todo list? No problem.
<Steps>
<Step title="Open the todo list">
Click the edit button in the expanded todo view
</Step>
<Step title="Edit the markdown file">
A markdown file opens in your editor:
```markdown Editing Todo List
# Focus Chain Todo List for Task abc123
<!-- Edit this markdown file to update your focus chain todo list -->
<!-- Use - [ ] for incomplete items and - [x] for completed items -->
- [x] Set up project structure
- [x] Install authentication dependencies (e.g., Firebase Auth)
- [x] Create user registration component
- [ ] Implement login functionality
- [ ] Add password reset feature
- [ ] Set up protected routes
- [ ] Implement logout functionality
- [ ] Add user profile page
- [ ] Write authentication tests
- [ ] Deploy to staging environment
<!-- Save this file to update the task's todo list -->
```
</Step>
<Step title="Make your changes">
Add, remove, or reorder items as needed
</Step>
<Step title="Save the file">
Cline automatically detects and uses your updates
</Step>
</Steps>
## File Structure
### Todo List Storage
Todo lists are stored as markdown files in your task directory:
``` markdown
<VSCode Global Storage>/
tasks/
<taskId>/
focus_chain_taskid_<taskId>.md
... other task files
```
### Markdown Format
Todo files use standard markdown checklist syntax:
```markdown Example Todo Syntax
# Focus Chain Todo List for Task abc123
<!-- Edit this markdown file to update your focus chain todo list -->
<!-- Use the format: - [ ] for incomplete items and - [x] for completed items -->
- [x] Set up project structure
- [x] Install authentication dependencies
- [ ] Create user registration component
- [ ] Implement login functionality
- [ ] Add password validation
- [ ] Set up user database schema
- [ ] Write authentication tests
- [ ] Deploy to staging environment
<!-- Save this file and the todo list will be updated in the task -->
```
## Integration with Plan/Act Mode
Focus Chain works seamlessly with Cline's [Plan/Act mode](/features/plan-and-act):
- **Plan Mode**: Optional todo lists for presenting concrete steps
- **Act Mode**: Automatic todo creation when switching from Plan Mode
<Tip>
For complex projects, start in Plan Mode to discuss and refine your approach before switching to Act Mode for implementation.
</Tip>
## Best Practices
<AccordionGroup>
<Accordion title="For Effective Todo Lists">
1. **Start with Clear Requests**
- Provide detailed initial task descriptions
- Include specific requirements and constraints
- Mention any preferred technologies or approaches
2. **Review Generated Lists**
- Check that Cline's breakdown aligns with your expectations
- Verify that all important steps are included
- Ensure the order makes sense for your project
3. **Edit When Needed**
- Add missing steps you identify
- Remove unnecessary items
- Reorder steps for better workflow
- Add more specific details to general items
</Accordion>
<Accordion title="For Complex Projects">
1. **Use Plan Mode First**
- Discuss the approach before implementation
- Refine requirements through conversation
- Switch to Act Mode when ready to begin work
2. **Break Down Large Tasks**
- Split complex projects into smaller, manageable tasks
- Create separate todo lists for different components
- Focus on one major area at a time
3. **Regular Reviews**
- Check progress periodically during long tasks
- Update todo lists as requirements evolve
- Communicate changes to Cline through edits
</Accordion>
<Accordion title="For Collaboration">
1. **Share Todo Files**
- Todo markdown files can be shared with team members
- Include in version control for project documentation
- Use as basis for project planning discussions
2. **Consistent Format**
- Follow the standard markdown checklist format
- Keep item descriptions clear and actionable
- Use consistent terminology across todo lists
</Accordion>
</AccordionGroup>
## Troubleshooting
Having issues? Try these quick fixes:
<AccordionGroup>
<Accordion title="Todo list not updating?">
- Check that Focus Chain is enabled in settings
- Focus Chain may not work as well with smaller, less capable models
- Ensure file permissions are correct in the task directory
</Accordion>
<Accordion title="Can't edit todo file?">
- Verify your editor supports markdown
- Check VSCode has write permissions for the directory
</Accordion>
<Accordion title="Progress not displaying?">
- Ensure todo items use correct syntax (`- [ ]` and `- [x]`)
- Verify the markdown file is properly formatted
</Accordion>
</AccordionGroup>
Still stuck? Use the [/reportbug](/features/slash-commands/report-bug) command in Cline to get help.
## Technical Details (for the curious)
<AccordionGroup>
<Accordion title="File Monitoring">
- Real-time file watching detects changes to todo markdown files
- Automatic synchronization between file edits and UI updates
- Graceful handling of file creation, modification, and deletion
</Accordion>
<Accordion title="Progress Calculation">
- Dynamic counting of completed vs. total todo items
- Support for both `- [x]` and `- [X]` completion syntax
- Unicode symbols (✓, ○) for enhanced visual display
</Accordion>
<Accordion title="Privacy Considerations">
- Todo lists stored locally in VSCode workspace
- No todo content transmitted to external services
- Usage telemetry (can be disabled in settings)
</Accordion>
</AccordionGroup>
Focus Chain turns Cline into your personal project manager, keeping you on track and your tasks organized. Give it a try on your next project!
-4
View File
@@ -24,10 +24,6 @@ Plan mode is where you and Cline figure out what you're trying to build and how
- Focuses on understanding requirements and creating a strategy
- Helps identify potential issues before you write a single line of code
<Tip>
Try [Dictation](/features/dictation) in Plan mode - instead of typing out complex requirements, you can speak naturally and share your complete thought process. It's perfect for rapid back-and-forth planning discussions.
</Tip>
#### Act Mode: Build It
Once you've got a plan, you switch to Act mode. Now Cline:
@@ -1,160 +0,0 @@
---
title: "Deep Planning Command"
sidebarTitle: "/deep-planning"
---
`/deep-planning` transforms Cline into a meticulous architect who investigates your codebase, asks clarifying questions, and creates a comprehensive implementation plan before writing a single line of code.
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/deep-planning.png"
alt="Deep Planning command in action showing investigation and planning process"
/>
</Frame>
When you use `/deep-planning`, Cline follows a four-step process that mirrors how senior developers approach complex features: thorough investigation, discussion & clarification of requirements, detailed planning, and structured task creation with progress tracking.
## The Four-Step Process
### Step 1: Silent Investigation
Cline becomes a detective, silently exploring your codebase to understand its structure, patterns, and constraints. He examines source files, analyzes import patterns, discovers class hierarchies, and identifies technical debt markers. No commentary, no narration - just focused research.
During this phase, Cline runs commands like:
- Finding all class and function definitions across your codebase
- Analyzing import patterns to understand dependencies
- Discovering project structure and file organization
- Identifying TODOs and technical debt
### Step 2: Discussion and Questions
Once Cline understands your codebase, he asks targeted questions that will shape the implementation. These aren't generic questions - they're specific to your project and the feature you're building.
Questions might cover:
- Clarifying ambiguous requirements
- Choosing between equally valid implementation approaches
- Confirming assumptions about system behavior
- Understanding preferences for technical decisions
### Step 3: Implementation Plan Document
Cline creates a structured markdown document (`implementation_plan.md`) that serves as your implementation blueprint. This isn't a vague outline - it's a detailed specification with exact file paths, function signatures, and implementation order.
The plan includes eight comprehensive sections:
- **Overview**: The goal and high-level approach
- **Types**: Complete type definitions and data structures
- **Files**: Exact files to create, modify, or delete
- **Functions**: New and modified functions with signatures
- **Classes**: Class modifications and inheritance details
- **Dependencies**: Package requirements and versions
- **Testing**: Validation strategies and test requirements
- **Implementation Order**: Step-by-step execution sequence
### Step 4: Implementation Task Creation
Cline creates a new task that references the plan document and includes trackable implementation steps. The task comes with specific commands to read each section of the plan, ensuring the implementing agent (whether that's you or Cline in Act Mode) can navigate the blueprint efficiently.
<Tip>
Deep Planning works beautifully with [Focus Chain](/features/focus-chain). The implementation steps automatically become a todo list with real-time progress tracking, keeping complex projects organized and on track.
</Tip>
## Using Deep Planning
Start a deep planning session by typing `/deep-planning` followed by your feature description:
```
/deep-planning Add user authentication with JWT tokens and role-based access control
```
Cline will begin his investigation immediately. You'll see him reading files and running commands to understand your codebase. Once he's gathered enough context, he'll engage you in discussion before creating the plan.
## Example Workflow
Here's how I use `/deep-planning` for a real feature:
<Steps>
<Step title="Initiate Planning">
I type `/deep-planning implement a caching layer for API responses`
</Step>
<Step title="Silent Investigation">
Cline explores my codebase, examining:
- Current API structure and endpoints
- Existing data flow patterns
- Database queries and performance bottlenecks
- Configuration and environment setup
</Step>
<Step title="Targeted Discussion">
Cline asks me:
- "Should we use Redis or in-memory caching?"
- "What's the acceptable cache staleness for user data?"
- "Do you need cache invalidation webhooks?"
</Step>
<Step title="Plan Creation">
Cline generates `implementation_plan.md` with:
- Cache service class specifications
- Redis connection configuration
- Modified API endpoints with caching logic
- Cache key generation strategies
- TTL configurations for different data types
</Step>
<Step title="Task Generation">
Cline creates a new task with:
- Reference to the implementation plan
- Commands to read specific sections
- Trackable todo items for each implementation step
- Request to switch to Act Mode for execution
</Step>
</Steps>
## Integration with Plan/Act Mode
Deep Planning is designed to work seamlessly with [Plan/Act Mode](/features/plan-and-act):
- Use `/deep-planning` in Plan Mode for the investigation and planning phases
- The generated task requests switching to Act Mode for implementation
- Focus Chain automatically tracks progress through the implementation steps
This separation ensures planning stays focused on architecture while implementation stays focused on execution.
## Best Practices
### When to Use Deep Planning
Use `/deep-planning` for:
- Features touching multiple parts of your codebase
- Architectural changes requiring careful coordination
- Complex integrations with external services
- Refactoring efforts that need systematic execution
- Any feature where you'd normally spend time whiteboarding
### Making the Most of Investigation
Let Cline complete his investigation thoroughly. The quality of the plan directly correlates with how well he understands your codebase. If you have specific areas he should examine, mention them in your initial request.
### Reviewing the Plan
Always review `implementation_plan.md` before starting implementation. The plan is comprehensive but not immutable - you can edit it directly if needed. Think of it as a collaborative document between you and Cline.
### Tracking Progress
With Focus Chain enabled, your implementation progress displays in the task header. Each completed step gets checked off automatically as Cline works through the plan, giving you real-time visibility into complex implementations.
## Inspiration
I use `/deep-planning` whenever I'm about to build something that would normally require a design document. Recent examples from my workflow:
- **Migrating authentication systems**: Deep Planning mapped every endpoint, identified all authentication touchpoints, and created a migration plan that avoided breaking changes.
- **Adding real-time features**: The plan covered WebSocket integration, event handling, state synchronization, and fallback mechanisms for disconnections.
- **Database schema refactoring**: Cline identified all affected queries, created migration scripts, and planned the rollout to minimize downtime.
- **API versioning implementation**: The plan detailed route changes, backward compatibility layers, deprecation notices, and client migration paths.
The power of `/deep-planning` is that it forces thoughtful architecture before implementation. It's like having a senior developer review your approach before you write code, except that developer has perfect knowledge of your entire codebase.
<Note>
Deep Planning requires models with strong reasoning capabilities. It works best with the latest generation of models, like GPT-5, Claude 4, Gemini 2.5, or Grok 4. Smaller models may struggle with the comprehensive analysis required.
</Note>
For simpler tasks that don't require extensive planning, consider using [/newtask](/features/slash-commands/new-task) to create focused tasks with context, or jump straight into implementation if the path forward is clear.
-83
View File
@@ -1,83 +0,0 @@
---
title: "YOLO Mode"
sidebarTitle: "YOLO Mode"
---
YOLO mode is exactly what it sounds like - Cline auto-approves everything. Check the box in feature settings and he'll execute file changes, terminal commands, even transitions from Plan to Act mode without asking.
Think of it as [Auto Approve](/features/auto-approve) on steroids - instead of granular permissions, YOLO mode gives Cline complete autonomy.
<Note>
**Warning: This is dangerous.** YOLO mode disables all safety checks. Cline will execute whatever he decides without asking permission.
</Note>
## What Gets Auto-Approved
When YOLO mode is enabled, Cline automatically approves:
- **All file operations** - reading, writing, and modifying files anywhere on your system
- **All terminal commands** - including potentially destructive operations
- **Browser actions** - web scraping, form submissions, navigation
- **MCP server tools** - external integrations and API calls
- **Mode transitions** - automatic switching from Plan to Act mode
Essentially, every safety guardrail is removed. Cline operates with complete autonomy.
## How to Enable YOLO Mode
Navigate to Cline Settings → Features and check the "YOLO Mode" box. That's it - no confirmation dialogs, no additional warnings. Once enabled, Cline will start auto-approving all actions immediately.
To disable it, simply uncheck the box. Any pending actions will still require your approval once YOLO mode is turned off.
## When You Might Use This
YOLO mode was built primarily for our upcoming scriptable CLI where fully autonomous execution makes sense. In the GUI, you might consider it for:
**Rapid prototyping** where you want zero friction and don't care about potential mistakes. Perfect for throwaway experiments or exploring new ideas quickly.
**Trusted, repetitive tasks** where you've already validated Cline's approach and want to eliminate approval overhead. Think routine refactoring or well-established patterns.
**Demonstration purposes** where you want to show Cline's capabilities without constant interruptions.
## What Could Go Wrong
Since YOLO mode removes all safety checks, Cline could:
- Delete important files without warning
- Execute commands that modify system settings
- Make network requests to external services
- Overwrite configuration files
- Install or uninstall software packages
- Commit and push changes to version control
The risk level depends entirely on what you ask Cline to do. Simple tasks remain relatively safe, but complex requests can have unpredictable consequences.
## Best Practices
If you decide to use YOLO mode:
**Start with isolated environments.** Use it in throwaway projects or sandboxed environments first. Never enable it on production codebases until you understand the risks.
**Be specific with requests.** Vague instructions combined with unlimited permissions can lead to unexpected results. The clearer your requirements, the more predictable Cline's actions.
**Monitor the output.** Even though Cline doesn't ask for permission, he still shows you what he's doing. Watch the terminal output and file changes as they happen.
**Keep version control handy.** Make sure you can easily revert changes if something goes wrong. Git becomes your safety net when YOLO mode is your workflow.
## Inspiration: What Becomes Possible
With YOLO mode enabled, you can:
**Build entire applications** from a single prompt. Describe what you want and let Cline handle everything - file creation, dependency installation, configuration setup, even deployment scripts.
**Automate complex workflows** that normally require dozens of approval clicks. Data processing pipelines, build system setup, or multi-step refactoring operations become seamless.
**Rapid iteration cycles** where you can quickly test ideas without approval friction. Perfect for exploring different approaches or experimenting with new technologies.
**Live demonstrations** where you can show Cline's full capabilities without stopping to approve every action. Great for presentations or teaching scenarios.
The key is understanding that YOLO mode transforms Cline from an interactive assistant into an autonomous agent. Use that power wisely.
---
Questions or feedback? Reach us in our [Discord](https://discord.gg/cline) or [r/cline](https://reddit.com/r/cline).
+11 -11
View File
@@ -3,9 +3,9 @@ title: "For New Coders"
description: "Welcome to Cline, your AI-powered coding companion! This guide will help you quickly set up your development environment and begin your coding journey with ease."
---
> **Tip:** If you're completely new to coding, take your time with each step. There's no rush — Cline is here to guide you!
> 💡 **Tip:** If you're completely new to coding, take your time with each step. There's no rush — Cline is here to guide you!
### Getting Started
### 🚀 Getting Started
Before you jump into coding, make sure you have these essentials ready:
@@ -15,9 +15,9 @@ A popular, free, and powerful code editor.
- [<u>Download VS Code</u>](https://code.visualstudio.com/)
**Recommended YouTube Tutorial:** [<u>How to Install VS Code</u>](https://www.youtube.com/watch?v=MlIzFUI1QGA)
📺 **Recommended YouTube Tutorial:** [<u>How to Install VS Code</u>](https://www.youtube.com/watch?v=MlIzFUI1QGA)
> **Pro Tip:** Install VS Code in your Applications folder (macOS) or Program Files (Windows) for easy access from your dock or start menu.
> **Pro Tip:** Install VS Code in your Applications folder (macOS) or Program Files (Windows) for easy access from your dock or start menu.
#### 2. **Organize Your Projects**
@@ -31,7 +31,7 @@ Inside your `Cline` folder, structure projects clearly:
- `Documents/Cline/workout-app` _(e.g., for a fitness tracking app)_
- `Documents/Cline/portfolio-website` _(e.g., to showcase your work)_
> **Tip:** Keeping your projects organized from the start will save you time and confusion later!
> 💡 **Tip:** Keeping your projects organized from the start will save you time and confusion later!
#### 3. **Install the Cline VS Code Extension**
@@ -39,9 +39,9 @@ Enhance your coding workflow by installing the Cline extension directly within V
- Get Started with Cline Extension Tutorial
**Recommended YouTube Tutorial:** [<u>How To Install Extensions in VS Code</u>](https://www.youtube.com/watch?v=E7trgwZa-mk)
📺 **Recommended YouTube Tutorial:** [<u>How To Install Extensions in VS Code</u>](https://www.youtube.com/watch?v=E7trgwZa-mk)
> **Pro Tip:** After installing, reload VS Code to ensure the extension is activated properly.
> **Pro Tip:** After installing, reload VS Code to ensure the extension is activated properly.
#### 4. **Essential Development Tools**
@@ -51,9 +51,9 @@ Basic software required for coding efficiently:
- Node.js
- Git
[<u>Follow our detailed guide on Installing Essential Development Tools with step-by-step help from Cline.</u>](https://docs.cline.bot/getting-started/installing-dev-essentials#installing-dev-essentials)
👉 [<u>Follow our detailed guide on Installing Essential Development Tools with step-by-step help from Cline.</u>](https://docs.cline.bot/getting-started/installing-dev-essentials#installing-dev-essentials)
**Recommended YouTube Tutorials for Manual Installation:**
📺 **Recommended YouTube Tutorials for Manual Installation:**
- **For macOS:**
- [<u>Install Homebrew on Mac</u>](https://www.youtube.com/watch?v=hwGNgVbqasc)
@@ -63,6 +63,6 @@ Basic software required for coding efficiently:
- [<u>Install Git on Windows 10/11 (2024)</u>](https://www.youtube.com/watch?v=yjxv1HuRQy0)
- [<u>Install Node.js in Windows 10/11</u>](https://www.youtube.com/watch?v=uCgAuOYpJd0)
> **Note:** If you run into permission issues during installation, try running your terminal or command prompt as an administrator.
> ⚠️ **Note:** If you run into permission issues during installation, try running your terminal or command prompt as an administrator.
You're all set! Dive in and start coding smarter and faster with **Cline**.
🎉 You're all set! Dive in and start coding smarter and faster with **Cline**.
+48 -237
View File
@@ -1,256 +1,67 @@
---
title: "Installing Cline"
description: "Get Cline set up in your editor and start building projects with AI assistance."
description: "Cline is a VS Code extension that brings AI-powered coding assistance directly
to your editor. Install using one of these methods:"
---
## Prerequisites
### Installation Options
Before installing Cline, make sure you have the following:
- **VS Code Marketplace (Recommended):** Fastest method for standard VS Code and Cursor users.
- **Open VSX Registry:** For VS Code-compatible editors like VSCodium.
### Create a Cline Account
### 🛠️ VS Code Marketplace: Step-by-Step Setup
Create a Cline account for the best experience. Creating a Cline account is completely free and you can [sign up here](https://app.cline.bot/signup). A Cline account provides:
- Access to multiple AI models including stealth models
- Seamless setup without needing to manage API keys
- At times, we partner with model providers to offer inferencing at no cost through your Cline account
Follow these steps to get Cline up and running:
### Compatible Editor
1. **Open VS Code:** Launch the VS Code application.
Cline works with the following IDEs:
- **VS Code** - Microsoft's popular code editor
- **Cursor** - AI-powered code editor based on VS Code
- **JetBrains IDEs** - IntelliJ IDEA, PyCharm, WebStorm, DataSpell, PhpStorm, and other JetBrains products
- **VSCodium** - Open-source version of VS Code
- **Windsurf** - VS Code-compatible editor
> ⚠️ **Note:** If VS Code shows "Running extensions might...", click "Allow".
Make sure you have one of these editors installed before proceeding with the Cline installation.
2. **Open Your Cline Folder:** In VS Code, open the Cline folder you created in Documents.
3. **Navigate to Extensions:** Click on the Extensions icon in the Activity Bar on the side of VS Code (`Ctrl + Shift + X` or `Cmd + Shift + X`).
4. **Search for 'Cline':** In the Extensions search bar, type `Cline`.
## Choose Your Editor
<Frame caption="VS Code marketplace with Cline extension ready to install">
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/image%20(20).png"
alt="VS Code marketplace showing Cline extension"
/>
</Frame>
Cline works across multiple IDEs. Select your preferred editor below for installation instructions:
1. **Install the Extension:** Click the "Install" button next to the Cline extension.
2. **Open Cline:**
- Click the Cline icon in the Activity Bar.
- Or, use the command palette (`Ctrl/Cmd + Shift + P`) and type "Cline: Open In New Tab" for a better view.
3. **Troubleshooting:** If you don't see the Cline icon, try restarting VS Code.
<Tabs>
<Tab title="VS Code/Cursor" icon="code">
### Installation Steps
> ✅ **Pro Tip:** You should see the Cline chat window appear in your VS Code editor!
1. **Open VS Code** and navigate to the Extensions view (`Ctrl/Cmd + Shift + X`)
2. **Search for "Cline"** in the Extensions marketplace
3. **Click Install** on the Cline extension
### 🌐 Open VSX Registry
<Frame caption="VS Code marketplace with Cline extension ready to install">
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/image%20(20).png"
alt="VS Code marketplace showing Cline extension"
/>
</Frame>
For VS Code-compatible editors without Marketplace access (like VSCodium and Windsurf):
4. **Access Cline** after installation:
- Click the Cline icon in the Activity Bar, or
- Use Command Palette (`Ctrl/Cmd + Shift + P`) → "Cline: Open In New Tab"
1. Open your editor.
2. Access the Extensions view.
3. Search for "Cline".
4. Select "Cline" by saoudrizwan and click **Install**.
5. Reload if prompted.
> **Note:** If VS Code shows "Running extensions might..." dialog, click "Allow". If you don't see the Cline icon, restart VS Code.
### 👤 Creating Your Cline Account
<Accordion title="Troubleshooting">
Now that you have Cline installed, let's get you set up with your account:
**Plugin Installation Issues**
1. **Sign In to Cline:**
- Click the **Sign In** button in the Cline extension.
- You'll be taken to [app.cline.bot](https://app.cline.bot) to create your account.
2. **Start with Free Credits:**
- No credit card needed!
3. **Available AI Models:**
- Anthropic Claude 3.5-Sonnet (recommended for coding)
- DeepSeek Chat (cost-effective alternative)
- Google Gemini 2.0 Flash
- And more — all through your Cline account.
If you can't find Cline in the marketplace:
- Make sure you're searching in the **Marketplace** tab (not Installed)
- Try searching for "Cline AI" or just "Cline"
- Check that your VS Code version is compatible
If installation fails:
- Restart your VS Code and try again
- Check your internet connection
- Try installing from VSIX file as an alternative
**Plugin Not Appearing**
If you don't see the Cline tool window after installation:
- Restart VS Code completely (File → Exit and reopen)
- Check **View** → **Command Palette** → "Cline: Open In New Tab"
- Verify the plugin is enabled in **Extensions** view
- Look for the Cline icon in your Activity Bar (usually on the left side)
**Common Issues**
Plugin appears to be installed but doesn't work:
- Ensure you've restarted VS Code after installation
- Check if there are any error messages in the Developer Console
- Try disabling and re-enabling the extension
Performance or compatibility issues:
- Make sure you're using a supported VS Code version
- Check for VS Code updates that might improve compatibility
- Consider closing other resource-intensive extensions if needed
Need help? Join our [Discord community](https://discord.gg/cline).
</Accordion>
</Tab>
<Tab title="JetBrains IDEs" icon="brain">
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/jetbrains-logo.svg"
alt="JetBrains logo"
style={{ width: "200px", height: "auto", margin: "0 auto 20px auto", display: "block" }}
/>
Cline for JetBrains works almost identically to Cline in VSCode. All the core features work properly: diff editing, using tools, logging in with different providers, MCP servers, Cline rules and workflows, and more.
### Installation Steps
**Method 1: From IDE (Recommended)**
1. Open your JetBrains IDE
2. Go to **Settings** (`Ctrl+Alt+S` on Windows/Linux, `Cmd+,` on macOS)
3. Navigate to **Plugins** → **Marketplace**
4. Search for "Cline" and click **Install**
5. Restart your IDE
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/cline-jetbrains-marketplace-search.png"
alt="JetBrains marketplace showing Cline plugin search results"
/>
</Frame>
**Method 2: Browser Install**
Visit the [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/28247-cline) and click **Install to IDE**.
<Accordion title="Method 3: Manual Installation">
1. Download the plugin from the [marketplace page](https://plugins.jetbrains.com/plugin/28247-cline)
2. Go to **Settings** → **Plugins**
3. Click the gear icon → **Install Plugin from Disk**
4. Select the downloaded `.zip` file
5. Restart your IDE
</Accordion>
### Using the Plugin
After installation, youll find Cline in your IDE. Look for the Cline tool window (usually on the right side) or go to View → Tool Windows → Cline.
### Key Features
Cline for JetBrains includes all core features:
- Diff editing and file modifications
- Multiple API providers (Anthropic, OpenAI, local models)
- MCP servers and custom tools
- Cline rules and workflows
- @ mentions for files, folders, and problems
- Drag & drop support
> **Note:** Terminal output appears in collapsible sections rather than streaming directly to chat.
### Key Differences from VSCode
The terminal integration works differently in JetBrains. Unlike VSCode where terminal output streams directly to the chat, JetBrains shows command output in a collapsible section. Commands still execute successfully - you just need to expand the Command Output section to see results.
<Accordion title="Troubleshooting">
**Plugin Installation Issues**
If you can't find Cline in the marketplace:
- Make sure you're searching in the **Marketplace** tab (not Installed)
- Try searching for "Cline AI" or just "Cline"
- Check that your IDE version is compatible (2023.1 or later recommended)
If installation fails:
- Restart your IDE and try again
- Check your internet connection
- Try installing from disk as an alternative
**Plugin Not Appearing**
If you don't see the Cline tool window after installation:
- Restart your IDE completely (File → Exit and reopen)
- Check **View** → **Tool Windows** → **Cline**
- Verify the plugin is enabled in **Settings** → **Plugins** → **Installed** tab
- Look for the Cline icon in your IDE's tool window bar (usually on the right side)
**Common Issues**
Plugin appears to be installed but doesn't work:
- Ensure you've restarted your IDE after installation
- Check if there are any error messages in the IDE's event log
- Try disabling and re-enabling the plugin in Settings
Performance or compatibility issues:
- Make sure you're using a supported JetBrains IDE version
- Check for IDE updates that might improve compatibility
- Consider allocating more memory to your IDE if needed
Need help? Join our [Discord community](https://discord.gg/cline).
</Accordion>
</Tab>
<Tab title="VSCodium/Windsurf" icon="terminal">
### Installation Steps
For VS Code-compatible editors using Open VSX Registry:
1. **Open your editor** (VSCodium, Windsurf, etc.)
2. **Navigate to Extensions view** (`Ctrl/Cmd + Shift + X`)
3. **Search for "Cline"** in the marketplace
4. **Select "Cline" by saoudrizwan** and click **Install**
5. **Reload** if prompted
> **Note:** These editors use the Open VSX Registry instead of the VS Code Marketplace.
<Accordion title="Troubleshooting">
**Plugin Installation Issues**
If you can't find Cline in the marketplace:
- Make sure you're searching in the **Marketplace** tab (not Installed)
- Try searching for "Cline AI" or just "Cline"
- Check that your editor version is compatible
If installation fails:
- Restart your editor and try again
- Check your internet connection
- Try installing from disk as an alternative
**Plugin Not Appearing**
If you don't see the Cline tool window after installation:
- Restart your editor completely (File → Exit and reopen)
- Check **View** → **Command Palette** → "Cline: Open In New Tab"
- Verify the plugin is enabled in **Extensions** view
- Look for the Cline icon in your Activity Bar (usually on the left side)
**Common Issues**
Plugin appears to be installed but doesn't work:
- Ensure you've restarted your editor after installation
- Check if there are any error messages in the Developer Console
- Try disabling and re-enabling the extension
Performance or compatibility issues:
- Make sure you're using a supported editor version
- Check for editor updates that might improve compatibility
- Consider closing other resource-intensive extensions if needed
Need help? Join our [Discord community](https://discord.gg/cline).
</Accordion>
</Tab>
</Tabs>
### Sign In to Your Cline Account
Now that you have Cline installed, sign in to access your account:
1. **Open Cline** in your editor (click the Cline icon in the Activity Bar or Tool Windows)
2. **Click "Sign In"** - you'll see this button in the Cline interface
3. **Complete authentication** - you'll be redirected to [app.cline.bot](https://app.cline.bot) to sign in
4. **Return to your editor** - once signed in, you'll be automatically redirected back
### Your First Interaction with Cline
### 💻 Your First Interaction with Cline
You're ready to start building! Copy and paste this prompt into the Cline chat window:
@@ -258,15 +69,15 @@ You're ready to start building! Copy and paste this prompt into the Cline chat w
Hey Cline! Could you help me create a new project folder called "hello-world" in my Cline directory and make a simple webpage that says "Hello World" in big blue text?
```
> **Pro Tip:** Cline will help you create the project folder and set up your first webpage!
> **Pro Tip:** Cline will help you create the project folder and set up your first webpage!
### Tips for Working with Cline
### 🧩 Tips for Working with Cline
- **Ask Questions:** If you're unsure about something, ask Cline!
- **Use Screenshots:** Cline can understand images — show him what you're working on.
- **Copy and Paste Errors:** Share error messages in the chat for solutions.
- **Speak Plainly:** Use your own words — Cline will translate them into code.
### Still Struggling?
### 🫂 Still Struggling?
Join our [Discord community](https://discord.gg/cline) and engage with our team and other Cline users directly.
Join our Discord community and engage with our team and other Cline users directly.
@@ -6,7 +6,7 @@ description: >-
guided way.
---
### The Essential Tools
### 🧰 The Essential Tools
Here are the core tools you'll need for development:
@@ -17,9 +17,9 @@ Here are the core tools you'll need for development:
- Chocolatey for Windows
- apt/yum for Linux
> **Tip:** These tools are the foundation of your developer toolkit. Installing them properly will set you up for success!
> 💡 **Tip:** These tools are the foundation of your developer toolkit. Installing them properly will set you up for success!
### Let Cline Install Everything
### 🚀 Let Cline Install Everything
Copy one of these prompts based on your operating system and paste it into **Cline**:
@@ -41,9 +41,9 @@ Hello Cline! I need help setting up my Windows PC for software development. Coul
Hello Cline! I need help setting up my Linux system for software development. Could you please help me install the essential development tools like Node.js, Git, and any other core utilities that are commonly needed for coding? I'd like you to guide me through the process step-by-step.
```
> **Pro Tip:** Cline will show you each command before running it. You stay in control the entire time!
> **Pro Tip:** Cline will show you each command before running it. You stay in control the entire time!
### What Will Happen
### 🔍 What Will Happen
Cline will guide you through the following steps:
@@ -52,9 +52,9 @@ Cline will guide you through the following steps:
3. Showing you the exact command before it runs (you approve each step!)
4. Verifying each installation is successful
> **Note:** You might need to enter your computer's password for some installations. This is normal!
> ⚠️ **Note:** You might need to enter your computer's password for some installations. This is normal!
### Why These Tools Are Important
### 💡 Why These Tools Are Important
- **Node.js & npm:**
- Build websites with frameworks like React or Next.js
@@ -68,15 +68,15 @@ Cline will guide you through the following steps:
- Quickly install and update development tools
- Keep your environment organized and up to date
### Notes
### 🧩 Notes
> **Tip:** The installation process is interactive — Cline will guide you step by step!
> 💡 **Tip:** The installation process is interactive — Cline will guide you step by step!
- All commands are shown to you for approval before they run.
- If you run into any issues, Cline will help troubleshoot them.
- You may need to enter your computer's password for certain steps.
### Additional Tips for New Coders
### 🧑‍💻 Additional Tips for New Coders
#### Understanding the Terminal
+100 -53
View File
@@ -1,79 +1,126 @@
---
title: "Model Selection Guide"
description: "Last updated: August 20, 2025."
description: "Last updated: Feb 5, 2025."
---
New models drop constantly, so this guide focuses on what's working well with Cline right now. We'll keep it updated as the landscape shifts.
## Understanding Context Windows
## Current Top Models
Think of a context window as your AI assistant's working memory - similar to RAM in a computer. It determines how much information the model can "remember" and process at once during your conversation. This includes:
| Model | Context Window | Input Price* | Output Price* | Best For |
|-------|---------------|--------------|---------------|----------|
| **Claude Sonnet 4.5** | 1M tokens | $3-6 | $15-22.50 | Reliable tool usage, complex codebases |
| **Qwen3 Coder** | 256K tokens | $0.20 | $0.80 | Coding tasks, open source flexibility |
| **Gemini 2.5 Pro** | 1M+ tokens | TBD | TBD | Large codebases, document analysis |
| **GPT-5** | 400K tokens | $1.25 | $10 | Latest OpenAI tech, three modes |
- Your code files and conversations
- The assistant's responses
- Any documentation or additional context provided
*Per million tokens
Context windows are measured in tokens (roughly 3/4 of a word in English). Different models have different context window sizes:
## Budget Options
- Claude 3.5 Sonnet: 200K tokens
- DeepSeek Models: 128K tokens
- Gemini Flash 2.0: 1M tokens
- Gemini 1.5 Pro: 2M tokens
| Model | Context Window | Input Price* | Output Price* | Notes |
|-------|---------------|--------------|---------------|-------|
| **DeepSeek V3** | 128K tokens | $0.14 | $0.28 | Great value for daily coding |
| **DeepSeek R1** | 128K tokens | $0.55 | $2.19 | Budget reasoning champion |
| **Qwen3 32B** | 128K tokens | Varies | Varies | Open source, multiple providers |
| **Z AI GLM 4.5** | 128K tokens | TBD | TBD | MIT licensed, hybrid reasoning |
When you reach the limit of your context window, older information needs to be removed to make room for new information - just like clearing RAM to run new programs. This is why sometimes AI assistants might seem to "forget" earlier parts of your conversation.
*Per million tokens
Cline helps you manage this limitation with its Context Window Progress Bar, which shows:
- Input tokens (what you've sent to the model)
- Output tokens (what the model has generated)
- A visual representation of how much of your context window you've used
- The total capacity for your chosen model
## Context Window Guide
<Frame caption="Visual representation of the context window usage in Cline">
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/image%20(11).png"
alt="Context window progress bar example"
/>
</Frame>
| Size | Word Count | Use Case |
|------|------------|----------|
| 32K tokens | ~24,000 words | Single files, small projects |
| 128K tokens | ~96,000 words | Most coding projects |
| 200K tokens | ~150,000 words | Large codebases |
| 400K+ tokens | ~300,000+ words | Entire applications |
This visibility helps you work more effectively with Cline by letting you know when you might need to start fresh or break tasks into smaller chunks.
**Performance note**: Most models start dropping in quality around 400-500K tokens, even if they claim higher limits.
### Model Comparison
## Open Source vs Closed Source
## LLM Model Comparison for Cline (Feb 2025)
### Open Source Advantages
- **Multiple providers** compete to host them
- **Cheaper pricing** due to competition
- **Provider choice** - switch if one goes down
- **Faster innovation** cycles
| Model | Input Cost\* | Output Cost\* | Context Window | Best For |
| ----------------- | ------------ | ------------- | -------------- | ----------------------------------- |
| Claude 3.5 Sonnet | $3.00 | $15.00 | 200K | Best code implementation & tool use |
| DeepSeek R1 | $0.55 | $2.19 | 128K | Planning & reasoning champion |
| DeepSeek V3 | $0.14 | $0.28 | 128K | Value code implementation |
| o3-mini | $1.10 | $4.40 | 200K | Flexible use, strong planning |
| Gemini Flash 2.0 | $0.00 | $0.00 | 1M | Strong all-rounder |
| Gemini 1.5 Pro | $0.00 | $0.00 | 2M | Large context processing |
### Open Source Models Available
- **Qwen3 Coder** (Apache 2.0)
- **Z AI GLM 4.5** (MIT)
- **Kimi K2** (Open source)
- **DeepSeek series** (Various licenses)
\*Costs per million tokens
## Quick Decision Matrix
### Top Picks for 2025
| If you want... | Use this |
|----------------|----------|
| Something that just works | Claude Sonnet 4.5 |
| To save money | DeepSeek V3 or Qwen3 variants |
| Huge context windows | Gemini 2.5 Pro or Claude Sonnet 4.5 |
| Open source | Qwen3 Coder, Z AI GLM 4.5, or Kimi K2 |
| Latest tech | GPT-5 |
| Speed | Qwen3 Coder on Cerebras (fastest available) |
1. **Claude 3.5 Sonnet**
- Best overall code implementation
- Most reliable tool usage
- Expensive but worth it for critical code
2. **DeepSeek R1**
- Exceptional planning & reasoning
- Great value pricing
3. **o3-mini**
- Strong for planning with adjustable reasoning
- Three reasoning modes for different needs
- Requires OpenAI Tier 3 API access
- 200K context window
4. **DeepSeek V3**
- Reliable code implementation
- Great for daily coding
- Cost-effective for implementation
5. **Gemini Flash 2.0**
- Massive 1M context window
- Improved speed and performance
- Good all-around capabilities
## What Others Are Using
### Best Models by Mode (Plan or Act)
Check [OpenRouter's Cline usage stats](https://openrouter.ai/apps?url=https%3A%2F%2Fcline.bot%2F) to see real usage patterns from the community.
#### Planning
## Context Management
1. **DeepSeek R1**
- Best reasoning capabilities in class
- Excellent at breaking down complex tasks
- Strong math/algorithm planning
- MoE architecture helps with reasoning
2. **o3-mini (high reasoning)**
- Three reasoning levels:
- High: Complex planning
- Medium: Daily tasks
- Low: Quick ideas
- 200K context helps with large projects
3. **Gemini Flash 2.0**
- Massive context window for complex planning
- Strong reasoning capabilities
- Good with multi-step tasks
Cline automatically handles context limits with [auto-compact](/features/auto-compact). When you approach your model's limit, Cline summarizes the conversation to keep working. You don't need to micromanage this.
#### Acting (coding)
## The Bottom Line
1. **Claude 3.5 Sonnet**
- Best code quality
- Most reliable with Cline tools
- Worth the premium for critical code
2. **DeepSeek V3**
- Nearly Sonnet-level code quality
- Better API stability than R1
- Great for daily coding
- Strong tool usage
3. **Gemini 1.5 Pro**
- 2M context window
- Good with complex codebases
- Reliable API
- Strong multi-file understanding
Start with **Claude Sonnet 4.5** if you want reliability. Experiment with **open source options** once you're comfortable to find the best fit for your workflow and budget.
### A Note on Local Models
The landscape moves fast - these recommendations reflect what's working now, but keep an eye on new releases.
While running models locally might seem appealing for cost savings, we currently don't recommend any local models for use with Cline. [Local models are significantly less reliable](https://docs.cline.bot/running-models-locally/read-me-first) at using Cline's essential tools and typically retain only 1-26% of the original model's capabilities. The full cloud version of DeepSeek-R1, for example, is 671B parameters - local versions are drastically simplified copies that struggle with complex tasks and tool usage. Even with high-end hardware (RTX 3070+, 32GB+ RAM), you'll experience slower responses, less reliable tool execution, and reduced capabilities. For the best development experience, we recommend sticking with the cloud models listed above.
### Key Takeaways
1. **Plan vs Act Matters**: Choose models based on task type
2. **Real Performance > Benchmarks**: Focus on actual Cline performance
3. **Mix & Match**: Use different models for planning and implementation
4. **Cost vs Quality**: Premium models worth it for critical code
5. **Keep Backups**: Have alternatives ready for API issues
_\*Note: Based on real usage patterns and community feedback rather than just benchmarks. Your experience may vary. This is not an exhaustive list of all the models available for use within Cline._
@@ -3,7 +3,7 @@ title: "Context Management"
description: "Context is key to getting the most out of Cline"
---
> **Quick Reference**
> 💡 **Quick Reference**
>
> - Context = The information Cline knows about your project
> - Context Window = How much information Cline can hold at once
@@ -38,7 +38,7 @@ Cline actively builds context in two ways:
- Guide focus areas
- Share design thoughts and requirements
**Key Point**: Cline isn't passive - it actively seeks to understand your project. You can either let it explore or guide its focus, especially in [Plan Mode](/features/plan-and-act).
💡 **Key Point**: Cline isn't passive - it actively seeks to understand your project. You can either let it explore or guide its focus, especially in [Plan](https://docs.cline.bot/features/plan-and-act) mode.
### Context & Context Windows
@@ -53,13 +53,12 @@ Think of context like a whiteboard you and Cline share:
- **Context Window** is the size of the whiteboard itself:
- Measured in tokens (1 token ≈ 3/4 of an English word)
- Each model has a fixed size:
- Claude Sonnet 4.5: 1,000,000 tokens
- Qwen3 Coder: 256,000 tokens
- Gemini 2.5 Pro: 1,000,000+ tokens
- GPT-5: 400,000 tokens
- When the whiteboard is full, Cline automatically summarizes the conversation to free up space
- Claude 3.5 Sonnet: 200,000 tokens
- DeepSeek: 64,000 tokens
- When the whiteboard is full, you need to erase (clear context) to write more
- [How Cline manages context under the hood](https://cline.bot/blog/understanding-the-new-context-window-progress-bar-in-cline)
**Important**: Having a large context window doesn't mean you should fill it completely. Models start degrading around 400-500K tokens even if they claim higher limits. Just like a cluttered whiteboard, too much information can make it harder to focus on what's important.
⚠️ **Important**: Having a large context window (like Claude's 200k tokens) doesn't mean you should fill it completely. Just like a cluttered whiteboard, too much information can make it harder to focus on what's important.
## Understanding the Context Window Progress Bar
@@ -77,7 +76,7 @@ Cline provides a visual way to monitor your context window usage through a progr
- ↑ shows input tokens (what you've sent to the LLM)
- ↓ shows output tokens (what the LLM has generated)
- The progress bar visualizes how much of your context window you've used
- The total shows your model's maximum capacity (e.g., 1M for Claude Sonnet 4.5)
- The total shows your model's maximum capacity (e.g., 200k for Claude 3.5-Sonnet)
### When to Watch the Bar
@@ -86,33 +85,7 @@ Cline provides a visual way to monitor your context window usage through a progr
- Before starting complex tasks
- When Cline seems to lose context
**Tip**: With [Auto Compact](/features/auto-compact), Cline can now handle long conversations automatically. When combined with [Focus Chain](/features/focus-chain), you can work on complex projects that span multiple context windows without losing progress.
## Automatic Context Management
Cline includes intelligent features to manage context automatically:
### Default Settings You Should Keep On
**Focus Chain** - Enabled by default in v3.25. Cline generates a todo list at task start and keeps it in context so the thread doesn't drift. You can edit the markdown to add or reorder steps and Cline will adapt. [Learn more about Focus Chain](/features/focus-chain).
**Auto Compact** - Always on. As the context window reaches its limit, Cline creates a comprehensive summary, replaces the bloated history, and continues where it left off. Decisions, code changes, and state are preserved. [Learn more about Auto Compact](/features/auto-compact).
## Advanced Context Tools
When you need more control over context management:
### Deep Planning (`/deep-planning`)
For substantial features, refactors, or integrations. Cline investigates your codebase, asks targeted questions, then writes `implementation_plan.md`. It creates a fresh task with distilled, high-value context. [Learn more about Deep Planning](/features/slash-commands/deep-planning).
### New Task (`/newtask`)
At natural transition points, packages only what matters into a fresh task. Clean slate for implementation after research, or crisp handoff between teammates. [Learn more about New Task](/features/slash-commands/new-task).
### Smol (`/smol`)
Compress the conversation in place to keep momentum. Ideal during debugging or exploratory work when you don't want to break flow. [Learn more about Smol](/features/slash-commands/smol).
### Memory Bank + .clinerules
For non-trivial projects. The Memory Bank captures project knowledge as Markdown in your repo. `.clinerules` are version-controlled instructions that align Cline's behavior with your team. [Learn more about Memory Bank](/prompting/cline-memory-bank) and [Cline Rules](/features/cline-rules).
💡 **Tip**: Consider starting a fresh session when usage reaches 70-80% to maintain optimal performance.
## Working with Context Files
@@ -120,12 +93,12 @@ Context files help maintain understanding across sessions. They serve as documen
#### Approaches to Context Files
1. **Evergreen Project Context (Memory Bank)**
1. **Evergreen Project Context (i.e.** [**Memory Bank**](https://docs.cline.bot/prompting/cline-memory-bank)**)**
- Living documentation that evolves with your project
- Updated as architecture and patterns emerge
- Example: The Memory Bank pattern maintains files like `techContext.md` and `systemPatterns.md`
- Useful for long-running projects and teams
2. **Task-Specific Context**
2. **Task-Specific Context (i.e.** [**Structured Approach**](https://cline.bot/blog/building-advanced-software-with-cline-a-structured-approach)**)**
- Created for specific implementation tasks
- Document requirements, constraints, and decisions
@@ -178,19 +151,9 @@ Context files help maintain understanding across sessions. They serve as documen
- Use Plan mode for complex discussions
- Start fresh sessions when needed
3. **Team Projects**
- Share common context files (consider using [.clinerules](/features/cline-rules) files in project roots)
- Share common context files (consider using [.clinerules](https://docs.cline.bot/features/cline-rules) files in project roots)
- Document architectural decisions
- Maintain consistent patterns
- Keep documentation current
## Bonus Context Tips
- You can @ links and have the webpage's context added to Cline (docs, blogs, etc.)
- Utilize MCP servers to pull in context from your external knowledge bases
- Screenshots can be used as context for models that support image inputs
## The Bottom Line
Cline already does a lot of context work for you - [Focus Chain](/features/focus-chain), [Auto Compact](/features/auto-compact), and the planning flow are designed to keep the thread intact across long horizons. The goal is to help Cline maintain consistent understanding of your project across sessions.
Remember: The goal is to keep only what matters in view, at every step.
Remember: The goal is to help Cline maintain consistent understanding of your project across sessions.
+3 -67
View File
@@ -1,72 +1,8 @@
---
title: "What is Cline?"
description: "An introduction to Cline, your AI-powered development assistant for modern IDEs."
description: "An introduction to Cline, your AI-powered development assistant in VS Code."
---
Cline is an open source AI coding agent that brings frontier AI models directly to your IDE. Unlike autocomplete tools, Cline is a true coding agent that can understand entire codebases, plan complex changes, and execute multi-step tasks.
Cline is an AI development assistant which integrates with Microsoft Visual Studio Code. It provides an interface between your IDE and LLMs facilitating code development, increasing productivity and lowering the barrier to entry for new coders. Depending on permissions, Cline can read/write files, execute commands, use your web browser, and expand its capabilities with Model Context Protocol servers.
## Open Source AI Coding, Uncompromised
Cline gives you direct, transparent access to frontier AI with no limits, no surprises, and no model ecosystem lock-in. See every decision. Choose any model. Control your costs.
### Complete Transparency
Watch in real-time as Cline reads files, considers approaches, and proposes changes. Every decision is visible, every edit reviewable before it's made. This isn't just "explainable AI" - it's complete transparency.
### Your Models, Your Control
Use Claude for complex reasoning, Gemini for massive contexts, or Qwen3 Coder for efficiency. Switch instantly as new models launch. Your API keys, your choice. No gatekeeping innovation.
### Built for Real Engineering
Cline can:
- **Read and write files** across your entire codebase
- **Execute terminal commands** and debug errors
- **Plan complex features** before writing code
- **Connect to external systems** through MCP servers
- **Understand large codebases** with intelligent context management
## Plan & Act Mode
Cline explores your codebase and works with you to create comprehensive plans before writing a single line of code, ensuring it understands the full context of your project.
**Plan Mode** for complex tasks - Cline explores, asks questions, and creates detailed implementation plans.
**Act Mode** for execution - Cline implements the plan with full transparency and control.
## Zero Trust by Design
Your code never touches our servers. Cline runs entirely client-side with your API keys, making it the only option for enterprises with strict security requirements.
**Open source** means your security team can review every line. See exactly how Cline works, what it sends to AI providers, and how decisions are made.
## Key Features
### Focus Chain
Automatic todo list management with real-time progress tracking throughout your tasks. Keeps Cline on track across long projects.
### Auto Compact
When conversations get long, Cline automatically summarizes to preserve context while freeing up space to continue working.
### Deep Planning
For complex features, Cline investigates your codebase, asks clarifying questions, and creates comprehensive implementation plans.
### MCP Integration
Connect to databases, APIs, and documentation through the Model Context Protocol. Cline becomes your bridge to any external system.
### .clinerules
Define project-specific instructions that Cline follows including coding standards, architecture patterns, or team conventions.
## Why Developers Choose Cline
**100% Open Source** - Every line of code on GitHub. 48k+ stars from developers who've read it, improved it, and trust it with their work.
**No Inference Games** - We don't profit from AI usage. While others limit context or route to cheaper models, we give you unrestricted access to any model's full capabilities.
**Future-Proof by Design** - New model released? Use it immediately. Cline works with any AI provider, any model.
**True Visibility** - See every file read, every decision considered, every token used.
## Getting Started
Ready to experience AI coding without limits? [Install Cline](/getting-started/installing-cline) for your preferred IDE and start with our [Model Selection Guide](/getting-started/model-selection-guide) to choose the right AI model for your needs.
What makes Cline distinctive is its thoughtful approach to code generation and its extensive integration capabilities. Rather than simply generating code snippets, Cline collaborates with developers by planning solutions step-by-step, maintaining awareness of the entire development environment, and requiring explicit approval for all changes. It can understand large codebases, accelerate onboarding for new engineers, and connect with hundreds of tools through its Model Context Protocol Marketplace, enabling everything from streamlined project deployments to automated incident response—all through natural language commands.
-14
View File
@@ -1,14 +0,0 @@
// HubSpot Tracking Code for Cline Documentation
;(() => {
// Check if HubSpot script is already loaded to prevent duplicates
if (!document.getElementById("hs-script-loader")) {
var script = document.createElement("script")
script.type = "text/javascript"
script.id = "hs-script-loader"
script.async = true
script.src = "https://js-na2.hs-scripts.com/243656267.js"
// Append the script to the document head
document.head.appendChild(script)
}
})()
@@ -17,7 +17,6 @@ There are multiple places online to find MCP servers:
- [mcpservers.org](https://mcpservers.org/)
- [mcp.so](https://mcp.so/)
- [glama.ai/mcp/servers](https://glama.ai/mcp/servers)
- [mcp.composio.dev](https://mcp.composio.dev/)
These directories allow users to sort the servers by various criteria such as downloads, date, stars, and use case. Each entry provides information such as features, tools, and configuration instructions.
+2 -2
View File
@@ -7,7 +7,7 @@ title: "Configuring MCP Servers"
Utilizing MCP servers will increase your token usage. Cline offers the ability to restrict or disable MCP server functionality as desired.
1. Click the "MCP Servers" icon in the top navigation bar of the Cline extension.
2. Select the "Configure" tab, and then Click the "Advanced MCP Settings" link at the bottom of that pane.
2. Select the "Installed" tab, and then Click the "Advanced MCP Settings" link at the bottom of that pane.
3. Cline will open a new settings window. find `Cline>Mcp:Mode` and make your selection from the dropdown menu.
<Frame>
@@ -56,7 +56,7 @@ To set the maximum time to wait for a response after a tool call to the MCP serv
Settings for all installed MCP servers are located in the `cline_mcp_settings.json` file:
1. Click the MCP Servers icon at the top navigation bar of the Cline pane.
2. Select the "Configure" tab.
2. Select the "Installed" tab.
3. Click the "Configure MCP Servers" button at the bottom of the pane.
The file uses a JSON format with a `mcpServers` object containing named server configurations:
+2 -2
View File
@@ -54,7 +54,7 @@ Please note: Smithery is maintained independently and is not affiliated with our
### Managing Installed MCP Servers
Once added, your MCP servers appear in the "Configure" tab where you can:
Once added, your MCP servers appear in the "Installed" tab where you can:
#### View Server Status
@@ -98,7 +98,7 @@ If a server fails to connect:
For advanced users, Cline stores MCP server configurations in a JSON file that can be modified:
1. In the "Configure" tab, click "Configure MCP Servers" to access the settings file
1. In the "Installed" tab, click "Configure MCP Servers" to access the settings file
2. The configuration for each server follows this format:
```json
+4 -4
View File
@@ -4,17 +4,17 @@ title: "Telemetry"
### Overview
To help make Cline better for everyone, we collect usage data that helps us understand how developers are using our open-source AI coding agent. This feedback loop is crucial for improving Cline's capabilities and user experience.
To help make Cline better for everyone, we collect anonymous usage data that helps us understand how developers are using our open-source AI coding agent. This feedback loop is crucial for improving Cline's capabilities and user experience.
We use PostHog, an open-source analytics platform, for data collection and analysis. Our telemetry implementation is fully transparent - you can review the [source code](https://github.com/cline/cline/blob/main/src/services/posthog/telemetry/TelemetryService.ts) to see exactly what we track.
### Tracking Policy
Privacy is our priority. By default, all collected data is anonymized. If you log in with a Cline account, your telemetry data will be associated with your account to help us improve the product and provide better support when you encounter issues. Your code, prompts, and conversation content always remain private and are never collected.
Privacy is our priority. All collected data is anonymized before being sent to PostHog, with no personally identifiable information (PII) included. Your code, prompts, and conversation content always remain private and are never collected.
### What We Track
We collect basic usage data including:
We collect basic anonymous usage data including:
**Task Interactions:** When tasks start and finish, conversation flow (without content)\
**Mode and Tool Usage:** Switches between plan/act modes, which tools are being used\
@@ -28,7 +28,7 @@ For complete transparency, you can inspect our [telemetry implementation](https:
Telemetry in Cline is entirely optional:
- When you update or install our VS Code extension, you'll see a message about our telemetry
- When you update or install our VS Code extension, you'll see a message about our anonymous telemetry
- You can change your preference anytime in settings
Cline also respects VS Code's global telemetry settings. If you've disabled telemetry at the VS Code level, Cline's telemetry will automatically be disabled as well.
+10116 -11647
View File
File diff suppressed because it is too large Load Diff
+2 -4
View File
@@ -4,15 +4,13 @@
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "mintlify dev",
"check": "mintlify broken-links",
"rename": "mintlify rename"
"dev": "mintlify dev"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"mintlify": "^4.2.23"
"mintlify": "^4.0.538"
}
}
+6 -4
View File
@@ -16,10 +16,12 @@ description: "Learn how to configure and use Anthropic Claude models with Cline.
Cline supports the following Anthropic Claude models:
- `claude-opus-4-1-20250805`
- `claude-opus-4-20250514`
- `anthropic/claude-sonnet-4.5` (Recommended)
- `claude-opus-4-20250514:thinking` (Extended Thinking variant)
- `claude-sonnet-4-20250514` (Recommended)
- `claude-sonnet-4-20250514:thinking` (Extended Thinking variant)
- `claude-3-7-sonnet-20250219`
- `claude-3-7-sonnet-20250219:thinking` (Extended Thinking variant)
- `claude-3-5-sonnet-20241022`
- `claude-3-5-haiku-20241022`
- `claude-3-opus-20240229`
@@ -44,8 +46,8 @@ Cline users can leverage this by checking the `Enable Extended Thinking` box bel
**Key Aspects of Extended Thinking:**
- **Supported Models:** This feature is available for select models, including Claude Opus 4, Claude Sonnet 4.5, and Claude Sonnet 3.7.
- **Summarized Thinking (Claude 4):** For Claude 4 and 4.5 models, the API returns a summary of the full thinking process to balance insight with efficiency and prevent misuse. You are billed for the full thinking tokens, not just the summary.
- **Supported Models:** This feature is available for select models, including variants of Claude Opus 4, Claude Sonnet 4, and Claude Sonnet 3.7. The specific models listed in the "Supported Models" section above with the `:thinking` suffix are pre-configured in Cline to utilize this.
- **Summarized Thinking (Claude 4):** For Claude 4 models, the API returns a summary of the full thinking process to balance insight with efficiency and prevent misuse. You are billed for the full thinking tokens, not just the summary.
- **Streaming:** Extended thinking responses, including the `thinking` blocks, can be streamed.
- **Tool Use & Prompt Caching:** Extended thinking interacts with tool use (requiring thinking blocks to be passed back) and prompt caching (with specific behaviors around cache invalidation and context).
@@ -1,7 +1,6 @@
---
title: "API Key (Simple Setup)"
sidebarTitle: "API Key"
description: "Set up AWS Bedrock with Cline using Bedrock API Keys. Simplest setup for individual developers to access frontier models."
title: "AWS Bedrock"
description: "Learn how to set up AWS Bedrock with Cline using credentials authentication. This guide covers AWS environment setup, regional access verification, and secure integration with the Cline VS Code extension."
---
### Overview
@@ -122,14 +121,14 @@ You can create a custom IAM policy with these permissions and attach it to your
### Conclusion
By following these steps, you can quickly integrate AWS Bedrock with the Cline VS Code extension to accelerate development:
By following these steps, your enterprise team can securely integrate AWS Bedrock with the Cline VS Code extension to accelerate development:
1. **Prepare Your AWS Environment:** Create a Bedrock API Key with the necessary permissions.
1. **Prepare Your AWS Environment:** Create or use a secure IAM role/user, attach the `AmazonBedrockLimitedAccess` policy, and ensure necessary permissions.
2. **Verify Region and Model Access:** Confirm that your selected region supports your required models.
3. **Configure Cline in VS Code:** Install and set up Cline with your AWS API Key and choose an appropriate model.
3. **Configure Cline in VS Code:** Install and set up Cline with your AWS credentials and choose an appropriate model.
4. **Implement Security and Monitoring:** Use best practices for IAM, network security, monitoring, and cost management.
For further details, consult the [AWS Bedrock Documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html). Happy coding!
For further details, consult the [AWS Bedrock Documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html) and coordinate with your internal cloud team. Happy coding!
---
@@ -1,7 +1,6 @@
---
title: "IAM Credentials"
sidebarTitle: "IAM Credentials"
description: "Set up AWS Bedrock with Cline using IAM Access Key and Secret Key credentials. Best for enterprise environments with established IAM policies."
title: "AWS Bedrock"
description: "Learn how to set up AWS Bedrock with Cline using credentials authentication. This guide covers AWS environment setup, regional access verification, and secure integration with the Cline VS Code extension."
---
### Overview
@@ -1,7 +1,6 @@
---
title: "CLI Profile (SSO)"
sidebarTitle: "CLI Profile (SSO)"
description: "Configure AWS Bedrock to use AWS CLI profiles for authentication with Cline. Best for SSO/federated roles and secure enterprise access."
title: "AWS Bedrock w/ Profile Authentication"
description: "Learn how to configure AWS Bedrock to use AWS Profiles for authentication with Cline, focusing on SSO/Federated roles for secure access."
---
### Overview
-115
View File
@@ -1,115 +0,0 @@
---
title: "Baseten"
description: "Learn how to configure and use Baseten's Model APIs with Cline. Access frontier open-source models with enterprise-grade performance, reliability, and competitive pricing."
---
Baseten provides on-demand frontier model APIs designed for production applications, not just experimentation. Built on the Baseten Inference Stack, these APIs deliver enterprise-grade performance and reliability with optimized inference for leading open-source models from OpenAI, DeepSeek, Meta, Moonshot AI, and Alibaba Cloud.
**Website:** [https://www.baseten.co/products/model-apis/](https://www.baseten.co/products/model-apis/)
### Getting an API Key
1. **Sign Up/Sign In:** Go to [Baseten](https://www.baseten.co/) and create an account or sign in.
2. **Navigate to API Keys:** Access your dashboard and go to the API Keys section.
3. **Create a Key:** Generate a new API key. Give it a descriptive name (e.g., "Cline").
4. **Copy the Key:** Copy the API key immediately and store it securely.
### Supported Models
Cline supports all current models under Baseten Model APIs, including:
For the most updated pricing, please visit: https://www.baseten.co/products/model-apis/
**Reasoning Models:**
- `deepseek-ai/DeepSeek-R1` - DeepSeek's first-generation reasoning model (163K context) - \$2.55/\$5.95 per 1M tokens
- `deepseek-ai/DeepSeek-R1-0528` - Latest revision of DeepSeek's reasoning model (163K context) - \$2.55/\$5.95 per 1M tokens
- `deepseek-ai/DeepSeek-V3.1` - Hybrid reasoning with advanced tool calling (163K context) - \$0.50/\$1.50 per 1M tokens
- `deepseek-ai/DeepSeek-V3-0324` - Fast general-purpose with enhanced reasoning (163K context) - \$0.77/\$0.77 per 1M tokens
**Flagship Models:**
- `openai/gpt-oss-120b` (OpenAI) - 120B MoE with strong reasoning capabilities (128K context) - \$0.10/\$0.50 per 1M tokens
- `moonshotai/Kimi-K2-Instruct` (Moonshot AI) - 1 trillion parameter model for agentic tasks (131K context) - \$0.60/\$2.50 per 1M tokens
- `moonshotai/Kimi-K2-Instruct-0905` (Moonshot AI) - September update with enhanced capabilities (262K context) - \$0.60/\$2.50 per 1M tokens
**Meta Llama 4 Series:**
- `meta-llama/Llama-4-Maverick-17B-128E-Instruct` - High-efficiency processing (1M context!) - \$0.19/\$0.72 per 1M tokens
- `meta-llama/Llama-4-Scout-17B-16E-Instruct` - Precise context understanding (1M context!) - \$0.13/\$0.50 per 1M tokens
**Coding Specialists:**
- `Qwen/Qwen3-Coder-480B-A35B-Instruct`- Advanced coding and reasoning (262K context) - \$0.38/\$1.53 per 1M tokens
- `Qwen/Qwen3-235B-A22B-Instruct-2507` - Math and reasoning expert (262K context) - \$0.22/\$0.80 per 1M tokens
### Configuration in Cline
1. **Open Cline Settings:** Click the settings icon (⚙️) in the Cline panel.
2. **Select Provider:** Choose "Baseten" from the "API Provider" dropdown.
3. **Enter API Key:** Paste your Baseten API key into the "Baseten API Key" field.
4. **Select Model:** Choose your desired model from the "Model" dropdown.
### Production-First Architecture
Baseten's Model APIs are built for production environments with several key advantages:
#### Enterprise-Grade Reliability
- **Four nines of uptime** (99.99%) through active-active redundancy
- **Cloud-agnostic, multi-cluster autoscaling** for consistent availability
- **SOC 2 Type II certified** and **HIPAA compliant** for security requirements
#### Optimized Performance
- **Pre-optimized models** shipped with the Baseten Inference Stack
- **Latest-generation GPUs** with multi-cloud infrastructure
- **Ultra-fast inference** optimized from the bottom up for production workloads
#### Cost Efficiency
- **5-10x less expensive** than closed alternatives
- **Optimized multi-cloud infrastructure** for efficient resource utilization
- **Transparent pricing** with no hidden costs or rate limit surprises
#### Developer Experience
- **OpenAI compatible API** - migrate by swapping a single URL
- **Drop-in replacement** for closed models with comprehensive observability
- **Seamless scaling** from Model APIs to dedicated deployments
### Special Features
#### Function Calling & Tool Use
All Baseten models support structured outputs, function calling, and tool use as part of the Baseten Inference Stack, making them ideal for agentic applications.
#### Reasoning Capabilities
DeepSeek models offer enhanced reasoning with step-by-step thought processes, while maintaining production-ready performance.
#### Long Context Support
- **Up to 1 million tokens** for Llama 4 models (Maverick and Scout)
- **262K tokens** for Qwen3 models
- **163K tokens** for DeepSeek models
- **Perfect for code repositories** and complex multi-turn conversations
#### Quantization Optimizations
Models are deployed with advanced quantization techniques (fp4, fp8, fp16) for optimal performance while maintaining quality.
### Migration from Other Providers
Baseten's OpenAI compatibility makes migration straightforward:
**From OpenAI:**
- Swap `api.openai.com` with `inference.baseten.co/v1`
- Keep existing request/response formats
- Benefit from significant cost savings
**From Other Providers:**
- Use standard OpenAI SDK format
- Maintain existing prompting strategies
- Access to newer open-source models
### Tips and Notes
- **Model Selection:** Choose models based on your specific use case - reasoning models for complex tasks, coding models for development work, and flagship models for general applications.
- **Cost Optimization:** Baseten offers some of the most competitive pricing in the market, especially for open-source models.
- **Context Windows:** Take advantage of large context windows (up to 1M tokens) for including substantial codebases and documentation.
- **Enterprise Ready:** Baseten is designed for production use with enterprise-grade security, compliance, and reliability.
- **Dynamic Model Updates:** Cline automatically fetches the latest model list from Baseten, ensuring access to new models as they're released.
- **Multi-Cloud Capacity Management (MCM):** Baseten's multi-cloud infrastructure ensures high availability and low latency globally.
- **Support:** Baseten provides dedicated support for production deployments and can work with you on dedicated resources as you scale.
### Pricing Information
Current pricing is highly competitive and transparent. For the most up-to-date pricing, visit the [Baseten Model APIs page](https://www.baseten.co/products/model-apis/). Prices typically range from \$0.10-\$6.00 per million tokens, making Baseten significantly more cost-effective than many closed-model alternatives while providing access to state-of-the-art open-source models.
-96
View File
@@ -1,96 +0,0 @@
---
title: "Cerebras"
description: "Learn how to configure and use Cerebras's ultra-fast inference with Cline. Experience up to 2,600 tokens per second with wafer-scale chip architecture and real-time reasoning models."
---
Cerebras delivers the world's fastest AI inference through their revolutionary wafer-scale chip architecture. Unlike traditional GPUs that shuttle model weights from external memory, Cerebras stores entire models on-chip, eliminating bandwidth bottlenecks and achieving speeds up to 2,600 tokens per second—often 20x faster than GPUs.
**Website:** [https://cloud.cerebras.ai/](https://cloud.cerebras.ai/)
### Getting an API Key
1. **Sign Up/Sign In:** Go to [Cerebras Cloud](https://cloud.cerebras.ai/) and create an account or sign in.
2. **Navigate to API Keys:** Access the API keys section in your dashboard.
3. **Create a Key:** Generate a new API key. Give it a descriptive name (e.g., "Cline").
4. **Copy the Key:** Copy the API key immediately. Store it securely.
### Supported Models
Cline supports the following Cerebras models:
- `qwen-3-coder-480b-free` (Free tier) - High-performance coding model at no cost
- `qwen-3-coder-480b` - Flagship 480B parameter coding model
- `qwen-3-235b-a22b-instruct-2507` - Advanced instruction-following model
- `qwen-3-235b-a22b-thinking-2507` - Reasoning model with step-by-step thinking
- `llama-3.3-70b` - Meta's Llama 3.3 model optimized for speed
- `qwen-3-32b` - Compact yet powerful model for general tasks
### Configuration in Cline
1. **Open Cline Settings:** Click the settings icon (⚙️) in the Cline panel.
2. **Select Provider:** Choose "Cerebras" from the "API Provider" dropdown.
3. **Enter API Key:** Paste your Cerebras API key into the "Cerebras API Key" field.
4. **Select Model:** Choose your desired model from the "Model" dropdown.
5. **(Optional) Custom Base URL:** Most users won't need to adjust this setting.
### Cerebras's Wafer-Scale Advantage
Cerebras has fundamentally reimagined AI hardware architecture to solve the inference speed problem:
#### Wafer-Scale Architecture
Traditional GPUs use separate chips for compute and memory, forcing them to constantly shuttle model weights back and forth. Cerebras built the world's largest AI chip—a wafer-scale engine that stores entire models on-chip. No external memory, no bandwidth bottlenecks, no waiting.
#### Revolutionary Speed
- **Up to 2,600 tokens per second** - often 20x faster than GPUs
- **Single-second reasoning** - what used to take minutes now happens instantly
- **Real-time applications** - reasoning models become practical for interactive use
- **No bandwidth limits** - entire models stored on-chip eliminate memory bottlenecks
#### The Cerebras Scaling Law
Cerebras discovered that **faster inference enables smarter AI**. Modern reasoning models generate thousands of tokens as "internal monologue" before answering. On traditional hardware, this takes too long for real-time use. Cerebras makes reasoning models fast enough for everyday applications.
#### Quality Without Compromise
Unlike other speed optimizations that sacrifice accuracy, Cerebras maintains full model quality while delivering unprecedented speed. You get the intelligence of frontier models with the responsiveness of lightweight ones.
Learn more about Cerebras's technology in their blog posts:
- [The Cerebras Scaling Law: Faster Inference Is Smarter AI](https://www.cerebras.ai/blog/the-cerebras-scaling-law-faster-inference-is-smarter-ai)
- [Introducing Cerebras Code](https://www.cerebras.ai/blog/introducing-cerebras-code)
### Cerebras Code Plans
Cerebras offers specialized plans for developers:
#### Code Pro ($50/month)
- Access to Qwen3-Coder with fast, high-context completions
- Up to 24 million tokens per day
- Ideal for indie developers and weekend projects
- 3-4 hours of uninterrupted coding per day
#### Code Max ($200/month)
- Heavy coding workflow support
- Up to 120 million tokens per day
- Perfect for full-time development and multi-agent systems
- No weekly limits, no IDE lock-in
### Special Features
#### Free Tier
The `qwen-3-coder-480b-free` model provides access to high-performance inference at no cost—unique among speed-focused providers.
#### Real-Time Reasoning
Reasoning models like `qwen-3-235b-a22b-thinking-2507` can complete complex multi-step reasoning in under a second, making them practical for interactive development workflows.
#### Coding Specialization
Qwen3-Coder models are specifically optimized for programming tasks, delivering performance comparable to Claude Sonnet 4 and GPT-4.1 in coding benchmarks.
#### No IDE Lock-In
Works with any OpenAI-compatible tool—Cursor, Continue.dev, Cline, or any other editor that supports OpenAI endpoints.
### Tips and Notes
- **Speed Advantage:** Cerebras excels at making reasoning models practical for real-time use. Perfect for agentic workflows that require multiple LLM calls.
- **Free Tier:** Start with the free model to experience Cerebras speed before upgrading to paid plans.
- **Context Windows:** Models support context windows ranging from 64K to 128K tokens for including substantial code context.
- **Rate Limits:** Generous rate limits designed for development workflows. Check your dashboard for current limits.
- **Pricing:** Competitive pricing with significant speed advantages. Visit [Cerebras Cloud](https://cloud.cerebras.ai/) for current rates.
- **Real-Time Applications:** Ideal for applications where AI response time matters—code generation, debugging, and interactive development.
+20 -3
View File
@@ -35,8 +35,26 @@ First, you'll need to install and authenticate Claude Code on your system:
<br />
<Accordion title="Windows Setup">
Anthropic introduced full support for Claude Code on Windows. Follow the [instructions on how to set up Claude Code
normally](#setup) and make sure you have the latest Claude Code and Cline versions.
On Windows, Cline supports integrating with Claude Code through WSL.
Windows doesn't support long commands, and Claude Code only accepts the system prompt through a flag, which means we can't properly prompt Claude through Claude Code. Anthropic is [working on a workaround to streamline this](https://github.com/anthropics/claude-code/issues/3411).
1. **Make sure you have WSL set-up**. You can follow [this](https://code.visualstudio.com/docs/remote/wsl#_installation) guide to do it.
2. **Open VSCode from WSL** and verify it's properly set-up. You should see an indicator in the bottom left that says "WSL". You can find an image of the indicator [here](https://code.visualstudio.com/docs/remote/wsl#_from-the-wsl-terminal).
3. Install Cline within WSL and make sure it shows the following:
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/cline_wsl_installed_extension.webp"
alt="Indicator that an extension is installed on WSL"
/>
</Frame>
4. Clone or [move](https://stackoverflow.com/a/42586455) your project over to WSL
5. Follow the [instructions on how to set up Claude Code normally](#setup), but from the WSL terminal.
</Accordion>
### Finding your Claude Code path
@@ -52,7 +70,6 @@ If you're not sure where Claude Code is installed:
The Claude Code provider supports these models:
- `claude-sonnet-4-20250514` (Recommended)
- `claude-opus-4-1-20250805`
- `claude-opus-4-20250514`
- `claude-3-7-sonnet-20250219`
- `claude-3-5-sonnet-20241022`
-87
View File
@@ -1,87 +0,0 @@
---
title: "Doubao"
description: "Learn how to configure and use ByteDance's Doubao AI models with Cline. Experience advanced reasoning, multimodal capabilities, and cost-effective inference with Chinese language optimization."
---
Doubao is ByteDance's flagship AI model series, featuring innovative sparse Mixture-of-Experts (MoE) architecture that delivers performance equivalent to much larger models while maintaining cost efficiency. With over 13 million users and advanced multimodal capabilities, Doubao offers competitive alternatives to Western AI systems with particular strength in Chinese language processing.
**Website:** [https://www.volcengine.com/](https://www.volcengine.com/)
### Getting an API Key
1. **Sign Up/Sign In:** Visit the [Volcano Engine Console](https://console.volcengine.com/). Create an account or sign in.
2. **Navigate to Model Service:** Access the AI model service section in the console.
3. **Create API Key:** Generate a new API key for the Doubao service.
4. **Copy the Key:** Copy the API key immediately and store it securely. You may not be able to view it again.
### Supported Models
Cline supports the following Doubao models:
- `doubao-seed-1-6-250615` (Default) - General purpose model with balanced performance
- `doubao-seed-1-6-thinking-250715` - Enhanced reasoning model with step-by-step thinking
- `doubao-seed-1-6-flash-250715` - Speed-optimized model for fast inference
All models feature:
- **128,000 token context window** for extensive document processing
- **32,768 max output tokens** for comprehensive responses
- **Image input support** for multimodal applications
- **Prompt caching** with 80% discount on cached reads
### Configuration in Cline
1. **Open Cline Settings:** Click the settings icon (⚙️) in the Cline panel.
2. **Select Provider:** Choose "Doubao" from the "API Provider" dropdown.
3. **Enter API Key:** Paste your Doubao API key into the "Doubao API Key" field.
4. **Select Model:** Choose your desired model from the "Model" dropdown.
**Note:** Doubao uses the base URL `https://ark.cn-beijing.volces.com/api/v3` and servers are located in Beijing, China.
### ByteDance's AI Innovation
Doubao represents ByteDance's strategic entry into the AI model space with several key innovations:
#### Sparse Mixture-of-Experts Architecture
Doubao 1.5 Pro employs an innovative sparse MoE framework where 20 billion activated parameters deliver performance equivalent to a 140-billion-parameter dense model. This architecture significantly reduces operational costs while maintaining high performance standards.
#### Extended Context Processing
With context windows ranging from 32,000 to 256,000 tokens, Doubao excels at processing long-form content including legal documents, academic research, market reports, and creative content generation.
#### Multimodal Excellence
- **Advanced Visual Processing:** Enhanced visual reasoning, document recognition, and fine-grained information understanding
- **Integrated Speech:** Seamless speech and text token integration with superior emotional continuity
- **Document Analysis:** Comprehensive document summarization and content processing capabilities
#### Chinese Language Optimization
Doubao was specifically trained for Chinese language fluency and cultural relevance, providing significant advantages for Chinese-speaking users and applications requiring deep cultural context understanding.
#### Cost Efficiency
Doubao maintains pricing approximately **half the cost of comparable OpenAI offerings**, making advanced AI more accessible while establishing competitive market positioning.
### Special Features
#### Reasoning Models
The `doubao-seed-1-6-thinking-250715` model offers enhanced reasoning capabilities with step-by-step thinking processes, making it ideal for complex problem-solving tasks.
#### Multimodal Capabilities
Unlike traditional cascaded approaches, Doubao integrates speech and text processing seamlessly, enabling more natural voice interactions and comprehensive document analysis.
#### Prompt Caching
All models support prompt caching with significant cost savings (80% discount on cached reads), making repeated queries more economical.
#### ByteDance Ecosystem Integration
Doubao integrates vertically with ByteDance properties including TikTok (Douyin), Toutiao, and Feishu, enabling seamless workflow integration across the ecosystem.
### Performance and Benchmarks
Doubao-1.5 Pro-AS1 Preview has demonstrated superior performance compared to OpenAI's O1-preview on specific benchmarks, including surpassing O1 models on AIME tests. The model continues to improve through reinforcement learning, with performance expected to enhance over time.
### Tips and Notes
- **Regional Advantage:** Optimized for Chinese language and cultural contexts, making it ideal for Chinese-speaking users and markets.
- **Cost Effectiveness:** Approximately 50% lower cost than comparable Western AI models while maintaining competitive performance.
- **Context Windows:** Large context windows (up to 256K tokens) enable processing of extensive documents and codebases.
- **Multimodal Applications:** Strong visual and speech processing capabilities make it suitable for diverse multimedia applications.
- **Server Location:** Servers located in Beijing, China - consider latency implications for global users.
- **Ecosystem Benefits:** Integration with ByteDance services provides additional workflow advantages for users of TikTok, Toutiao, and Feishu.
- **Pricing:** Check the Volcano Engine console for current pricing information and regional availability.
-51
View File
@@ -1,51 +0,0 @@
---
title: "Fireworks AI"
description: "Learn how to configure and use Fireworks AI models with Cline. Access high-performance open-source language models with fast, cost-effective APIs."
---
Cline supports accessing models through the Fireworks AI platform, which offers fast, cost-effective access to a wide range of state-of-the-art open-source language models. Built for speed and reliability, Fireworks AI provides serverless deployment options with OpenAI-compatible APIs and context windows up to 256,000 tokens.
**Website:** [https://fireworks.ai/](https://fireworks.ai/)
### Getting an API Key
1. **Sign Up/Sign In:** Go to [Fireworks AI](https://fireworks.ai/) and create an account or sign in.
2. **Navigate to API Keys:** After logging in, go to the [API Keys page](https://app.fireworks.ai/settings/users/api-keys) in the account settings.
3. **Create a Key:** Click "Create API key" and give your key a descriptive name (e.g., "Cline").
4. **Copy the Key:** **Important:** Copy the API key _immediately_. You will not be able to see it again. Store it securely.
### Supported Models
Cline supports the following Fireworks AI models:
- `accounts/fireworks/models/kimi-k2-instruct` (Default)
- `accounts/fireworks/models/qwen3-235b-a22b-instruct-2507`
- `accounts/fireworks/models/qwen3-coder-480b-a35b-instruct`
- `accounts/fireworks/models/deepseek-r1-0528`
- `accounts/fireworks/models/deepseek-v3`
**Model Details:**
| Model | Context Window | Best For | Pricing (per 1M tokens) |
|-------|----------------|----------|-------------------------|
| Kimi K2 | 128K | General tasks, agentic capabilities | \$0.60 input, \$2.50 output |
| Qwen3 235B | 256K | Cost-effective general use | \$0.22 input, \$0.88 output |
| Qwen3 Coder | 256K | Code generation and debugging | \$0.45 input, \$1.80 output |
| DeepSeek R1 | 160K | Complex reasoning, function calling | \$3.00 input, \$8.00 output |
| DeepSeek V3 | 128K | Strong general performance | \$0.90 input, \$0.90 output |
### Configuration in Cline
1. **Open Cline Settings:** Click the settings icon (⚙️) in the Cline panel.
2. **Select Provider:** Choose "Fireworks AI" from the "API Provider" dropdown.
3. **Enter API Key:** Paste your Fireworks AI API key into the "Fireworks AI API Key" field.
4. **Select Model:** Choose your desired model from the "Model" dropdown. The default model is Kimi K2.
### Tips and Notes
- **Cost-Effective:** Fireworks AI offers significantly lower pricing than proprietary models while maintaining competitive performance.
- **Large Context Windows:** Most models support 128K-256K tokens, suitable for processing large documents and maintaining extended conversations.
- **OpenAI Compatibility:** The provider uses an OpenAI-compatible API format with streaming support and usage tracking.
- **Rate Limits:** Fireworks AI has usage-based rate limits. Monitor your usage in the dashboard and consider upgrading your plan if needed.
- **API Keys:** Stored locally on your machine for security.
- **Pricing:** See the [Fireworks AI pricing page](https://fireworks.ai/pricing) for current rates. Prices shown are per million tokens.
-131
View File
@@ -1,131 +0,0 @@
---
title: "Fireworks AI"
description: "Learn how to configure and use Fireworks AI's lightning-fast inference platform with Cline. Experience up to 4x faster inference speeds with optimized models and competitive pricing."
---
Fireworks AI is a leading infrastructure platform for generative AI that focuses on delivering exceptional performance through optimized inference capabilities. With up to 4x faster inference speeds than alternative platforms and support for over 40 different AI models, Fireworks eliminates the operational complexity of running AI models at scale.
**Website:** [https://fireworks.ai/](https://fireworks.ai/)
### Getting an API Key
1. **Sign Up/Sign In:** Go to [Fireworks AI](https://fireworks.ai/) and create an account or sign in.
2. **Navigate to API Keys:** Access the API keys section in your dashboard.
3. **Create a Key:** Generate a new API key. Give it a descriptive name (e.g., "Cline").
4. **Copy the Key:** Copy the API key immediately. Store it securely.
### Supported Models
Fireworks AI supports a wide variety of models across different categories. Popular models include:
**Text Generation Models:**
- Llama 3.1 series (8B, 70B, 405B)
- Mixtral 8x7B and 8x22B
- Qwen 2.5 series
- DeepSeek models with reasoning capabilities
- Code Llama models for programming tasks
**Vision Models:**
- Llama 3.2 Vision models
- Qwen 2-VL models
**Embedding Models:**
- Various text embedding models for semantic search
The platform curates, optimizes, and deploys models with custom kernels and inference optimizations for maximum performance.
### Configuration in Cline
1. **Open Cline Settings:** Click the settings icon (⚙️) in the Cline panel.
2. **Select Provider:** Choose "Fireworks" from the "API Provider" dropdown.
3. **Enter API Key:** Paste your Fireworks API key into the "Fireworks API Key" field.
4. **Enter Model ID:** Specify the model you want to use (e.g., "accounts/fireworks/models/llama-v3p1-70b-instruct").
5. **Configure Tokens:** Optionally set max completion tokens and context window size.
### Fireworks AI's Performance Focus
Fireworks AI's competitive advantages center on performance optimization and developer experience:
#### Lightning-Fast Inference
- **Up to 4x faster inference** than alternative platforms
- **250% higher throughput** compared to open source inference engines
- **50% faster speed** with significantly reduced latency
- **6x lower cost** than HuggingFace Endpoints with 2.5x generation speed
#### Advanced Optimization Technology
- **Custom kernels** and inference optimizations increase throughput per GPU
- **Multi-LoRA architecture** enables efficient resource sharing
- **Hundreds of fine-tuned model variants** can run on shared base model infrastructure
- **Asset-light model** focuses on optimization software rather than expensive GPU ownership
#### Comprehensive Model Support
- **40+ different AI models** curated and optimized for performance
- **Multiple GPU types** supported: A100, H100, H200, B200, AMD MI300X
- **Pay-per-GPU-second billing** with no extra charges for start-up times
- **OpenAI API compatibility** for seamless integration
### Pricing Structure
Fireworks AI uses a usage-based pricing model with competitive rates:
#### Text and Vision Models (2025)
| Parameter Count | Price per 1M Input Tokens |
|---|---|
| Less than 4B parameters | $0.10 |
| 4B - 16B parameters | $0.20 |
| More than 16B parameters | $0.90 |
| MoE 0B - 56B parameters | $0.50 |
#### Fine-Tuning Services
| Base Model Size | Price per 1M Training Tokens |
|---|---|
| Up to 16B parameters | $0.50 |
| 16.1B - 80B parameters | $3.00 |
| DeepSeek R1 / V3 | $10.00 |
#### Dedicated Deployments
| GPU Type | Price per Hour |
|---|---|
| A100 80GB | $2.90 |
| H100 80GB | $5.80 |
| H200 141GB | $6.99 |
| B200 180GB | $11.99 |
| AMD MI300X | $4.99 |
### Special Features
#### Fine-Tuning Capabilities
Fireworks offers sophisticated fine-tuning services accessible through CLI interface, supporting JSON-formatted data from databases like MongoDB Atlas. Fine-tuned models cost the same as base models for inference.
#### Developer Experience
- **Browser playground** for direct model interaction
- **REST API** with OpenAI compatibility
- **Comprehensive cookbook** with ready-to-use recipes
- **Multiple deployment options** from serverless to dedicated GPUs
#### Enterprise Features
- **HIPAA and SOC 2 Type II compliance** for regulated industries
- **Self-serve onboarding** for developers
- **Enterprise sales** for larger deployments
- **Post-paid billing options** and Business tier
#### Reasoning Model Support
Advanced support for reasoning models with `<think>` tag processing and reasoning content extraction, making complex multi-step reasoning practical for real-time applications.
### Performance Advantages
Fireworks AI's optimization delivers measurable improvements:
- **250% higher throughput** vs open source engines
- **50% faster speed** with reduced latency
- **6x cost reduction** compared to alternatives
- **2.5x generation speed** improvement per request
### Tips and Notes
- **Model Selection:** Choose models based on your specific use case - smaller models for speed, larger models for complex reasoning.
- **Performance Focus:** Fireworks excels at making AI inference fast and cost-effective through advanced optimizations.
- **Fine-Tuning:** Leverage fine-tuning capabilities to improve model accuracy with your proprietary data.
- **Compliance:** HIPAA and SOC 2 Type II compliance enables use in regulated industries.
- **Pricing Model:** Usage-based pricing scales with your success rather than traditional seat-based models.
- **Developer Resources:** Extensive documentation and cookbook recipes accelerate implementation.
- **GPU Options:** Multiple GPU types available for dedicated deployments based on performance needs.
-80
View File
@@ -1,80 +0,0 @@
---
title: "Groq"
description: "Learn how to configure and use Groq's lightning-fast inference with Cline. Access models from OpenAI, Meta, DeepSeek, and more on Groq's purpose-built LPU architecture."
---
Groq provides ultra-fast AI inference through their custom LPU™ (Language Processing Unit) architecture, purpose-built for inference rather than adapted from training hardware. Groq hosts open-source models from various providers including OpenAI, Meta, DeepSeek, Moonshot AI, and others.
**Website:** [https://groq.com/](https://groq.com/)
### Getting an API Key
1. **Sign Up/Sign In:** Go to [Groq](https://groq.com/) and create an account or sign in.
2. **Navigate to Console:** Go to the [Groq Console](https://console.groq.com/) to access your dashboard.
3. **Create a Key:** Navigate to the API Keys section and create a new API key. Give your key a descriptive name (e.g., "Cline").
4. **Copy the Key:** Copy the API key immediately. You will not be able to see it again. Store it securely.
### Supported Models
Cline supports the following Groq models:
- `llama-3.3-70b-versatile` (Meta) - Balanced performance with 131K context
- `llama-3.1-8b-instant` (Meta) - Fast inference with 131K context
- `openai/gpt-oss-120b` (OpenAI) - Featured flagship model with 131K context
- `openai/gpt-oss-20b` (OpenAI) - Featured compact model with 131K context
- `moonshotai/kimi-k2-instruct` (Moonshot AI) - 1 trillion parameter model with prompt caching
- `deepseek-r1-distill-llama-70b` (DeepSeek/Meta) - Reasoning-optimized model
- `qwen/qwen3-32b` (Alibaba Cloud) - Enhanced for Q&A tasks
- `meta-llama/llama-4-maverick-17b-128e-instruct` (Meta) - Latest Llama 4 variant
- `meta-llama/llama-4-scout-17b-16e-instruct` (Meta) - Latest Llama 4 variant
### Configuration in Cline
1. **Open Cline Settings:** Click the settings icon (⚙️) in the Cline panel.
2. **Select Provider:** Choose "Groq" from the "API Provider" dropdown.
3. **Enter API Key:** Paste your Groq API key into the "Groq API Key" field.
4. **Select Model:** Choose your desired model from the "Model" dropdown.
### Groq's Speed Revolution
Groq's LPU architecture delivers several key advantages over traditional GPU-based inference:
#### LPU Architecture
Unlike GPUs that are adapted from training workloads, Groq's LPU is purpose-built for inference. This eliminates architectural bottlenecks that create latency in traditional systems.
#### Unmatched Speed
- **Sub-millisecond latency** that stays consistent across traffic, regions, and workloads
- **Static scheduling** with pre-computed execution graphs eliminates runtime coordination delays
- **Tensor parallelism** optimized for low-latency single responses rather than high-throughput batching
#### Quality Without Tradeoffs
- **TruePoint numerics** reduce precision only in areas that don't affect accuracy
- **100-bit intermediate accumulation** ensures lossless computation
- **Strategic precision control** maintains quality while achieving 2-4× speedup over BF16
#### Memory Architecture
- **SRAM as primary storage** (not cache) with hundreds of megabytes on-chip
- **Eliminates DRAM/HBM latency** that plagues traditional accelerators
- **Enables true tensor parallelism** by splitting layers across multiple chips
Learn more about Groq's technology in their [LPU architecture blog post](https://groq.com/blog/inside-the-lpu-deconstructing-groq-speed).
### Special Features
#### Prompt Caching
The Kimi K2 model supports prompt caching, which can significantly reduce costs and latency for repeated prompts.
#### Vision Support
Select models support image inputs and vision capabilities. Check the model details in the Groq Console for specific capabilities.
#### Reasoning Models
Some models like DeepSeek variants offer enhanced reasoning capabilities with step-by-step thought processes.
### Tips and Notes
- **Model Selection:** Choose models based on your specific use case and performance requirements.
- **Speed Advantage:** Groq excels at single-request latency rather than high-throughput batch processing.
- **OSS Model Provider:** Groq hosts open-source models from multiple providers (OpenAI, Meta, DeepSeek, etc.) on their fast infrastructure.
- **Context Windows:** Most models offer large context windows (up to 131K tokens) for including substantial code and context.
- **Pricing:** Groq offers competitive pricing with their speed advantages. Check the [Groq Pricing](https://groq.com/pricing) page for current rates.
- **Rate Limits:** Groq has generous rate limits, but check their documentation for current limits based on your usage tier.
@@ -43,6 +43,7 @@ While the "OpenAI Compatible" provider type allows connecting to various endpoin
- `o1`
- `o1-preview`
- `o1-mini`
- `gpt-4.5-preview`
- `gpt-4o`
- `gpt-4o-mini`
+1
View File
@@ -26,6 +26,7 @@ Cline is compatible with a variety of OpenAI models, including but not limited t
- `o1`
- `o1-preview`
- `o1-mini`
- `gpt-4.5-preview`
- `gpt-4o`
- `gpt-4o-mini`
- 'gpt-4.1'
+2 -2
View File
@@ -10,7 +10,7 @@ Cline supports accessing models through the [Requesty](https://www.requesty.ai/)
### Getting an API Key
1. **Sign Up/Sign In:** Go to the [Requesty website](https://www.requesty.ai/) and create an account or sign in.
2. **Get API Key:** You can get an API key from the [API Management](https://app.requesty.ai/api-keys) section of your Requesty dashboard.
2. **Get API Key:** You can get an API key from the [API Management](https://app.requesty.ai/manage-api) section of your Requesty dashboard.
### Supported Models
@@ -26,7 +26,7 @@ Requesty provides access to a wide range of models. Cline will automatically fet
### Tips and Notes
- **Optimizations**: Requesty offers a range of in-flight cost optimizations to lower your costs.
- **Unified and simplified billing**: Unrestricted access to all providers and models, automatic balance top ups and more via a single [API key](https://app.requesty.ai/api-keys).
- **Unified and simplified billing**: Unrestricted access to all providers and models, automatic balance top ups and more via a single [API key](https://app.requesty.ai/manage-api).
- **Cost tracking**: Track cost per model, coding language, changed file, and more via the [Cost dashboard](https://app.requesty.ai/cost-management) or the [Requesty VS Code extension](https://marketplace.visualstudio.com/items?itemName=Requesty.requesty).
- **Stats and logs**: See your [coding stats dashboard](https://app.requesty.ai/usage-stats) or go through your [LLM interaction logs](https://app.requesty.ai/logs).
- **Fallback policies**: Keep your LLM working for you with fallback policies when providers are down.
-76
View File
@@ -1,76 +0,0 @@
---
title: "SAP AI Core"
description: "Learn how to configure and use LLM models from Generative AI Hub in SAP AI Core with Cline."
---
SAP AI Core and the generative AI hub help you to integrate LLMs and AI into new business processes in a cost-efficient manner.
**Website:** [SAP Help Portal](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/what-is-sap-ai-core)
> 💡 **Information**
>
> SAP AI Core, and Generative AI Hub, are offerings from SAP BTP.
> You need an active SAP BTP contract and a existing subaccount with a SAP AI Core instance with the `extended` service plan (For more details about SAP AI Core service plans and their capabilities, see the [Service Plans documentation](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/service-plans)) to perform these steps.
### Getting a Service Binding
1. **Access:** Go to your subaccount via [BTP Cloud Cockpit](cockpit.btp.cloud.sap/cockpit)
2. **Create a Service Binding:** Go to "Instances and Subscriptions", select your SAP AI Core service instance and click on Service Bindings > Create.
3. **Copy the Service Binding:** Copy the service binding values.
### Supported Models
SAP AI Core supports a large and growing number of models.
Refer to the [Generative AI Hub Supported Models page](https://me.sap.com/notes/3437766) for the complete and up-to-date list.
### Configuration in Cline
1. **Open Cline Settings:** Click the settings icon (⚙️) in the Cline panel.
2. **Select Provider:** Choose "SAP AI Core" from the "API Provider" dropdown.
3. **Enter Client Id:** Add the `.clientid` field from the service binding into the "AI Core Client Id" field.
4. **Enter Client Secret:** Add the `.clientsecret` field from the service binding into the "AI Core Client Secret" field.
5. **Enter Base URL:** Add the `.serviceurls.AI_API_URL` field from the service binding into the "AI Core Base URL" field.
6. **Enter Auth URL:** Add the `.url` field from the service binding into the "AI Core Auth URL" field.
7. **Enter Resource Group:** Add the resource group where you have your model deployments. See [Create a Deployment for a Generative AI Model](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-deployment-for-generative-ai-model-in-sap-ai-core).
8. **Configure Orchestration Mode:** If you have an `extended` service plan, the "Orchestration Mode" checkbox will automatically appear.
9. **Select Model:** Choose your desired model from the "Model" dropdown.
### Orchestration Mode vs Native API
**Orchestration Mode:**
- **Simplified usage:** Provides access to all available models without requiring individual deployments using the [Harmonized API](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/harmonized-api)
**Native API Mode:**
- **Manual deployments:** Requires manual model deployment and management in your SAP AI Core service instance
### Tips and Notes
- **Service Plan Requirement:** You must have the SAP AI Core `extended` service plan to use LLMs with Cline. Other service plans do not provide access to Generative AI Hub.
- **Orchestration Mode (Recommended):** Keep Orchestration Mode enabled for the simplest setup. It provides automatic access to all available models without requiring manual deployments.
- **Native API Mode:** Only disable Orchestration Mode if you have specific requirements that necessitate direct AI Core API access or need features not supported by the orchestration mode.
- **When using Native API Mode:**
- **Model Selection:** The model dropdown displays models in two separate lists:
- **Deployed Models:** These models are already deployed in your specified resource group and are ready to use immediately.
- **Not Deployed Models:** These models don't have active deployments in your specified resource group. You won't be able to use these models until you create deployments for them in SAP AI Core.
- **Creating Deployments:** To use a model that has not been deployed yet, you'll need to create a deployment in your SAP AI Core service instance. See [Create a Deployment for a Generative AI Model](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-deployment-for-generative-ai-model-in-sap-ai-core) for instructions.
#### Configuring Reasoning Effort for OpenAI Models
When using OpenAI reasoning models (such as o1, o3, o3-mini, o4-mini) through SAP AI Core, you can control the reasoning effort to balance performance and cost:
1. **Open Cline Settings:** Click the settings icon (⚙️) in the Cline panel.
2. **Navigate to Features:** Go to the "Features" section in the settings.
3. **Find OpenAI Reasoning Effort:** Locate the "OpenAI Reasoning Effort" setting.
4. **Choose Effort Level:** Select between:
- **Low:** Faster responses with lower token usage, suitable for simpler tasks
- **Medium:** Balanced performance and token usage for most tasks
- **High:** More thorough analysis with higher token usage, better for complex reasoning tasks
> 💡 **Note**
>
> This setting only applies when using OpenAI reasoning models (o1, o3, o3-mini, o4-mini, gpt-5, etc.) deployed through SAP AI Core. Other models will ignore this setting.
@@ -1,98 +0,0 @@
---
title: "Vercel AI Gateway"
description: "Use Vercel AI Gateway in Cline to reach 100+ models from one endpoint with routing, retries, and spend observability."
---
Vercel AI Gateway gives you a single API to access models from many providers. You switch by model id without swapping SDKs or juggling multiple keys. Cline integrates directly so you can pick a Gateway model in the dropdown, use it like any other provider, and see token and cache usage in the stream.
Useful links:
- Team dashboard: https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai
- Models catalog: https://vercel.com/ai-gateway/models
- Docs: https://vercel.com/docs/ai-gateway
## What you get
- One endpoint for 100+ models with a single key
- Automatic retries and fallbacks that you configure on the dashboard
- Spend monitoring with requests by model, token counts, cache usage, latency percentiles, and cost
- OpenAI-compatible surface so existing clients work
## Getting an API Key
1. Sign in at https://vercel.com
2. Dashboard → AI Gateway → API Keys → Create key
3. Copy the key
For more on authentication and OIDC options, see https://vercel.com/docs/ai-gateway/authentication
## Configuration in Cline
1. Open Cline settings
2. Select **Vercel AI Gateway** as the API Provider
3. Paste your Gateway API Key
4. Pick a model from the list. Cline fetches the catalog automatically. You can also paste an exact id
Notes:
- Model ids often follow `provider/model`. Copy the exact id from the catalog
Examples:
- `openai/gpt-5`
- `anthropic/claude-sonnet-4`
- `google/gemini-2.5-pro`
- `groq/llama-3.1-70b`
- `deepseek/deepseek-v3`
## Observability you can act on
<Frame>
<img src="https://assets.vercel.com/image/upload/v1753121283/gateway-overhead-dark_zhqwwj.svg" alt="Vercel AI Gateway observability with requests by model, tokens, cache, latency, and cost." />
</Frame>
What to watch:
- Requests by model - confirm routing and adoption
- Tokens - input vs output, including reasoning if exposed
- Cache - cached input and cache creation tokens
- Latency - p75 duration and p75 time to first token
- Cost - per project and per model
Use it to:
- Compare output tokens per request before and after a model change
- Validate cache strategy by tracking cache reads and write creation
- Catch TTFT regressions during experiments
- Align budgets with real usage
## Supported models
The gateway supports a large and changing set of models. Cline pulls the list from the Gateway API and caches it locally. For the current catalog, see https://vercel.com/ai-gateway/models
## Tips
<Tip>
Use separate gateway keys per environment (dev, staging, prod). It keeps dashboards clean and budgets isolated.
</Tip>
<Note>
Pricing is pass-through at provider list price. Bring-your-own key has 0% markup. You still pay provider and processing fees.
</Note>
<Info>
Vercel does not add rate limits. Upstream providers may. New accounts receive $5 credits every 30 days until the first payment.
</Info>
## Troubleshooting
- 401 - send the Gateway key to the Gateway endpoint, not an upstream URL
- 404 model - copy the exact id from the Vercel catalog
- Slow first token - check p75 TTFT in the dashboard and try a model optimized for streaming
- Cost spikes - break down by model in the dashboard and cap or route traffic
## Inspiration
- Multi-model evals - swap only the model id in Cline and compare latency and output tokens
- Progressive rollout - route a small percent to a new model in the dashboard and ramp with metrics
- Budget enforcement - set per-project limits without code changes
## Crosslinks
- OpenAI-Compatible setup: /provider-config/openai-compatible
- Model Selection Guide: /getting-started/model-selection-guide
- Understanding Context Management: /getting-started/understanding-context-management
-162
View File
@@ -1,162 +0,0 @@
---
title: "Z AI (Zhipu AI)"
description: "Learn how to configure and use Z AI's GLM-4.5 models with Cline. Experience advanced hybrid reasoning, agentic capabilities, and open-source excellence with regional optimization."
---
Z AI (formerly Zhipu AI) offers the groundbreaking GLM-4.5 series, featuring hybrid reasoning capabilities and agentic AI design. Released in July 2025, these models excel in unified reasoning, coding, and intelligent agent applications while maintaining open-source accessibility under MIT license.
**Website:** [https://z.ai/model-api](https://z.ai/model-api) (International) | [https://open.bigmodel.cn/](https://open.bigmodel.cn/) (China)
### Getting an API Key
#### International Users
1. **Sign Up/Sign In:** Go to [https://z.ai/model-api](https://z.ai/model-api). Create an account or sign in.
2. **Navigate to API Keys:** Access your account dashboard and find the API keys section.
3. **Create a Key:** Generate a new API key for your application.
4. **Copy the Key:** Copy the API key immediately and store it securely.
#### China Mainland Users
1. **Sign Up/Sign In:** Go to [https://open.bigmodel.cn/](https://open.bigmodel.cn/). Create an account or sign in.
2. **Navigate to API Keys:** Access your account dashboard and find the API keys section.
3. **Create a Key:** Generate a new API key for your application.
4. **Copy the Key:** Copy the API key immediately and store it securely.
### Supported Models
Z AI provides different model catalogs based on your selected region:
#### GLM-4.5 Series
- **GLM-4.5** - Flagship model with 355B total parameters, 32B active parameters
- **GLM-4.5-Air** - Compact model with 106B total parameters, 12B active parameters
#### GLM-4.5 Hybrid Reasoning Models
- **GLM-4.5 (Thinking Mode)** - Advanced reasoning with step-by-step analysis
- **GLM-4.5-Air (Thinking Mode)** - Efficient reasoning for mainstream hardware
All models feature:
- **128,000 token context window** for extensive document processing
- **Mixture of Experts (MoE) architecture** for optimal performance
- **Agent-native design** integrating reasoning, coding, and tool usage
- **Open-source availability** under MIT license
### Configuration in Cline
1. **Open Cline Settings:** Click the settings icon (⚙️) in the Cline panel.
2. **Select Provider:** Choose "Z AI" from the "API Provider" dropdown.
3. **Select Region:** Choose your region:
- "International" for global access
- "China" for mainland China access
4. **Enter API Key:** Paste your Z AI API key into the "Z AI API Key" field.
5. **Select Model:** Choose your desired model from the "Model" dropdown.
### GLM Coding Plans
Z AI offers subscription plans specifically designed for coding applications. These plans provide cost-effective access to GLM-4.5 models through a prompt-based structure rather than traditional API usage billing.
#### Plan Options
**GLM Coding Lite** - $3/month
- 120 prompts per 5-hour cycle
- Access to GLM-4.5 model
- Works exclusively through coding tools like Cline
**GLM Coding Pro** - $15/month
- 600 prompts per 5-hour cycle
- Access to GLM-4.5 model
- Works exclusively through coding tools like Cline
Both plans offer promotional pricing for the first month: Lite drops from \$6 to \$3, Pro drops from \$30 to \$15.
<Frame>
<img src="https://storage.googleapis.com/cline_public_images/docs/assets/zAI-coding-plan.png" alt="zAI subscription page showing GLM Coding Lite and Pro plans with pricing" />
</Frame>
#### Setting up GLM Coding Plans
To use the GLM Coding Plans with Cline:
1. **Subscribe:** Go to [https://z.ai/subscribe](https://z.ai/subscribe) and choose your plan.
2. **Create API Key:** After subscribing, log into your zAI dashboard and create an API key for your coding plan.
3. **Configure in Cline:** Open Cline settings, select "Z AI" as your provider, and paste your API key into the "Z AI API Key" field.
<Frame>
<img src="https://storage.googleapis.com/cline_public_images/docs/assets/zAI-provider.png" alt="Cline settings with zAI provider selected and API key field highlighted" />
</Frame>
The setup connects your subscription directly to Cline, giving you access to GLM-4.5's tool-calling capabilities optimized for coding workflows.
### Z AI's Hybrid Intelligence
Z AI's GLM-4.5 series introduces revolutionary capabilities that set it apart from conventional language models:
#### Hybrid Reasoning Architecture
GLM-4.5 operates in two distinct modes:
- **Thinking Mode:** Designed for complex reasoning tasks and tool usage, engaging in deeper analytical processes
- **Non-Thinking Mode:** Provides immediate responses for straightforward queries, optimizing efficiency
This dual-mode architecture represents an "agent-native" design philosophy that adapts processing intensity based on query complexity.
#### Exceptional Performance
GLM-4.5 achieves a comprehensive score of **63.2** across 12 benchmarks spanning agentic tasks, reasoning, and coding challenges, securing **3rd place** among all proprietary and open-source models. GLM-4.5-Air maintains competitive performance with a score of **59.8** while delivering superior efficiency.
#### Mixture of Experts Excellence
The sophisticated MoE architecture optimizes performance while maintaining computational efficiency:
- **GLM-4.5:** 355B total parameters with 32B active parameters
- **GLM-4.5-Air:** 106B total parameters with 12B active parameters
#### Extended Context Capabilities
The 128,000-token context window enables comprehensive understanding of lengthy documents and codebases, with real-world testing confirming effective processing of nearly 2,000-line codebases while maintaining remarkable performance.
#### Open-Source Leadership
Released under MIT license, GLM-4.5 provides researchers and developers with access to state-of-the-art capabilities without proprietary restrictions, including base models, hybrid reasoning versions, and optimized FP8 variants.
### Regional Optimization
#### API Endpoints
- **International:** Uses `https://api.z.ai/api/paas/v4`
- **China:** Uses `https://open.bigmodel.cn/api/paas/v4`
#### Model Availability
The region setting determines both API endpoint and available models, with automatic filtering to ensure compatibility with your selected region.
### Special Features
#### Agentic Capabilities
GLM-4.5's unified architecture makes it particularly suitable for complex intelligent agent applications requiring integrated reasoning, coding, and tool utilization capabilities.
#### Comprehensive Benchmarking
Performance evaluation encompasses:
- **3 agentic task benchmarks**
- **7 reasoning benchmarks**
- **2 coding benchmarks**
This comprehensive assessment demonstrates versatility across diverse AI applications.
#### Developer Integration
Models support integration through multiple frameworks:
- **transformers**
- **vLLM**
- **SGLang**
Complete with dedicated model code, tool parser, and reasoning parser implementations.
### Performance Comparisons
#### vs Claude 4 Sonnet
GLM-4.5 shows competitive performance in agentic coding and reasoning tasks, though Claude Sonnet 4 maintains advantages in coding success rates and autonomous multi-feature application development.
#### vs GPT-4.5
GLM-4.5 ranks competitively in reasoning and agent benchmarks, with GPT-4.5 generally leading in raw task accuracy on professional benchmarks like MMLU and AIME.
### Tips and Notes
- **Region Selection:** Choose the appropriate region for optimal performance and compliance with local regulations.
- **Model Selection:** GLM-4.5 for maximum performance, GLM-4.5-Air for efficiency and mainstream hardware compatibility.
- **Context Advantage:** Large 128K context window enables processing of substantial codebases and documents.
- **Open Source Benefits:** MIT license enables both commercial use and secondary development.
- **Agentic Applications:** Particularly strong for applications requiring reasoning, coding, and tool usage integration.
- **Hybrid Reasoning:** Use Thinking Mode for complex problems, Non-Thinking Mode for simple queries.
- **API Compatibility:** OpenAI-compatible API provides streaming responses and usage reporting.
- **Framework Support:** Multiple integration options available for different deployment scenarios.
-47
View File
@@ -1,47 +0,0 @@
/* Custom styles for Cline documentation */
/* Make h1 titles lighter in font weight */
h1 {
font-weight: 500 !important;
}
/* Also apply to any h1 elements within content areas */
.content h1,
.markdown h1,
article h1,
main h1 {
font-weight: 500 !important;
}
/* JetBrains logo visibility fix for dark mode */
/* Add a subtle background and border to ensure visibility in both light and dark modes */
img[alt="JetBrains logo"] {
background-color: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 8px;
padding: 12px;
transition: all 0.3s ease;
}
/* Dark mode specific styling */
[data-theme="dark"] img[alt="JetBrains logo"],
.dark img[alt="JetBrains logo"] {
background-color: rgba(255, 255, 255, 0.95);
border: 1px solid rgba(0, 0, 0, 0.2);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* Media query for system dark mode preference */
@media (prefers-color-scheme: dark) {
img[alt="JetBrains logo"] {
background-color: rgba(255, 255, 255, 0.95);
border: 1px solid rgba(0, 0, 0, 0.2);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
}
/* Hover effect for better interactivity */
img[alt="JetBrains logo"]:hover {
transform: scale(1.02);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
@@ -244,60 +244,13 @@ Recent macOS versions have stricter terminal permissions:
### Windows Issues
If you're using Windows and still experiencing issues with shell integration after trying the previous steps, it's recommended you use Git Bash (or PowerShell).
#### PowerShell Execution Policy
### Git Bash
Git Bash is a terminal emulator that provides a Unix-like command line experience on Windows. To use Git Bash, you need to:
1. Download and run the Git for Windows installer from [https://git-scm.com/downloads/win](https://git-scm.com/downloads/win)
2. Quit and re-open VSCode
3. Press `Ctrl + Shift + P` to open the Command Palette
4. Type "Terminal: Select Default Profile" and choose it
5. Select "Git Bash"
### PowerShell
If you'd still like to use PowerShell, make sure you're using an updated version (at least v7+).
- Check your current PowerShell version by running: `$PSVersionTable.PSVersion`
- If your version is below 7, [update PowerShell](https://learn.microsoft.com/en-us/powershell/scripting/whats-new/migrating-from-windows-powershell-51-to-powershell-7?view=powershell-7.4#installing-powershell-7).
You may also need to adjust your PowerShell execution policy. By default, PowerShell restricts script execution for security reasons.
#### Understanding PowerShell Execution Policies
PowerShell uses execution policies to determine which scripts can run on your system. Here are the most common policies:
- `Restricted`: No PowerShell scripts can run. This is the default setting.
- `AllSigned`: All scripts, including local ones, must be signed by a trusted publisher.
- `RemoteSigned`: Scripts created locally can run, but scripts downloaded from the internet must be signed.
- `Unrestricted`: No restrictions. Any script can run, though you will be warned before running internet-downloaded scripts.
For development work in VSCode, the `RemoteSigned` policy is generally recommended. It allows locally created scripts to run without restrictions while maintaining security for downloaded scripts. To learn more about PowerShell execution policies and understand the security implications of changing them, visit Microsoft's documentation: [About Execution Policies](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies).
#### Steps to Change the Execution Policy
1. Open PowerShell as an Administrator: Press `Win + X` and select "Windows PowerShell (Administrator)" or "Windows Terminal (Administrator)".
2. Check Current Execution Policy by running this command:
```powershell
Get-ExecutionPolicy
```
- If the output is already `RemoteSigned`, `Unrestricted`, or `Bypass`, you likely don't need to change your execution policy. These policies should allow shell integration to work.
- If the output is `Restricted` or `AllSigned`, you may need to change your policy to enable shell integration.
3. Change the Execution Policy by running the following command:
```powershell
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
```
- This sets the policy to `RemoteSigned` for the current user only, which is safer than changing it system-wide.
4. Confirm the Change by typing `Y` and pressing Enter when prompted.
5. Verify the Policy Change by running `Get-ExecutionPolicy` again to confirm the new setting.
6. Restart VSCode and try the shell integration again.
If commands fail silently:
```powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
#### WSL Integration
+13 -31
View File
@@ -1,12 +1,8 @@
import fs from "node:fs"
import path from "node:path"
import { fileURLToPath } from "node:url"
import * as esbuild from "esbuild"
const esbuild = require("esbuild")
const fs = require("fs")
const path = require("path")
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const production = process.argv.includes("--production") || process.env["IS_DEBUG_BUILD"] === "false"
const production = process.argv.includes("--production")
const watch = process.argv.includes("--watch")
const standalone = process.argv.includes("--standalone")
const e2eBuild = process.argv.includes("--e2e-build")
@@ -20,6 +16,7 @@ const aliasResolverPlugin = {
setup(build) {
const aliases = {
"@": path.resolve(__dirname, "src"),
"@api": path.resolve(__dirname, "src/api"),
"@core": path.resolve(__dirname, "src/core"),
"@integrations": path.resolve(__dirname, "src/integrations"),
"@services": path.resolve(__dirname, "src/services"),
@@ -123,29 +120,17 @@ const copyWasmFiles = {
},
}
const buildEnvVars = { "import.meta.url": "_importMetaUrl" }
if (production) {
// IS_DEV is always disable in production builds.
buildEnvVars["process.env.IS_DEV"] = "false"
}
// Set the environment and telemetry env vars. The API key env vars need to be populated in the GitHub
// workflows from the secrets.
if (process.env.CLINE_ENVIRONMENT) {
buildEnvVars["process.env.CLINE_ENVIRONMENT"] = JSON.stringify(process.env.CLINE_ENVIRONMENT)
}
if (process.env.TELEMETRY_SERVICE_API_KEY) {
buildEnvVars["process.env.TELEMETRY_SERVICE_API_KEY"] = JSON.stringify(process.env.TELEMETRY_SERVICE_API_KEY)
}
if (process.env.ERROR_SERVICE_API_KEY) {
buildEnvVars["process.env.ERROR_SERVICE_API_KEY"] = JSON.stringify(process.env.ERROR_SERVICE_API_KEY)
}
// Base configuration shared between extension and standalone builds
const baseConfig = {
bundle: true,
minify: production,
sourcemap: !production,
logLevel: "silent",
define: buildEnvVars,
define: production
? {
"process.env.IS_DEV": JSON.stringify(!production),
}
: undefined,
tsconfig: path.resolve(__dirname, "tsconfig.json"),
plugins: [
copyWasmFiles,
@@ -156,9 +141,6 @@ const baseConfig = {
format: "cjs",
sourcesContent: false,
platform: "node",
banner: {
js: "const _importMetaUrl=require('url').pathToFileURL(__filename)",
},
}
// Extension-specific configuration
@@ -174,16 +156,16 @@ const standaloneConfig = {
...baseConfig,
entryPoints: ["src/standalone/cline-core.ts"],
outfile: `${destDir}/cline-core.js`,
// These modules need to load files from the module directory at runtime,
// These gRPC protos need to load files from the module directory at runtime,
// so they cannot be bundled.
external: ["vscode", "@grpc/reflection", "grpc-health-check", "better-sqlite3"],
external: ["vscode", "@grpc/reflection", "grpc-health-check"],
}
// E2E build script configuration
const e2eBuildConfig = {
...baseConfig,
entryPoints: ["src/test/e2e/utils/build.ts"],
outfile: `${destDir}/e2e-build.mjs`,
outfile: `${destDir}/e2e-build.js`,
external: ["@vscode/test-electron", "execa"],
sourcemap: false,
plugins: [aliasResolverPlugin, esbuildProblemMatcherPlugin],
@@ -0,0 +1,123 @@
const { RuleTester: DirectApiRuleTester } = require("eslint")
const noDirectVscodeApiRule = require("../no-direct-vscode-api")
const directApiRuleTester = new DirectApiRuleTester({
parser: require.resolve("@typescript-eslint/parser"),
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
})
directApiRuleTester.run("no-direct-vscode-api", noDirectVscodeApiRule, {
valid: [
// Should allow vscode.postMessage in grpc-client-base.ts
{
code: `vscode.postMessage({ type: "grpc_request", data: {} })`,
filename: "grpc-client-base.ts",
},
{
code: `vscode.postMessage({ type: "grpc_request_cancel" })`,
filename: "/path/to/grpc-client-base.ts",
},
// Should allow in exception directories
{
code: `vscode.workspace.workspaceFolders`,
filename: "/src/hosts/vscode/host-bridge.ts",
},
{
code: `vscode.workspace.fs.stat(uri)`,
filename: "/standalone/runtime-files/helpers.ts",
},
// Should allow other vscode API calls
{
code: `vscode.window.showInformationMessage("Hello")`,
filename: "test.ts",
},
// Should allow postMessage calls on other objects
{
code: `window.postMessage({ type: "test" }, "*")`,
filename: "test.ts",
},
// Should allow variables named vscode but not calling postMessage
{
code: `const vscode = { other: "method" }; vscode.other()`,
filename: "test.ts",
},
],
invalid: [
// Should disallow vscode.postMessage in regular files
{
code: `vscode.postMessage({ type: "test", data: {} })`,
filename: "test.ts",
errors: [
{
messageId: "useGrpcClient",
},
],
},
// Should disallow vscode.postMessage in components
{
code: `vscode.postMessage({ type: "apiConfiguration", apiConfiguration })`,
filename: "ApiOptions.tsx",
errors: [
{
messageId: "useGrpcClient",
},
],
},
// Should disallow vscode.postMessage in test files
{
code: `vscode.postMessage({ type: "newTask", text: message.text })`,
filename: "test.test.ts",
errors: [
{
messageId: "useGrpcClient",
},
],
},
// Should disallow property access for disallowed APIs
{
code: `const folders = vscode.workspace.workspaceFolders;`,
filename: "workspace.ts",
errors: [
{
messageId: "useHostBridge",
},
],
},
// Should disallow method calls for disallowed APIs
{
code: `const relativePath = vscode.workspace.asRelativePath(filePath);`,
filename: "path-utils.ts",
errors: [
{
messageId: "usePathUtils",
},
],
},
// Should disallow nested property access
{
code: `const stats = await vscode.workspace.fs.stat(uri);`,
filename: "file-utils.ts",
errors: [
{
messageId: "useFsUtils",
},
],
},
// Should disallow getting a workspace folder
{
code: `const folder = vscode.workspace.getWorkspaceFolder(uri);`,
filename: "path-helper.ts",
errors: [
{
messageId: "usePathUtils",
},
],
},
],
})
@@ -0,0 +1,174 @@
const { RuleTester: GrpcRuleTester } = require("eslint")
const grpcRule = require("../no-grpc-client-object-literals")
const grpcRuleTester = new GrpcRuleTester({
parser: require.resolve("@typescript-eslint/parser"),
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
})
grpcRuleTester.run("no-grpc-client-object-literals", grpcRule, {
valid: [
// Valid case: Using .create() method with gRPC client
{
code: `
import { TogglePlanActModeRequest } from '@shared/proto/state';
import { StateServiceClient } from '../services/grpc-client';
StateServiceClient.togglePlanActMode(
TogglePlanActModeRequest.create({
chatSettings: {
mode: PlanActMode.PLAN,
preferredLanguage: 'en',
},
})
);
`,
},
// Valid case: Using .fromPartial() method with gRPC client
{
code: `
import { TogglePlanActModeRequest, ChatSettings } from '@shared/proto/state';
import { StateServiceClient } from '../services/grpc-client';
const chatSettings = ChatSettings.fromPartial({
mode: PlanActMode.PLAN,
preferredLanguage: 'en',
});
StateServiceClient.togglePlanActMode(
TogglePlanActModeRequest.create({
chatSettings: chatSettings,
})
);
`,
},
// Valid case: Regular function call with object literal (not a gRPC client)
{
code: `
function processData(data) {
console.log(data);
}
processData({
id: 123,
name: 'test',
});
`,
},
// Valid case: Using proper nested protobuf objects
{
code: `
import { TogglePlanActModeRequest, ChatSettings } from '@shared/proto/state';
import { StateServiceClient } from '../services/grpc-client';
// Using proper nested protobuf objects
const chatSettings = ChatSettings.create({
mode: 0,
preferredLanguage: 'en',
});
const request = TogglePlanActModeRequest.create({
chatSettings: chatSettings,
});
StateServiceClient.togglePlanActMode(request);
`,
},
// Valid case: Object literal in second parameter (should not be checked)
{
code: `
import { StateSubscribeRequest } from '@shared/proto/state';
import { StateServiceClient } from '../services/grpc-client';
const request = StateSubscribeRequest.create({
topics: ['apiConfig', 'tasks']
});
// Second parameter is an object literal but should not trigger the rule
StateServiceClient.subscribe(request, {
metadata: {
userId: 123,
sessionId: "abc-123"
}
});
`,
},
],
invalid: [
// Invalid case: Using object literal directly with gRPC client
{
code: `
import { StateServiceClient } from '../services/grpc-client';
StateServiceClient.togglePlanActMode({
chatSettings: {
mode: 0,
preferredLanguage: 'en',
},
});
`,
errors: [{ messageId: "useProtobufMethod" }],
},
// Invalid case: Using object literal with nested properties
{
code: `
import { ChatSettings } from '@shared/proto/state';
import { StateServiceClient } from '../services/grpc-client';
const chatSettings = ChatSettings.create({
mode: 0,
preferredLanguage: 'en',
});
StateServiceClient.togglePlanActMode({
chatSettings: {
mode: 1,
preferredLanguage: 'fr',
},
});
`,
errors: [{ messageId: "useProtobufMethod" }],
},
// Invalid case: Nested object literal in protobuf create method
{
code: `
import { TogglePlanActModeRequest, ChatSettings } from '@shared/proto/state';
import { StateServiceClient } from '../services/grpc-client';
// Using nested object literal instead of ChatSettings.create()
const request = TogglePlanActModeRequest.create({
chatSettings: {
mode: 0,
preferredLanguage: 'en',
},
});
StateServiceClient.togglePlanActMode(request);
`,
errors: [{ messageId: "useProtobufMethod" }],
},
// Invalid case: Object literal as first parameter to subscribe method
{
code: `
import { StateServiceClient } from '../services/grpc-client';
// First parameter is an object literal, which should trigger the rule
StateServiceClient.subscribe({
topics: ['apiConfig', 'tasks']
}, {
metadata: {
userId: 123,
sessionId: "abc-123"
}
});
`,
errors: [{ messageId: "useProtobufMethod" }],
},
],
})
@@ -0,0 +1,214 @@
const { RuleTester } = require("eslint")
const rule = require("../no-protobuf-object-literals")
const ruleTester = new RuleTester({
parser: require.resolve("@typescript-eslint/parser"),
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
})
ruleTester.run("no-protobuf-object-literals", rule, {
valid: [
// Valid case: Using .create() method
{
code: `
import { State } from '@shared/proto/state';
const state = State.create({
stateJson: '{"apiConfig":{"provider":"anthropic","model":"claude-3-haiku"}}'
});
`,
},
// Valid case: Using .fromPartial() method
{
code: `
import { ChatSettings } from '@shared/proto/state';
const settings = ChatSettings.fromPartial({
mode: 0,
preferredLanguage: 'en',
openAiReasoningEffort: 'thorough'
});
`,
},
// Valid case: Object literal not used with protobuf type
{
code: `
interface MyInterface {
id: number;
name: string;
}
const obj: MyInterface = {
id: 123,
name: 'test'
};
`,
},
// Valid case: Using object literal for non-protobuf import
{
code: `
import { SomeType } from '@some/other/package';
const obj: SomeType = {
id: 123,
name: 'test'
};
`,
},
// Valid case: Regular function call with object literal (should not be flagged)
{
code: `
import { State } from '@shared/proto/state';
// This should not be flagged because it's a regular function call
// not directly tied to a protobuf type
process({
id: 123,
name: 'test',
data: { nested: true }
});
`,
},
],
invalid: [
// Invalid case: Using object literal with imported protobuf type
{
code: `
import { State } from '@shared/proto/state';
const state: State = {
stateJson: '{"apiConfig":{"provider":"anthropic","model":"claude-3-haiku"}}'
};
`,
output: `
import { State } from '@shared/proto/state';
const state: State = State.create({
stateJson: '{"apiConfig":{"provider":"anthropic","model":"claude-3-haiku"}}'
});
`,
errors: [{ messageId: "useProtobufMethod" }],
},
// Invalid case: Using object literal with namespaced protobuf type
{
code: `
import * as stateProto from '@shared/proto/state';
const state: stateProto.State = {
stateJson: '{"apiConfig":{"provider":"anthropic","model":"claude-3-haiku"}}'
};
`,
output: `
import * as stateProto from '@shared/proto/state';
const state: stateProto.State = stateProto.State.create({
stateJson: '{"apiConfig":{"provider":"anthropic","model":"claude-3-haiku"}}'
});
`,
errors: [{ messageId: "useProtobufMethodGeneric" }],
},
// Invalid case: Using object literal in a return statement (with protobuf return type)
{
code: `
import { ChatSettings } from '@shared/proto/state';
function createSettings(): ChatSettings {
return {
mode: 0,
preferredLanguage: 'en',
openAiReasoningEffort: 'thorough'
};
}
`,
output: `
import { ChatSettings } from '@shared/proto/state';
function createSettings(): ChatSettings {
return ChatSettings.create({
mode: 0,
preferredLanguage: 'en',
openAiReasoningEffort: 'thorough'
});
}
`,
errors: [{ messageId: "useProtobufMethod" }],
},
// Invalid case: Using object literal in a function parameter (with protobuf types imported)
{
code: `
import { ChatContent } from '@shared/proto/state';
function processContent(content: ChatContent) {
// process the content
}
processContent({
message: 'Hello, this is a test message',
images: ['image1.png', 'image2.jpg'],
files: ['file1.txt', 'file2.pdf']
});
`,
output: `
import { ChatContent } from '@shared/proto/state';
function processContent(content: ChatContent) {
// process the content
}
processContent(ChatContent.create({
message: 'Hello, this is a test message',
images: ['image1.png', 'image2.jpg'],
files: ['file1.txt', 'file2.pdf']
}));
`,
errors: [{ messageId: "useProtobufMethodGeneric" }],
},
// Invalid case: Using object literal in assignment expression
{
code: `
import { State } from '@shared/proto/state';
let state: State;
state = {
stateJson: '{"apiConfig":{"provider":"anthropic","model":"claude-3-haiku"}}'
};
`,
output: `
import { State } from '@shared/proto/state';
let state: State;
state = State.create({
stateJson: '{"apiConfig":{"provider":"anthropic","model":"claude-3-haiku"}}'
});
`,
errors: [{ messageId: "useProtobufMethod" }],
},
// Test with custom protobufPackages option
{
code: `
import { CustomProto } from 'custom/proto/package';
const obj: CustomProto = {
field1: 'value',
field2: 123
};
`,
output: `
import { CustomProto } from 'custom/proto/package';
const obj: CustomProto = CustomProto.create({
field1: 'value',
field2: 123
});
`,
options: [{ protobufPackages: ["custom/proto"] }],
errors: [{ messageId: "useProtobufMethod" }],
},
],
})
+22
View File
@@ -0,0 +1,22 @@
// eslint-rules/index.js
const noProtobufObjectLiterals = require("./no-protobuf-object-literals")
const noGrpcClientObjectLiterals = require("./no-grpc-client-object-literals")
const noDirectVscodeApi = require("./no-direct-vscode-api")
module.exports = {
rules: {
"no-protobuf-object-literals": noProtobufObjectLiterals,
"no-grpc-client-object-literals": noGrpcClientObjectLiterals,
"no-direct-vscode-api": noDirectVscodeApi,
},
configs: {
recommended: {
plugins: ["local"],
rules: {
"local/no-protobuf-object-literals": "error",
"local/no-grpc-client-object-literals": "error",
"local/no-direct-vscode-api": "warn",
},
},
},
}
+164
View File
@@ -0,0 +1,164 @@
const { ESLintUtils } = require("@typescript-eslint/utils")
const path = require("path")
const createRule = ESLintUtils.RuleCreator((name) => `https://cline.bot/eslint-rules/${name}`)
// Configuration of disallowed VSCode APIs and their recommended alternatives
const disallowedApis = {
"vscode.postMessage": {
messageId: "useGrpcClient",
},
"vscode.workspace.fs.stat": {
messageId: "useFsUtils",
},
"vscode.workspace.workspaceFolders": {
messageId: "useHostBridge",
},
"vscode.workspace.asRelativePath": {
messageId: "usePathUtils",
},
"vscode.workspace.getWorkspaceFolder": {
messageId: "usePathUtils",
},
}
module.exports = createRule({
name: "no-direct-vscode-api",
meta: {
type: "problem",
docs: {
description:
"Disallow direct VSCode API usage in favor of Cline's abstraction layers, except in src/hosts/vscode and standalone/runtime-files directories",
recommended: "error",
},
messages: {
useGrpcClient:
"Use gRPC service clients instead of vscode.postMessage().\n" +
"Example: AccountServiceClient.methodName(RequestType.create({...})) instead of vscode.postMessage({type: '...'}).\n" +
"Found: {{code}}",
useFsUtils:
"Use utilities in @/utils/fs instead of vscode.workspace.fs.stat.\n" +
"Example: import { isDirectory } from '@/utils/fs' or use the file system methods from the host bridge provider.\n" +
"Found: {{code}}",
useHostBridge:
"Use getHostBridgeProvider().workspaceClient.getWorkspacePaths({}) instead of vscode.workspace.workspaceFolders.\n" +
"This provides a consistent abstraction across VSCode and standalone environments.\n" +
"Found: {{code}}",
usePathUtils:
"Use path utilities from @/utils/path instead of direct VSCode workspace path methods.\n" +
"This provides consistent path handling across different environments.\n" +
"Found: {{code}}",
},
schema: [],
},
defaultOptions: [],
create(context) {
// Check if current file is in an exception directory or is grpc-client-base.ts
const filename = context.filename
const isGrpcClientBase = path.basename(filename) === "grpc-client-base.ts"
// Skip checking files in src/hosts/vscode or standalone/runtime-files
const isExceptionDirectory = filename.includes("/src/hosts/vscode/") || filename.includes("/standalone/runtime-files/")
// Pattern for checking memberExpressions like vscode.workspace.fs.stat
function checkMemberExpression(node) {
// Skip if this file is in an exception directory or is grpc-client-base.ts
if (isGrpcClientBase || isExceptionDirectory) {
return
}
// For handling nested properties like vscode.workspace.fs.stat
function getFullPropertyPath(node) {
if (node.type !== "MemberExpression") {
return node.name || ""
}
const objectPart = getFullPropertyPath(node.object)
const propertyPart = node.property.name || ""
return objectPart ? `${objectPart}.${propertyPart}` : propertyPart
}
// Check if the expression matches one of our disallowed patterns
if (node.object && node.object.type === "Identifier" && node.object.name === "vscode") {
const fullPath = `vscode.${node.property.name}`
checkDisallowedApi(fullPath, node)
}
// Handle nested expressions like vscode.workspace.fs.stat
else if (node.object && node.object.type === "MemberExpression") {
const fullPath = getFullPropertyPath(node)
// Only proceed if it starts with vscode
if (fullPath.startsWith("vscode.")) {
checkDisallowedApi(fullPath, node)
}
}
}
// Check if an expression matches a disallowed API and report if it does
function checkDisallowedApi(expressionPath, node) {
// Check exact matches
if (disallowedApis[expressionPath]) {
reportViolation(expressionPath, node)
return
}
// Check prefix matches (for nested properties)
for (const disallowedApi in disallowedApis) {
// For direct property access like vscode.workspace.workspaceFolders
if (expressionPath === disallowedApi) {
reportViolation(disallowedApi, node)
return
}
// For method calls like vscode.workspace.asRelativePath(...)
if (expressionPath.startsWith(`${disallowedApi}.`) || expressionPath.startsWith(`${disallowedApi}(`)) {
reportViolation(disallowedApi, node)
return
}
}
}
// Report a violation with the appropriate message
function reportViolation(disallowedApi, node) {
const sourceCode = context.sourceCode
const config = disallowedApis[disallowedApi]
// For method calls, get the whole call expression
let reportNode = node
let parentNode = sourceCode.getAncestors(node).pop()
if (parentNode && parentNode.type === "CallExpression" && parentNode.callee === node) {
reportNode = parentNode
}
const callText = sourceCode.getText(reportNode).trim()
context.report({
node: reportNode,
messageId: config.messageId,
data: {
code: callText,
},
})
}
return {
// Detect basic member expressions (e.g., vscode.postMessage)
MemberExpression(node) {
checkMemberExpression(node)
},
// Detect property access through destructuring
VariableDeclarator(node) {
// Skip if this file is in an exception directory or is grpc-client-base.ts
if (isGrpcClientBase || isExceptionDirectory) {
return
}
// Destructuring pattern checks removed as developers don't use the API this way
// They always use direct imports: import * as vscode from "vscode" and direct access: vscode.thing.foo
},
}
},
})
@@ -0,0 +1,216 @@
const { ESLintUtils } = require("@typescript-eslint/utils")
const createRule = ESLintUtils.RuleCreator((name) => `https://cline.bot/eslint-rules/${name}`)
module.exports = createRule({
name: "no-grpc-client-object-literals",
meta: {
type: "problem",
docs: {
description:
"Enforce using .create() or .fromPartial() for gRPC service client parameters instead of object literals",
recommended: "error",
},
messages: {
useProtobufMethod:
"Use the appropriate protobuf .create() or .fromPartial() method instead of " +
"object literal for gRPC client parameters.\n" +
"Found: {{code}}\n" +
"gRPC client methods should always receive properly created protobuf objects.",
},
schema: [],
},
defaultOptions: [],
create(context) {
// Check if a name matches the gRPC service client pattern using regex
// Must start with an uppercase letter and end with ServiceClient
const isGrpcServiceClient = (name) => {
return typeof name === "string" && /^[A-Z].*ServiceClient$/.test(name)
}
const safeObjectExpressions = new Map() // Track object expressions in create/fromPartial calls
return {
// Skip object literals inside create() or fromPartial() method calls
CallExpression(node) {
if (
node.callee &&
node.callee.type === "MemberExpression" &&
(node.callee.property.name === "create" || node.callee.property.name === "fromPartial") &&
node.arguments.length > 0 &&
node.arguments[0].type === "ObjectExpression"
) {
// Track this object expression as being used with create/fromPartial
safeObjectExpressions.set(node.arguments[0], { isProblematic: false })
}
},
// Track create/fromPartial calls that contain nested object literals
"CallExpression[callee.type='MemberExpression'][callee.property.name=/^(create|fromPartial)$/]"(node) {
if (node.arguments.length > 0 && node.arguments[0].type === "ObjectExpression") {
// Track problematic nested object literals
const nestedObjectLiterals = new Map() // Map of object expressions to their containing property paths
// Search for nested object literals
const queue = [
...node.arguments[0].properties.map((prop) => ({
property: prop,
path: prop.key && prop.key.name ? prop.key.name : "unknown",
})),
]
while (queue.length > 0) {
const { property, path } = queue.shift()
// Skip spread elements
if (property.type !== "Property") continue
// If this is an object literal, mark it as problematic
if (property.value.type === "ObjectExpression") {
nestedObjectLiterals.set(property.value, path)
// Add nested properties to queue
queue.push(
...property.value.properties.map((prop) => ({
property: prop,
path: `${path}.${prop.key && prop.key.name ? prop.key.name : "unknown"}`,
})),
)
}
}
// For each problematic nested object, track it with its path
nestedObjectLiterals.forEach((path, objectExpr) => {
safeObjectExpressions.set(objectExpr, {
isProblematic: true,
path: path,
parentNode: node,
})
})
}
},
// Check calls to gRPC service clients
"CallExpression[callee.type='MemberExpression']"(node) {
// Get the object (left side) of the member expression
const callee = node.callee
if (callee.object && callee.object.type === "Identifier") {
const objectName = callee.object.name
// Check if this is a call to one of our gRPC service clients
if (isGrpcServiceClient(objectName)) {
// Only check the first argument of gRPC service client calls
if (node.arguments.length > 0) {
const arg = node.arguments[0] // Only check the first parameter
if (arg.type === "ObjectExpression" && !safeObjectExpressions.has(arg)) {
// This is an object literal being passed directly to a gRPC client
const sourceCode = context.getSourceCode()
const callText = sourceCode.getText(node).trim()
context.report({
node: arg,
messageId: "useProtobufMethod",
data: {
code: callText,
},
})
} else if (arg.type === "ObjectExpression") {
// Search for nested object literals that aren't protected
const queue = [...arg.properties]
while (queue.length > 0) {
const property = queue.shift()
// Skip spread elements
if (property.type !== "Property") continue
// Check value
if (
property.value.type === "ObjectExpression" &&
!safeObjectExpressions.has(property.value)
) {
// Found a nested object literal
const sourceCode = context.getSourceCode()
const propertyText = sourceCode.getText(property).trim()
context.report({
node: property.value,
messageId: "useProtobufMethod",
data: {
code: `${objectName}.${callee.property.name}(... ${propertyText} ...)`,
},
})
}
// Add any nested properties to the queue
if (property.value.type === "ObjectExpression") {
queue.push(...property.value.properties)
}
}
} else if (arg.type === "Identifier") {
// This is a variable - check if it references a problematic protobuf object
const varName = arg.name
const sourceCode = context.getSourceCode()
const scope = sourceCode.getScope(node)
// Find the variable declaration
const variable = scope.variables.find((v) => v.name === varName)
if (variable && variable.references && variable.references.length > 0) {
// Look for definitions
const def = variable.defs.find(
(d) => d.node && d.node.type === "VariableDeclarator" && d.node.init,
)
if (
def &&
def.node.init.type === "CallExpression" &&
def.node.init.callee.type === "MemberExpression" &&
(def.node.init.callee.property.name === "create" ||
def.node.init.callee.property.name === "fromPartial")
) {
// Flag if we find problematic nested object literals in this create/fromPartial call
const callText = sourceCode.getText(node).trim()
const initCallText = sourceCode.getText(def.node.init).trim()
// Check for nested object literals in init node
let foundNestedLiteral = false
if (
def.node.init.arguments.length > 0 &&
def.node.init.arguments[0].type === "ObjectExpression"
) {
// Find any nested object literals
const queue = [...def.node.init.arguments[0].properties]
while (queue.length > 0 && !foundNestedLiteral) {
const property = queue.shift()
// Skip spread elements
if (property.type !== "Property") continue
if (property.value.type === "ObjectExpression") {
foundNestedLiteral = true
context.report({
node,
messageId: "useProtobufMethod",
data: {
code: `${callText} - using request created with nested object literal at: ${property.key.name}`,
},
})
}
// Add any nested properties to the queue
if (property.value.type === "ObjectExpression") {
queue.push(...property.value.properties)
}
}
}
}
}
}
}
}
}
},
}
},
})
+556
View File
@@ -0,0 +1,556 @@
const { ESLintUtils } = require("@typescript-eslint/utils")
const createRule = ESLintUtils.RuleCreator((name) => `https://cline.bot/eslint-rules/${name}`)
module.exports = createRule({
name: "no-protobuf-object-literals",
meta: {
type: "problem",
docs: {
description: "Enforce using .create() or .fromPartial() for protobuf objects instead of object literals",
recommended: "error",
},
fixable: "code",
messages: {
useProtobufMethod:
"Use {{typeName}}.create() or {{typeName}}.fromPartial() instead of " +
"object literal for protobuf type from @shared/proto\n" +
"Found: {{code}}\n Suggestion: " +
"{{typeName}}.create({{objectContent}})",
useProtobufMethodGeneric:
"Use .create() or .fromPartial() instead of object literal for protobuf " +
"type from @shared/proto\n Found: {{code}}",
},
schema: [
{
type: "object",
properties: {
protobufPackages: {
type: "array",
items: { type: "string" },
default: ["shared/proto/"],
},
},
additionalProperties: false,
},
],
},
defaultOptions: [{ protobufPackages: ["shared/proto/"] }],
create(context, [options]) {
const protobufPackages = options.protobufPackages
const protobufImports = new Set() // Set of imported protobuf types
const protobufNamespaceImports = new Set() // For namespace imports like "import * as proto"
const safeObjectExpressions = new Set() // Track object expressions in create/fromPartial calls
return {
// Skip object literals inside create() or fromPartial() method calls
CallExpression(node) {
if (
node.callee &&
node.callee.type === "MemberExpression" &&
(node.callee.property.name === "create" || node.callee.property.name === "fromPartial") &&
node.arguments.length > 0 &&
node.arguments[0].type === "ObjectExpression"
) {
// Track this object expression as being used with create/fromPartial
safeObjectExpressions.add(node.arguments[0])
}
},
// Track imports from protobuf packages
ImportDeclaration(node) {
const packageName = node.source.value
if (matchesProtobufPackage(packageName, protobufPackages)) {
// This is a protobuf package.
node.specifiers.forEach((spec) => {
if (spec.type === "ImportSpecifier") {
// import { MyRequest } from '@shared/proto'
protobufImports.add(spec.imported.name)
} else if (spec.type === "ImportNamespaceSpecifier") {
// import * as proto from '@shared/proto'
protobufNamespaceImports.add(spec.local.name)
}
})
}
},
// Check variable declarations with type annotations
"VariableDeclarator > ObjectExpression"(node) {
// Skip if this is inside a create/fromPartial call
if (safeObjectExpressions.has(node)) {
return
}
// Found object literal in variable declaration
const declarator = node.parent
if (declarator.id && declarator.id.typeAnnotation) {
const typeName = getTypeName(declarator.id.typeAnnotation.typeAnnotation)
if (typeName) {
// Check if it's a direct protobuf import
if (protobufImports.has(typeName)) {
//console.log('🚨 VIOLATION: Using object literal for protobuf type:', typeName);
const sourceCode = context.getSourceCode()
const declaratorText = sourceCode.getText(declarator)
const objectText = sourceCode.getText(node)
context.report({
node,
messageId: "useProtobufMethod",
data: {
typeName,
code: declaratorText,
objectContent: objectText,
},
fix(fixer) {
// Replace the object literal with Type.create() call
return fixer.replaceText(node, `${typeName}.create(${objectText})`)
},
})
return
}
// Check if it's a namespaced protobuf type (e.g., proto.MyRequest)
if (isNamespacedProtobufType(protobufNamespaceImports, typeName)) {
//console.log('🚨 VIOLATION: Using object literal for namespaced protobuf type:', typeName);
const sourceCode = context.getSourceCode()
const declaratorText = sourceCode.getText(declarator)
context.report({
node,
messageId: "useProtobufMethodGeneric",
data: { code: declaratorText },
fix(fixer) {
// For namespaced types, use the full type name to call create()
return fixer.replaceText(node, `${typeName}.create(${sourceCode.getText(node)})`)
},
})
}
}
}
},
// Check assignment expressions
"AssignmentExpression > ObjectExpression"(node) {
// Skip if this is inside a create/fromPartial call
if (safeObjectExpressions.has(node)) {
return
}
const assignment = node.parent
// For assignment to variables without inline type annotation
if (assignment.left && assignment.right === node) {
let typeName = null
// Check if there's a typeAnnotation directly on the left
if (assignment.left.typeAnnotation) {
typeName = getTypeName(assignment.left.typeAnnotation.typeAnnotation)
}
// Otherwise try to infer from the variable name if it's a simple identifier
else if (assignment.left.type === "Identifier") {
const varName = assignment.left.name
// Check variable declarations in the current scope
const sourceCode = context.getSourceCode()
const scope = sourceCode.getScope(node)
const variable = scope.variables.find((v) => v.name === varName)
if (variable && variable.defs.length > 0) {
const def = variable.defs[0]
if (def.node.id && def.node.id.typeAnnotation) {
typeName = getTypeName(def.node.id.typeAnnotation.typeAnnotation)
}
}
}
if (typeName && protobufImports.has(typeName)) {
//console.log('🚨 VIOLATION: Using object literal in assignment for protobuf type:', typeName);
const sourceCode = context.getSourceCode()
const assignmentText = sourceCode.getText(assignment.left) + " = "
const objectText = sourceCode.getText(node)
context.report({
node,
messageId: "useProtobufMethod",
data: {
typeName,
code: assignmentText + "{",
objectContent: objectText,
},
fix(fixer) {
// Replace the object literal with Type.create() call in assignments
return fixer.replaceText(node, `${typeName}.create(${objectText})`)
},
})
}
}
},
// Check return statements
"ReturnStatement > ObjectExpression"(node) {
// Skip if this is inside a create/fromPartial call
if (safeObjectExpressions.has(node)) {
return
}
// Find the parent function to get its return type
const functionNode = findParentFunction(node)
if (!functionNode) {
return
}
// Try to get the return type using our enhanced helper
const sourceCode = context.getSourceCode()
let returnTypeName = getFunctionReturnType(functionNode, sourceCode)
// For async functions with Promise<Type> return type, extract the inner type
if (returnTypeName && returnTypeName.startsWith("Promise<") && returnTypeName.endsWith(">")) {
returnTypeName = returnTypeName.slice(8, -1)
}
// Check if the return type is a protobuf type
if (returnTypeName) {
if (protobufImports.has(returnTypeName)) {
//console.log('🚨 VIOLATION: Return type is a protobuf type:', returnTypeName);
const sourceCode = context.getSourceCode()
const returnText = sourceCode.getText(node.parent)
context.report({
node,
messageId: "useProtobufMethod",
data: {
typeName: returnTypeName,
code: returnText,
objectContent: sourceCode.getText(node),
},
fix(fixer) {
// Replace the object literal with Type.create() call in return statements
return fixer.replaceText(node, `${returnTypeName}.create(${sourceCode.getText(node)})`)
},
})
return
}
// Check if it's a namespaced protobuf type
if (isNamespacedProtobufType(protobufNamespaceImports, returnTypeName)) {
const sourceCode = context.getSourceCode()
const returnText = sourceCode.getText(node.parent)
//console.log('🚨 VIOLATION: Return type is a namespaced protobuf type:', returnTypeName);
context.report({
node,
messageId: "useProtobufMethodGeneric",
data: { code: returnText },
fix(fixer) {
// For namespaced types in return statements, we need to extract the full type name
const objectCode = sourceCode.getText(node)
// Since we may not know the exact type, we'll use the more generic namespaced type
return fixer.replaceText(node, `${returnTypeName}.create(${objectCode})`)
},
})
return
}
}
// Final fallback - if there are any protobuf imports and the function signature
// mentions a return type that matches one of the imported types
const functionText = functionNode ? sourceCode.getText(functionNode) : ""
for (const protoType of protobufImports) {
// Use more precise regex to match return type patterns specifically
// Rather than just checking if the type name appears anywhere in the signature
const returnTypeRegex = new RegExp(
// Match arrow function return type
`=>\\s*:?\\s*${protoType}\\b|` +
// Match function declaration return type
`\\)\\s*:?\\s*${protoType}\\b|` +
// Match Promise return type
`\\)\\s*:?\\s*Promise<\\s*${protoType}\\s*>|` +
// Match function type in variable declaration
`:\\s*\\(.*\\)\\s*=>\\s*${protoType}\\b`,
)
if (returnTypeRegex.test(functionText)) {
const returnText = sourceCode.getText(node.parent)
//console.log('🚨 VIOLATION: regex matched protobuf type:', functionText);
context.report({
node,
messageId: "useProtobufMethod",
data: {
typeName: protoType,
code: returnText,
objectContent: sourceCode.getText(node),
},
fix(fixer) {
// Replace the object literal with Type.create() call
return fixer.replaceText(node, `${protoType}.create(${sourceCode.getText(node)})`)
},
})
return
}
}
// Check for namespace imports too
for (const namespace of protobufNamespaceImports) {
// Similar to above, but for namespaced types
const namespaceReturnTypeRegex = new RegExp(
// Match arrow function return type
`=>\\s*:?\\s*${namespace}\\.\\w+\\b|` +
// Match function declaration return type
`\\)\\s*:?\\s*${namespace}\\.\\w+\\b|` +
// Match Promise return type
`\\)\\s*:?\\s*Promise<\\s*${namespace}\\.\\w+\\s*>|` +
// Match function type in variable declaration
`:\\s*\\(.*\\)\\s*=>\\s*${namespace}\\.\\w+\\b`,
)
if (namespaceReturnTypeRegex.test(functionText)) {
const returnText = sourceCode.getText(node.parent)
//console.log('🚨 VIOLATION: regex matched namespaced protobuf type:', functionText, "namespace:", namespace);
context.report({
node,
messageId: "useProtobufMethodGeneric",
data: { code: returnText },
fix(fixer) {
// For namespaced types based on function signature patterns
// Extract the namespace and type from the function text using more precise patterns
const match = functionText.match(
new RegExp(
// Match return type patterns more precisely
`\\)\\s*:?\\s*(${namespace}\\.[\\w]+)\\b|` + // Function declaration
`=>\\s*:?\\s*(${namespace}\\.[\\w]+)\\b|` + // Arrow function
`Promise<\\s*(${namespace}\\.[\\w]+)\\s*>`, // Promise wrapped
),
)
if (match) {
const fullType = match[1] || match[2]
return fixer.replaceText(node, `${fullType}.create(${sourceCode.getText(node)})`)
}
// Fallback - we can't determine the exact type, but we know it's from the namespace
// Use a namespace-based approach
return fixer.replaceText(node, `${namespace}.create(${sourceCode.getText(node)})`)
},
})
return
}
}
},
// Check function call arguments (more selective approach)
"CallExpression > ObjectExpression"(node) {
// Skip if this is inside a create/fromPartial call
if (safeObjectExpressions.has(node)) {
return
}
// We need to be more selective to avoid false positives
// Only warn if:
// 1. The function is called on a protobuf namespace
// 2. The call argument has a type annotation that matches a protobuf type
// 3. The call is to a function that we know takes a protobuf type
// Check if it's a call on a protobuf namespace
if (
node.parent.callee &&
node.parent.callee.type === "MemberExpression" &&
node.parent.callee.object.type === "Identifier"
) {
const namespace = node.parent.callee.object.name
if (protobufNamespaceImports.has(namespace)) {
const sourceCode = context.getSourceCode()
const callText = sourceCode.getText(node.parent)
//console.log('🚨 VIOLATION: Check function call arguments object literal:', callText);
context.report({
node,
messageId: "useProtobufMethodGeneric",
data: { code: callText },
fix(fixer) {
// For calls on a protobuf namespace
const memberExpr = node.parent.callee
// Try to determine if this is calling a method that expects a specific type
const methodName = memberExpr.property.name
// If method name looks like 'create' + Type, we can infer the type
const possibleTypeName = methodName.replace(/^create/, "")
// Check if namespace has a type with this name
// Since we can't directly check at lint time, we'll use the namespace + inferred type
if (possibleTypeName && possibleTypeName !== methodName) {
return fixer.replaceText(
node,
`${namespace}.${possibleTypeName}.create(${sourceCode.getText(node)})`,
)
}
// Fallback - use a more generic approach with namespace
return fixer.replaceText(node, `${namespace}.create(${sourceCode.getText(node)})`)
},
})
return
}
}
// For regular function calls with object literals, check if there are protobuf imports
// and if the function might expect a protobuf type
if (node.parent.callee) {
// This is a more permissive check to catch cases like processContent({ ... })
// which might be passing a protobuf type
const sourceCode = context.getSourceCode()
const scope = sourceCode.getScope(node)
// Try to find the function definition
if (node.parent.callee.type === "Identifier") {
const functionName = node.parent.callee.name
const variable = scope.variables.find((v) => v.name === functionName)
// If we found the function and it has parameter type annotations
// that match protobuf types, flag it
if (variable && variable.defs.length > 0) {
const def = variable.defs[0]
if (def.node.params && node.parent.arguments.indexOf(node) < def.node.params.length) {
const param = def.node.params[node.parent.arguments.indexOf(node)]
if (param.typeAnnotation) {
const typeName = getTypeName(param.typeAnnotation.typeAnnotation)
if (
typeName &&
(protobufImports.has(typeName) ||
isNamespacedProtobufType(protobufNamespaceImports, typeName))
) {
const callText = sourceCode.getText(node.parent)
//console.log('🚨 VIOLATION: Function call arguments object literal:', callText);
context.report({
node,
messageId: "useProtobufMethodGeneric",
data: { code: callText },
fix(fixer) {
// For function calls with protobuf type parameters
return fixer.replaceText(node, `${typeName}.create(${sourceCode.getText(node)})`)
},
})
return
}
}
}
}
}
}
},
}
},
})
// Helper functions
function getTypeName(typeAnnotation) {
if (!typeAnnotation) {
return null
}
if (typeAnnotation.type === "TSTypeReference") {
if (typeAnnotation.typeName.type === "Identifier") {
return typeAnnotation.typeName.name
} else if (typeAnnotation.typeName.type === "TSQualifiedName") {
// Handle namespaced types like proto.MyRequest
return `${typeAnnotation.typeName.left.name}.${typeAnnotation.typeName.right.name}`
}
}
return null
}
function matchesProtobufPackage(packageName, protobufPackages) {
return protobufPackages.some((protobufPackage) => {
// Remove leading and trailing @ and / from protobufPackage
const cleanedPackage = protobufPackage.replace(/^[@\/]/, "").replace(/[\/]$/, "")
const pattern = new RegExp(`(.*[@/]|)${escapeRegex(cleanedPackage)}[/].*`)
return pattern.test(packageName)
})
}
// Helper function to escape special regex characters
function escapeRegex(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
}
// Helper to extract function return type more reliably
function getFunctionReturnType(functionNode, sourceCode) {
// 1. Check explicit return type annotation
if (functionNode.returnType) {
return getTypeName(functionNode.returnType.typeAnnotation)
}
// 2. For variable declarations like const foo: (arg: Type) => ReturnType = ...
if (functionNode.parent && functionNode.parent.type === "VariableDeclarator") {
const declarator = functionNode.parent
if (declarator.id && declarator.id.typeAnnotation) {
const typeAnnotation = declarator.id.typeAnnotation.typeAnnotation
// Handle function type annotations
if (typeAnnotation.type === "TSFunctionType" && typeAnnotation.typeAnnotation) {
return getTypeName(typeAnnotation.typeAnnotation)
}
// Handle type references to function types
if (typeAnnotation.type === "TSTypeReference") {
// This might be a type like Promise<ReturnType>
if (
typeAnnotation.typeName.name === "Promise" &&
typeAnnotation.typeParameters &&
typeAnnotation.typeParameters.params.length > 0
) {
return getTypeName(typeAnnotation.typeParameters.params[0])
}
}
}
}
// 3. For class methods, check if it's part of an interface implementation
if (
functionNode.parent &&
functionNode.parent.type === "MethodDefinition" &&
functionNode.parent.parent &&
functionNode.parent.parent.type === "ClassBody"
) {
const className = getEnclosingClassName(functionNode)
const methodName = functionNode.parent.key.name
if (className && methodName) {
// Look for interface declarations in the scope
const scope = sourceCode.getScope(functionNode)
// This would require more complex scope analysis which is limited in ESLint
// For now, we'll return null and rely on other methods
}
}
return null
}
// Helper to get the class name for a method
function getEnclosingClassName(node) {
let current = node.parent
while (current) {
if (current.type === "ClassDeclaration" && current.id) {
return current.id.name
}
current = current.parent
}
return null
}
function isNamespacedProtobufType(protobufNamespaceImports, typeName) {
if (!typeName.includes(".")) {
return false
}
const namespace = typeName.split(".")[0]
return protobufNamespaceImports.has(namespace)
}
function findParentFunction(node) {
let current = node.parent
while (current) {
if (
current.type === "FunctionDeclaration" ||
current.type === "FunctionExpression" ||
current.type === "ArrowFunctionExpression"
) {
return current
}
current = current.parent
}
return null
}
+2479
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
{
"name": "eslint-plugin-eslint-rules",
"version": "1.0.0",
"description": "Custom ESLint rules for Cline",
"main": "index.js",
"scripts": {
"test": "mocha --no-config --require ts-node/register __tests__/**/*.test.ts"
},
"keywords": [
"eslint",
"eslintplugin"
],
"author": "Cline Bot Inc.",
"license": "Apache-2.0",
"dependencies": {
"@typescript-eslint/utils": "^8.33.0"
},
"devDependencies": {
"@types/eslint": "^8.0.0",
"@types/mocha": "^10.0.7",
"@types/node": "^20.0.0",
"@typescript-eslint/parser": "^7.14.1",
"eslint": "^8.57.0",
"mocha": "^10.0.0",
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
},
"peerDependencies": {
"eslint": ">=8.0.0"
}
}
+16
View File
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "dist",
"resolveJsonModule": true,
"declaration": true
},
"include": ["**/*.ts", "**/*.js", "**/*.tsx", "__tests__/**/*"],
"exclude": ["node_modules", "dist"]
}
-3
View File
@@ -10,7 +10,6 @@ interface RunDiffEvalOptions {
parsingFunction: string
diffEditFunction: string
thinkingBudget: number
provider: string
parallel: boolean
verbose: boolean
testPath: string
@@ -40,8 +39,6 @@ export async function runDiffEvalHandler(options: RunDiffEvalOptions) {
options.parsingFunction,
"--diff-edit-function",
options.diffEditFunction,
"--provider",
options.provider,
]
// Conditionally add the optional arguments
-1
View File
@@ -92,7 +92,6 @@ program
.option("--parsing-function <name>", "The parsing function to use", "parseAssistantMessageV2")
.option("--diff-edit-function <name>", "The diff editing function to use", "constructNewFileContentV2")
.option("--thinking-budget <tokens>", "Set the thinking tokens budget", "0")
.option("--provider <provider>", "API provider to use (openrouter, openai)", "openrouter")
.option("--parallel", "Run tests in parallel", false)
.option("--replay", "Run evaluation from a pre-recorded LLM output, skipping the API call", false)
.option("--replay-run-id <run_id>", "The ID of the run to replay from the database")
+17
View File
@@ -148,6 +148,11 @@ export async function spawnVSCode(workspacePath: string, vsixPath?: string): Pro
command: "workbench.view.extension.saoudrizwan.claude-dev-ActivityBar",
when: "viewContainer.workbench.view.extension.saoudrizwan.claude-dev-ActivityBar.enabled",
},
{
key: "alt+shift+c",
command: "cline.openInNewTab",
when: "viewContainer.workbench.view.extension.saoudrizwan.claude-dev-ActivityBar.enabled",
},
]
fs.writeFileSync(keybindingsPath, JSON.stringify(keybindings, null, 2))
console.log(`Created keybindings.json to help with Cline activation`)
@@ -182,6 +187,11 @@ export async function spawnVSCode(workspacePath: string, vsixPath?: string): Pro
setTimeout(() => {
// Try to open Cline in the sidebar
require('vscode').commands.executeCommand('workbench.view.extension.saoudrizwan.claude-dev-ActivityBar');
// Also try to open Cline in a tab as a fallback
setTimeout(() => {
require('vscode').commands.executeCommand('cline.openInNewTab');
}, 5000);
}, 5000);
`
fs.writeFileSync(startupScriptPath, startupScript)
@@ -278,6 +288,13 @@ export async function spawnVSCode(workspacePath: string, vsixPath?: string): Pro
// Wait a moment for the sidebar to initialize
await new Promise(resolve => setTimeout(resolve, 2000));
// Also open Cline in a tab as a fallback
console.log('Opening Cline in a tab...');
await vscode.commands.executeCommand('cline.openInNewTab');
// Wait a moment for the tab to initialize
await new Promise(resolve => setTimeout(resolve, 2000));
// Create the test server if it doesn't exist
console.log('Creating test server...');
+22 -30
View File
@@ -1,9 +1,11 @@
import { OpenRouterHandler } from "../../src/api/providers/openrouter"
import { OpenAiNativeHandler } from "../../src/api/providers/openai-native"
import { ApiHandlerOptions } from "../../src/shared/api"
import { Anthropic } from "@anthropic-ai/sdk"
import {
parseAssistantMessageV1,
parseAssistantMessageV2,
parseAssistantMessageV3,
AssistantMessageContent,
} from "./parsing/parse-assistant-message-06-06-25" // "../../src/core/assistant-message"
import { constructNewFileContent as constructNewFileContent_06_06_25 } from "./diff-apply/diff-06-06-25"
@@ -15,7 +17,9 @@ type ParseAssistantMessageFn = (message: string) => AssistantMessageContent[]
type ConstructNewFileContentFn = (diff: string, original: string, strict: boolean) => Promise<string | any>
const parsingFunctions: Record<string, ParseAssistantMessageFn> = {
parseAssistantMessageV1: parseAssistantMessageV1,
parseAssistantMessageV2: parseAssistantMessageV2,
parseAssistantMessageV3: parseAssistantMessageV3,
}
const diffEditingFunctions: Record<string, ConstructNewFileContentFn> = {
@@ -50,7 +54,7 @@ interface StreamResult {
* Process the stream and return full response with timing data
*/
async function processStream(
handler: OpenRouterHandler | OpenAiNativeHandler,
handler: OpenRouterHandler,
systemPrompt: string,
messages: Anthropic.Messages.MessageParam[],
): Promise<StreamResult> {
@@ -186,7 +190,19 @@ export async function runSingleEvaluation(input: TestInput): Promise<TestResult>
}
}
const provider = input.provider || "openrouter"
const options: ApiHandlerOptions = {
openRouterApiKey: apiKey,
openRouterModelId: modelId,
thinkingBudgetTokens: thinkingBudgetTokens,
openRouterModelInfo: {
maxTokens: 10_000,
contextWindow: 1_000_000,
supportsImages: true,
supportsPromptCache: true, // may need to turn this on
inputPrice: 0,
outputPrice: 0,
},
}
// Get the output of streaming output of this llm call
let streamResult: StreamResult
@@ -198,34 +214,10 @@ export async function runSingleEvaluation(input: TestInput): Promise<TestResult>
usage: { inputTokens: 0, outputTokens: 0, cacheWriteTokens: 0, cacheReadTokens: 0, totalCost: 0 },
}
} else {
// Live mode: provider-specific API call logic
// Live mode: existing API call logic
try {
let handler: OpenRouterHandler | OpenAiNativeHandler
if (provider === "openai") {
const openAiOptions = {
openAiNativeApiKey: apiKey,
apiModelId: modelId,
}
handler = new OpenAiNativeHandler(openAiOptions)
} else {
const openRouterOptions = {
openRouterApiKey: apiKey,
openRouterModelId: modelId,
thinkingBudgetTokens: thinkingBudgetTokens,
openRouterModelInfo: {
maxTokens: 10_000,
contextWindow: 1_000_000,
supportsImages: true,
supportsPromptCache: true,
inputPrice: 0,
outputPrice: 0,
},
}
handler = new OpenRouterHandler(openRouterOptions)
}
streamResult = await processStream(handler, systemPrompt, messages)
const openRouterHandler = new OpenRouterHandler(options)
streamResult = await processStream(openRouterHandler, systemPrompt, messages)
} catch (error: any) {
return {
success: false,
+6 -17
View File
@@ -49,25 +49,16 @@ type TestResultSet = { [test_id: string]: (TestResult & { test_id?: string })[]
class NodeTestRunner {
private apiKey: string | undefined
private provider: string
private currentRunId: string | null = null
private systemPromptHash: string | null = null
private processingFunctionsHash: string | null = null
private caseIdMap: Map<string, string> = new Map() // test_id -> case_id mapping
constructor(isReplay: boolean, provider: string = "openrouter") {
this.provider = provider
constructor(isReplay: boolean) {
if (!isReplay) {
if (provider === "openai") {
this.apiKey = process.env.OPENAI_API_KEY
if (!this.apiKey) {
throw new Error("OPENAI_API_KEY environment variable not set for a non-replay run with OpenAI provider.")
}
} else {
this.apiKey = process.env.OPENROUTER_API_KEY
if (!this.apiKey) {
throw new Error("OPENROUTER_API_KEY environment variable not set for a non-replay run with OpenRouter provider.")
}
this.apiKey = process.env.OPENROUTER_API_KEY
if (!this.apiKey) {
throw new Error("OPENROUTER_API_KEY environment variable not set for a non-replay run.")
}
}
}
@@ -644,7 +635,6 @@ class NodeTestRunner {
thinkingBudgetTokens: testConfig.thinking_tokens_budget,
originalDiffEditToolCallMessage: testConfig.replay ? testCase.original_diff_edit_tool_call_message : undefined,
diffApplyFile: testConfig.diff_apply_file,
provider: this.provider,
isVerbose: isVerbose,
}
@@ -937,7 +927,6 @@ async function main() {
.option("--parsing-function <name>", "The parsing function to use", "parseAssistantMessageV2")
.option("--diff-edit-function <name>", "The diff editing function to use", "diff-06-26-25")
.option("--thinking-budget <tokens>", "Set the thinking tokens budget", "0")
.option("--provider <provider>", "API provider to use (openrouter, openai)", "openrouter")
.option("--parallel", "Run tests in parallel", false)
.option("--replay", "Run evaluation from a pre-recorded LLM output, skipping the API call", false)
.option("--replay-run-id <run_id>", "The ID of the run to replay from the database")
@@ -970,7 +959,7 @@ async function main() {
? parseInt(options.maxAttemptsPerCase, 10)
: validAttemptsPerCase * 10;
const runner = new NodeTestRunner(options.replay || !!options.replayRunId, options.provider)
const runner = new NodeTestRunner(options.replay || !!options.replayRunId)
if (options.replayRunId) {
if (!options.diffApplyFile) {
@@ -990,7 +979,7 @@ async function main() {
log(isVerbose, "Warning: Could not load OpenRouter model data. Context window filtering might be affected for OpenRouter models.");
}
const runner = new NodeTestRunner(options.replay, options.provider)
const runner = new NodeTestRunner(options.replay)
let allLoadedTestCases = runner.loadTestCases(testPath, isVerbose) // Pass isVerbose
const allProcessedTestCasesGlobal: ProcessedTestCase[] = allLoadedTestCases.map((tc) => ({
+7 -107
View File
@@ -331,42 +331,6 @@ def get_performance_grade(success_rate):
else:
return "C", "poor"
def get_error_description(error_enum, error_string=None):
"""Map error enum values to user-friendly descriptions"""
error_map = {
1: "No tool calls - Model didn't use the replace_in_file tool",
2: "Multiple tool calls - Model called multiple tools instead of one",
3: "Wrong tool call - Model used wrong tool (not replace_in_file)",
4: "Missing parameters - Tool call missing required path or diff",
5: "Wrong file edited - Model edited different file than expected",
6: "Wrong tool call - Model used wrong tool type",
7: "Wrong file edited - Model targeted incorrect file path",
8: "API/Stream error - Problem with model API connection",
9: "Configuration error - Invalid evaluation parameters",
10: "Function error - Invalid parsing/diff functions",
11: "Other error - Unexpected failure"
}
base_description = error_map.get(error_enum, f"Unknown error (code: {error_enum})")
if error_string:
return f"{base_description}: {error_string}"
return base_description
def get_error_guidance(error_enum):
"""Provide specific guidance based on error type"""
guidance_map = {
1: "💡 The model provided a response but didn't use the replace_in_file tool. Check the raw output to see what the model actually said.",
2: "💡 The model called multiple tools when it should only call replace_in_file once. Check the parsed tool call section.",
3: "💡 The model used a different tool instead of replace_in_file. This might indicate confusion about the task.",
4: "💡 The model called replace_in_file but didn't provide the required 'path' or 'diff' parameters.",
5: "💡 The model tried to edit a different file than expected. Check the parsed tool call to see which file it targeted.",
6: "💡 The model used the wrong tool type. Check the raw output to see what tool it attempted to use.",
7: "💡 The model tried to edit a different file path than expected. This could indicate path confusion or hallucination.",
}
return guidance_map.get(error_enum, "")
def render_hero_section(current_run, model_performance):
"""Render the hero section with key metrics"""
run_title = current_run['description'] if current_run['description'] else f"Run {current_run['run_id'][:8]}..."
@@ -606,16 +570,12 @@ def render_result_detail(result):
"""Render detailed view of a single result"""
st.markdown("### 🔬 Result Deep Dive")
# Check if this is a valid result (only invalid if no tool calls or wrong file)
is_valid = True
if not pd.isna(result['error_enum']):
# Only these specific errors make a result "invalid" for the benchmark:
# 1 = no_tool_calls, 5 = wrong_file_edited, 7 = wrong_file_edited
is_valid = result['error_enum'] not in [1, 5, 7]
# Check if this is a valid result
is_valid = (result['error_enum'] not in [1, 6, 7]) if not pd.isna(result['error_enum']) else True
# Show validity warning if needed
if not is_valid:
st.warning("⚠️ **This is an invalid result** - The model didn't call the replace_in_file tool or edited the wrong file. This result is excluded from success rate calculations.")
st.warning("⚠️ **This is an invalid result** - The model didn't properly call the diff edit tool or edited the wrong file. This result is excluded from success rate calculations.")
# Result metadata
col1, col2, col3, col4 = st.columns(4)
@@ -631,10 +591,7 @@ def render_result_detail(result):
st.markdown(f"**Round Trip:** {result['time_round_trip_ms']:.0f}ms")
with col4:
if pd.notna(result['cost_usd']) and result['cost_usd'] is not None:
st.markdown(f"**Cost:** ${result['cost_usd']:.4f}")
else:
st.markdown(f"**Cost:** Free")
st.markdown(f"**Cost:** ${result['cost_usd']:.4f}")
# Tabbed interface for different views
tab1, tab2, tab3, tab4 = st.tabs(["📄 File & Edits", "🤖 Raw Output", "🔧 Parsed Tool Call", "📊 Metrics"])
@@ -736,46 +693,8 @@ def render_file_and_edits_view(result):
# Show error information
st.error("❌ **Edit Failed**")
# Show detailed error reason
if not pd.isna(result['error_enum']):
error_description = get_error_description(
result['error_enum'],
result.get('error_string')
)
st.markdown(f"**Reason:** {error_description}")
# Show specific guidance based on error type
guidance = get_error_guidance(result['error_enum'])
if guidance:
st.info(guidance)
# For valid results that failed, check for diff application failures
elif not result['succeeded']:
# This is a valid result that failed - likely due to diff application issues
raw_output = result.get('raw_model_output', '')
# Check if we have specific error information in the raw output
if 'does not match anything in the file' in str(raw_output).lower():
st.warning("⚠️ **Diff Application Failed**")
st.info("💡 The SEARCH block in the diff didn't match any content in the original file. This usually means the model hallucinated code that doesn't exist.")
elif 'malformatted' in str(raw_output).lower() or 'malformed' in str(raw_output).lower():
st.warning("⚠️ **Diff Format Error**")
st.info("💡 The diff format was incorrect. Check the raw tool call to see the formatting issues.")
elif 'error:' in str(raw_output).lower():
# Try to extract the specific error message
lines = str(raw_output).split('\n')
error_lines = [line for line in lines if 'error:' in line.lower()]
if error_lines:
error_msg = error_lines[0].strip()
st.warning("⚠️ **Diff Application Failed**")
st.info(f"💡 {error_msg}")
else:
st.warning("⚠️ **Diff Application Failed**")
st.info("💡 The diff couldn't be applied to the original file. Check the raw output and parsed tool call for more details.")
else:
# Generic diff application failure
st.warning("⚠️ **Diff Application Failed**")
st.info("💡 The model made a valid tool call but the diff couldn't be applied to the original file. This usually indicates a mismatch between the expected and actual file content.")
st.markdown(f"**Error Code:** {result['error_enum']}")
else:
# Show successful edit information
st.success("✅ **Edit Successful**")
@@ -806,25 +725,8 @@ def render_file_and_edits_view(result):
if len(edited_lines) > 50:
st.text(f"... ({len(edited_lines) - 50} more lines)")
# Show raw and parsed tool calls if available
# Show parsed tool call if available
if not pd.isna(result['parsed_tool_call_json']):
with st.expander("View Raw Tool Call"):
# Extract the raw tool call text from the model output
raw_output = result['raw_model_output'] if not pd.isna(result['raw_model_output']) else ""
# Try to extract just the tool call portion
if raw_output and '<replace_in_file>' in raw_output:
# Find the tool call block
start_idx = raw_output.find('<replace_in_file>')
end_idx = raw_output.find('</replace_in_file>') + len('</replace_in_file>')
if start_idx != -1 and end_idx != -1:
raw_tool_call = raw_output[start_idx:end_idx]
st.code(raw_tool_call, language='xml')
else:
st.text("Tool call not found in raw output")
else:
st.text("No raw tool call available")
with st.expander("View Parsed Tool Call"):
try:
parsed_call = json.loads(result['parsed_tool_call_json'])
@@ -893,10 +795,8 @@ def render_metrics_view(result):
if not pd.isna(result['completion_tokens']):
st.metric("Completion Tokens", int(result['completion_tokens']))
if pd.notna(result['cost_usd']) and result['cost_usd'] is not None:
if not pd.isna(result['cost_usd']):
st.metric("Cost", f"${result['cost_usd']:.4f}")
else:
st.metric("Cost", "Free")
if not pd.isna(result['tokens_in_context']):
st.metric("Context Tokens", int(result['tokens_in_context']))
@@ -70,7 +70,246 @@ export interface ToolUse {
partial: boolean
}
// parseAssistantmessageV1 removed in https://github.com/cline/cline/pull/5425
/**
* @description **Version 1**
* Parses an assistant message string potentially containing mixed text and tool usage blocks
* marked with XML-like tags into an array of structured content objects.
*
* This version iterates through the message character by character, building an accumulator string.
* It maintains state to track whether it's currently parsing text, a tool use block, or a specific tool parameter.
* It detects the start and end of tool uses and parameters by checking if the accumulator ends with
* the corresponding opening or closing tags.
* Special handling is included for `write_to_file` and `new_rule` tool uses to correctly parse
* the `content` parameter, which might contain the closing tag itself, by looking for the *last*
* occurrence of the closing tag.
* If the input string ends mid-tag or mid-content, the last block (text or tool use) is marked as partial.
*
* @param assistantMessage The raw string output from the assistant.
* @returns An array of `AssistantMessageContent` objects, which can be `TextContent` or `ToolUse`.
* Blocks that were not fully closed by the end of the input string will have their `partial` flag set to `true`.
*/
export function parseAssistantMessageV1(assistantMessage: string): AssistantMessageContent[] {
const contentBlocks: AssistantMessageContent[] = []
let currentTextContent: TextContent | undefined = undefined
let currentTextContentStartIndex = 0
let currentToolUse: ToolUse | undefined = undefined
let currentToolUseStartIndex = 0
let currentParamName: ToolParamName | undefined = undefined
let currentParamValueStartIndex = 0
let accumulator = ""
for (let i = 0; i < assistantMessage.length; i++) {
const char = assistantMessage[i]
accumulator += char
// --- State: Parsing a Tool Parameter ---
// there should not be a param without a tool use
if (currentToolUse && currentParamName) {
const currentParamValue = accumulator.slice(currentParamValueStartIndex)
const paramClosingTag = `</${currentParamName}>`
if (currentParamValue.endsWith(paramClosingTag)) {
// End of param value found
currentToolUse.params[currentParamName] = currentParamValue.slice(0, -paramClosingTag.length).trim()
currentParamName = undefined // Go back to parsing tool content or looking for next param
continue // Move to next character
} else {
// Partial param value is accumulating
continue // Move to next character
}
}
// --- State: Parsing a Tool Use (but not a specific parameter) ---
// no currentParamName
if (currentToolUse) {
const currentToolValue = accumulator.slice(currentToolUseStartIndex)
const toolUseClosingTag = `</${currentToolUse.name}>`
if (currentToolValue.endsWith(toolUseClosingTag)) {
// End of a tool use found
currentToolUse.partial = false
contentBlocks.push(currentToolUse)
currentToolUse = undefined // Go back to parsing text or looking for next tool
// Reset text start index in case text follows immediately
currentTextContentStartIndex = i + 1
continue // Move to next character
} else {
// Check if starting a new parameter within the current tool use
const possibleParamOpeningTags = toolParamNames.map((name) => `<${name}>`)
let foundParamStart = false
for (const paramOpeningTag of possibleParamOpeningTags) {
if (accumulator.endsWith(paramOpeningTag)) {
// Start of a new parameter found
currentParamName = paramOpeningTag.slice(1, -1) as ToolParamName
currentParamValueStartIndex = accumulator.length
foundParamStart = true
break
}
}
if (foundParamStart) {
continue // Move to next character
}
// Special case for write_to_file/new_rule content param allowing nested tags
// Check if a </content> tag appears, potentially indicating the end of the content param
// even if the main tool closing tag hasn't been seen yet.
const contentParamName: ToolParamName = "content"
if (
(currentToolUse.name === "write_to_file" || currentToolUse.name === "new_rule") &&
accumulator.endsWith(`</${contentParamName}>`)
) {
const toolContent = accumulator.slice(currentToolUseStartIndex)
const contentStartTag = `<${contentParamName}>`
const contentEndTag = `</${contentParamName}>`
const contentStartIndex = toolContent.indexOf(contentStartTag) + contentStartTag.length
// Use lastIndexOf to handle cases where </content> might appear within the content itself
const contentEndIndex = toolContent.lastIndexOf(contentEndTag)
// Ensure we found valid start/end tags and end is after start
if (
contentStartIndex !== -1 &&
contentEndIndex !== -1 &&
contentEndIndex > contentStartIndex - contentStartTag.length // Ensure end tag is after start tag begins
) {
// Check if this content param was already being parsed. If so, update it.
// If not, and we just found the closing tag, assign it.
// This handles cases where the </content> detection might fire before
// the <content> tag detection logic, or if the content is very short.
if (currentParamName === contentParamName) {
// Already parsing content, now we found the end tag
currentToolUse.params[contentParamName] = toolContent.slice(contentStartIndex, contentEndIndex).trim()
currentParamName = undefined // Finished with this param
} else if (currentParamName === undefined) {
// Not parsing a param, but found </content>. Assume it closes the content block.
currentToolUse.params[contentParamName] = toolContent.slice(contentStartIndex, contentEndIndex).trim()
// We stay in the "parsing tool use" state, looking for more params or the tool end tag.
}
}
}
// If none of the above, partial tool value is accumulating
continue // Move to next character
}
}
// --- State: Parsing Text (or looking for start of a tool use) ---
// no currentToolUse
let didStartToolUse = false
const possibleToolUseOpeningTags = toolUseNames.map((name) => `<${name}>`)
for (const toolUseOpeningTag of possibleToolUseOpeningTags) {
if (accumulator.endsWith(toolUseOpeningTag)) {
// Start of a new tool use found
const toolName = toolUseOpeningTag.slice(1, -1) as ToolUseName
currentToolUse = {
type: "tool_use",
name: toolName,
params: {},
partial: true,
}
currentToolUseStartIndex = accumulator.length
// This also indicates the end of the current text content block (if any)
if (currentTextContent) {
currentTextContent.partial = false
// Extract text content, removing the part that formed the tool opening tag
const textEndIndex = accumulator.length - toolUseOpeningTag.length
currentTextContent.content = accumulator.slice(currentTextContentStartIndex, textEndIndex).trim()
// Only add if there's actual content
if (currentTextContent.content.length > 0) {
contentBlocks.push(currentTextContent)
}
currentTextContent = undefined
} else {
// Check if there was text before this tool use started
const textEndIndex = accumulator.length - toolUseOpeningTag.length
const potentialText = accumulator.slice(currentTextContentStartIndex, textEndIndex).trim()
if (potentialText.length > 0) {
contentBlocks.push({
type: "text",
content: potentialText,
partial: false, // Ended because tool use started
})
}
}
didStartToolUse = true
break // Found tool start, stop checking for others
}
}
if (!didStartToolUse) {
// No tool use started, so it must be text content accumulating
// (or continuing after a closed tool use)
if (currentTextContent === undefined) {
// Start of a new text block
currentTextContentStartIndex = i - (accumulator.length - currentTextContentStartIndex - 1) // Adjust start index based on how much we've accumulated since the last block ended or the beginning
// If accumulator starts from 0, start index is i
if (contentBlocks.length === 0 && currentToolUse === undefined) {
currentTextContentStartIndex = accumulator.length - 1 // i
} else {
// Re-calculate based on the actual start of the current text segment
// Find the end of the last block
let lastBlockEndIndex = 0
if (contentBlocks.length > 0) {
const lastBlock = contentBlocks[contentBlocks.length - 1]
// Approximation: find where the accumulator matches the end of the message string representation of the last block. This is complex.
// Simpler: Assume text starts right after the last block ended implicitly at index i.
lastBlockEndIndex = i // Where the loop *was* when the last block finished processing
// Need a more robust way to track the end index of the *raw string* corresponding to the last block.
// Let's stick to the accumulator slice approach for simplicity in this version.
// The start index should be where the current *unmatched* text began.
let lastProcessedIndex = -1
if (contentBlocks.length > 0) {
// This requires knowing the raw string length of the previous block, which V1 doesn't explicitly track easily.
// We'll approximate based on the current accumulator and start index logic.
// The issue arises if a tool tag was just closed. accumulator contains everything up to i.
// lastBlockEndIndex should point to the character *after* the closing tag of the last block.
}
// Reset start index to the beginning of the *current* potential text block
currentTextContentStartIndex = accumulator.length - 1 // Start accumulating from the current character `i`
}
// If we just closed a tool, text starts *after* its closing tag
// The logic needs refinement here for accurate start index after a tool closure.
// Let's assume for now the start index logic inside the loop handles it via slicing.
}
currentTextContent = {
type: "text",
content: "", // Content will be filled by slicing accumulator
partial: true,
}
}
// Update text content based on the accumulator from its start index
currentTextContent.content = accumulator.slice(currentTextContentStartIndex).trimStart() // Trim start to avoid leading space if text follows tool
}
} // End of loop
// --- Finalization after loop ---
// If a tool use was open at the end
if (currentToolUse) {
// If a parameter was open within that tool use
if (currentParamName) {
// The remaining accumulator content belongs to this partial parameter
currentToolUse.params[currentParamName] = accumulator.slice(currentParamValueStartIndex).trim()
}
// Add the potentially partial tool use block
contentBlocks.push(currentToolUse)
}
// If text content was being accumulated at the end
// Note: Only one of currentToolUse or currentTextContent can be defined here,
// as starting a tool use finalizes the preceding text block.
else if (currentTextContent) {
// Update content one last time
currentTextContent.content = accumulator.slice(currentTextContentStartIndex).trim()
// Add the potentially partial text block only if it contains content
if (currentTextContent.content.length > 0) {
contentBlocks.push(currentTextContent)
}
}
return contentBlocks
}
/**
* @description **Version 2**
@@ -304,3 +543,621 @@ export function parseAssistantMessageV2(assistantMessage: string): AssistantMess
return contentBlocks
}
export function parseAssistantMessageV3(assistantMessage: string): AssistantMessageContent[] {
const contentBlocks: AssistantMessageContent[] = []
let currentTextContentStart = 0 // Index where the current text block started
let currentTextContent: TextContent | undefined = undefined
let currentToolUseStart = 0 // Index *after* the opening tag of the current tool use
let currentToolUse: ToolUse | undefined = undefined
let currentParamValueStart = 0 // Index *after* the opening tag of the current param
let currentParamName: ToolParamName | undefined = undefined
// Precompute tags for faster lookups
const toolUseOpenTags = new Map<string, ToolUseName>()
const toolParamOpenTags = new Map<string, ToolParamName>()
for (const name of toolUseNames) {
toolUseOpenTags.set(`<${name}>`, name)
}
for (const name of toolParamNames) {
toolParamOpenTags.set(`<${name}>`, name)
}
// Function calls format detection
const isFunctionCallsOpen = "<function_calls>"
const isFunctionCallsClose = "</function_calls>"
const isInvokeStart = '<invoke name="'
const isInvokeEnd = '">'
const isInvokeClose = "</invoke>"
const isParameterStart = '<parameter name="'
const isParameterNameEnd = '">'
const isParameterClose = "</parameter>"
// Variables for function calls parsing
let inFunctionCalls = false
let currentInvokeName = ""
let currentParameterName = ""
const len = assistantMessage.length
for (let i = 0; i < len; i++) {
const currentCharIndex = i
// --- State: Parsing Function Calls ---
// Check for opening function_calls tag
if (
!inFunctionCalls &&
currentCharIndex >= isFunctionCallsOpen.length - 1 &&
assistantMessage.startsWith(isFunctionCallsOpen, currentCharIndex - isFunctionCallsOpen.length + 1)
) {
// End current text block if one was active
if (currentTextContent) {
currentTextContent.content = assistantMessage
.slice(currentTextContentStart, currentCharIndex - isFunctionCallsOpen.length + 1)
.trim()
currentTextContent.partial = false
if (currentTextContent.content.length > 0) {
contentBlocks.push(currentTextContent)
}
currentTextContent = undefined
}
inFunctionCalls = true
continue
}
// Check for invoke start within function_calls
if (
inFunctionCalls &&
currentInvokeName === "" &&
!currentToolUse && // Don't create a new tool if we already have one
currentCharIndex >= isInvokeStart.length - 1 &&
assistantMessage.startsWith(isInvokeStart, currentCharIndex - isInvokeStart.length + 1)
) {
// Find the end of the invoke name
const nameEndPos = assistantMessage.indexOf(isInvokeEnd, currentCharIndex + 1)
if (nameEndPos !== -1) {
// Extract the invoke name
currentInvokeName = assistantMessage.slice(currentCharIndex + 1, nameEndPos)
i = nameEndPos + isInvokeEnd.length - 1 // Skip to after the '">
// If this is an LS invoke, create a list_files tool
if (currentInvokeName === "LS") {
currentToolUse = {
type: "tool_use",
name: "list_files",
params: {},
partial: true,
}
}
// If this is a Grep invoke, create a search_files tool
if (currentInvokeName === "Grep") {
currentToolUse = {
type: "tool_use",
name: "search_files",
params: {},
partial: true,
}
}
if (currentInvokeName === "Bash") {
currentToolUse = {
type: "tool_use",
name: "execute_command",
params: {},
partial: true,
}
}
if (currentInvokeName === "Read") {
currentToolUse = {
type: "tool_use",
name: "read_file",
params: {},
partial: true,
}
}
if (currentInvokeName === "Write") {
currentToolUse = {
type: "tool_use",
name: "write_to_file",
params: {},
partial: true,
}
}
if (currentInvokeName === "WebFetch") {
currentToolUse = {
type: "tool_use",
name: "web_fetch",
params: {},
partial: true,
}
}
if (currentInvokeName === "AskQuestion") {
currentToolUse = {
type: "tool_use",
name: "ask_followup_question",
params: {},
partial: true,
}
}
if (currentInvokeName === "UseMCPTool") {
currentToolUse = {
type: "tool_use",
name: "use_mcp_tool",
params: {},
partial: true,
}
}
if (currentInvokeName === "AccessMCPResource") {
currentToolUse = {
type: "tool_use",
name: "access_mcp_resource",
params: {},
partial: true,
}
}
if (currentInvokeName === "ListCodeDefinitionNames") {
currentToolUse = {
type: "tool_use",
name: "list_code_definition_names",
params: {},
partial: true,
}
}
if (currentInvokeName === "PlanModeRespond") {
currentToolUse = {
type: "tool_use",
name: "plan_mode_respond",
params: {},
partial: true,
}
}
if (currentInvokeName === "LoadMcpDocumentation") {
currentToolUse = {
type: "tool_use",
name: "load_mcp_documentation",
params: {},
partial: true,
}
}
if (currentInvokeName === "AttemptCompletion") {
currentToolUse = {
type: "tool_use",
name: "attempt_completion",
params: {},
partial: true,
}
}
if (currentInvokeName === "BrowserAction") {
currentToolUse = {
type: "tool_use",
name: "browser_action",
params: {},
partial: true,
}
}
if (currentInvokeName === "NewTask") {
currentToolUse = {
type: "tool_use",
name: "new_task",
params: {},
partial: true,
}
}
// If this is a MultiEdit invoke, create a replace_in_file tool
if (currentInvokeName === "MultiEdit") {
currentToolUse = {
type: "tool_use",
name: "replace_in_file",
params: {},
partial: true,
}
}
continue
}
}
// Check for parameter start within invoke
if (
inFunctionCalls &&
currentInvokeName !== "" &&
currentParameterName === "" &&
currentCharIndex >= isParameterStart.length - 1 &&
assistantMessage.startsWith(isParameterStart, currentCharIndex - isParameterStart.length + 1)
) {
// Find the end of the parameter name
const nameEndPos = assistantMessage.indexOf(isParameterNameEnd, currentCharIndex + 1)
if (nameEndPos !== -1) {
// Extract the parameter name
currentParameterName = assistantMessage.slice(currentCharIndex + 1, nameEndPos)
currentParamValueStart = nameEndPos + isParameterNameEnd.length
i = nameEndPos + isParameterNameEnd.length - 1 // Skip to after the '">'
continue
}
}
// Check for parameter end
if (
inFunctionCalls &&
currentInvokeName !== "" &&
currentParameterName !== "" &&
currentCharIndex >= isParameterClose.length - 1 &&
assistantMessage.startsWith(isParameterClose, currentCharIndex - isParameterClose.length + 1)
) {
// Extract parameter value
const value = assistantMessage.slice(currentParamValueStart, currentCharIndex - isParameterClose.length + 1).trim()
// Map parameter to tool params
if (currentToolUse && currentInvokeName === "LS" && currentParameterName === "path") {
currentToolUse.params["path"] = value
// Default recursive to false - only show top level
currentToolUse.params["recursive"] = "false"
}
if (currentToolUse && currentInvokeName === "Read" && currentParameterName === "file_path") {
currentToolUse.params["path"] = value
}
if (currentToolUse && currentInvokeName === "PlanModeRespond" && currentParameterName === "response") {
currentToolUse.params["response"] = value
}
if (currentToolUse && currentInvokeName === "WebFetch" && currentParameterName === "url") {
currentToolUse.params["url"] = value
}
if (currentToolUse && currentInvokeName === "ListCodeDefinitionNames" && currentParameterName === "path") {
currentToolUse.params["path"] = value
}
if (currentToolUse && currentInvokeName === "NewTask" && currentParameterName === "context") {
currentToolUse.params["context"] = value
}
// Map parameter to tool params for Grep
if (currentToolUse && currentInvokeName === "Grep") {
if (currentParameterName === "pattern") {
currentToolUse.params["regex"] = value
} else if (currentParameterName === "path") {
currentToolUse.params["path"] = value
} else if (currentParameterName === "include") {
currentToolUse.params["file_pattern"] = value
}
}
if (currentToolUse && currentInvokeName === "Bash") {
if (currentParameterName === "command") {
currentToolUse.params["command"] = value
} else if (currentParameterName === "requires_approval") {
currentToolUse.params["requires_approval"] = value === "true" ? "true" : "false"
}
}
if (currentToolUse && currentInvokeName === "Write") {
if (currentParameterName === "file_path") {
currentToolUse.params["path"] = value
} else if (currentParameterName === "content") {
currentToolUse.params["content"] = value
}
}
if (currentToolUse && currentInvokeName === "AskQuestion") {
if (currentParameterName === "question") {
currentToolUse.params["question"] = value
} else if (currentParameterName === "options") {
currentToolUse.params["options"] = value
}
}
if (currentToolUse && currentInvokeName === "UseMCPTool") {
if (currentParameterName === "server_name") {
currentToolUse.params["server_name"] = value
} else if (currentParameterName === "tool_name") {
currentToolUse.params["tool_name"] = value
} else if (currentParameterName === "arguments") {
currentToolUse.params["arguments"] = value
}
}
if (currentToolUse && currentInvokeName === "AccessMCPResource") {
if (currentParameterName === "server_name") {
currentToolUse.params["server_name"] = value
} else if (currentParameterName === "uri") {
currentToolUse.params["uri"] = value
}
}
if (currentToolUse && currentInvokeName === "AttemptCompletion") {
if (currentParameterName === "result") {
currentToolUse.params["result"] = value
}
if (currentParameterName === "command") {
currentToolUse.params["command"] = value
}
}
if (currentToolUse && currentInvokeName === "BrowserAction") {
if (currentParameterName === "action") {
currentToolUse.params["action"] = value
} else if (currentParameterName === "url") {
currentToolUse.params["url"] = value
} else if (currentParameterName === "coordinate") {
currentToolUse.params["coordinate"] = value
} else if (currentParameterName === "text") {
currentToolUse.params["text"] = value
}
}
// Map parameter to tool params for MultiEdit
if (currentToolUse && currentInvokeName === "MultiEdit") {
if (currentParameterName === "file_path") {
currentToolUse.params["path"] = value
} else if (currentParameterName === "edits") {
// Save the value to the diff parameter for replace_in_file
currentToolUse.params["diff"] = value
}
}
currentParameterName = ""
continue
}
// Check for invoke end
if (
inFunctionCalls &&
currentInvokeName !== "" &&
currentCharIndex >= isInvokeClose.length - 1 &&
assistantMessage.startsWith(isInvokeClose, currentCharIndex - isInvokeClose.length + 1)
) {
// If we have a tool use from this invoke, finalize it
if (
currentToolUse &&
(currentInvokeName === "LS" ||
currentInvokeName === "Grep" ||
currentInvokeName === "Bash" ||
currentInvokeName === "Read" ||
currentInvokeName === "Write" ||
currentInvokeName === "WebFetch" ||
currentInvokeName === "AskQuestion" ||
currentInvokeName === "UseMCPTool" ||
currentInvokeName === "AccessMCPResource" ||
currentInvokeName === "ListCodeDefinitionNames" ||
currentInvokeName === "PlanModeRespond" ||
currentInvokeName === "LoadMcpDocumentation" ||
currentInvokeName === "AttemptCompletion" ||
currentInvokeName === "BrowserAction" ||
currentInvokeName === "NewTask" ||
currentInvokeName === "MultiEdit")
) {
currentToolUse.partial = false
contentBlocks.push(currentToolUse)
currentToolUse = undefined
}
currentInvokeName = ""
continue
}
// Check for function_calls end
if (
inFunctionCalls &&
currentCharIndex >= isFunctionCallsClose.length - 1 &&
assistantMessage.startsWith(isFunctionCallsClose, currentCharIndex - isFunctionCallsClose.length + 1)
) {
inFunctionCalls = false
currentTextContentStart = currentCharIndex + 1
// Start a new text content block for any text after function_calls
currentTextContent = {
type: "text",
content: "",
partial: true,
}
continue
}
// Skip normal parsing when inside function_calls
if (inFunctionCalls) {
continue
}
// --- State: Parsing a Tool Parameter ---
if (currentToolUse && currentParamName) {
const closeTag = `</${currentParamName}>`
// Check if the string *ending* at index `i` matches the closing tag
if (
currentCharIndex >= closeTag.length - 1 &&
assistantMessage.startsWith(
closeTag,
currentCharIndex - closeTag.length + 1, // Start checking from potential start of tag
)
) {
// Found the closing tag for the parameter
const value = assistantMessage
.slice(
currentParamValueStart, // Start after the opening tag
currentCharIndex - closeTag.length + 1, // End before the closing tag
)
.trim()
currentToolUse.params[currentParamName] = value
currentParamName = undefined // Go back to parsing tool content
// We don't continue loop here, need to check for tool close or other params at index i
} else {
continue // Still inside param value, move to next char
}
}
// --- State: Parsing a Tool Use (but not a specific parameter) ---
if (currentToolUse && !currentParamName) {
// Ensure we are not inside a parameter already
// Check if starting a new parameter
let startedNewParam = false
for (const [tag, paramName] of toolParamOpenTags.entries()) {
if (currentCharIndex >= tag.length - 1 && assistantMessage.startsWith(tag, currentCharIndex - tag.length + 1)) {
currentParamName = paramName
currentParamValueStart = currentCharIndex + 1 // Value starts after the tag
startedNewParam = true
break
}
}
if (startedNewParam) {
continue // Handled start of param, move to next char
}
// Check if closing the current tool use
const toolCloseTag = `</${currentToolUse.name}>`
if (
currentCharIndex >= toolCloseTag.length - 1 &&
assistantMessage.startsWith(toolCloseTag, currentCharIndex - toolCloseTag.length + 1)
) {
// End of the tool use found
// Special handling for content params *before* finalizing the tool
const toolContentSlice = assistantMessage.slice(
currentToolUseStart, // From after the tool opening tag
currentCharIndex - toolCloseTag.length + 1, // To before the tool closing tag
)
// Check if content parameter needs special handling (write_to_file/new_rule)
// This check is important if the closing </content> tag was missed by the parameter parsing logic
// (e.g., if content is empty or parsing logic prioritizes tool close)
const contentParamName: ToolParamName = "content"
if (
currentToolUse.name === "write_to_file" /* || currentToolUse.name === "new_rule" */ &&
toolContentSlice.includes(`<${contentParamName}>`)
) {
const contentStartTag = `<${contentParamName}>`
const contentEndTag = `</${contentParamName}>`
const contentStart = toolContentSlice.indexOf(contentStartTag)
// Use lastIndexOf for robustness against nested tags
const contentEnd = toolContentSlice.lastIndexOf(contentEndTag)
if (contentStart !== -1 && contentEnd !== -1 && contentEnd > contentStart) {
const contentValue = toolContentSlice.slice(contentStart + contentStartTag.length, contentEnd).trim()
currentToolUse.params[contentParamName] = contentValue
}
}
currentToolUse.partial = false // Mark as complete
contentBlocks.push(currentToolUse)
currentToolUse = undefined // Reset state
currentTextContentStart = currentCharIndex + 1 // Potential text starts after this tag
continue // Move to next char
}
// If not starting a param and not closing the tool, continue accumulating tool content implicitly
continue
}
// --- State: Parsing Text / Looking for Tool Start ---
if (!currentToolUse) {
// Check if starting a new tool use
let startedNewTool = false
for (const [tag, toolName] of toolUseOpenTags.entries()) {
if (currentCharIndex >= tag.length - 1 && assistantMessage.startsWith(tag, currentCharIndex - tag.length + 1)) {
// End current text block if one was active
if (currentTextContent) {
currentTextContent.content = assistantMessage
.slice(
currentTextContentStart, // From where text started
currentCharIndex - tag.length + 1, // To before the tool tag starts
)
.trim()
currentTextContent.partial = false // Ended because tool started
if (currentTextContent.content.length > 0) {
contentBlocks.push(currentTextContent)
}
currentTextContent = undefined
} else {
// Check for any text between the last block and this tag
const potentialText = assistantMessage
.slice(
currentTextContentStart, // From where text *might* have started
currentCharIndex - tag.length + 1, // To before the tool tag starts
)
.trim()
if (potentialText.length > 0) {
contentBlocks.push({
type: "text",
content: potentialText,
partial: false,
})
}
}
// Start the new tool use
currentToolUse = {
type: "tool_use",
name: toolName,
params: {},
partial: true, // Assume partial until closing tag is found
}
currentToolUseStart = currentCharIndex + 1 // Tool content starts after the opening tag
startedNewTool = true
break
}
}
if (startedNewTool) {
continue // Handled start of tool, move to next char
}
// If not starting a tool, it must be text content
if (!currentTextContent) {
// Start a new text block if we aren't already in one
currentTextContentStart = currentCharIndex // Text starts at the current character
// Check if the current char is the start of potential text *immediately* after a tag
// This needs the previous state - simpler to let slicing handle it later.
// Resetting start index accurately is key.
// It should be the index *after* the last processed tag.
// The logic managing currentTextContentStart after closing tags handles this.
currentTextContent = {
type: "text",
content: "", // Will be determined by slicing at the end or when a tool starts
partial: true,
}
}
// Continue accumulating text implicitly; content is extracted later.
}
} // End of loop
// --- Finalization after loop ---
// Finalize any open parameter within an open tool use
if (currentToolUse && currentParamName) {
currentToolUse.params[currentParamName] = assistantMessage
.slice(currentParamValueStart) // From param start to end of string
.trim()
// Tool use remains partial
}
// Finalize any open tool use (which might contain the finalized partial param)
if (currentToolUse) {
// Tool use is partial because the loop finished before its closing tag
contentBlocks.push(currentToolUse)
}
// Finalize any trailing text content
// Only possible if a tool use wasn't open at the very end
else if (currentTextContent) {
currentTextContent.content = assistantMessage
.slice(currentTextContentStart) // From text start to end of string
.trim()
// Text is partial because the loop finished
if (currentTextContent.content.length > 0) {
contentBlocks.push(currentTextContent)
}
}
return contentBlocks
}
+2 -4
View File
@@ -1,6 +1,5 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { ToolParamName } from "../../src/core/assistant-message"
import { ClineDefaultTool } from "../../src/shared/tools"
import { ToolUseName, ToolParamName } from "../../src/core/assistant-message"
export interface InputMessage {
role: "user" | "assistant"
@@ -89,7 +88,7 @@ export interface TestResult {
}
export interface ExtractedToolCall {
name: ClineDefaultTool
name: ToolUseName
input: Partial<Record<ToolParamName, string>>
}
@@ -105,6 +104,5 @@ export interface TestInput {
thinkingBudgetTokens: number
originalDiffEditToolCallMessage?: string
diffApplyFile?: string
provider?: string
isVerbose: boolean
}
+31 -82
View File
@@ -9,9 +9,9 @@
"version": "0.1.0",
"license": "MIT",
"dependencies": {
"axios": "^1.12.0",
"axios": "^1.8.2",
"better-sqlite3": "^11.10.0",
"chalk": "5.6.2",
"chalk": "^4.1.2",
"commander": "^9.4.1",
"dotenv": "^16.5.0",
"execa": "^5.1.1",
@@ -200,13 +200,12 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"license": "MIT",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
"integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
@@ -293,12 +292,15 @@
}
},
"node_modules/chalk": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
"integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
"license": "MIT",
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
@@ -605,10 +607,9 @@
}
},
"node_modules/form-data": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"license": "MIT",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz",
"integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
@@ -707,7 +708,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
@@ -843,22 +843,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/log-symbols/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
@@ -1019,22 +1003,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ora/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -1283,7 +1251,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -1668,12 +1635,12 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"axios": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
"integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
"requires": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
@@ -1728,9 +1695,13 @@
}
},
"chalk": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
"integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"chownr": {
"version": "1.1.4",
@@ -1938,9 +1909,9 @@
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="
},
"form-data": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz",
"integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
@@ -2083,17 +2054,6 @@
"requires": {
"chalk": "^4.1.0",
"is-unicode-supported": "^0.1.0"
},
"dependencies": {
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
}
}
},
"make-error": {
@@ -2204,17 +2164,6 @@
"log-symbols": "^4.1.0",
"strip-ansi": "^6.0.0",
"wcwidth": "^1.0.1"
},
"dependencies": {
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
}
}
},
"path-key": {
+2 -2
View File
@@ -19,9 +19,9 @@
"author": "",
"license": "MIT",
"dependencies": {
"axios": "^1.12.0",
"axios": "^1.8.2",
"better-sqlite3": "^11.10.0",
"chalk": "5.6.2",
"chalk": "^4.1.2",
"dotenv": "^16.5.0",
"commander": "^9.4.1",
"execa": "^5.1.1",
-23
View File
@@ -1,23 +0,0 @@
{
"entry": [
"src/extension.ts",
"src/standalone/cline-core.ts",
"src/generated/hosts/standalone/protobus-server-setup.ts",
"src/generated/hosts/standalone/host-bridge-clients.ts",
"src/generated/hosts/vscode/protobus-services.ts",
"src/generated/hosts/vscode/hostbridge-grpc-service-config.ts"
],
"project": [
"src/**/*.ts"
],
"ignore": [
"out/**",
"node_modules/**",
"*.d.ts",
"**/*.test.ts",
"**/__tests__",
"src/test/**",
"src/shared/**"
],
"vite": true
}

Some files were not shown because too many files have changed in this diff Show More