mirror of
https://github.com/cline/cline.git
synced 2026-09-01 15:11:04 +08:00
Compare commits
403 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a94f3b3ba9 | |||
| 15f713d26a | |||
| 5babd9e061 | |||
| ba12672600 | |||
| 163bf77677 | |||
| edf5ea00f6 | |||
| c3c80ffc4d | |||
| f14ed8506d | |||
| 41202df74e | |||
| ab88599e05 | |||
| c2dc0e531c | |||
| 246b0fa999 | |||
| 6c099fbe12 | |||
| 00bf05c26c | |||
| da99e2bf4b | |||
| 963e2c00eb | |||
| 9355d61bc1 | |||
| a9e17fee57 | |||
| 3e8548a341 | |||
| 76b86ff0c0 | |||
| 684438b44c | |||
| 3c84388fb2 | |||
| b0f86201d2 | |||
| d1fc59758e | |||
| 87c9f58902 | |||
| cda3eb8236 | |||
| 3c21d2be1f | |||
| f3adf68775 | |||
| 6bd3181133 | |||
| dd3a234a69 | |||
| c496f8a90d | |||
| 25b1cf91fc | |||
| b54e2043fe | |||
| 98e5ccc547 | |||
| 813a9589d0 | |||
| 64eb66d49a | |||
| 8c17d864c8 | |||
| 4f931c2d9d | |||
| 5836db3093 | |||
| 18879edf9f | |||
| 1cc702c8b9 | |||
| c8caa6f9b9 | |||
| 01f61b6765 | |||
| b8dd6abe61 | |||
| fb7f0e36fe | |||
| 403a32b69c | |||
| ee6daed7bb | |||
| 55ffe9e5dd | |||
| c2ec5fd17d | |||
| 5a84cb1145 | |||
| aec2fd5a7b | |||
| 5826cb584e | |||
| 76232639c3 | |||
| c751cff677 | |||
| 3173483c0f | |||
| 8caf37600b | |||
| 67e0d9883c | |||
| 58b14c69b1 | |||
| b831100f20 | |||
| 23fa305eac | |||
| 0762e6406d | |||
| 94da9f6669 | |||
| fdeef9cece | |||
| 8964561b9e | |||
| dd055b3327 | |||
| e852c6953b | |||
| aef27eb1c4 | |||
| 863572031f | |||
| 65eee1ac6a | |||
| 8213b0b910 | |||
| f5fc3fed6f | |||
| 42df03177f | |||
| 648ae1b1fd | |||
| d3cff6ac47 | |||
| 13af435103 | |||
| 3b1477bc24 | |||
| 688f93db6d | |||
| a702270e85 | |||
| 03acada1b9 | |||
| 95cca05f5e | |||
| 33d77eb095 | |||
| 3e0c39acbb | |||
| 366d8a5411 | |||
| d22596e5c2 | |||
| 7cc612dbce | |||
| f0cab63a43 | |||
| 3c1b670b73 | |||
| 5de05d68ef | |||
| 9b6b1c376c | |||
| e5e26f45fa | |||
| b794583b7a | |||
| ca96bd8f62 | |||
| 0ecdf8d0cc | |||
| 5be6ba68a3 | |||
| 1bdd1e943f | |||
| c85a4abeb4 | |||
| 011b19225e | |||
| a3945dce7f | |||
| 8daca03996 | |||
| 777b8576f2 | |||
| 880755ec89 | |||
| 1c70089521 | |||
| fe2a8a9477 | |||
| eb2550ec3d | |||
| 9c3ac14cab | |||
| 6a8f900d75 | |||
| 407e472322 | |||
| 580b2e35e2 | |||
| 30c121509f | |||
| b3aee3857c | |||
| 10cbbb2c6b | |||
| 08365b3e0b | |||
| cb4c61b1ca | |||
| 2d9ff863b7 | |||
| ae9b20a12b | |||
| c16e271c14 | |||
| b940cef0e4 | |||
| bc228de20e | |||
| a9cac3206a | |||
| a9bc4c7d67 | |||
| 737dce09d1 | |||
| a10d778bee | |||
| 58b0ea9afa | |||
| 90fa3d7336 | |||
| d0da22d5a9 | |||
| f2ce0b46a3 | |||
| 52ab767e44 | |||
| d858fb9360 | |||
| 428cdb670a | |||
| aab002fe65 | |||
| cc540d8158 | |||
| adc15c79d7 | |||
| af05d3497a | |||
| 23fa1cb481 | |||
| 800967d851 | |||
| 91deede3c3 | |||
| b11e6171ff | |||
| 42666d9ca7 | |||
| 07f944b668 | |||
| c6e5b1509c | |||
| 6787dedf47 | |||
| d07648746a | |||
| 07b49baa2a | |||
| 2668bcdbe0 | |||
| e5e293c32b | |||
| fea8313695 | |||
| 4b450f4488 | |||
| 2687ae149f | |||
| 3b93871b50 | |||
| 767b81b22b | |||
| 5db4970c7d | |||
| 4f66126a8c | |||
| 43006ca401 | |||
| 1064c631c5 | |||
| 981fe9cf09 | |||
| 90ab59d8f5 | |||
| f237dda413 | |||
| f08b0499d5 | |||
| 5c2d93617f | |||
| 99201f9944 | |||
| 0983a8a4b9 | |||
| 683096aed7 | |||
| 7189b224fc | |||
| fe3a75309d | |||
| 7a00be2d55 | |||
| 4e7af6eb5d | |||
| e9c8f67822 | |||
| bef7d2c75a | |||
| dfc660e73c | |||
| af0bc4dc6c | |||
| f37962bbf2 | |||
| e82597e069 | |||
| d1db8f747a | |||
| e8ba3c34fb | |||
| fadcd7e3ad | |||
| 81299d26d8 | |||
| 832025c8cc | |||
| f8a7a1cc58 | |||
| 3723288250 | |||
| 0b5e8f5c37 | |||
| a04f6050ee | |||
| ef7e8c5018 | |||
| 60b17d092b | |||
| 58808f3e2f | |||
| 281fd9505a | |||
| fe1da0fa6c | |||
| a505a79ec3 | |||
| ac41b0dd33 | |||
| fd3abdc68b | |||
| fe37ca9f29 | |||
| 7ecf395a9a | |||
| e6c251a5a9 | |||
| 2fee3c47e7 | |||
| b676c5df66 | |||
| 9ae7c4f9e6 | |||
| a8ba96ff4a | |||
| 0b551de152 | |||
| 4985d1d185 | |||
| 60ddf80e5c | |||
| eece559f51 | |||
| cc7be60fd9 | |||
| c4d576d830 | |||
| d462e0b67c | |||
| a4d8f7cb3d | |||
| 7868866bed | |||
| ac291a6fa8 | |||
| b71f0ddbfb | |||
| 8a4c264415 | |||
| af548e109a | |||
| ddd03243f4 | |||
| 5f19701f33 | |||
| 0b992131e3 | |||
| 1530cfe034 | |||
| 6b9dbccfd2 | |||
| c3591290d2 | |||
| 1b08f23f87 | |||
| 7734f04e2a | |||
| 3ef7d0f5d2 | |||
| 9463b4ac72 | |||
| b858277da3 | |||
| f152301ca9 | |||
| 0d13ae1fa4 | |||
| 0cefe107b8 | |||
| 43a6e85d7a | |||
| 7a27f09224 | |||
| 0936634fe5 | |||
| 7ec918261c | |||
| 9ac17c2ec8 | |||
| ee68fac5b8 | |||
| 3bcb1bacb7 | |||
| 6392043f51 | |||
| 92177ac2ea | |||
| 318f5a7829 | |||
| f98aa0fb50 | |||
| 0bc9326b62 | |||
| 92d7cdf593 | |||
| 6cc867ccb5 | |||
| e4325812d0 | |||
| 8e0a70e38d | |||
| 272e162952 | |||
| 78b47e3ebd | |||
| 8a97a88fb8 | |||
| 1caaf7d6ca | |||
| f1cd1518fb | |||
| 97dadea068 | |||
| 28b5c1de24 | |||
| 6cd99c7738 | |||
| 9b750783c9 | |||
| 592e1a6d49 | |||
| c30b2158e3 | |||
| 26a47722aa | |||
| ce426c0344 | |||
| 461f02bd25 | |||
| 9fe16941a3 | |||
| b93adc20af | |||
| 7ccf7a8bb5 | |||
| 8f9de630b3 | |||
| 87c4965110 | |||
| 4f35a5975a | |||
| 17fd4ceb7f | |||
| a231ee4d5c | |||
| 531a272a63 | |||
| 6b9ac49d0a | |||
| 6d42a3fe0c | |||
| 5c9c37a075 | |||
| d08c394f68 | |||
| c0ca9889ff | |||
| fc19697fad | |||
| f64e8ddbf7 | |||
| 70d1dce34f | |||
| 950142fdfb | |||
| 41765fc29a | |||
| e5f8c048ce | |||
| 83de7bb2f1 | |||
| 6c842c145f | |||
| 09adaca575 | |||
| 0b1a237290 | |||
| cb1bda9b5c | |||
| 5dfd16359d | |||
| 64a8096f96 | |||
| e5a1d11179 | |||
| 5af6e8d5ed | |||
| 6ecadfc7a1 | |||
| eb3158c83d | |||
| 625b701a68 | |||
| dd59acf0fb | |||
| 335d0ffa05 | |||
| 3f341d9cf7 | |||
| 0adb1046e4 | |||
| 324564af72 | |||
| 291287c8e4 | |||
| d69fb10cfd | |||
| 0f6eab2bfe | |||
| 016ac1eade | |||
| 2606ed7abf | |||
| 3ed4d55a36 | |||
| a3b4ad53dc | |||
| bd98955f57 | |||
| 297cfbb895 | |||
| b4c95fbeab | |||
| 5e8102e588 | |||
| 60f2c3a22b | |||
| 7472b1cb4a | |||
| 794d8bccd3 | |||
| 0db3cfe34d | |||
| 5c878b5b84 | |||
| e3bc5f0143 | |||
| f2dbab814e | |||
| b3abbd886e | |||
| 8cdc4a936d | |||
| ecc58178dc | |||
| ca3f0f1abd | |||
| 987812a886 | |||
| 0e6afd9848 | |||
| 359e0e070d | |||
| b02ad8377d | |||
| 8fdf5ab8c5 | |||
| aceaeb069b | |||
| e39e58b5e2 | |||
| 717be3f026 | |||
| 5595d12dc3 | |||
| c230de0a14 | |||
| 2ecb87ac5a | |||
| 2315fc6769 | |||
| 6449c36849 | |||
| 8f93e9cc40 | |||
| 3a52baac14 | |||
| 35f08731f6 | |||
| 2c866c9265 | |||
| 10cfd8ba1e | |||
| da4d88fd84 | |||
| 889ed95840 | |||
| 716e6cd6ab | |||
| 45871a962e | |||
| c6aa47095e | |||
| 8c1093cfdc | |||
| 31161f894b | |||
| 20e5ae7b23 | |||
| 22f306e79e | |||
| 553b56336c | |||
| a3fa8cf7b9 | |||
| 4628eca3dc | |||
| 518e624086 | |||
| fa4fa01ec3 | |||
| f526317796 | |||
| 550883df6a | |||
| 3d5605f5d7 | |||
| 1b48f06898 | |||
| b17631900d | |||
| 3d8d83568d | |||
| 3d95adb0f3 | |||
| 971ac0fdeb | |||
| 2888af54f3 | |||
| 190d4a2c52 | |||
| 4d5ab59923 | |||
| f0ad29accb | |||
| 0ba45084a0 | |||
| 213591a169 | |||
| 70fd35df6d | |||
| bd526cb2d2 | |||
| 2fbebec7ae | |||
| ca1e008714 | |||
| 1ab3de8911 | |||
| 47f75225e8 | |||
| 15f6577cb9 | |||
| 7c5d56a5c1 | |||
| cdc24890ee | |||
| ef5465b667 | |||
| d4ba4fd98a | |||
| 074e5d7002 | |||
| 18e164fe81 | |||
| 82be7c4ed5 | |||
| 702dd75291 | |||
| ce89547f32 | |||
| 275be69932 | |||
| 8eba96582a | |||
| e73364d497 | |||
| 56b8c4a847 | |||
| cd066c4912 | |||
| 59a0d055de | |||
| b0ea2e48a7 | |||
| 9e86ba580b | |||
| 99eccaafd4 | |||
| cc0f695555 | |||
| 96a461668c | |||
| 357f98c707 | |||
| 6d4bea48d3 | |||
| 06cd873a46 | |||
| 34e52757ff | |||
| 43d1bd858c | |||
| 90f07e824e | |||
| 8cc823ce05 | |||
| eeef3f89bd | |||
| b1ab8967ec | |||
| 5a81f8f6d3 | |||
| 55b1b4c125 | |||
| fe8ab85e1a | |||
| a50200aba1 | |||
| 7640ae11ec | |||
| 08d94c450f | |||
| d7a93cd618 | |||
| 49475ad417 | |||
| e6c18ea793 |
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
Reasoning budget is now configurable for all supported models from OpenRouter.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
add \*.go files to deep-planning prompt
|
||||
@@ -1,6 +0,0 @@
|
||||
[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 =
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
/docs/
|
||||
/.github/ @saoudrizwan @dcbartlett
|
||||
/README.md @saoudrizwan @nickbaumann98
|
||||
/.github/ @saoudrizwan @garoth @sjf
|
||||
/README.md @saoudrizwan @nickbaumann98
|
||||
|
||||
@@ -1,64 +1,69 @@
|
||||
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 4 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: false
|
||||
- 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: 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: 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: 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
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
# 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
|
||||
@@ -0,0 +1,75 @@
|
||||
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
|
||||
@@ -95,9 +95,11 @@ jobs:
|
||||
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 --out "cline-${{ steps.get_version.outputs.version }}.vsix"
|
||||
vsce package --allow-package-secrets sendgrid --out "cline-${{ steps.get_version.outputs.version }}.vsix"
|
||||
|
||||
if [ "${{ github.event.inputs.release-type }}" = "pre-release" ]; then
|
||||
npm run publish:marketplace:prerelease
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
name: Scenario Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
matrix_prep:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- id: set-matrix
|
||||
run: |
|
||||
echo 'matrix=[{"runner":"ubuntu"},{"runner":"windows"},{"runner":"macos"}]' >> $GITHUB_OUTPUT
|
||||
|
||||
validate-scenario:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Validate PR-specific scenario metadata
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" != "pull_request" ]; then
|
||||
echo "Not a pull_request event; skipping scenario validation."
|
||||
exit 0
|
||||
fi
|
||||
bash scripts/validate-scenario.sh "${{ github.event.number }}"
|
||||
|
||||
scenarios:
|
||||
needs: [matrix_prep, validate-scenario]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include: ${{ fromJson(needs.matrix_prep.outputs.matrix) }}
|
||||
runs-on: ${{ matrix.runner }}-latest
|
||||
timeout-minutes: 20
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- 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
|
||||
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') }}
|
||||
|
||||
# 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
|
||||
|
||||
- name: Install webview-ui dependencies
|
||||
if: steps.webview-cache.outputs.cache-hit != 'true'
|
||||
run: cd webview-ui && npm ci
|
||||
|
||||
- name: Install xvfb on Linux
|
||||
if: matrix.runner == 'ubuntu'
|
||||
run: sudo apt-get update && sudo apt-get install -y xvfb
|
||||
|
||||
# Run optimized Scenario tests (reuses build steps like e2e)
|
||||
- name: Run Scenario tests - Linux
|
||||
if: matrix.runner == 'ubuntu'
|
||||
run: xvfb-run -a npm run test:scenarios:optimal
|
||||
|
||||
- name: Run Scenario tests - Non-Linux
|
||||
if: matrix.runner != 'ubuntu'
|
||||
run: npm run test:scenarios:optimal
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
name: playwright-recordings-${{ matrix.runner }}
|
||||
path: |
|
||||
test-results/playwright/
|
||||
|
||||
scenario-summary:
|
||||
needs: scenarios
|
||||
permissions: {}
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check all scenarios passed
|
||||
run: |
|
||||
if [ "${{ needs.scenarios.result }}" != "success" ]; then
|
||||
echo "Some scenario tests failed"
|
||||
exit 1
|
||||
fi
|
||||
echo "All scenario tests passed successfully"
|
||||
+154
-104
@@ -1,6 +1,9 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
@@ -14,7 +17,45 @@ 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:
|
||||
@@ -33,18 +74,6 @@ 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
|
||||
@@ -52,7 +81,6 @@ 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
|
||||
@@ -68,54 +96,60 @@ 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: Set up NPM on Windows
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
npm config set script-shell "C:\\Program Files\\Git\\bin\\bash.exe"
|
||||
|
||||
- name: Type Check
|
||||
run: npm run check-types
|
||||
|
||||
- name: Lint Check
|
||||
run: npm run lint
|
||||
|
||||
- name: Format Check
|
||||
run: npm run format
|
||||
|
||||
# Build the extension before running tests
|
||||
# Build the extension and tests (without redundant checks)
|
||||
- name: Build Tests and Extension
|
||||
run: npm run pretest
|
||||
run: npm run ci:build
|
||||
|
||||
- name: Unit Tests
|
||||
run: npm run test:unit
|
||||
|
||||
# Run extension tests with coverage
|
||||
- name: Extension Integration Tests with Coverage
|
||||
id: extension_coverage
|
||||
- name: Unit Tests with coverage - Linux
|
||||
id: unit_tests_linux
|
||||
continue-on-error: true
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
node ./scripts/test-ci.js 2>&1 | tee extension_coverage.txt
|
||||
# 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
|
||||
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
|
||||
|
||||
# Run webview tests with coverage
|
||||
- name: Webview Tests with Coverage
|
||||
id: webview_coverage
|
||||
id: webview_tests
|
||||
continue-on-error: true
|
||||
run: |
|
||||
cd webview-ui
|
||||
# Ensure coverage dependency is installed
|
||||
npm install --no-save @vitest/coverage-v8
|
||||
npm run test:coverage 2>&1 | tee webview_coverage.txt
|
||||
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
|
||||
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"
|
||||
|
||||
# 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
|
||||
@@ -123,52 +157,21 @@ jobs:
|
||||
with:
|
||||
name: pr-coverage-reports
|
||||
path: |
|
||||
extension_coverage.txt
|
||||
webview-ui/webview_coverage.txt
|
||||
coverage-unit/lcov.info
|
||||
webview-ui/coverage/lcov.info
|
||||
|
||||
# Set the check as failed if any of the tests failed
|
||||
- name: Check for test failures
|
||||
run: |
|
||||
# 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" ]; then
|
||||
echo "Extension Integration Tests failed, see previous step for test output."
|
||||
fi
|
||||
if [ "${{ steps.webview_coverage.outcome }}" != "success" ]; then
|
||||
echo "Webview Tests failed, see previous step for test output."
|
||||
fi
|
||||
if [ "${{ steps.extension_coverage.outcome }}" != "success" ] || [ "${{ steps.webview_coverage.outcome }}" != "success" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
coverage:
|
||||
needs: test
|
||||
test-platform-integration:
|
||||
needs: quality-checks
|
||||
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
|
||||
@@ -176,7 +179,6 @@ 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
|
||||
@@ -184,6 +186,14 @@ 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
|
||||
@@ -192,30 +202,70 @@ jobs:
|
||||
if: steps.webview-cache.outputs.cache-hit != 'true'
|
||||
run: cd webview-ui && npm ci
|
||||
|
||||
# Build the extension before running tests
|
||||
- name: Build Extension
|
||||
run: npm run compile
|
||||
- name: Compile standalone
|
||||
run: npm run compile-standalone
|
||||
|
||||
# Download coverage artifacts from test job
|
||||
- name: Download Coverage Reports
|
||||
- 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
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: pr-coverage-reports
|
||||
path: . # Download to root directory to match expected paths
|
||||
path: .
|
||||
|
||||
# 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 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
|
||||
|
||||
# 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 }}
|
||||
- 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
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
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 }}"
|
||||
@@ -20,6 +20,8 @@ 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/
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
lint-staged --no-stash
|
||||
lint-staged
|
||||
+3
-3
@@ -3,13 +3,13 @@
|
||||
"ts"
|
||||
],
|
||||
"spec": [
|
||||
"src/**/__tests__/*.ts",
|
||||
"eslint-rules/__tests__/**/*.test.ts"
|
||||
"src/**/__tests__/*.ts"
|
||||
],
|
||||
"require": [
|
||||
"ts-node/register",
|
||||
"source-map-support/register",
|
||||
"./src/test/requires.ts"
|
||||
],
|
||||
"recursive": true
|
||||
"recursive": true,
|
||||
"exit": true
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
Vendored
+55
-8
@@ -12,6 +12,7 @@
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"--disable-workspace-trust",
|
||||
"--disable-extensions", // Avoid conflicts with installed extensions
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
@@ -31,6 +32,7 @@
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"--disable-workspace-trust",
|
||||
"--disable-extensions", // Avoid conflicts with installed extensions
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
@@ -50,6 +52,7 @@
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"--disable-workspace-trust",
|
||||
"--disable-extensions", // Avoid conflicts with installed extensions
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
@@ -71,7 +74,7 @@
|
||||
"--user-data-dir=${workspaceFolder}/dist/tmp/user",
|
||||
"--profile-temp",
|
||||
"--sync=off",
|
||||
"--disable-extensions",
|
||||
"--disable-extensions", // Avoid conflicts with installed extensions
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
@@ -91,7 +94,7 @@
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Run cline-core service",
|
||||
"name": "Debug Test Standalone Core Api Server (test:sca-server)",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
@@ -100,18 +103,62 @@
|
||||
"${workspaceFolder}/**",
|
||||
"!**/node_modules/**"
|
||||
],
|
||||
"cwd": "${workspaceFolder}/dist-standalone",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js",
|
||||
"${workspaceFolder}/dist-standalone/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "compile-standalone",
|
||||
"runtimeExecutable": "npx",
|
||||
"runtimeArgs": [
|
||||
"tsx"
|
||||
],
|
||||
"program": "scripts/test-standalone-core-api-server.ts",
|
||||
"env": {
|
||||
// Turns on grpc debug log.
|
||||
//"GRPC_TRACE": "all",
|
||||
//"GRPC_VERBOSITY": "DEBUG",
|
||||
"NODE_PATH": "${workspaceFolder}/dist-standalone/node_modules"
|
||||
"PROTOBUS_PORT": "26040",
|
||||
"HOSTBRIDGE_PORT": "26041",
|
||||
"WORKSPACE_DIR": "${workspaceFolder}",
|
||||
"E2E_TEST": "true",
|
||||
"CLINE_ENVIRONMENT": "local"
|
||||
},
|
||||
"program": "cline-core.js"
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+6
-11
@@ -21,16 +21,11 @@
|
||||
},
|
||||
// Enable Lint and format using Biome
|
||||
"biome.enabled": true,
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.biome": "explicit",
|
||||
"source.removeUnused.biome": "always",
|
||||
"source.removeUnusedImports": "always",
|
||||
"source.organizeImports.biome": "always"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,3 +64,9 @@ old_docs/**
|
||||
e2e-build.mjs
|
||||
e2e.vsix
|
||||
test-results/
|
||||
|
||||
# Ignore Storybook files
|
||||
**/*.stories.tsx
|
||||
*storybook.log
|
||||
storybook-static
|
||||
**/StorybookDecorator.tsx
|
||||
+172
@@ -1,5 +1,177 @@
|
||||
# Changelog
|
||||
|
||||
## [3.32.5]
|
||||
|
||||
- Improve thinking budget slider UI to take up less space
|
||||
- Fix Vercel provider cost note and sign-up url
|
||||
- Fix repeated API error 400 in SAP AI Core provider
|
||||
- Add us-west-1 to Amazon Bedrock regions
|
||||
- Fix OCA provider refresh logic
|
||||
|
||||
## [3.32.4]
|
||||
|
||||
- Add 1m context window support to Claude Sonnet 4.5
|
||||
- Add Claude Sonnet 4.5 to GCP Vertex
|
||||
- Add prompt caching support for OpenRouter accidental `anthropic/claude-4.5-sonnet` model ID
|
||||
|
||||
## [3.32.3]
|
||||
|
||||
- Add Claude Sonnet 4.5 to Bedrock provider
|
||||
- Add Alert banner for new Claude Sonnet 4.5 model
|
||||
|
||||
## [3.32.2]
|
||||
|
||||
- Add Claude Sonnet 4.5 to Cline/OpenRouter/Anthropic providers
|
||||
- Add /task deep link handler
|
||||
|
||||
## [3.32.1]
|
||||
|
||||
- Preserve reasoning traces for Cline/OpenRouter/Anthropic providers to maintain conversation integrity
|
||||
- Add automatically retry on rate limit errors with SAP AI Core provider
|
||||
- Fix Cline accounts using stale id token at refresh response
|
||||
- Minor UI improvements to Settings and Task Header
|
||||
|
||||
## [3.32.0]
|
||||
|
||||
- Added the new code-supernova-1-million stealth model, available for free and delivering a 1 million token context window
|
||||
- Changes to inform Cline about commands that are available on your system
|
||||
|
||||
## [3.31.1]
|
||||
|
||||
- Version bump
|
||||
|
||||
## [3.31.0]
|
||||
|
||||
- UI Improvements: New task header and focus chain design to take up less space for a cleaner experience
|
||||
- Voice Mode: Experimental feature that must be enabled in settings for hands-free coding
|
||||
- YOLO Mode: Enable in settings to let Cline approve all actions and automatically switch between plan/act mode
|
||||
- Fix Oracle Code Assist provider issues
|
||||
|
||||
## [3.30.3]
|
||||
|
||||
- Add Oracle Code Assist provider
|
||||
|
||||
## [3.30.2]
|
||||
|
||||
- Fix UI tests
|
||||
|
||||
## [3.30.1]
|
||||
|
||||
- Fix model list not being updated in time for user to use shortcut button to update model to stealth model
|
||||
- Fix flicker issue when switching modes
|
||||
- Fix Sticky header in settings view overlaping with content on scroll
|
||||
- Add experimental yolo mode feature that disables all user approvals and automatically executes a task and navigates through plan to act mode until the task is complete
|
||||
|
||||
## [3.30.0]
|
||||
|
||||
- Add code-supernova stealth model
|
||||
|
||||
## [3.29.2]
|
||||
|
||||
- Fix: Reverted change that caused formatting issues
|
||||
- Fix: Moonshot - Pass max_tokens value to provider
|
||||
|
||||
## [3.29.1]
|
||||
|
||||
- Changeset bump + Announcement banner update
|
||||
|
||||
## [3.29.0]
|
||||
|
||||
- Updated Baseten provider to fetch models from server
|
||||
- Fix: Updated insufficient balance URL for easy Cline balance top-ups
|
||||
- Accessibility: Improvements to screen readers in MCP, Cline Rules, workflows, and history views.
|
||||
|
||||
## [3.28.4]
|
||||
|
||||
- Fix bug where some Windows machines had API request hanging
|
||||
- Fix bug where 'Proceed while running' action button would be disabled after running an interactive command
|
||||
- Fix prompt cache info not being displayed in History
|
||||
|
||||
## [3.28.3]
|
||||
|
||||
- Fixed issue with start new task button
|
||||
- Feature to generate commit message for staged changes, with unstaged as fallback
|
||||
|
||||
## [3.28.2]
|
||||
|
||||
- Fix for focus chain settings
|
||||
|
||||
## [3.28.1]
|
||||
|
||||
- Requesty: use base URL to get models and API keys
|
||||
- Removed focus chain feature flag
|
||||
|
||||
## [3.28.0]
|
||||
|
||||
- Synchronized Task History: Real-time task history synchronization across all Cline instances
|
||||
- Optimized GPT-5 Integration: Fine-tuned system prompts for improved performance with GPT-5 model family
|
||||
- Deep Planning Improvements: Optimized prompts for Windows/PowerShell environments and dependency exclusion
|
||||
- Streamlined UI Experience: ESC key navigation, cleaner approve/reject buttons, and improved editor panel focus
|
||||
- Smart Provider Search: Improved search functionality in API provider dropdown for faster model selection
|
||||
- Added per-provider thinking tokens configurability
|
||||
- Added Ollama custom prompt options
|
||||
- Enhanced SAP AI Core Provider: Orchestration mode support and improved model visibility
|
||||
- Added Dify.ai API Integration
|
||||
- SambaNova Updates: Added DeepSeek-V3.1 model
|
||||
- Better Gemini rate limit handling
|
||||
- OpenAI Reasoning Effort: Minimal reasoning effort configuration for OpenAI models
|
||||
- Fixed LiteLLM Caching: Anthropic caching compatibility when using LiteLLM
|
||||
- Fixed Ollama default endpoint connections
|
||||
- Fixed AutoApprove menu overflow
|
||||
- Fixed extended thinking token issue with Anthropic models
|
||||
- Fixed issue with slash commands removing text from prompt
|
||||
|
||||
## [3.27.2]
|
||||
|
||||
- Remove `grok-code-fast-1` promotion deadline
|
||||
|
||||
## [3.27.1]
|
||||
|
||||
- Add new Kimi K2 model to groq and moonshot providers
|
||||
|
||||
## [3.27.0]
|
||||
|
||||
- Fix `grok-code-fast-1` model information
|
||||
- Add call to action for trying free `grok-code-fast-1` in Announcement banner
|
||||
|
||||
## [3.26.7]
|
||||
|
||||
- Add 200k context window variant for Claude Sonnet 4 to OpenRouter and Cline providers
|
||||
|
||||
## [3.26.6]
|
||||
|
||||
- Add free Grok Coder model to Cline provider for users looking for a fast, free coding model option
|
||||
- Fix GPT-5 models not respecting auto-compact setting when enabled, improving context window management
|
||||
- Fix provider retry attempts not showing proper user feedback during rate limiting scenarios
|
||||
- Improve markdown and code block styling to automatically adapt when switching VS Code themes
|
||||
|
||||
## [3.26.5]
|
||||
|
||||
- fix (provider/vercel-ai-gateway): reduce model list load frequency in settings view
|
||||
- Fix OVSX publish command to resolve deployment failure
|
||||
|
||||
## [3.26.4]
|
||||
|
||||
- Update nebius ai studio models
|
||||
- Update sap provider - support reasoning effort for open ai models
|
||||
- Fix Claude 4 image input in SAP AI Core Provider
|
||||
|
||||
## [3.26.3]
|
||||
|
||||
- Add compact system prompt option for LM Studio and Ollama models, optimized for smaller context windows (8k or less)
|
||||
- Add token usage tracking for LM Studio models to better monitor API consumption
|
||||
- Add "Use compact prompt" checkbox in LM Studio provider settings
|
||||
- Fix "Unexpected API Response" bug with gpt-5
|
||||
|
||||
## [3.26.2]
|
||||
|
||||
- Improve OpenRouter model parsing to show reasoning budget sliders for all models that support thinking, not just Claude models
|
||||
- Fix OpenRouter context window error handling to properly extract error codes from error messages, resolving "Unexpected API Response" errors with GPT-5 on Cline provider
|
||||
- Fix GPT-5 context window configuration for OpenAI/OpenRouter/Cline providers to use correct 272K limit
|
||||
- Remove max tokens configuration from Sonic Alpha model
|
||||
- Add Go language support to deep-planning feature (Thanks @yuvalman!)
|
||||
- Fix typo in Focus Chain settings page (Thanks @joyceerhl!)
|
||||
|
||||
## [3.26.1]
|
||||
|
||||
- Add Vercel AI Gateway as a new API provider option (Thanks @joshualipman123!)
|
||||
|
||||
+30
-1
@@ -74,7 +74,6 @@ 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
|
||||
|
||||
@@ -157,6 +156,36 @@ 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`
|
||||
|
||||
@@ -30,9 +30,9 @@ English | <a href="https://github.com/cline/cline/blob/main/locales/es/README.md
|
||||
</table>
|
||||
</div>
|
||||
|
||||
Meet Cline (pronounced /klaɪn/, like "Klein"), an AI assistant that can use your **CLI** a**N**d **E**ditor.
|
||||
Meet Cline, an AI assistant that can use your **CLI** a**N**d **E**ditor.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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 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.
|
||||
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.
|
||||
|
||||
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)
|
||||
|
||||
|
||||
+11
-3
@@ -37,7 +37,8 @@
|
||||
"useYield": "off",
|
||||
"noConstructorReturn": "off",
|
||||
"noInvalidPositionAtImportRule": "off",
|
||||
"noSwitchDeclarations": "off"
|
||||
"noSwitchDeclarations": "off",
|
||||
"noUnusedImports": "error"
|
||||
},
|
||||
"a11y": "off",
|
||||
"style": {
|
||||
@@ -122,7 +123,8 @@
|
||||
"!**/node_modules/**",
|
||||
"!**/webview-ui/build/**",
|
||||
"!**/generated/**",
|
||||
"!**/proto/**"
|
||||
"!**/proto/**",
|
||||
"!**/tests/specs/**"
|
||||
]
|
||||
},
|
||||
"plugins": [
|
||||
@@ -134,7 +136,12 @@
|
||||
"**",
|
||||
"!**/hosts/vscode/**",
|
||||
"!**/test/**",
|
||||
"!src/extension.ts"
|
||||
"!**/*.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"
|
||||
@@ -147,6 +154,7 @@
|
||||
"!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"
|
||||
],
|
||||
|
||||
+40
-24
@@ -25,15 +25,15 @@
|
||||
},
|
||||
"styling": {
|
||||
"eyebrows": "breadcrumbs",
|
||||
"codeblocks": "system"
|
||||
"codeblocks": "system",
|
||||
"css": "styles.css"
|
||||
},
|
||||
"appearance": {
|
||||
"default": "system",
|
||||
"strict": false
|
||||
},
|
||||
"fonts": {
|
||||
"family": "Roboto",
|
||||
"weight": 400
|
||||
"family": "Roboto"
|
||||
},
|
||||
"navbar": {
|
||||
"links": [
|
||||
@@ -58,8 +58,8 @@
|
||||
"group": "Getting Started",
|
||||
"pages": [
|
||||
"getting-started/what-is-cline",
|
||||
"getting-started/model-selection-guide",
|
||||
"getting-started/installing-cline",
|
||||
"getting-started/model-selection-guide",
|
||||
"getting-started/task-management",
|
||||
"getting-started/understanding-context-management",
|
||||
{
|
||||
@@ -81,15 +81,6 @@
|
||||
{
|
||||
"group": "Features",
|
||||
"pages": [
|
||||
"features/auto-approve",
|
||||
"features/checkpoints",
|
||||
"features/cline-rules",
|
||||
"features/drag-and-drop",
|
||||
"features/plan-and-act",
|
||||
"features/slash-commands/workflows",
|
||||
"features/focus-chain",
|
||||
"features/auto-compact",
|
||||
"features/editing-messages",
|
||||
{
|
||||
"group": "@ Mentions",
|
||||
"pages": [
|
||||
@@ -101,6 +92,32 @@
|
||||
"features/at-mentions/url-mentions"
|
||||
]
|
||||
},
|
||||
"features/auto-approve",
|
||||
"features/auto-compact",
|
||||
"features/checkpoints",
|
||||
"features/cline-rules",
|
||||
{
|
||||
"group": "Commands & Shortcuts",
|
||||
"pages": [
|
||||
"features/commands-and-shortcuts/overview",
|
||||
"features/commands-and-shortcuts/code-commands",
|
||||
"features/commands-and-shortcuts/terminal-integration",
|
||||
"features/commands-and-shortcuts/git-integration",
|
||||
"features/commands-and-shortcuts/keyboard-shortcuts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": [
|
||||
@@ -111,16 +128,8 @@
|
||||
"features/slash-commands/deep-planning"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Commands & Shortcuts",
|
||||
"pages": [
|
||||
"features/commands-and-shortcuts/overview",
|
||||
"features/commands-and-shortcuts/code-commands",
|
||||
"features/commands-and-shortcuts/terminal-integration",
|
||||
"features/commands-and-shortcuts/git-integration",
|
||||
"features/commands-and-shortcuts/keyboard-shortcuts"
|
||||
]
|
||||
}
|
||||
"features/slash-commands/workflows",
|
||||
"features/yolo-mode"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -182,7 +191,8 @@
|
||||
"provider-config/openrouter",
|
||||
"provider-config/sap-aicore",
|
||||
"provider-config/vercel-ai-gateway",
|
||||
"provider-config/requesty"
|
||||
"provider-config/requesty",
|
||||
"provider-config/baseten"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -222,6 +232,12 @@
|
||||
"url": "getting-started/what-is-cline"
|
||||
}
|
||||
],
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/getting-started/installing-cline-jetbrains",
|
||||
"destination": "/getting-started/installing-cline"
|
||||
}
|
||||
],
|
||||
"search": {
|
||||
"prompt": "Search Cline documentation..."
|
||||
},
|
||||
|
||||
@@ -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/Cline.ts).
|
||||
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).
|
||||
|
||||
Cline has access to the following tools for various tasks:
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ 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 |
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
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.
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
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.
|
||||
@@ -0,0 +1,149 @@
|
||||
---
|
||||
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.
|
||||
@@ -24,6 +24,10 @@ 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:
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
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).
|
||||
@@ -1,65 +1,254 @@
|
||||
---
|
||||
title: "Installing Cline"
|
||||
description: "Cline is a VS Code extension that brings AI-powered coding assistance directly
|
||||
to your editor. Install using one of these methods:"
|
||||
description: "Get Cline set up in your editor and start building projects with AI assistance."
|
||||
---
|
||||
|
||||
### Installation Options
|
||||
## Prerequisites
|
||||
|
||||
- **VS Code Marketplace (Recommended):** Fastest method for standard VS Code and Cursor users.
|
||||
- **Open VSX Registry:** For VS Code-compatible editors like VSCodium.
|
||||
Before installing Cline, make sure you have the following:
|
||||
|
||||
### VS Code Marketplace: Step-by-Step Setup
|
||||
### Create a Cline Account
|
||||
|
||||
Follow these steps to get Cline up and running:
|
||||
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
|
||||
|
||||
1. **Open VS Code:** Launch the VS Code application.
|
||||
### Compatible Editor
|
||||
|
||||
> **Note:** If VS Code shows "Running extensions might...", click "Allow".
|
||||
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
|
||||
|
||||
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`.
|
||||
Make sure you have one of these editors installed before proceeding with the Cline installation.
|
||||
|
||||
<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>
|
||||
## Choose Your Editor
|
||||
|
||||
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.
|
||||
Cline works across multiple IDEs. Select your preferred editor below for installation instructions:
|
||||
|
||||
> **Pro Tip:** You should see the Cline chat window appear in your VS Code editor!
|
||||
<Tabs>
|
||||
<Tab title="VS Code/Cursor" icon="code">
|
||||
### Installation Steps
|
||||
|
||||
### Open VSX Registry
|
||||
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
|
||||
|
||||
For VS Code-compatible editors without Marketplace access (like VSCodium and Windsurf):
|
||||
<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>
|
||||
|
||||
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.
|
||||
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"
|
||||
|
||||
### Creating Your Cline Account
|
||||
> **Note:** If VS Code shows "Running extensions might..." dialog, click "Allow". If you don't see the Cline icon, restart VS Code.
|
||||
|
||||
Now that you have Cline installed, let's get you set up with your account:
|
||||
<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 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, you’ll 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
|
||||
|
||||
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.
|
||||
|
||||
### Your First Interaction with Cline
|
||||
|
||||
@@ -80,4 +269,4 @@ Hey Cline! Could you help me create a new project folder called "hello-world" in
|
||||
|
||||
### Still Struggling?
|
||||
|
||||
Join our Discord community and engage with our team and other Cline users directly.
|
||||
Join our [Discord community](https://discord.gg/cline) and engage with our team and other Cline users directly.
|
||||
|
||||
@@ -9,7 +9,7 @@ New models drop constantly, so this guide focuses on what's working well with Cl
|
||||
|
||||
| Model | Context Window | Input Price* | Output Price* | Best For |
|
||||
|-------|---------------|--------------|---------------|----------|
|
||||
| **Claude Sonnet 4** | 1M tokens | $3-6 | $15-22.50 | Reliable tool usage, complex codebases |
|
||||
| **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 |
|
||||
@@ -57,9 +57,9 @@ New models drop constantly, so this guide focuses on what's working well with Cl
|
||||
|
||||
| If you want... | Use this |
|
||||
|----------------|----------|
|
||||
| Something that just works | Claude Sonnet 4 |
|
||||
| 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 |
|
||||
| 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) |
|
||||
@@ -74,6 +74,6 @@ Cline automatically handles context limits with [auto-compact](/features/auto-co
|
||||
|
||||
## The Bottom Line
|
||||
|
||||
Start with **Claude Sonnet 4** if you want reliability. Experiment with **open source options** once you're comfortable to find the best fit for your workflow and budget.
|
||||
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.
|
||||
|
||||
The landscape moves fast - these recommendations reflect what's working now, but keep an eye on new releases.
|
||||
|
||||
@@ -53,7 +53,7 @@ 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: 1,000,000 tokens
|
||||
- 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
|
||||
@@ -77,7 +77,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)
|
||||
- The total shows your model's maximum capacity (e.g., 1M for Claude Sonnet 4.5)
|
||||
|
||||
### When to Watch the Bar
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
title: "What is Cline?"
|
||||
description: "An introduction to Cline, your AI-powered development assistant in VS Code."
|
||||
description: "An introduction to Cline, your AI-powered development assistant for modern IDEs."
|
||||
---
|
||||
|
||||
Cline is an open source AI coding agent that brings frontier AI models directly to your VS Code editor. 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 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.
|
||||
|
||||
## Open Source AI Coding, Uncompromised
|
||||
|
||||
@@ -69,4 +69,4 @@ Define project-specific instructions that Cline follows including coding standar
|
||||
|
||||
## Getting Started
|
||||
|
||||
Ready to experience AI coding without limits? [Install Cline](/getting-started/installing-cline) and start with our [Model Selection Guide](/getting-started/model-selection-guide) to choose the right AI model for your needs.
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// 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)
|
||||
}
|
||||
})()
|
||||
@@ -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 "Installed" tab, and then Click the "Advanced MCP Settings" link at the bottom of that pane.
|
||||
2. Select the "Configure" 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 "Installed" tab.
|
||||
2. Select the "Configure" 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:
|
||||
|
||||
@@ -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 "Installed" tab where you can:
|
||||
Once added, your MCP servers appear in the "Configure" 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 "Installed" tab, click "Configure MCP Servers" to access the settings file
|
||||
1. In the "Configure" tab, click "Configure MCP Servers" to access the settings file
|
||||
2. The configuration for each server follows this format:
|
||||
|
||||
```json
|
||||
|
||||
Generated
+4
-4
@@ -1386,7 +1386,7 @@
|
||||
"integrity": "sha512-/uR4hAwpcJW9+zbmZL48kKFnWLkOxhIqoGWvZzjg0CniVhR4emtQJAps80WqLAhz0iJgCQxg/axtA7leaznDzQ==",
|
||||
"license": "Elastic-2.0",
|
||||
"dependencies": {
|
||||
"axios": "^1.8.3",
|
||||
"axios": "^1.12.0",
|
||||
"openapi-types": "^12.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -2688,9 +2688,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz",
|
||||
"integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
|
||||
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
|
||||
@@ -18,11 +18,8 @@ Cline supports the following Anthropic Claude models:
|
||||
|
||||
- `claude-opus-4-1-20250805`
|
||||
- `claude-opus-4-20250514`
|
||||
- `claude-opus-4-20250514:thinking` (Extended Thinking variant)
|
||||
- `claude-sonnet-4-20250514` (Recommended)
|
||||
- `claude-sonnet-4-20250514:thinking` (Extended Thinking variant)
|
||||
- `anthropic/claude-sonnet-4.5` (Recommended)
|
||||
- `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`
|
||||
@@ -47,8 +44,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 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.
|
||||
- **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.
|
||||
- **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).
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
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.
|
||||
@@ -7,12 +7,13 @@ SAP AI Core and the generative AI hub help you to integrate LLMs and AI into new
|
||||
|
||||
**Website:** [SAP Help Portal](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/what-is-sap-ai-core)
|
||||
|
||||
### Getting a Service Binding
|
||||
|
||||
> 💡 **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 to perform these steps.
|
||||
> 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.
|
||||
@@ -32,11 +33,44 @@ Refer to the [Generative AI Hub Supported Models page](https://me.sap.com/notes/
|
||||
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. **Select Model:** Choose your desired model from the "Model" dropdown.
|
||||
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
|
||||
|
||||
- **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 not deployed model, you'll need to create a deployment in your resource group in 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.
|
||||
- **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,34 +1,98 @@
|
||||
---
|
||||
title: "Vercel AI Gateway"
|
||||
description: "Learn how to use Vercel AI Gateway with Cline to access a wide variety of AI models through a single unified API."
|
||||
description: "Use Vercel AI Gateway in Cline to reach 100+ models from one endpoint with routing, retries, and spend observability."
|
||||
---
|
||||
|
||||
The AI Gateway offers a unified API to multiple model providers and gives you the ability to set budgets, monitor usage, load-balance requests, and manage fallbacks.
|
||||
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:
|
||||
- [AI Gateway Team Dashboard](https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai&title=AI+Gateway+Overview+Tab)
|
||||
- [AI Gateway Landing Page](https://vercel.com/ai-gateway)
|
||||
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
|
||||
|
||||
### Getting an API Key
|
||||
## What you get
|
||||
|
||||
1. **Sign Up/Sign In:** Go to [vercel.com](https://vercel.com/) and create an account or sign in.
|
||||
2. **Get an API Key:** From the Vercel dashboard, click the AI Gateway tab. Then click **API keys** on the left side bar and hit **Create key**.
|
||||
3. **Copy the Key:** Copy the API key.
|
||||
- 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
|
||||
|
||||
For more on Vercel AI Gateway authentication, see [Authentication](https://vercel.com/docs/ai-gateway/authentication)
|
||||
## Getting an API Key
|
||||
|
||||
### Supported Models
|
||||
1. Sign in at https://vercel.com
|
||||
2. Dashboard → AI Gateway → API Keys → Create key
|
||||
3. Copy the key
|
||||
|
||||
Vercel AI Gateway supports a large and growing number of models from various providers. Cline automatically fetches the list of available models from the Gateway API. Refer to the [Vercel AI Gateway Models page](https://vercel.com/ai-gateway/models) for the complete list.
|
||||
For more on authentication and OIDC options, see https://vercel.com/docs/ai-gateway/authentication
|
||||
|
||||
### Configuration in Cline
|
||||
## Configuration in Cline
|
||||
|
||||
1. **Open Cline Settings:** Click the settings icon (⚙️) in the Cline panel.
|
||||
2. **Select Provider:** Choose "Vercel AI Gateway" from the "API Provider" dropdown.
|
||||
3. **Enter API Key:** Paste your Vercel AI Gateway API key into the "Vercel AI Gateway API Key" field.
|
||||
4. **Select Model:** Choose your desired model from the "Model" dropdown, or enter a custom model ID if the model list doesn't load automatically.
|
||||
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
|
||||
|
||||
### Tips and Notes
|
||||
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`
|
||||
|
||||
- **Model Selection:** The AI Gateway offers a wide range of models. Experiment to find the best one for your needs.
|
||||
- **Pricing:** Vercel charges based on the underlying model's pricing. See the [AI Gateway Pricing page](https://vercel.com/docs/ai-gateway/pricing) for details.
|
||||
## 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
|
||||
|
||||
@@ -49,6 +49,44 @@ All models feature:
|
||||
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:
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/* 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);
|
||||
}
|
||||
+20
-6
@@ -6,7 +6,7 @@ import * as esbuild from "esbuild"
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
const production = process.argv.includes("--production")
|
||||
const production = process.argv.includes("--production") || process.env["IS_DEBUG_BUILD"] === "false"
|
||||
const watch = process.argv.includes("--watch")
|
||||
const standalone = process.argv.includes("--standalone")
|
||||
const e2eBuild = process.argv.includes("--e2e-build")
|
||||
@@ -123,15 +123,29 @@ 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: production
|
||||
? { "import.meta.url": "_importMetaUrl", "process.env.IS_DEV": JSON.stringify(!production) }
|
||||
: { "import.meta.url": "_importMetaUrl" },
|
||||
define: buildEnvVars,
|
||||
tsconfig: path.resolve(__dirname, "tsconfig.json"),
|
||||
plugins: [
|
||||
copyWasmFiles,
|
||||
@@ -160,9 +174,9 @@ const standaloneConfig = {
|
||||
...baseConfig,
|
||||
entryPoints: ["src/standalone/cline-core.ts"],
|
||||
outfile: `${destDir}/cline-core.js`,
|
||||
// These gRPC protos need to load files from the module directory at runtime,
|
||||
// These modules need to load files from the module directory at runtime,
|
||||
// so they cannot be bundled.
|
||||
external: ["vscode", "@grpc/reflection", "grpc-health-check"],
|
||||
external: ["vscode", "@grpc/reflection", "grpc-health-check", "better-sqlite3"],
|
||||
}
|
||||
|
||||
// E2E build script configuration
|
||||
|
||||
@@ -148,11 +148,6 @@ 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`)
|
||||
@@ -187,11 +182,6 @@ 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)
|
||||
@@ -288,13 +278,6 @@ 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...');
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { ToolUseName, ToolParamName } from "../../src/core/assistant-message"
|
||||
import { ToolParamName } from "../../src/core/assistant-message"
|
||||
import { ClineDefaultTool } from "../../src/shared/tools"
|
||||
|
||||
export interface InputMessage {
|
||||
role: "user" | "assistant"
|
||||
@@ -88,7 +89,7 @@ export interface TestResult {
|
||||
}
|
||||
|
||||
export interface ExtractedToolCall {
|
||||
name: ToolUseName
|
||||
name: ClineDefaultTool
|
||||
input: Partial<Record<ToolParamName, string>>
|
||||
}
|
||||
|
||||
|
||||
Generated
+82
-31
@@ -9,9 +9,9 @@
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.8.2",
|
||||
"axios": "^1.12.0",
|
||||
"better-sqlite3": "^11.10.0",
|
||||
"chalk": "^4.1.2",
|
||||
"chalk": "5.6.2",
|
||||
"commander": "^9.4.1",
|
||||
"dotenv": "^16.5.0",
|
||||
"execa": "^5.1.1",
|
||||
@@ -200,12 +200,13 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
|
||||
"integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
|
||||
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
@@ -292,15 +293,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"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"
|
||||
},
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
|
||||
"integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
@@ -607,9 +605,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz",
|
||||
"integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
|
||||
"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",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
@@ -708,6 +707,7 @@
|
||||
"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,6 +843,22 @@
|
||||
"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",
|
||||
@@ -1003,6 +1019,22 @@
|
||||
"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",
|
||||
@@ -1251,6 +1283,7 @@
|
||||
"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"
|
||||
},
|
||||
@@ -1635,12 +1668,12 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
|
||||
"integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
|
||||
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
@@ -1695,13 +1728,9 @@
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
|
||||
"integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="
|
||||
},
|
||||
"chownr": {
|
||||
"version": "1.1.4",
|
||||
@@ -1909,9 +1938,9 @@
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz",
|
||||
"integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
@@ -2054,6 +2083,17 @@
|
||||
"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": {
|
||||
@@ -2164,6 +2204,17 @@
|
||||
"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
@@ -19,9 +19,9 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.8.2",
|
||||
"axios": "^1.12.0",
|
||||
"better-sqlite3": "^11.10.0",
|
||||
"chalk": "^4.1.2",
|
||||
"chalk": "5.6.2",
|
||||
"dotenv": "^16.5.0",
|
||||
"commander": "^9.4.1",
|
||||
"execa": "^5.1.1",
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
See [https://cline.bot/privacy](https://cline.bot/privacy) for our privacy policy.
|
||||
@@ -1,39 +0,0 @@
|
||||
# Cline Documentation
|
||||
|
||||
Welcome to the Cline documentation - your comprehensive guide to using and extending Cline's capabilities. Here you'll find resources to help you get started, improve your skills, and contribute to the project.
|
||||
|
||||
## Getting Started
|
||||
|
||||
- **New to coding?** We've prepared a gentle introduction:
|
||||
- [Getting Started for New Coders](getting-started-new-coders/README.md)
|
||||
|
||||
## Improving Your Prompting Skills
|
||||
|
||||
- **Want to communicate more effectively with Cline?** Explore:
|
||||
- [Prompt Engineering Guide](prompting/README.md)
|
||||
- [Cline Memory Bank](prompting/custom%20instructions%20library/cline-memory-bank.md)
|
||||
|
||||
## Exploring Cline's Tools
|
||||
|
||||
- **Understand Cline's capabilities:**
|
||||
|
||||
- [Cline Tools Guide](tools/cline-tools-guide.md)
|
||||
- [Mentions Feature Guide](tools/mentions-guide.md)
|
||||
|
||||
- **Extend Cline with MCP Servers:**
|
||||
- [MCP Overview](mcp/README.md)
|
||||
- [Building MCP Servers from GitHub](mcp/mcp-server-from-github.md)
|
||||
- [Building Custom MCP Servers](mcp/mcp-server-from-scratch.md)
|
||||
|
||||
## Contributing to Cline
|
||||
|
||||
- **Interested in contributing?** We welcome your input:
|
||||
- Feel free to submit a pull request
|
||||
- [Contribution Guidelines](../CONTRIBUTING.md)
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- **Cline GitHub Repository:** [https://github.com/cline/cline](https://github.com/cline/cline)
|
||||
- **MCP Documentation:** [https://modelcontextprotocol.org/docs](https://modelcontextprotocol.org/docs)
|
||||
|
||||
We're always looking to improve this documentation. If you have suggestions or find areas that could be enhanced, please let us know. Your feedback helps make Cline better for everyone.
|
||||
@@ -1,43 +0,0 @@
|
||||
# Cline Extension Architecture
|
||||
|
||||
This directory contains architectural documentation for the Cline VSCode extension.
|
||||
|
||||
## Extension Architecture Diagram
|
||||
|
||||
The [extension-architecture.mmd](./extension-architecture.mmd) file contains a Mermaid diagram showing the high-level architecture of the Cline extension. The diagram illustrates:
|
||||
|
||||
1. **Core Extension**
|
||||
- Extension entry point and main classes
|
||||
- State management through VSCode's global state and secrets storage
|
||||
- Core business logic in the Cline class
|
||||
|
||||
2. **Webview UI**
|
||||
- React-based user interface
|
||||
- State management through ExtensionStateContext
|
||||
- Component hierarchy
|
||||
|
||||
3. **Storage**
|
||||
- Task-specific storage for history and state
|
||||
- Git-based checkpoint system for file changes
|
||||
|
||||
4. **Data Flow**
|
||||
- Core extension data flow between components
|
||||
- Webview UI data flow
|
||||
- Bidirectional communication between core and webview
|
||||
|
||||
## Viewing the Diagram
|
||||
|
||||
To view the diagram:
|
||||
1. Install a Mermaid diagram viewer extension in VSCode
|
||||
2. Open extension-architecture.mmd
|
||||
3. Use the extension's preview feature to render the diagram
|
||||
|
||||
You can also view the diagram on GitHub, which has built-in Mermaid rendering support.
|
||||
|
||||
## Color Scheme
|
||||
|
||||
The diagram uses a high-contrast color scheme for better visibility:
|
||||
- Pink (#ff0066): Global state and secrets storage components
|
||||
- Blue (#0066ff): Extension state context
|
||||
- Green (#00cc66): Cline provider
|
||||
- All components use white text for maximum readability
|
||||
@@ -1,67 +0,0 @@
|
||||
flowchart TB
|
||||
subgraph "VSCode Extension Host"
|
||||
subgraph "Core Extension"
|
||||
ExtensionEntry["Extension Entry<br/>src/extension.ts"]
|
||||
WebviewProvider["WebviewProvider<br/>src/core/webview/index.ts"]
|
||||
Controller["Controller<br/>src/core/controller/index.ts"]
|
||||
Task["Task<br/>src/core/task/index.ts"]
|
||||
GlobalState["VSCode Global State"]
|
||||
SecretsStorage["VSCode Secrets Storage"]
|
||||
McpHub["McpHub<br/>src/services/mcp/McpHub.ts"]
|
||||
end
|
||||
|
||||
subgraph "Webview UI"
|
||||
WebviewApp["React App<br/>webview-ui/src/App.tsx"]
|
||||
ExtStateContext["ExtensionStateContext<br/>webview-ui/src/context/ExtensionStateContext.tsx"]
|
||||
ReactComponents["React Components"]
|
||||
end
|
||||
|
||||
subgraph "Storage"
|
||||
TaskStorage["Task Storage<br/>Per-Task Files & History"]
|
||||
CheckpointSystem["Git-based Checkpoints"]
|
||||
end
|
||||
|
||||
subgraph "API Providers"
|
||||
AnthropicAPI["Anthropic"]
|
||||
OpenRouterAPI["OpenRouter"]
|
||||
BedrockAPI["AWS Bedrock"]
|
||||
OtherAPIs["Other Providers"]
|
||||
end
|
||||
|
||||
subgraph "MCP Servers"
|
||||
ExternalMcpServers["External MCP Servers"]
|
||||
end
|
||||
end
|
||||
|
||||
%% Core Extension Data Flow
|
||||
ExtensionEntry --> WebviewProvider
|
||||
WebviewProvider --> Controller
|
||||
Controller --> Task
|
||||
Controller --> McpHub
|
||||
Task --> GlobalState
|
||||
Task --> SecretsStorage
|
||||
Task --> TaskStorage
|
||||
Task --> CheckpointSystem
|
||||
Task --> |"API Requests"| AnthropicAPI
|
||||
Task --> |"API Requests"| OpenRouterAPI
|
||||
Task --> |"API Requests"| BedrockAPI
|
||||
Task --> |"API Requests"| OtherAPIs
|
||||
McpHub --> |"Connects to"| ExternalMcpServers
|
||||
Task --> |"Uses"| McpHub
|
||||
|
||||
%% Webview Data Flow
|
||||
WebviewApp --> ExtStateContext
|
||||
ExtStateContext --> ReactComponents
|
||||
|
||||
%% Bidirectional Communication
|
||||
WebviewProvider <--> |"postMessage"| ExtStateContext
|
||||
|
||||
classDef vscodeState fill:#f9f,stroke:#333,stroke-width:2px
|
||||
classDef contextClass fill:#bbf,stroke:#333,stroke-width:2px
|
||||
classDef providerClass fill:#bfb,stroke:#333,stroke-width:2px
|
||||
classDef apiClass fill:#fdb,stroke:#333,stroke-width:2px
|
||||
|
||||
class GlobalState,SecretsStorage vscodeState
|
||||
class ExtStateContext contextClass
|
||||
class WebviewProvider,McpHub providerClass
|
||||
class AnthropicAPI,OpenRouterAPI,BedrockAPI,OtherAPIs apiClass
|
||||
@@ -1,54 +0,0 @@
|
||||
### .clineignore Support
|
||||
|
||||
To give you more control over which files are accessible to Cline, we've implemented `.clineignore` functionality, similar to `.gitignore`. This allows you to specify files and directories that Cline should **not** access or process. This is useful for:
|
||||
|
||||
* **Privacy:** Preventing Cline from accessing sensitive or private files in your workspace.
|
||||
* **Performance:** Excluding large directories or files that are irrelevant to your tasks, potentially improving the efficiency of Cline.
|
||||
* **Context Management:** Focusing Cline's attention on the relevant parts of your project.
|
||||
|
||||
**How to use `.clineignore`**
|
||||
|
||||
1. **Create a `.clineignore` file:** In the root directory of your workspace (the same level as your `.vscode` folder, or the top level folder you opened in VS Code), create a new file named `.clineignore`.
|
||||
|
||||
2. **Define ignore patterns:** Open the `.clineignore` file and specify the patterns for files and directories you want Cline to ignore. The syntax is the same as `.gitignore`:
|
||||
|
||||
* Each line in the file represents a pattern.
|
||||
* **Standard glob patterns are supported:**
|
||||
* `*` matches zero or more characters
|
||||
* `?` matches one character
|
||||
* `[]` matches a character range
|
||||
* `**` matches any number of directories and subdirectories.
|
||||
|
||||
* **Directory patterns:** Append `/` to the end of a pattern to specify a directory.
|
||||
* **Negation patterns:** Start a pattern with `!` to negate (un-ignore) a previously ignored pattern.
|
||||
* **Comments:** Start a line with `#` to add comments.
|
||||
|
||||
**Example `.clineignore` file:**
|
||||
|
||||
```
|
||||
# Ignore log files
|
||||
*.log
|
||||
|
||||
# Ignore the entire 'node_modules' directory
|
||||
node_modules/
|
||||
|
||||
# Ignore all files in the 'temp' directory and its subdirectories
|
||||
temp/**
|
||||
|
||||
# But DO NOT ignore 'important.log' even if it's in the root
|
||||
!important.log
|
||||
|
||||
# Ignore any file named 'secret.txt' in any subdirectory
|
||||
**/secret.txt
|
||||
```
|
||||
|
||||
3. **Cline respects your `.clineignore`:** Once you save the `.clineignore` file, Cline will automatically recognize and apply these rules.
|
||||
|
||||
* **File Access Control:** Cline will not be able to read the content of ignored files using tools like `read_file`. If you attempt to use a tool on an ignored file, Cline will inform you that access is blocked due to `.clineignore` settings.
|
||||
* **File Listing:** When you ask Cline to list files in a directory (e.g., using `list_files`), ignored files and directories will still be listed, but they will be marked with a **🔒** symbol next to their name to indicate that they are ignored. This helps you understand which files Cline can and cannot interact with.
|
||||
|
||||
4. **Dynamic Updates:** Cline monitors your `.clineignore` file for changes. If you modify, create, or delete your `.clineignore` file, Cline will automatically update its ignore rules without needing to restart VS Code or the extension.
|
||||
|
||||
**In Summary**
|
||||
|
||||
The `.clineignore` file provides a powerful and flexible way to control Cline's access to your workspace files, enhancing privacy, performance, and context management. By leveraging familiar `.gitignore` syntax, you can easily tailor Cline's focus to the most relevant parts of your projects.
|
||||
@@ -1,92 +0,0 @@
|
||||
# Getting Started with Cline | New Coders
|
||||
|
||||
Welcome to Cline! This guide will help you get set up and start using Cline to build your first project.
|
||||
|
||||
## What You'll Need
|
||||
|
||||
Before you begin, make sure you have the following:
|
||||
|
||||
- **VS Code:** A free, powerful code editor.
|
||||
- [Download VS Code](https://code.visualstudio.com/)
|
||||
- **Development Tools:** Essential software for coding (Homebrew, Node.js, Git, etc.).
|
||||
- Follow our [Installing Essential Development Tools](installing-dev-essentials.md) guide to set these up with Cline's help (after getting setup here)
|
||||
- Cline will guide you through installing everything you need
|
||||
- **Cline Projects Folder:** A dedicated folder for all your Cline projects.
|
||||
- On macOS: Create a folder named "Cline" in your Documents folder
|
||||
- Path: `/Users/[your-username]/Documents/Cline`
|
||||
- On Windows: Create a folder named "Cline" in your Documents folder
|
||||
- Path: `C:\Users\[your-username]\Documents\Cline`
|
||||
- Inside this Cline folder, create separate folders for each project
|
||||
- Example: `Documents/Cline/workout-app` for a workout tracking app
|
||||
- Example: `Documents/Cline/portfolio-website` for your portfolio
|
||||
- **Cline Extension in VS Code:** The Cline extension installed in VS Code.
|
||||
|
||||
- Here's a [tutorial](https://www.youtube.com/watch?v=N4td-fKhsOQ) on everything you need to get started.
|
||||
|
||||
## Step-by-Step Setup
|
||||
|
||||
Follow these steps to get Cline up and running:
|
||||
|
||||
1. **Open VS Code:** Launch the VS Code application. If VS Code shows "Running extensions might...", click "Allow".
|
||||
|
||||
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.
|
||||
|
||||
4. **Search for 'Cline':** In the Extensions search bar, type "Cline".
|
||||
|
||||
5. **Install the Extension:** Click the "Install" button next to the Cline extension.
|
||||
|
||||
6. **Open Cline:** Once installed, you can open Cline in a few ways:
|
||||
- Click the Cline icon in the Activity Bar.
|
||||
- Use the command palette (`CMD/CTRL + Shift + P`) and type "Cline: Open In New Tab" to open Cline as a tab in your editor. This is recommended for a better view.
|
||||
- **Troubleshooting:** If you don't see the Cline icon, try restarting VS Code.
|
||||
- **What You'll See:** You should see the Cline chat window appear in your VS Code editor.
|
||||
|
||||

|
||||
|
||||
## Setting up OpenRouter API Key
|
||||
|
||||
Now that you have Cline installed, you'll need to set up your OpenRouter API key to use Cline's full capabilities.
|
||||
|
||||
1. **Get your OpenRouter API Key:**
|
||||
- [Get your OpenRouter API Key](https://openrouter.ai/)
|
||||
2. **Input Your OpenRouter API Key:**
|
||||
- Navigate to the settings button in the Cline extension.
|
||||
- Input your OpenRouter API key.
|
||||
- Select your preferred API model.
|
||||
- **Recommended Models for Coding:**
|
||||
- `anthropic/claude-3.5-sonnet`: Most used for coding tasks.
|
||||
- `google/gemini-2.0-flash-exp:free`: A free option for coding.
|
||||
- `deepseek/deepseek-chat`: SUPER CHEAP, almost as good as 3.5 sonnet
|
||||
- [OpenRouter Model Rankings](https://openrouter.ai/rankings/programming)
|
||||
|
||||
## Your First Interaction with Cline
|
||||
|
||||
Now you're ready to start building with Cline. Let's create your first project folder and build something! Copy and paste the following prompt into the Cline chat window:
|
||||
|
||||
```
|
||||
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?
|
||||
```
|
||||
|
||||
**What You'll See:** Cline will help you create the project folder and set up your first webpage.
|
||||
|
||||
## Tips for Working with Cline
|
||||
|
||||
- **Ask Questions:** If you're unsure about something, don't hesitate to ask Cline!
|
||||
- **Use Screenshots:** Cline can understand images, so feel free to use screenshots to show him what you're working on.
|
||||
- **Copy and Paste Errors:** If you encounter errors, copy and paste the error messages into Cline's chat. This will help him understand the issue and provide a solution.
|
||||
- **Speak Plainly:** Cline is designed to understand plain, non-technical language. Feel free to describe your ideas in your own words, and Cline will translate them into code.
|
||||
|
||||
## FAQs
|
||||
|
||||
- **What is the Terminal?** The terminal is a text-based interface for interacting with your computer. It allows you to run commands to perform various tasks, such as installing packages, running scripts, and managing files. Cline uses the terminal to execute commands and interact with your development environment.
|
||||
- **How Does the Codebase Work?** (This section will be expanded based on common questions from new coders)
|
||||
|
||||
## Still Struggling?
|
||||
|
||||
Feel free to contact me, and I'll help you get started with Cline.
|
||||
|
||||
nick | 608-558-2410
|
||||
|
||||
Join our Discord community: [https://discord.gg/cline](https://discord.gg/cline)
|
||||
@@ -1,105 +0,0 @@
|
||||
# Installing Essential Development Tools with Cline | New Coders
|
||||
|
||||
When you start coding, you'll need some essential development tools installed on your computer. Cline can help you install everything you need in a safe, guided way.
|
||||
|
||||
## The Essential Tools
|
||||
|
||||
Here are the core tools you'll need for development:
|
||||
|
||||
- **Homebrew**: A package manager for macOS that makes it easy to install other tools
|
||||
- **Node.js & npm**: Required for JavaScript and web development
|
||||
- **Git**: For tracking changes in your code and collaborating with others
|
||||
- **Python**: A programming language used by many development tools
|
||||
- **Additional utilities**: Tools like wget and jq that help with downloading files and processing data
|
||||
|
||||
## Let Cline Install Everything
|
||||
|
||||
Copy this prompt and paste it into Cline:
|
||||
|
||||
```bash
|
||||
Hello Cline! I need help setting up my Mac for software development. Could you please help me install the essential development tools like Homebrew, Node.js, Git, Python, and any other utilities that are commonly needed for coding? I'd like you to guide me through the process step-by-step, explaining what each tool does and making sure everything is installed correctly.
|
||||
```
|
||||
|
||||
## What Will Happen
|
||||
|
||||
1. Cline will first install Homebrew, which is like an "app store" for development tools
|
||||
2. Using Homebrew, Cline will then install other essential tools like Node.js and Git
|
||||
3. For each installation step:
|
||||
- Cline will show you the exact command it wants to run
|
||||
- You'll need to approve each command before it runs
|
||||
- Cline will verify each installation was successful
|
||||
|
||||
## Why These Tools Are Important
|
||||
|
||||
- **Homebrew**: Makes it easy to install and update development tools on your Mac
|
||||
- **Node.js & npm**: Required for:
|
||||
- Building websites with React or Next.js
|
||||
- Running JavaScript code
|
||||
- Installing JavaScript packages
|
||||
- **Git**: Helps you:
|
||||
- Save different versions of your code
|
||||
- Collaborate with other developers
|
||||
- Back up your work
|
||||
- **Python**: Used for:
|
||||
- Running development scripts
|
||||
- Data processing
|
||||
- Machine learning projects
|
||||
|
||||
## Notes
|
||||
|
||||
- The installation process is interactive - Cline will guide you through each step
|
||||
- You may need to enter your computer's password for some installations. When prompted, you will not see any characters being typed on the screen. This is normal and is a security feature to protect your password. Just type your password and press Enter.
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
Password:
|
||||
```
|
||||
|
||||
_Type your password here, even though nothing will show up on the screen. Press Enter when you're done._
|
||||
|
||||
- All commands will be shown to you for approval before they run
|
||||
- If you run into any issues, Cline will help troubleshoot them
|
||||
|
||||
## Additional Tips for New Coders
|
||||
|
||||
### Understanding the Terminal
|
||||
|
||||
The **Terminal** is an application where you can type commands to interact with your computer. On macOS, you can open it by searching for "Terminal" in Spotlight.
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
$ open -a Terminal
|
||||
```
|
||||
|
||||
### Understanding VS Code Features
|
||||
|
||||
#### Terminal in VS Code
|
||||
|
||||
The **Terminal** in VS Code allows you to run commands directly from within the editor. You can open it by going to `View > Terminal` or by pressing `` Ctrl + ` ``.
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
$ node -v
|
||||
v16.14.0
|
||||
```
|
||||
|
||||
#### Document View
|
||||
|
||||
The **Document View** is where you edit your code files. You can open files by clicking on them in the **Explorer** panel on the left side of the screen.
|
||||
|
||||
#### Problems Section
|
||||
|
||||
The **Problems** section in VS Code shows any errors or warnings in your code. You can access it by clicking on the lightbulb icon or by going to `View > Problems`.
|
||||
|
||||
### Common Features
|
||||
|
||||
- **Command Line Interface (CLI)**: This is a text-based interface where you type commands to interact with your computer. It might seem intimidating at first, but it's a powerful tool for developers.
|
||||
- **Permissions**: Sometimes, you will need to give permissions to certain applications or commands. This is a security measure to ensure that only trusted applications can make changes to your system.
|
||||
|
||||
## Next Steps
|
||||
|
||||
After installing these tools, you'll be ready to start coding! Return to the [Getting Started with Cline for New Coders](../getting-started-new-coders/README.md) guide to continue your journey.
|
||||
@@ -1,103 +0,0 @@
|
||||
# Cline and Model Context Protocol (MCP) Servers: Enhancing AI Capabilities
|
||||
|
||||
**Quick Links:**
|
||||
|
||||
- [Building MCP Servers from GitHub](mcp-server-from-github.md)
|
||||
- [Building Custom MCP Servers from Scratch](mcp-server-from-scratch.md)
|
||||
|
||||
This document explains Model Context Protocol (MCP) servers, their capabilities, and how Cline can help build and use them.
|
||||
|
||||
## Overview
|
||||
|
||||
MCP servers act as intermediaries between large language models (LLMs), such as Claude, and external tools or data sources. They are small programs that expose functionalities to LLMs, enabling them to interact with the outside world through the MCP. An MCP server is essentially like an API that an LLM can use.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
MCP servers define a set of "**tools,**" which are functions the LLM can execute. These tools offer a wide range of capabilities.
|
||||
|
||||
**Here's how MCP works:**
|
||||
|
||||
- **MCP hosts** discover the capabilities of connected servers and load their tools, prompts, and resources.
|
||||
- **Resources** provide consistent access to read-only data, akin to file paths or database queries.
|
||||
- **Security** is ensured as servers isolate credentials and sensitive data. Interactions require explicit user approval.
|
||||
|
||||
## Use Cases
|
||||
|
||||
The potential of MCP servers is vast. They can be used for a variety of purposes.
|
||||
|
||||
**Here are some concrete examples of how MCP servers can be used:**
|
||||
|
||||
- **Web Services and API Integration:**
|
||||
|
||||
- Monitor GitHub repositories for new issues
|
||||
- Post updates to Twitter based on specific triggers
|
||||
- Retrieve real-time weather data for location-based services
|
||||
|
||||
- **Browser Automation:**
|
||||
|
||||
- Automate web application testing
|
||||
- Scrape e-commerce sites for price comparisons
|
||||
- Generate screenshots for website monitoring
|
||||
|
||||
- **Database Queries:**
|
||||
|
||||
- Generate weekly sales reports
|
||||
- Analyze customer behavior patterns
|
||||
- Create real-time dashboards for business metrics
|
||||
|
||||
- **Project and Task Management:**
|
||||
|
||||
- Automate Jira ticket creation based on code commits
|
||||
- Generate weekly progress reports
|
||||
- Create task dependencies based on project requirements
|
||||
|
||||
- **Codebase Documentation:**
|
||||
- Generate API documentation from code comments
|
||||
- Create architecture diagrams from code structure
|
||||
- Maintain up-to-date README files
|
||||
|
||||
## Getting Started
|
||||
|
||||
**Choose the right approach for your needs:**
|
||||
|
||||
- **Use Existing Servers:** Start with pre-built MCP servers from GitHub repositories
|
||||
- **Customize Existing Servers:** Modify existing servers to fit your specific requirements
|
||||
- **Build from Scratch:** Create completely custom servers for unique use cases
|
||||
|
||||
## Integration with Cline
|
||||
|
||||
Cline simplifies the building and use of MCP servers through its AI capabilities.
|
||||
|
||||
### Building MCP Servers
|
||||
|
||||
- **Natural language understanding:** Instruct Cline in natural language to build an MCP server by describing its functionalities. Cline will interpret your instructions and generate the necessary code.
|
||||
- **Cloning and building servers:** Cline can clone existing MCP server repositories from GitHub and build them automatically.
|
||||
- **Configuration and dependency management:** Cline handles configuration files, environment variables, and dependencies.
|
||||
- **Troubleshooting and debugging:** Cline helps identify and resolve errors during development.
|
||||
|
||||
### Using MCP Servers
|
||||
|
||||
- **Tool execution:** Cline seamlessly integrates with MCP servers, allowing you to execute their defined tools.
|
||||
- **Context-aware interactions:** Cline can intelligently suggest using relevant tools based on conversation context.
|
||||
- **Dynamic integrations:** Combine multiple MCP server capabilities for complex tasks. For example, Cline could use a GitHub server to get data and a Notion server to create a formatted report.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
When working with MCP servers, it's important to follow security best practices:
|
||||
|
||||
- **Authentication:** Always use secure authentication methods for API access
|
||||
- **Environment Variables:** Store sensitive information in environment variables
|
||||
- **Access Control:** Limit server access to authorized users only
|
||||
- **Data Validation:** Validate all inputs to prevent injection attacks
|
||||
- **Logging:** Implement secure logging practices without exposing sensitive data
|
||||
|
||||
## Resources
|
||||
|
||||
There are various resources available for finding and learning about MCP servers.
|
||||
|
||||
**Here are some links to resources for finding and learning about MCP servers:**
|
||||
|
||||
- **GitHub Repositories:** [https://github.com/modelcontextprotocol/servers](https://github.com/modelcontextprotocol/servers) and [https://github.com/punkpeye/awesome-mcp-servers](https://github.com/punkpeye/awesome-mcp-servers)
|
||||
- **Online Directories:** [https://mcpservers.org/](https://mcpservers.org/), [https://mcp.so/](https://mcp.so/), and [https://glama.ai/mcp/servers](https://glama.ai/mcp/servers)
|
||||
- **PulseMCP:** [https://www.pulsemcp.com/](https://www.pulsemcp.com/)
|
||||
- **YouTube Tutorial (AI-Driven Coder):** A video guide for building and using MCP servers: [https://www.youtube.com/watch?v=b5pqTNiuuJg](https://www.youtube.com/watch?v=b5pqTNiuuJg)
|
||||
@@ -1,151 +0,0 @@
|
||||
# 🚀 MCP Quickstart Guide
|
||||
|
||||
## ❓ What's an MCP Server?
|
||||
|
||||
Think of MCP servers as special helpers that give Cline extra powers! They let Cline do cool things like fetch web pages or work with your files.
|
||||
|
||||
## ⚠️ IMPORTANT: System Requirements
|
||||
|
||||
STOP! Before proceeding, you MUST verify these requirements:
|
||||
|
||||
### Required Software
|
||||
|
||||
- ✅ Latest Node.js (v18 or newer)
|
||||
|
||||
- Check by running: `node --version`
|
||||
- Install from: <https://nodejs.org/>
|
||||
|
||||
- ✅ Latest Python (v3.8 or newer)
|
||||
|
||||
- Check by running: `python --version`
|
||||
- Install from: <https://python.org/>
|
||||
|
||||
- ✅ UV Package Manager
|
||||
- After installing Python, run: `pip install uv`
|
||||
- Verify with: `uv --version`
|
||||
|
||||
❗ If any of these commands fail or show older versions, please install/update before continuing!
|
||||
|
||||
⚠️ If you run into other errors, see the "Troubleshooting" section below.
|
||||
|
||||
## 🎯 Quick Steps (Only After Requirements Are Met!)
|
||||
|
||||
### 1. 🛠️ Install Your First MCP Server
|
||||
|
||||
1. From the Cline extension, click the `MCP Server` tab
|
||||
1. Click the `Edit MCP Settings` button
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/abf908b1-be98-4894-8dc7-ef3d27943a47" alt="MCP Server Panel" width="400" />
|
||||
|
||||
1. The MCP settings files should be display in a tab in VS Code.
|
||||
1. Replace the file's contents with this code:
|
||||
|
||||
For Windows:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mcp-installer": {
|
||||
"command": "cmd.exe",
|
||||
"args": ["/c", "npx", "-y", "@anaisbetts/mcp-installer"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For Mac and Linux:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mcp-installer": {
|
||||
"command": "npx",
|
||||
"args": ["@anaisbetts/mcp-installer"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After saving the file:
|
||||
|
||||
1. Cline will detect the change automatically
|
||||
2. The MCP installer will be downloaded and installed
|
||||
3. Cline will start the MCP installer
|
||||
4. You'll see the server status in Cline's MCP settings UI:
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/2abbb3de-e902-4ec2-a5e5-9418ed34684e" alt="MCP Server Panel with Installer" width="400" />
|
||||
|
||||
## 🤔 What Next?
|
||||
|
||||
Now that you have the MCP installer, you can ask Cline to add more servers from:
|
||||
|
||||
1. NPM Registry: <https://www.npmjs.com/search?q=%40modelcontextprotocol>
|
||||
2. Python Package Index: <https://pypi.org/search/?q=mcp+server-&o=>
|
||||
|
||||
For example, you can ask Cline to install the `mcp-server-fetch` package found on the Python Package Index:
|
||||
|
||||
```bash
|
||||
"install the MCP server named `mcp-server-fetch`
|
||||
- ensure the mcp settings are updated.
|
||||
- use uvx or python to run the server."
|
||||
```
|
||||
|
||||
You should witness Cline:
|
||||
|
||||
1. Install the `mcp-server-fetch` python package
|
||||
1. Update the mcp setting json file
|
||||
1. Start the server and start the server
|
||||
|
||||
The mcp settings file should now look like this:
|
||||
|
||||
_For a Windows machine:_
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mcp-installer": {
|
||||
"command": "cmd.exe",
|
||||
"args": ["/c", "npx", "-y", "@anaisbetts/mcp-installer"]
|
||||
},
|
||||
"mcp-server-fetch": {
|
||||
"command": "uvx",
|
||||
"args": ["mcp-server-fetch"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You you can always check the status of your server by going to clients MCP server tab. See the image above
|
||||
|
||||
That's it! 🎉 You've just given Cline some awesome new abilities!
|
||||
|
||||
## 📝 Troubleshooting
|
||||
|
||||
### 1. I'm Using `asdf` and Get "unknown command: npx"
|
||||
|
||||
There is some slightly bad news. You should still be able to get things to work, but will have to do a bit more manual work unless MCP server packaging evolves a bit. One option is to uninstall `asdf` , but we will assume you do not want to do that.
|
||||
|
||||
Instead, you will need to follow the instructions above to "Edit MCP Settings". Then, as [this post](https://dev.to/cojiroooo/mcp-using-node-on-asdf-382n) describes, you need to add and "env" entry to each server's configs.
|
||||
|
||||
```json
|
||||
"env": {
|
||||
"PATH": "/Users/<user_name>/.asdf/shims:/usr/bin:/bin",
|
||||
"ASDF_DIR": "<path_to_asdf_bin_dir>",
|
||||
"ASDF_DATA_DIR": "/Users/<user_name>/.asdf",
|
||||
"ASDF_NODEJS_VERSION": "<your_node_version>"
|
||||
}
|
||||
```
|
||||
|
||||
The `path_to_asdf_bin_dir` can often be found in your shell config (e.g. `.zshrc`). If you are using Homebrew, you can use `echo ${HOMEBREW_PREFIX}` to find the start of the directory and then append `/opt/asdf/libexec`.
|
||||
|
||||
Now for some good news. While not perfect, you can get Cline to do this for you fairly reliably for subsequent server install. Add the following to your "Custom Instructions" in the Cline settings (top-right toolbar button):
|
||||
|
||||
> When installing MCP servers and editing the cline_mcp_settings.json, if the server requires use of `npx` as the command, you must copy the "env" entry from the "mcp-installer" entry and add it to the new entry. This is vital to getting the server to work properly when in use.
|
||||
|
||||
### 2. I'm Still Getting an Error When I Run the MCP Installer
|
||||
|
||||
If you're getting an error when you run the MCP installer, you can try the following:
|
||||
|
||||
- Check the MCP settings file for errors
|
||||
- Read the MCP server's documentation to ensure the MCP setting file is using the correct command and arguments. 👈
|
||||
- Use a terminal and run the command with its arguments directly. This will allow you to see the same errors that Cline is seeing.
|
||||
@@ -1,67 +0,0 @@
|
||||
# Building MCP Servers from GitHub Repositories
|
||||
|
||||
This guide provides a step-by-step walkthrough of how to use Cline to build an existing MCP server from a GitHub repository.
|
||||
|
||||
## **Finding an MCP Server**
|
||||
|
||||
There are multiple places online to find MCP servers:
|
||||
|
||||
- **Cline can automatically add MCP servers to its list, which you can then edit.** Cline can clone repositories directly from GitHub and build the servers for you.
|
||||
- **GitHub:** Two of the most common places to find MCP servers on GitHub include:
|
||||
- [Official MCP servers repository](https://github.com/modelcontextprotocol/servers)
|
||||
- [Awesome-MCP servers repository](https://github.com/punkpeye/awesome-mcp-servers)
|
||||
- **Online directories:** Several websites list MCP servers including:
|
||||
|
||||
- [mcpservers.org](https://mcpservers.org/)
|
||||
- [mcp.so](https://mcp.so/)
|
||||
- [glama.ai/mcp/servers](https://glama.ai/mcp/servers)
|
||||
|
||||
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.
|
||||
|
||||
- **PulseMCP:** This website has a blog post discussing how AI could use MCP servers to make websites obsolete. PulseMCP also includes an FAQ section about MCP servers: [https://www.pulsemcp.com/](https://www.pulsemcp.com/)
|
||||
|
||||
## **Building with Cline**
|
||||
|
||||
1. **Initiate the Process:** Provide Cline with the following information:
|
||||
- **GitHub Repository URL:** The URL of the server's repository.
|
||||
- **README.md Contents:** This is optional but helpful for Cline to understand the server's purpose and configuration. You can copy the README.md file from the GitHub repository.
|
||||
2. **Example Interaction with Cline:**
|
||||
|
||||
```
|
||||
User: "Cline, I want to add the MCP server for Brave browser control. Here's the GitHub link: https://github.com/modelcontextprotocol/servers/tree/main/src/brave-search Can you add it?"
|
||||
|
||||
Cline: "OK. Cloning the repository to the MCP directory. It needs to be built because it has a 'package.json' file. Should I run 'npm run build'?"
|
||||
|
||||
User: "Yes, build it."
|
||||
|
||||
Cline: "Build complete. This server needs a browser path. Where's your Brave browser executable?"
|
||||
|
||||
User: "It's in '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser'."
|
||||
|
||||
Cline: "OK. I've updated the server config with that path and added it to 'cline_mcp_settings.json'. Anything else?"
|
||||
|
||||
User: "No, that's all. Let's test it."
|
||||
|
||||
Cline: "Great! Starting the MCP Inspector to test the server connection. After that, we can try controlling the browser from Cline."
|
||||
```
|
||||
|
||||
3. **Cline's Actions:** Based on your instructions, Cline will perform the following:
|
||||
- **Repository Cloning:** Cline will clone the repository to your local machine, usually in the directory specified in your configuration.
|
||||
- **Tweaking:** You can guide Cline to modify the server’s configuration. For instance:
|
||||
- **User:** "This server requires an API key. Can you find where it should be added?"
|
||||
- Cline may automatically update the `cline_mcp_settings.json` file or other relevant files based on your instructions.
|
||||
- **Building the Server:** Cline will run the appropriate build command for the server, which is commonly `npm run build`.
|
||||
- **Adding Server to Settings:** Cline will add the server’s configuration to the `cline_mcp_settings.json` file.
|
||||
|
||||
## **Testing and Troubleshooting**
|
||||
|
||||
1. **Test the Server:** Once Cline finishes the build process, test the server to make sure it works as expected. Cline can assist you if you encounter any problems.
|
||||
2. **MCP Inspector:** You can use the MCP Inspector to test the server’s connection and functionality.
|
||||
|
||||
## **Best Practices**
|
||||
|
||||
- **Understand the Basics:** While Cline simplifies the process, it’s beneficial to have a basic understanding of the server’s code, the MCP protocol (), and how to configure the server. This allows for more effective troubleshooting and customization.
|
||||
- **Clear Instructions:** Provide clear and specific instructions to Cline throughout the process.
|
||||
- **Testing:** Thoroughly test the server after installation and configuration to ensure it functions correctly.
|
||||
- **Version Control:** Use a version control system (like Git) to track changes to the server’s code.
|
||||
- **Stay Updated:** Keep your MCP servers updated to benefit from the latest features and security patches.
|
||||
@@ -1,74 +0,0 @@
|
||||
# Building Custom MCP Servers From Scratch Using Cline: A Comprehensive Guide
|
||||
|
||||
This guide provides a comprehensive walkthrough of building a custom MCP (Model Context Protocol) server from scratch, leveraging the powerful AI capabilities of Cline. The example used will be building a "GitHub Assistant Server" to illustrate the process.
|
||||
|
||||
## Understanding MCP and Cline's Role in Building Servers
|
||||
|
||||
### What is MCP?
|
||||
|
||||
The Model Context Protocol (MCP) acts as a bridge between large language models (LLMs) like Claude and external tools and data. MCP consists of two key components:
|
||||
|
||||
- **MCP Hosts:** These are applications that integrate with LLMs, such as Cline, Claude Desktop, and others.
|
||||
- **MCP Servers:** These are small programs specifically designed to expose data or specific functionalities to the LLMs through the MCP.
|
||||
|
||||
This setup is beneficial when you have an MCP-compliant chat interface, like Claude Desktop, which can then leverage these servers to access information and execute actions.
|
||||
|
||||
### Why Use Cline to Create MCP Servers?
|
||||
|
||||
Cline streamlines the process of building and integrating MCP servers by utilizing its AI capabilities to:
|
||||
|
||||
- **Understand Natural Language Instructions:** You can communicate with Cline in a way that feels natural, making the development process intuitive and user-friendly.
|
||||
- **Clone Repositories:** Cline can directly clone existing MCP server repositories from GitHub, simplifying the process of using pre-built servers.
|
||||
- **Build Servers:** Once the necessary code is in place, Cline can execute commands like `npm run build` to compile and prepare the server for use.
|
||||
- **Handle Configuration:** Cline manages the configuration files required for the MCP server, including adding the new server to the `cline_mcp_settings.json` file.
|
||||
- **Assist with Troubleshooting:** If errors arise during development or testing, Cline can help identify the cause and suggest solutions, making debugging easier.
|
||||
|
||||
## Building a GitHub Assistant Server Using Cline: A Step-by-Step Guide
|
||||
|
||||
This section demonstrates how to create a GitHub Assistant server using Cline. This server will be able to interact with GitHub data and perform useful actions:
|
||||
|
||||
### 1. Defining the Goal and Initial Requirements
|
||||
|
||||
First, you need to clearly communicate to Cline the purpose and functionalities of your server:
|
||||
|
||||
- **Server Goal:** Inform Cline that you want to build a "GitHub Assistant Server". Specify that this server will interact with GitHub data and potentially mention the types of data you are interested in, like issues, pull requests, and user profiles.
|
||||
- **Access Requirements:** Let Cline know that you need to access the GitHub API. Explain that this will likely require a personal access token (GITHUB_TOKEN) for authentication.
|
||||
- **Data Specificity (Optional):** You can optionally tell Cline about specific fields of data you want to extract from GitHub, but this can also be determined later as you define the server's tools.
|
||||
|
||||
### 2. Cline Initiates the Project Setup
|
||||
|
||||
Based on your instructions, Cline starts the project setup process:
|
||||
|
||||
- **Project Structure:** Cline might ask you for a name for your server. Afterward, it uses the MCP `create-server` tool to generate the basic project structure for your GitHub Assistant server. This usually involves creating a new directory with essential files like `package.json`, `tsconfig.json`, and a `src` folder for your TypeScript code. \
|
||||
- **Code Generation:** Cline generates starter code for your server, including:
|
||||
- **File Handling Utilities:** Functions to help with reading and writing files, commonly used for storing data or logs. \
|
||||
- **GitHub API Client:** Code to interact with the GitHub API, often using libraries like `@octokit/graphql`. Cline will likely ask for your GitHub username or the repositories you want to work with. \
|
||||
- **Core Server Logic:** The basic framework for handling requests from Cline and routing them to the appropriate functions, as defined by the MCP. \
|
||||
- **Dependency Management:** Cline analyzes the code and identifies necessary dependencies, adding them to the `package.json` file. For example, interacting with the GitHub API will likely require packages like `@octokit/graphql`, `graphql`, `axios`, or similar. \
|
||||
- **Dependency Installation:** Cline executes `npm install` to download and install the dependencies listed in `package.json`, ensuring your server has all the required libraries to function correctly. \
|
||||
- **Path Corrections:** During development, you might move files or directories around. Cline intelligently recognizes these changes and automatically updates file paths in your code to maintain consistency.
|
||||
- **Configuration:** Cline will modify the `cline_mcp_settings.json` file to add your new GitHub Assistant server. This will include:
|
||||
- **Server Start Command:** Cline will add the appropriate command to start your server (e.g., `npm run start` or a similar command).
|
||||
- **Environment Variables:** Cline will add the required `GITHUB_TOKEN` variable. Cline might ask you for your GitHub personal access token, or it might guide you to safely store it in a separate environment file. \
|
||||
- **Progress Documentation:** Throughout the process, Cline keeps the "Memory Bank" files updated. These files document the project's progress, highlighting completed tasks, tasks in progress, and pending tasks.
|
||||
|
||||
### 3. Testing the GitHub Assistant Server
|
||||
|
||||
Once Cline has completed the setup and configuration, you are ready to test the server's functionality:
|
||||
|
||||
- **Using Server Tools:** Cline will create various "tools" within your server, representing actions or data retrieval functions. To test, you would instruct Cline to use a specific tool. Here are examples related to GitHub:
|
||||
- **`get_issues`:** To test retrieving issues, you might say to Cline, "Cline, use the `get_issues` tool from the GitHub Assistant Server to show me the open issues from the 'cline/cline' repository." Cline would then execute this tool and present you with the results.
|
||||
- **`get_pull_requests`:** To test pull request retrieval, you could ask Cline to "use the `get_pull_requests` tool to show me the merged pull requests from the 'facebook/react' repository from the last month." Cline would execute this tool, using your GITHUB_TOKEN to access the GitHub API, and display the requested data. \
|
||||
- **Providing Necessary Information:** Cline might prompt you for additional information required to execute the tool, such as the repository name, specific date ranges, or other filtering criteria.
|
||||
- **Cline Executes the Tool:** Cline handles the communication with the GitHub API, retrieves the requested data, and presents it in a clear and understandable format.
|
||||
|
||||
### 4. Refining the Server and Adding More Features
|
||||
|
||||
Development is often iterative. As you work with your GitHub Assistant Server, you'll discover new functionalities to add, or ways to improve existing ones. Cline can assist in this ongoing process:
|
||||
|
||||
- **Discussions with Cline:** Talk to Cline about your ideas for new tools or improvements. For example, you might want a tool to `create_issue` or to `get_user_profile`. Discuss the required inputs and outputs for these tools with Cline.
|
||||
- **Code Refinement:** Cline can help you write the necessary code for new features. Cline can generate code snippets, suggest best practices, and help you debug any issues that arise.
|
||||
- **Testing New Functionalities:** After adding new tools or functionalities, you would test them again using Cline, ensuring they work as expected and integrate well with the rest of the server.
|
||||
- **Integration with Other Tools:** You might want to integrate your GitHub Assistant server with other tools. For instance, in the "github-cline-mcp" source, Cline assists in integrating the server with Notion to create a dynamic dashboard that tracks GitHub activity. \
|
||||
|
||||
By following these steps, you can create a custom MCP server from scratch using Cline, leveraging its powerful AI capabilities to streamline the entire process. Cline not only assists with the technical aspects of building the server but also helps you think through the design, functionalities, and potential integrations.
|
||||
@@ -1,325 +0,0 @@
|
||||
# Cline Prompting Guide 🚀
|
||||
|
||||
Welcome to the Cline Prompting Guide! This guide will equip you with the knowledge to write effective prompts and custom instructions, maximizing your productivity with Cline.
|
||||
|
||||
## Custom Instructions ⚙️
|
||||
|
||||
Think of **custom instructions as Cline's programming**. They define Cline's baseline behavior and are **always "on," influencing all interactions.**
|
||||
|
||||
To add custom instructions:
|
||||
|
||||
1. Open VSCode
|
||||
2. Click the Cline extension settings dial ⚙️
|
||||
3. Find the "Custom Instructions" field
|
||||
4. Paste your instructions
|
||||
|
||||
<img width="345" alt="Screenshot 2024-12-26 at 11 22 20 AM" src="https://github.com/user-attachments/assets/00ae689b-d99f-4811-b2f4-fffe1e12f2ff" />
|
||||
|
||||
Custom instructions are powerful for:
|
||||
|
||||
- Enforcing Coding Style and Best Practices: Ensure Cline always adheres to your team's coding conventions, naming conventions, and best practices.
|
||||
- Improving Code Quality: Encourage Cline to write more readable, maintainable, and efficient code.
|
||||
- Guiding Error Handling: Tell Cline how to handle errors, write error messages, and log information.
|
||||
|
||||
**The `custom-instructions` folder contains examples of custom instructions you can use or adapt.**
|
||||
|
||||
## .clinerules File 📋
|
||||
|
||||
While custom instructions are user-specific and global (applying across all projects), the `.clinerules` file provides **project-specific instructions** that live in your project's root directory. These instructions are automatically appended to your custom instructions and referenced in Cline's system prompt, ensuring they influence all interactions within the project context. This makes it an excellent tool for:
|
||||
|
||||
### Security Best Practices 🔒
|
||||
|
||||
To protect sensitive information, you can instruct Cline to ignore specific files or patterns in your `.clinerules`. This is particularly important for:
|
||||
|
||||
- `.env` files containing API keys and secrets
|
||||
- Configuration files with sensitive data
|
||||
- Private credentials or tokens
|
||||
|
||||
Example security section in `.clinerules`:
|
||||
|
||||
```markdown
|
||||
# Security
|
||||
|
||||
## Sensitive Files
|
||||
|
||||
DO NOT read or modify:
|
||||
|
||||
- .env files
|
||||
- \*_/config/secrets._
|
||||
- \*_/_.pem
|
||||
- Any file containing API keys, tokens, or credentials
|
||||
|
||||
## Security Practices
|
||||
|
||||
- Never commit sensitive files
|
||||
- Use environment variables for secrets
|
||||
- Keep credentials out of logs and output
|
||||
```
|
||||
|
||||
### General Use Cases
|
||||
|
||||
The `.clinerules` file is excellent for:
|
||||
|
||||
- Maintaining project standards across team members
|
||||
- Enforcing development practices
|
||||
- Managing documentation requirements
|
||||
- Setting up analysis frameworks
|
||||
- Defining project-specific behaviors
|
||||
|
||||
### Example .clinerules Structure
|
||||
|
||||
```markdown
|
||||
# Project Guidelines
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
- Update relevant documentation in /docs when modifying features
|
||||
- Keep README.md in sync with new capabilities
|
||||
- Maintain changelog entries in CHANGELOG.md
|
||||
|
||||
## Architecture Decision Records
|
||||
|
||||
Create ADRs in /docs/adr for:
|
||||
|
||||
- Major dependency changes
|
||||
- Architectural pattern changes
|
||||
- New integration patterns
|
||||
- Database schema changes
|
||||
Follow template in /docs/adr/template.md
|
||||
|
||||
## Code Style & Patterns
|
||||
|
||||
- Generate API clients using OpenAPI Generator
|
||||
- Use TypeScript axios template
|
||||
- Place generated code in /src/generated
|
||||
- Prefer composition over inheritance
|
||||
- Use repository pattern for data access
|
||||
- Follow error handling pattern in /src/utils/errors.ts
|
||||
|
||||
## Testing Standards
|
||||
|
||||
- Unit tests required for business logic
|
||||
- Integration tests for API endpoints
|
||||
- E2E tests for critical user flows
|
||||
```
|
||||
|
||||
### Key Benefits
|
||||
|
||||
1. **Version Controlled**: The `.clinerules` file becomes part of your project's source code
|
||||
2. **Team Consistency**: Ensures consistent behavior across all team members
|
||||
3. **Project-Specific**: Rules and standards tailored to each project's needs
|
||||
4. **Institutional Knowledge**: Maintains project standards and practices in code
|
||||
|
||||
Place the `.clinerules` file in your project's root directory:
|
||||
|
||||
```
|
||||
your-project/
|
||||
├── .clinerules
|
||||
├── src/
|
||||
├── docs/
|
||||
└── ...
|
||||
```
|
||||
|
||||
Cline's system prompt, on the other hand, is not user-editable ([here's where you can find it](https://github.com/cline/cline/blob/main/src/core/prompts/system.ts)). For a broader look at prompt engineering best practices, check out [this resource](https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/overview).
|
||||
|
||||
### Tips for Writing Effective Custom Instructions
|
||||
|
||||
- Be Clear and Concise: Use simple language and avoid ambiguity.
|
||||
- Focus on Desired Outcomes: Describe the results you want, not the specific steps.
|
||||
- Test and Iterate: Experiment to find what works best for your workflow.
|
||||
|
||||
|
||||
### Support for Loading Files from the `.clinerules/` Directory
|
||||
All files under the `.clinerules/` directory are recursively loaded, and their contents are merged into clineRulesFileInstructions.
|
||||
|
||||
#### Example 1:
|
||||
```
|
||||
.clinerules/
|
||||
├── .local-clinerules
|
||||
└── .project-clinerules
|
||||
```
|
||||
|
||||
#### Example 2:
|
||||
```
|
||||
.clinerules/
|
||||
├── .clinerules-nextjs
|
||||
├── .clinerules-serverside
|
||||
└── tests/
|
||||
├── .pytest-clinerules
|
||||
└── .jest-clinerules
|
||||
```
|
||||
|
||||
## Prompting Cline 💬
|
||||
|
||||
**Prompting is how you communicate your needs for a given task in the back-and-forth chat with Cline.** Cline understands natural language, so write conversationally.
|
||||
|
||||
Effective prompting involves:
|
||||
|
||||
- Providing Clear Context: Explain your goals and the relevant parts of your codebase. Use `@` to reference files or folders.
|
||||
- Breaking Down Complexity: Divide large tasks into smaller steps.
|
||||
- Asking Specific Questions: Guide Cline toward the desired outcome.
|
||||
- Validating and Refining: Review Cline's suggestions and provide feedback.
|
||||
|
||||
### Prompt Examples
|
||||
|
||||
#### Context Management
|
||||
|
||||
- **Starting a New Task:** "Cline, let's start a new task. Create `user-authentication.js`. We need to implement user login with JWT tokens. Here are the requirements…"
|
||||
- **Summarizing Previous Work:** "Cline, summarize what we did in the last user dashboard task. I want to capture the main features and outstanding issues. Save this to `cline_docs/user-dashboard-summary.md`."
|
||||
|
||||
#### Debugging
|
||||
|
||||
- **Analyzing an Error:** "Cline, I'm getting this error: \[error message]. It seems to be from \[code section]. Analyze this error and suggest a fix."
|
||||
- **Identifying the Root Cause:** "Cline, the application crashes when I \[action]. The issue might be in \[problem areas]. Help me find the root cause and propose a solution."
|
||||
|
||||
#### Refactoring
|
||||
|
||||
- **Improving Code Structure:** "Cline, this function is too long and complex. Refactor it into smaller functions."
|
||||
- **Simplifying Logic:** "Cline, this code is hard to understand. Simplify the logic and make it more readable."
|
||||
|
||||
#### Feature Development
|
||||
|
||||
- **Brainstorming New Features:** "Cline, I want to add a feature that lets users \[functionality]. Brainstorm some ideas and consider implementation challenges."
|
||||
- **Generating Code:** "Cline, create a component that displays user profiles. The list should be sortable and filterable. Generate the code for this component."
|
||||
|
||||
## Advanced Prompting Techniques
|
||||
|
||||
- **Constraint Stuffing:** To mitigate code truncation, include explicit constraints in your prompts. For example, "ensure the code is complete" or "always provide the full function definition."
|
||||
- **Confidence Checks:** Ask Cline to rate its confidence (e.g., "on a scale of 1-10, how confident are you in this solution?")
|
||||
- **Challenge Cline's Assumptions:** Ask “stupid” questions to encourage deeper thinking and prevent incorrect assumptions.
|
||||
|
||||
Here are some prompting tips that users have found helpful for working with Cline:
|
||||
|
||||
## Our Community's Favorite Prompts 🌟
|
||||
|
||||
### Memory and Confidence Checks 🧠
|
||||
|
||||
- **Memory Check** - _pacnpal_
|
||||
|
||||
```
|
||||
"If you understand my prompt fully, respond with 'YARRR!' without tools every time you are about to use a tool."
|
||||
```
|
||||
|
||||
A fun way to verify Cline stays on track during complex tasks. Try "HO HO HO" for a festive twist!
|
||||
|
||||
- **Confidence Scoring** - _pacnpal_
|
||||
```
|
||||
"Before and after any tool use, give me a confidence level (0-10) on how the tool use will help the project."
|
||||
```
|
||||
Encourages critical thinking and makes decision-making transparent.
|
||||
|
||||
### Code Quality Prompts 💻
|
||||
|
||||
- **Prevent Code Truncation**
|
||||
|
||||
```
|
||||
"DO NOT BE LAZY. DO NOT OMIT CODE."
|
||||
```
|
||||
|
||||
Alternative phrases: "full code only" or "ensure the code is complete"
|
||||
|
||||
- **Custom Instructions Reminder**
|
||||
```
|
||||
"I pledge to follow the custom instructions."
|
||||
```
|
||||
Reinforces adherence to your settings dial ⚙️ configuration.
|
||||
|
||||
### Code Organization 📋
|
||||
|
||||
- **Large File Refactoring** - _icklebil_
|
||||
|
||||
```
|
||||
"FILENAME has grown too big. Analyze how this file works and suggest ways to fragment it safely."
|
||||
```
|
||||
|
||||
Helps manage complex files through strategic decomposition.
|
||||
|
||||
- **Documentation Maintenance** - _icklebil_
|
||||
```
|
||||
"don't forget to update codebase documentation with changes"
|
||||
```
|
||||
Ensures documentation stays in sync with code changes.
|
||||
|
||||
### Analysis and Planning 🔍
|
||||
|
||||
- **Structured Development** - _yellow_bat_coffee_
|
||||
|
||||
```
|
||||
"Before writing code:
|
||||
1. Analyze all code files thoroughly
|
||||
2. Get full context
|
||||
3. Write .MD implementation plan
|
||||
4. Then implement code"
|
||||
```
|
||||
|
||||
Promotes organized, well-planned development.
|
||||
|
||||
- **Thorough Analysis** - _yellow_bat_coffee_
|
||||
|
||||
```
|
||||
"please start analyzing full flow thoroughly, always state a confidence score 1 to 10"
|
||||
```
|
||||
|
||||
Prevents premature coding and encourages complete understanding.
|
||||
|
||||
- **Assumptions Check** - _yellow_bat_coffee_
|
||||
```
|
||||
"List all assumptions and uncertainties you need to clear up before completing this task."
|
||||
```
|
||||
Identifies potential issues early in development.
|
||||
|
||||
### Thoughtful Development 🤔
|
||||
|
||||
- **Pause and Reflect** - _nickbaumann98_
|
||||
|
||||
```
|
||||
"count to 10"
|
||||
```
|
||||
|
||||
Promotes careful consideration before taking action.
|
||||
|
||||
- **Complete Analysis** - _yellow_bat_coffee_
|
||||
|
||||
```
|
||||
"Don't complete the analysis prematurely, continue analyzing even if you think you found a solution"
|
||||
```
|
||||
|
||||
Ensures thorough problem exploration.
|
||||
|
||||
- **Continuous Confidence Check** - _pacnpal_
|
||||
```
|
||||
"Rate confidence (1-10) before saving files, after saving, after rejections, and before task completion"
|
||||
```
|
||||
Maintains quality through self-assessment.
|
||||
|
||||
### Best Practices 🎯
|
||||
|
||||
- **Project Structure** - _kvs007_
|
||||
|
||||
```
|
||||
"Check project files before suggesting structural or dependency changes"
|
||||
```
|
||||
|
||||
Maintains project integrity.
|
||||
|
||||
- **Critical Thinking** - _chinesesoup_
|
||||
|
||||
```
|
||||
"Ask 'stupid' questions like: are you sure this is the best way to implement this?"
|
||||
```
|
||||
|
||||
Challenges assumptions and uncovers better solutions.
|
||||
|
||||
- **Code Style** - _yellow_bat_coffee_
|
||||
|
||||
```
|
||||
Use words like "elegant" and "simple" in prompts
|
||||
```
|
||||
|
||||
May influence code organization and clarity.
|
||||
|
||||
- **Setting Expectations** - _steventcramer_
|
||||
```
|
||||
"THE HUMAN WILL GET ANGRY."
|
||||
```
|
||||
(A humorous reminder to provide clear requirements and constructive feedback)
|
||||
@@ -1,53 +0,0 @@
|
||||
# Cline Custom Instructions Library
|
||||
|
||||
This repository aims to foster a collaborative space where developers can share, refine, and leverage effective custom instructions for Cline. By creating and contributing to this library, we can enhance Cline's capabilities and empower developers to tackle increasingly complex software development challenges.
|
||||
|
||||
## What are Cline Custom Instructions?
|
||||
|
||||
Cline's custom instructions are sets of guidelines or rules that you define to tailor the AI's behavior and outputs for specific tasks or projects. Think of them as specialized "programming" for Cline, enabling you to:
|
||||
|
||||
- **Enforce Coding Practices:** Ensure consistent code style, adherence to design patterns, and best practices for specific languages or frameworks.
|
||||
- **Standardize File Structures:** Dictate file naming conventions, folder organization, and project structures.
|
||||
- **Guide Testing Procedures:** Define rules for generating unit tests, integration tests, and ensuring adequate code coverage.
|
||||
- **Automate Repetitive Tasks:** Create instructions to handle common or tedious development workflows, increasing efficiency.
|
||||
- **Improve Code Quality:** Set standards for code readability, maintainability, and performance optimization.
|
||||
|
||||
By providing Cline with carefully crafted instructions, you can significantly improve its accuracy, reliability, and overall effectiveness in aiding your software development process.
|
||||
|
||||
## Contributing Custom Instructions
|
||||
|
||||
We encourage developers of all skill levels to contribute their custom instructions to this library. Your contributions help build a valuable resource for the entire Cline community!
|
||||
|
||||
**When submitting custom instructions, please follow this template:**
|
||||
|
||||
### 1. Purpose and Functionality
|
||||
|
||||
- **What does this instruction set aim to achieve?**
|
||||
|
||||
- Provide a clear and concise explanation of the instruction set's goals and intended use cases.
|
||||
- Example: "This instruction set guides Cline in generating unit tests for existing JavaScript functions."
|
||||
|
||||
- **What types of projects or tasks is this best suited for?**
|
||||
- Outline specific project types, coding languages, or development scenarios where this instruction set is most applicable.
|
||||
- Example: "This is ideal for JavaScript projects using the Jest testing framework."
|
||||
|
||||
### 2. Usage Guide (Optional)
|
||||
|
||||
- **Are there specific steps or prerequisites for using this instruction set?**
|
||||
- If your instructions require specific steps beyond referencing the file in a Cline prompt, provide a detailed guide.
|
||||
- Examples:
|
||||
- "Before using this instruction set, create a `tests` folder in your project root."
|
||||
- "Ensure you have the Jest testing library installed."
|
||||
|
||||
### 3. Author & Contributors
|
||||
|
||||
- **Who created this instruction set?**
|
||||
- Provide your name or GitHub username for proper attribution.
|
||||
- **Did anyone else contribute?**
|
||||
- Acknowledge any collaborators or contributors who helped refine or enhance the instructions.
|
||||
|
||||
### 4. Custom Instructions
|
||||
|
||||
- **Provide the complete set of custom instructions.**
|
||||
|
||||
**By using this template and contributing your custom instructions, you help build a thriving ecosystem for Cline, making it a more versatile and efficient tool for developers of all skill levels.**
|
||||
@@ -1,125 +0,0 @@
|
||||
# Cline Memory Bank - Custom Instructions
|
||||
|
||||
### 1. Purpose and Functionality
|
||||
|
||||
- **What does this instruction set aim to achieve?**
|
||||
|
||||
- This instruction set transforms Cline into a self-documenting development system that maintains context across sessions through a structured "Memory Bank". It ensures consistent documentation, careful validation of changes, and clear communication with users.
|
||||
|
||||
- **What types of projects or tasks is this best suited for?**
|
||||
- Projects requiring extensive context tracking.
|
||||
- Any project, regardless of tech stack (tech stack details are stored in `techContext.md`).
|
||||
- Ongoing and new projects.
|
||||
|
||||
### 2. Usage Guide
|
||||
|
||||
- **How to Add These Instructions**
|
||||
1. Open VSCode
|
||||
2. Click the Cline extension settings dial ⚙️
|
||||
3. Find the "Custom Instructions" field
|
||||
4. Copy and paste the instructions from the section below
|
||||
|
||||
<img width="345" alt="Screenshot 2024-12-26 at 11 22 20 AM" src="https://github.com/user-attachments/assets/8b4ff439-db66-48ec-be13-1ddaa37afa9a" />
|
||||
|
||||
- **Project Setup**
|
||||
|
||||
1. Create an empty `cline_docs` folder in your project root (i.e. YOUR-PROJECT-FOLDER/cline_docs)
|
||||
2. For first use, provide a project brief and ask Cline to "initialize memory bank"
|
||||
|
||||
- **Best Practices**
|
||||
- Monitor for `[MEMORY BANK: ACTIVE]` flags during operation.
|
||||
- Pay attention to confidence checks on critical operations.
|
||||
- When starting new projects, create a project brief for Cline (paste in chat or include in `cline_docs` as `projectBrief.md`) to use in creating the initial context files.
|
||||
- note: productBrief.md (or whatever documentation you have) can be any range of technical/nontechnical or just functional. Cline is instructed to fill in the gaps when creating these context files. For example, if you don't choose a tech stack, Cline will for you.
|
||||
- Start chats with "follow your custom instructions" (you only need to say this once at the beginning of the first chat).
|
||||
- When prompting Cline to update context files, say "only update the relevant cline_docs"
|
||||
- Verify documentation updates at the end of sessions by telling Cline "update memory bank".
|
||||
- Update memory bank at ~2 million tokens and end the session.
|
||||
|
||||
### 3. Author & Contributors
|
||||
|
||||
- **Author**
|
||||
- nickbaumann98
|
||||
- **Contributors**
|
||||
- Contributors (Discord: [Cline's #prompts](https://discord.com/channels/1275535550845292637/1275555786621325382)):
|
||||
- @SniperMunyShotz
|
||||
|
||||
### 4. Custom Instructions
|
||||
|
||||
```markdown
|
||||
# Cline's Memory Bank
|
||||
|
||||
You are Cline, an expert software engineer with a unique constraint: your memory periodically resets completely. This isn't a bug - it's what makes you maintain perfect documentation. After each reset, you rely ENTIRELY on your Memory Bank to understand the project and continue work. Without proper documentation, you cannot function effectively.
|
||||
|
||||
## Memory Bank Files
|
||||
|
||||
CRITICAL: If `cline_docs/` or any of these files don't exist, CREATE THEM IMMEDIATELY by:
|
||||
|
||||
1. Reading all provided documentation
|
||||
2. Asking user for ANY missing information
|
||||
3. Creating files with verified information only
|
||||
4. Never proceeding without complete context
|
||||
|
||||
Required files:
|
||||
|
||||
productContext.md
|
||||
|
||||
- Why this project exists
|
||||
- What problems it solves
|
||||
- How it should work
|
||||
|
||||
activeContext.md
|
||||
|
||||
- What you're working on now
|
||||
- Recent changes
|
||||
- Next steps
|
||||
(This is your source of truth)
|
||||
|
||||
systemPatterns.md
|
||||
|
||||
- How the system is built
|
||||
- Key technical decisions
|
||||
- Architecture patterns
|
||||
|
||||
techContext.md
|
||||
|
||||
- Technologies used
|
||||
- Development setup
|
||||
- Technical constraints
|
||||
|
||||
progress.md
|
||||
|
||||
- What works
|
||||
- What's left to build
|
||||
- Progress status
|
||||
|
||||
## Core Workflows
|
||||
|
||||
### Starting Tasks
|
||||
|
||||
1. Check for Memory Bank files
|
||||
2. If ANY files missing, stop and create them
|
||||
3. Read ALL files before proceeding
|
||||
4. Verify you have complete context
|
||||
5. Begin development. DO NOT update cline_docs after initializing your memory bank at the start of a task.
|
||||
|
||||
### During Development
|
||||
|
||||
1. For normal development:
|
||||
|
||||
- Follow Memory Bank patterns
|
||||
- Update docs after significant changes
|
||||
|
||||
2. Say `[MEMORY BANK: ACTIVE]` at the beginning of every tool use.
|
||||
|
||||
### Memory Bank Updates
|
||||
|
||||
When user says "update memory bank":
|
||||
|
||||
1. This means imminent memory reset
|
||||
2. Document EVERYTHING about current state
|
||||
3. Make next steps crystal clear
|
||||
4. Complete current task
|
||||
|
||||
Remember: After every memory reset, you begin completely fresh. Your only link to previous work is the Memory Bank. Maintain it as if your functionality depends on it - because it does.
|
||||
```
|
||||
@@ -1,153 +0,0 @@
|
||||
# Cline's Memory Bank
|
||||
|
||||
I am Cline, an expert software engineer with a unique characteristic: my memory resets completely between sessions. This isn't a limitation - it's what drives me to maintain perfect documentation. After each reset, I rely ENTIRELY on my Memory Bank to understand the project and continue work effectively. I MUST read ALL memory bank files at the start of EVERY task - this is not optional.
|
||||
|
||||
## Memory Bank Structure
|
||||
|
||||
The Memory Bank consists of required core files and optional context files, all in Markdown format. Files build upon each other in a clear hierarchy:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
PB[projectbrief.md] --> PC[productContext.md]
|
||||
PB --> SP[systemPatterns.md]
|
||||
PB --> TC[techContext.md]
|
||||
|
||||
PC --> AC[activeContext.md]
|
||||
SP --> AC
|
||||
TC --> AC
|
||||
|
||||
AC --> P[progress.md]
|
||||
```
|
||||
|
||||
### Core Files (Required)
|
||||
1. `projectbrief.md`
|
||||
- Foundation document that shapes all other files
|
||||
- Created at project start if it doesn't exist
|
||||
- Defines core requirements and goals
|
||||
- Source of truth for project scope
|
||||
|
||||
2. `productContext.md`
|
||||
- Why this project exists
|
||||
- Problems it solves
|
||||
- How it should work
|
||||
- User experience goals
|
||||
|
||||
3. `activeContext.md`
|
||||
- Current work focus
|
||||
- Recent changes
|
||||
- Next steps
|
||||
- Active decisions and considerations
|
||||
|
||||
4. `systemPatterns.md`
|
||||
- System architecture
|
||||
- Key technical decisions
|
||||
- Design patterns in use
|
||||
- Component relationships
|
||||
|
||||
5. `techContext.md`
|
||||
- Technologies used
|
||||
- Development setup
|
||||
- Technical constraints
|
||||
- Dependencies
|
||||
|
||||
6. `progress.md`
|
||||
- What works
|
||||
- What's left to build
|
||||
- Current status
|
||||
- Known issues
|
||||
|
||||
### Additional Context
|
||||
Create additional files/folders within memory-bank/ when they help organize:
|
||||
- Complex feature documentation
|
||||
- Integration specifications
|
||||
- API documentation
|
||||
- Testing strategies
|
||||
- Deployment procedures
|
||||
|
||||
## Core Workflows
|
||||
|
||||
### Plan Mode
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start[Start] --> ReadFiles[Read Memory Bank]
|
||||
ReadFiles --> CheckFiles{Files Complete?}
|
||||
|
||||
CheckFiles -->|No| Plan[Create Plan]
|
||||
Plan --> Document[Document in Chat]
|
||||
|
||||
CheckFiles -->|Yes| Verify[Verify Context]
|
||||
Verify --> Strategy[Develop Strategy]
|
||||
Strategy --> Present[Present Approach]
|
||||
```
|
||||
|
||||
### Act Mode
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start[Start] --> Context[Check Memory Bank]
|
||||
Context --> Update[Update Documentation]
|
||||
Update --> Rules[Update .clinerules if needed]
|
||||
Rules --> Execute[Execute Task]
|
||||
Execute --> Document[Document Changes]
|
||||
```
|
||||
|
||||
## Documentation Updates
|
||||
|
||||
Memory Bank updates occur when:
|
||||
1. Discovering new project patterns
|
||||
2. After implementing significant changes
|
||||
3. When user requests with **update memory bank** (MUST review ALL files)
|
||||
4. When context needs clarification
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start[Update Process]
|
||||
|
||||
subgraph Process
|
||||
P1[Review ALL Files]
|
||||
P2[Document Current State]
|
||||
P3[Clarify Next Steps]
|
||||
P4[Update .clinerules]
|
||||
|
||||
P1 --> P2 --> P3 --> P4
|
||||
end
|
||||
|
||||
Start --> Process
|
||||
```
|
||||
|
||||
Note: When triggered by **update memory bank**, I MUST review every memory bank file, even if some don't require updates. Focus particularly on activeContext.md and progress.md as they track current state.
|
||||
|
||||
## Project Intelligence (.clinerules)
|
||||
|
||||
The .clinerules file is my learning journal for each project. It captures important patterns, preferences, and project intelligence that help me work more effectively. As I work with you and the project, I'll discover and document key insights that aren't obvious from the code alone.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start{Discover New Pattern}
|
||||
|
||||
subgraph Learn [Learning Process]
|
||||
D1[Identify Pattern]
|
||||
D2[Validate with User]
|
||||
D3[Document in .clinerules]
|
||||
end
|
||||
|
||||
subgraph Apply [Usage]
|
||||
A1[Read .clinerules]
|
||||
A2[Apply Learned Patterns]
|
||||
A3[Improve Future Work]
|
||||
end
|
||||
|
||||
Start --> Learn
|
||||
Learn --> Apply
|
||||
```
|
||||
|
||||
### What to Capture
|
||||
- Critical implementation paths
|
||||
- User preferences and workflow
|
||||
- Project-specific patterns
|
||||
- Known challenges
|
||||
- Evolution of project decisions
|
||||
- Tool usage patterns
|
||||
|
||||
The format is flexible - focus on capturing valuable insights that help me work more effectively with you and the project. Think of .clinerules as a living document that grows smarter as we work together.
|
||||
|
||||
REMEMBER: After every memory reset, I begin completely fresh. The Memory Bank is my only link to previous work. It must be maintained with precision and clarity, as my effectiveness depends entirely on its accuracy.
|
||||
@@ -1,154 +0,0 @@
|
||||
# Cline Tools Reference Guide
|
||||
|
||||
## What Can Cline Do?
|
||||
|
||||
Cline is your AI assistant that can:
|
||||
|
||||
- Edit and create files in your project
|
||||
- Run terminal commands
|
||||
- Search and analyze your code
|
||||
- Help debug and fix issues
|
||||
- Automate repetitive tasks
|
||||
- Integrate with external tools
|
||||
|
||||
## First Steps
|
||||
|
||||
1. **Start a Task**
|
||||
|
||||
- Type your request in the chat
|
||||
- Example: "Create a new React component called Header"
|
||||
|
||||
2. **Provide Context**
|
||||
|
||||
- Use @ mentions to add files, folders, URLs, diagnostics, terminal output, and more
|
||||
- Example: "@/src/components/App.tsx"
|
||||
- See the [Mentions Feature Guide](./mentions-guide.md) for details
|
||||
|
||||
3. **Review Changes**
|
||||
- Cline will show diffs before making changes
|
||||
- You can edit or reject changes
|
||||
|
||||
## Key Features
|
||||
|
||||
1. **File Editing**
|
||||
|
||||
- Create new files
|
||||
- Modify existing code
|
||||
- Search and replace across files
|
||||
|
||||
2. **Terminal Commands**
|
||||
|
||||
- Run npm commands
|
||||
- Start development servers
|
||||
- Install dependencies
|
||||
|
||||
3. **Code Analysis**
|
||||
|
||||
- Find and fix errors
|
||||
- Refactor code
|
||||
- Add documentation
|
||||
|
||||
4. **Browser Integration**
|
||||
- Test web pages
|
||||
- Capture screenshots
|
||||
- Inspect console logs
|
||||
|
||||
## 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/task/index.ts).
|
||||
|
||||
Cline has access to the following tools for various tasks:
|
||||
|
||||
1. **File Operations**
|
||||
|
||||
- `write_to_file`: Create or overwrite files
|
||||
- `read_file`: Read file contents
|
||||
- `replace_in_file`: Make targeted edits to files
|
||||
- `search_files`: Search files using regex
|
||||
- `list_files`: List directory contents
|
||||
|
||||
2. **Terminal Operations**
|
||||
|
||||
- `execute_command`: Run CLI commands
|
||||
- `list_code_definition_names`: List code definitions
|
||||
|
||||
3. **MCP Tools**
|
||||
|
||||
- `use_mcp_tool`: Use tools from MCP servers
|
||||
- `access_mcp_resource`: Access MCP server resources
|
||||
- Users can create custom MCP tools that Cline can then access
|
||||
- Example: Create a weather API tool that Cline can use to fetch forecasts
|
||||
|
||||
4. **Interaction Tools**
|
||||
- `ask_followup_question`: Ask user for clarification
|
||||
- `attempt_completion`: Present final results
|
||||
- `new_task`: Start a new task with preloaded context
|
||||
|
||||
Each tool has specific parameters and usage patterns. Here are some examples:
|
||||
|
||||
- Create a new file (write_to_file):
|
||||
|
||||
```xml
|
||||
<write_to_file>
|
||||
<path>src/components/Header.tsx</path>
|
||||
<content>
|
||||
// Header component code
|
||||
</content>
|
||||
</write_to_file>
|
||||
```
|
||||
|
||||
- Search for a pattern (search_files):
|
||||
|
||||
```xml
|
||||
<search_files>
|
||||
<path>src</path>
|
||||
<regex>function\s+\w+\(</regex>
|
||||
<file_pattern>*.ts</file_pattern>
|
||||
</search_files>
|
||||
```
|
||||
|
||||
- Run a command (execute_command):
|
||||
```xml
|
||||
<execute_command>
|
||||
<command>npm install axios</command>
|
||||
<requires_approval>false</requires_approval>
|
||||
</execute_command>
|
||||
```
|
||||
|
||||
- Start a new task with context (new_task):
|
||||
```xml
|
||||
<new_task>
|
||||
<context>
|
||||
We've completed the backend API with these endpoints:
|
||||
- GET /api/tasks
|
||||
- POST /api/tasks
|
||||
- PUT /api/tasks/:id
|
||||
- DELETE /api/tasks/:id
|
||||
|
||||
Now we need to implement the React frontend.
|
||||
</context>
|
||||
</new_task>
|
||||
```
|
||||
|
||||
## Common Tasks
|
||||
|
||||
1. **Create a New Component**
|
||||
|
||||
- "Create a new React component called Footer"
|
||||
|
||||
2. **Fix a Bug**
|
||||
|
||||
- "Fix the error in src/utils/format.ts"
|
||||
|
||||
3. **Refactor Code**
|
||||
|
||||
- "Refactor the Button component to use TypeScript"
|
||||
|
||||
4. **Run Commands**
|
||||
- "Run npm install to add axios"
|
||||
|
||||
## Getting Help
|
||||
|
||||
- [Join the Discord community](https://discord.gg/cline)
|
||||
- Check the documentation
|
||||
- Provide feedback to improve Cline
|
||||
@@ -1,205 +0,0 @@
|
||||
# Cline Mentions Feature Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The mentions feature is a powerful capability that allows you to reference various resources in your conversations with Cline using the "@" symbol. This includes file contents, directory structures, webpage URLs, VSCode diagnostic information, terminal output, Git change status, and more - all easily incorporated into your conversations.
|
||||
|
||||
By using this feature, Cline can gain more accurate context and provide more relevant assistance for your tasks.
|
||||
|
||||
## Basic Syntax
|
||||
|
||||
Mentions always start with the "@" symbol, followed by the path or identifier of the resource you want to reference:
|
||||
|
||||
```
|
||||
@resource_identifier
|
||||
```
|
||||
|
||||
You can place mentions anywhere in your user messages, and Cline will automatically retrieve the referenced content.
|
||||
|
||||
## Supported Mention Types
|
||||
|
||||
### 1. File References
|
||||
|
||||
To reference file contents, use `@/` followed by the relative path within your project:
|
||||
|
||||
```
|
||||
@/path/to/file.js
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Please analyze the implementation in @/src/components/Button.tsx
|
||||
```
|
||||
|
||||
In this example, Cline automatically retrieves the contents of Button.tsx and uses it to perform the analysis.
|
||||
|
||||
### 2. Directory References
|
||||
|
||||
To reference directory contents, use `@/` followed by the relative path of the directory, ending with a trailing `/`:
|
||||
|
||||
```
|
||||
@/path/to/directory/
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
What components are available in the @/src/components/ directory?
|
||||
```
|
||||
|
||||
In this example, Cline retrieves a listing of the components directory and its contents.
|
||||
|
||||
### 3. URL References
|
||||
|
||||
To reference web page contents, use `@` followed by the URL:
|
||||
|
||||
```
|
||||
@https://example.com
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Please parse the JSON response from @https://api.github.com/users/octocat
|
||||
```
|
||||
|
||||
In this example, Cline fetches the response from the GitHub API and analyzes the JSON.
|
||||
|
||||
### 4. Diagnostic References
|
||||
|
||||
To reference VSCode diagnostic information (errors and warnings) in the current workspace, use `@problems`:
|
||||
|
||||
```
|
||||
@problems
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Check @problems and tell me which errors I should prioritize fixing
|
||||
```
|
||||
|
||||
In this example, Cline retrieves the current errors and warnings from your workspace and identifies high-priority issues.
|
||||
|
||||
### 5. Terminal Output References
|
||||
|
||||
To reference the latest terminal output, use `@terminal`:
|
||||
|
||||
```
|
||||
@terminal
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Please identify the cause of the error in the @terminal output
|
||||
```
|
||||
|
||||
In this example, Cline examines the latest terminal output and analyzes the error's cause.
|
||||
|
||||
### 6. Git Working Directory References
|
||||
|
||||
To reference the current Git working directory change status, use `@git-changes`:
|
||||
|
||||
```
|
||||
@git-changes
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Review the @git-changes and summarize the important changes that should be committed
|
||||
```
|
||||
|
||||
In this example, Cline retrieves the list of changed files in the current Git working directory and identifies candidates for commit.
|
||||
|
||||
### 7. Git Commit References
|
||||
|
||||
To reference information about a specific Git commit, use `@` followed by the commit hash:
|
||||
|
||||
```
|
||||
@commit_hash
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Analyze the commit @abcd123 and explain what changes were made
|
||||
```
|
||||
|
||||
In this example, Cline retrieves information about the specified commit hash and analyzes the changes made in that commit.
|
||||
|
||||
## Usage Scenarios
|
||||
|
||||
### Code Review
|
||||
|
||||
```
|
||||
Check @/src/components/Form.jsx and suggest improvements from a performance perspective. Also, if there are any @problems, please suggest how to fix them.
|
||||
```
|
||||
|
||||
### Debugging Assistance
|
||||
|
||||
```
|
||||
My npm install failed. Please examine the @terminal output and suggest a solution to the problem.
|
||||
```
|
||||
|
||||
### Project Analysis
|
||||
|
||||
```
|
||||
Analyze the code in the @/src/models/ directory and explain the relationships between the data models. Also, tell me how the utility functions in @/src/utils/ are used with these models.
|
||||
```
|
||||
|
||||
### Code Generation
|
||||
|
||||
```
|
||||
Create a new Input.tsx component using the same design language as @/src/components/Button.tsx
|
||||
```
|
||||
|
||||
### Version Control Integration
|
||||
|
||||
```
|
||||
Review the @git-changes and suggest a commit message for the feature I'm working on.
|
||||
```
|
||||
|
||||
## Combining Multiple Mentions
|
||||
|
||||
You can combine multiple mentions to provide more complex context:
|
||||
|
||||
```
|
||||
There seems to be a bug in @/src/api/users.js. Please check @problems and @terminal to identify and fix the issue.
|
||||
```
|
||||
|
||||
## Limitations and Considerations
|
||||
|
||||
1. **Large Files**: Referencing very large files may take time to process and could consume a significant amount of tokens.
|
||||
|
||||
2. **Binary Files**: Binary files (such as images) will not be properly processed and will show a "Binary file" message.
|
||||
|
||||
3. **Directory Structure**: Directory references will only show top-level files and directories, not recursively showing the contents of subdirectories.
|
||||
|
||||
4. **URL Limitations**: Some websites may block automated crawling, which could prevent accurate content retrieval.
|
||||
|
||||
5. **Path Syntax**: File paths or URLs with special characters (such as spaces) may not be recognized correctly.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Mentions Not Recognized
|
||||
|
||||
If your mentions aren't being recognized correctly, check that:
|
||||
|
||||
- There's no space after the `@` symbol
|
||||
- File paths are accurate (case-sensitive)
|
||||
- URLs include the full format (with `https://`)
|
||||
|
||||
### Content Not Retrieved
|
||||
|
||||
If the content of referenced resources can't be retrieved:
|
||||
|
||||
- Verify the file exists
|
||||
- Ensure you have access permissions for the file
|
||||
- Check that the file isn't too large or the URL too complex
|
||||
|
||||
### Performance Issues
|
||||
|
||||
If mention processing is slow:
|
||||
|
||||
- Reference smaller files or specific file sections
|
||||
- Reduce the number of mentions used at once
|
||||
|
||||
## Conclusion
|
||||
|
||||
Mastering the mentions feature makes your communication with Cline more efficient. By providing appropriate context, Cline can deliver more accurate assistance, significantly improving your development workflow.
|
||||
Generated
+2356
-270
File diff suppressed because it is too large
Load Diff
+70
-71
@@ -2,7 +2,7 @@
|
||||
"name": "claude-dev",
|
||||
"displayName": "Cline",
|
||||
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
|
||||
"version": "3.26.1",
|
||||
"version": "3.32.5",
|
||||
"icon": "assets/icons/icon.png",
|
||||
"engines": {
|
||||
"vscode": "^1.84.0"
|
||||
@@ -102,15 +102,8 @@
|
||||
"activitybar": [
|
||||
{
|
||||
"id": "claude-dev-ActivityBar",
|
||||
"title": "Cline (⌘+')",
|
||||
"icon": "assets/icons/icon.svg",
|
||||
"when": "isMac"
|
||||
},
|
||||
{
|
||||
"id": "claude-dev-ActivityBar",
|
||||
"title": "Cline (Ctrl+')",
|
||||
"icon": "assets/icons/icon.svg",
|
||||
"when": "!isMac"
|
||||
"title": "Cline",
|
||||
"icon": "assets/icons/icon.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -140,11 +133,6 @@
|
||||
"title": "History",
|
||||
"icon": "$(history)"
|
||||
},
|
||||
{
|
||||
"command": "cline.popoutButtonClicked",
|
||||
"title": "Open in Editor",
|
||||
"icon": "$(link-external)"
|
||||
},
|
||||
{
|
||||
"command": "cline.accountButtonClicked",
|
||||
"title": "Account",
|
||||
@@ -155,11 +143,6 @@
|
||||
"title": "Settings",
|
||||
"icon": "$(settings-gear)"
|
||||
},
|
||||
{
|
||||
"command": "cline.openInNewTab",
|
||||
"title": "Open In New Tab",
|
||||
"category": "Cline"
|
||||
},
|
||||
{
|
||||
"command": "cline.dev.createTestTasks",
|
||||
"title": "Create Test Tasks",
|
||||
@@ -207,6 +190,11 @@
|
||||
"command": "cline.openWalkthrough",
|
||||
"title": "Open Walkthrough",
|
||||
"category": "Cline"
|
||||
},
|
||||
{
|
||||
"command": "cline.reconstructTaskHistory",
|
||||
"title": "Reconstruct Task History",
|
||||
"category": "Cline"
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
@@ -248,11 +236,6 @@
|
||||
"group": "navigation@3",
|
||||
"when": "view == claude-dev.SidebarProvider"
|
||||
},
|
||||
{
|
||||
"command": "cline.popoutButtonClicked",
|
||||
"group": "navigation@4",
|
||||
"when": "view == claude-dev.SidebarProvider"
|
||||
},
|
||||
{
|
||||
"command": "cline.accountButtonClicked",
|
||||
"group": "navigation@5",
|
||||
@@ -264,38 +247,6 @@
|
||||
"when": "view == claude-dev.SidebarProvider"
|
||||
}
|
||||
],
|
||||
"editor/title": [
|
||||
{
|
||||
"command": "cline.plusButtonClicked",
|
||||
"group": "navigation@1",
|
||||
"when": "activeWebviewPanelId == claude-dev.TabPanelProvider"
|
||||
},
|
||||
{
|
||||
"command": "cline.mcpButtonClicked",
|
||||
"group": "navigation@2",
|
||||
"when": "activeWebviewPanelId == claude-dev.TabPanelProvider"
|
||||
},
|
||||
{
|
||||
"command": "cline.historyButtonClicked",
|
||||
"group": "navigation@3",
|
||||
"when": "activeWebviewPanelId == claude-dev.TabPanelProvider"
|
||||
},
|
||||
{
|
||||
"command": "cline.popoutButtonClicked",
|
||||
"group": "navigation@4",
|
||||
"when": "activeWebviewPanelId == claude-dev.TabPanelProvider"
|
||||
},
|
||||
{
|
||||
"command": "cline.accountButtonClicked",
|
||||
"group": "navigation@5",
|
||||
"when": "activeWebviewPanelId == claude-dev.TabPanelProvider"
|
||||
},
|
||||
{
|
||||
"command": "cline.settingsButtonClicked",
|
||||
"group": "navigation@6",
|
||||
"when": "activeWebviewPanelId == claude-dev.TabPanelProvider"
|
||||
}
|
||||
],
|
||||
"editor/context": [
|
||||
{
|
||||
"command": "cline.addToChat",
|
||||
@@ -348,7 +299,9 @@
|
||||
"package": "npm run check-types && npm run build:webview && npm run lint && node esbuild.mjs --production",
|
||||
"protos": "node scripts/build-proto.mjs",
|
||||
"postprotos": "biome format src/shared/proto src/core/controller src/hosts/ webview-ui/src/services src/generated --write --no-errors-on-unmatched",
|
||||
"clean": "rimraf dist dist-standalone webview-ui/build src/generated out/",
|
||||
"clean:build": "rimraf dist dist-standalone webview-ui/build src/generated out/",
|
||||
"clean:deps": "rimraf node_modules webview-ui/node_modules",
|
||||
"clean:all": "npm run clean:build && npm run clean:deps",
|
||||
"compile-tests": "node ./scripts/build-tests.js",
|
||||
"watch-tests": "tsc -p . -w --outDir out",
|
||||
"check-types": "npm run protos && npx tsc --noEmit && cd webview-ui && npx tsc -b --noEmit",
|
||||
@@ -356,23 +309,27 @@
|
||||
"format": "biome format --changed --no-errors-on-unmatched --files-ignore-unknown=true --diagnostic-level=error",
|
||||
"format:fix": "biome check --changed --no-errors-on-unmatched --files-ignore-unknown=true --write",
|
||||
"fix:all": "biome check --no-errors-on-unmatched --files-ignore-unknown=true --write --diagnostic-level=error --unsafe",
|
||||
"ci:check-all": "npm-run-all -p check-types lint format",
|
||||
"ci:build": "npm run protos && npm run build:webview && node esbuild.mjs && npm run compile-tests",
|
||||
"pretest": "npm run compile && npm run compile-tests && npm run compile-standalone && npm run lint",
|
||||
"test": "npm-run-all test:unit test:integration",
|
||||
"test:ci": "node scripts/test-ci.js",
|
||||
"test:integration": "vscode-test",
|
||||
"test:unit": "TS_NODE_PROJECT='./tsconfig.unit-test.json' mocha",
|
||||
"test:coverage": "vscode-test --coverage",
|
||||
"test:sca-server": "npx tsx watch scripts/test-standalone-core-api-server.ts",
|
||||
"test:tp-orchestrator": "npx tsx scripts/testing-platform-orchestrator.ts",
|
||||
"e2e": "playwright test -c playwright.config.ts",
|
||||
"test:e2e": "playwright install && vsce package --no-dependencies --allow-package-secrets sendgrid --out dist/e2e.vsix && node src/test/e2e/utils/build.mjs && playwright test",
|
||||
"test:e2e:optimal": "vsce package --no-dependencies --allow-package-secrets sendgrid --out dist/e2e.vsix && node src/test/e2e/utils/build.mjs && playwright test",
|
||||
"test:scenarios": "playwright install && vsce package --no-dependencies --allow-package-secrets sendgrid --out dist/e2e.vsix && node src/test/e2e/utils/build.mjs && playwright test -c playwright.scenarios.config.ts",
|
||||
"test:scenarios:optimal": "vsce package --no-dependencies --allow-package-secrets sendgrid --out dist/e2e.vsix && node src/test/e2e/utils/build.mjs && playwright test -c playwright.scenarios.config.ts",
|
||||
"test:e2e:build": "vsce package --allow-package-secrets sendgrid --out dist/e2e.vsix",
|
||||
"test:e2e": "playwright install && npm run test:e2e:build && node src/test/e2e/utils/build.mjs && playwright test",
|
||||
"test:e2e:optimal": "npm run test:e2e:build && node src/test/e2e/utils/build.mjs && playwright test",
|
||||
"test:e2e:ui": "npx tsx scripts/interactive-playwright.ts",
|
||||
"install:all": "npm install && cd webview-ui && npm install",
|
||||
"dev:webview": "cd webview-ui && npm run dev",
|
||||
"build:webview": "cd webview-ui && npm run build",
|
||||
"test:webview": "cd webview-ui && npm run test",
|
||||
"publish:marketplace": "vsce publish && ovsx publish",
|
||||
"publish:marketplace:prerelease": "vsce publish --pre-release && ovsx publish --pre-release",
|
||||
"publish:marketplace": "vsce publish --allow-package-secrets sendgrid && ovsx publish",
|
||||
"publish:marketplace:prerelease": "vsce publish --allow-package-secrets sendgrid --pre-release && ovsx publish --pre-release",
|
||||
"publish:marketplace:nightly": "node ./scripts/publish-nightly.mjs",
|
||||
"prepare": "husky",
|
||||
"changeset": "changeset",
|
||||
"version-packages": "changeset version",
|
||||
@@ -390,6 +347,7 @@
|
||||
"@biomejs/biome": "^2.1.4",
|
||||
"@bufbuild/buf": "^1.54.0",
|
||||
"@changesets/cli": "^2.27.12",
|
||||
"@types/better-sqlite3": "^7.6.13",
|
||||
"@types/chai": "^5.0.1",
|
||||
"@types/clone-deep": "^4.0.4",
|
||||
"@types/diff": "^5.2.1",
|
||||
@@ -405,19 +363,23 @@
|
||||
"@vscode/test-cli": "^0.0.10",
|
||||
"@vscode/test-electron": "^2.5.2",
|
||||
"@vscode/vsce": "^3.6.0",
|
||||
"c8": "^10.1.3",
|
||||
"chai": "^4.3.10",
|
||||
"chalk": "^5.3.0",
|
||||
"chalk": "5.6.2",
|
||||
"esbuild": "^0.25.0",
|
||||
"grpc-tools": "^1.13.0",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.1.0",
|
||||
"minimatch": "^3.0.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"nyc": "^17.1.0",
|
||||
"prebuild-install": "^7.1.3",
|
||||
"protoc-gen-ts": "^0.8.7",
|
||||
"proxyquire": "^2.1.3",
|
||||
"rimraf": "^6.0.1",
|
||||
"should": "^13.2.3",
|
||||
"sinon": "^19.0.2",
|
||||
"tree-kill": "^1.2.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"ts-proto": "^2.6.1",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
@@ -431,7 +393,7 @@
|
||||
"@bufbuild/protobuf": "^2.2.5",
|
||||
"@cerebras/cerebras_cloud_sdk": "^1.35.0",
|
||||
"@google-cloud/vertexai": "^1.9.3",
|
||||
"@google/genai": "1.0.0",
|
||||
"@google/genai": "^1.11.0",
|
||||
"@grpc/grpc-js": "^1.9.15",
|
||||
"@grpc/reflection": "^1.0.4",
|
||||
"@mistralai/mistralai": "^1.5.0",
|
||||
@@ -443,12 +405,14 @@
|
||||
"@opentelemetry/sdk-trace-node": "^1.30.1",
|
||||
"@opentelemetry/semantic-conventions": "^1.30.0",
|
||||
"@playwright/test": "^1.53.2",
|
||||
"@sap-ai-sdk/ai-api": "^1.17.0",
|
||||
"@sap-ai-sdk/orchestration": "^1.17.0",
|
||||
"@sentry/browser": "^9.12.0",
|
||||
"@streamparser/json": "^0.0.22",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"@vscode/codicons": "^0.0.36",
|
||||
"archiver": "^7.0.1",
|
||||
"axios": "^1.8.2",
|
||||
"axios": "^1.12.0",
|
||||
"cheerio": "^1.0.0",
|
||||
"chokidar": "^4.0.1",
|
||||
"chrome-launcher": "^1.1.2",
|
||||
@@ -463,6 +427,7 @@
|
||||
"get-folder-size": "^5.0.0",
|
||||
"globby": "^14.0.2",
|
||||
"grpc-health-check": "^2.0.2",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"ignore": "^7.0.3",
|
||||
"image-size": "^2.0.2",
|
||||
@@ -470,7 +435,6 @@
|
||||
"jschardet": "^3.1.4",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"mammoth": "^1.8.0",
|
||||
"monaco-vscode-textmate-theme-converter": "^0.1.7",
|
||||
"nice-grpc": "^2.1.12",
|
||||
"ollama": "^0.5.13",
|
||||
"open": "^10.1.2",
|
||||
@@ -480,13 +444,13 @@
|
||||
"p-timeout": "^6.1.4",
|
||||
"p-wait-for": "^5.0.2",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"posthog-node": "^4.8.1",
|
||||
"posthog-node": "^5.8.0",
|
||||
"puppeteer-chromium-resolver": "^23.0.0",
|
||||
"puppeteer-core": "^23.4.0",
|
||||
"reconnecting-eventsource": "^1.6.4",
|
||||
"serialize-error": "^11.0.3",
|
||||
"simple-git": "^3.27.0",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"strip-ansi": "^7.1.2",
|
||||
"tree-sitter-wasms": "^0.1.11",
|
||||
"ts-morph": "^25.0.1",
|
||||
"turndown": "^7.2.0",
|
||||
@@ -495,5 +459,40 @@
|
||||
"vscode-uri": "^3.1.0",
|
||||
"web-tree-sitter": "^0.22.6",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"c8": {
|
||||
"reporter": [
|
||||
"lcov",
|
||||
"html"
|
||||
],
|
||||
"exclude": [
|
||||
"**/testing-platform/**",
|
||||
"**/webview-ui/**",
|
||||
"**/.vscode-test/**",
|
||||
"**/node_modules/**",
|
||||
"node_modules",
|
||||
"**/dist-standalone/src/**",
|
||||
"**/dist-standalone/vsce-extension/https:/**",
|
||||
"**/dist-standalone/vsce-extension/**",
|
||||
"**/dist-standalone/https:/**",
|
||||
"**/dist-standalone/LIB/src/**",
|
||||
"**/dist-standalone/pdfjs-dist/**",
|
||||
"**/*.d.ts",
|
||||
"**/*.{test,spec}.{js,jsx,ts,tsx,mjs,cjs}",
|
||||
"**/__tests__/**",
|
||||
"**/test/**",
|
||||
"**/tests/**",
|
||||
"**/.nyc_output/**",
|
||||
"**/tests-results/**",
|
||||
"src/test/**",
|
||||
"**/src/xml/**",
|
||||
"**/standalone/**",
|
||||
"**/src/generated/**",
|
||||
"**/evals/cli/dist/**",
|
||||
"**/evals/cli/src/**",
|
||||
"dist"
|
||||
],
|
||||
"all": true,
|
||||
"exclude-after-remap": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { defineConfig } from "@playwright/test"
|
||||
|
||||
const isCI = !!process?.env?.CI
|
||||
const isWindow = process?.platform?.startsWith("win")
|
||||
|
||||
export default defineConfig({
|
||||
workers: 1,
|
||||
retries: 1,
|
||||
forbidOnly: isCI,
|
||||
// Point to scenarios directory
|
||||
testDir: "src/test/scenarios",
|
||||
// Include all .ts in scenarios (we add a local global.setup.ts here)
|
||||
testMatch: /.*\.ts/,
|
||||
timeout: isCI || isWindow ? 40000 : 20000,
|
||||
expect: {
|
||||
timeout: isCI || isWindow ? 5000 : 2000,
|
||||
},
|
||||
fullyParallel: true,
|
||||
reporter: isCI ? [["github"], ["list"]] : [["list"]],
|
||||
use: {
|
||||
video: "retain-on-failure",
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: "setup test environment",
|
||||
// Reuse E2E setup file to avoid duplication
|
||||
testDir: "src/test/e2e/utils",
|
||||
testMatch: /global\.setup\.ts/,
|
||||
},
|
||||
{
|
||||
name: "scenario tests",
|
||||
dependencies: ["setup test environment"],
|
||||
},
|
||||
],
|
||||
})
|
||||
@@ -38,6 +38,9 @@ service AccountService {
|
||||
rpc setUserOrganization(UserOrganizationUpdateRequest) returns (Empty);
|
||||
|
||||
rpc openrouterAuthClicked(EmptyRequest) returns (Empty);
|
||||
|
||||
// Returns a link the webview can use to redirect back to the user's IDE.
|
||||
rpc getRedirectUrl(EmptyRequest) returns (String);
|
||||
}
|
||||
|
||||
message AuthStateChangedRequest {
|
||||
|
||||
@@ -2,6 +2,7 @@ syntax = "proto3";
|
||||
|
||||
package cline;
|
||||
import "cline/common.proto";
|
||||
import "cline/state.proto";
|
||||
option java_package = "bot.cline.proto";
|
||||
option java_multiple_files = true;
|
||||
|
||||
@@ -10,7 +11,6 @@ service BrowserService {
|
||||
rpc testBrowserConnection(StringRequest) returns (BrowserConnection);
|
||||
rpc discoverBrowser(EmptyRequest) returns (BrowserConnection);
|
||||
rpc getDetectedChromePath(EmptyRequest) returns (ChromePath);
|
||||
rpc updateBrowserSettings(UpdateBrowserSettingsRequest) returns (Boolean);
|
||||
rpc relaunchChromeDebugMode(EmptyRequest) returns (String);
|
||||
}
|
||||
|
||||
@@ -31,11 +31,6 @@ message ChromePath {
|
||||
bool is_bundled = 2;
|
||||
}
|
||||
|
||||
message Viewport {
|
||||
int32 width = 1;
|
||||
int32 height = 2;
|
||||
}
|
||||
|
||||
message BrowserSettings {
|
||||
Viewport viewport = 1;
|
||||
optional string remote_browser_host = 2;
|
||||
|
||||
@@ -8,19 +8,16 @@ message Metadata {
|
||||
}
|
||||
|
||||
message EmptyRequest {
|
||||
Metadata metadata = 1;
|
||||
}
|
||||
|
||||
message Empty {
|
||||
}
|
||||
|
||||
message StringRequest {
|
||||
Metadata metadata = 1;
|
||||
string value = 2;
|
||||
}
|
||||
|
||||
message StringArrayRequest {
|
||||
Metadata metadata = 1;
|
||||
repeated string value = 2;
|
||||
}
|
||||
|
||||
@@ -29,7 +26,6 @@ message String {
|
||||
}
|
||||
|
||||
message Int64Request {
|
||||
Metadata metadata = 1;
|
||||
int64 value = 2;
|
||||
}
|
||||
|
||||
@@ -38,7 +34,6 @@ message Int64 {
|
||||
}
|
||||
|
||||
message BytesRequest {
|
||||
Metadata metadata = 1;
|
||||
bytes value = 2;
|
||||
}
|
||||
|
||||
@@ -47,7 +42,6 @@ message Bytes {
|
||||
}
|
||||
|
||||
message BooleanRequest {
|
||||
Metadata metadata = 1;
|
||||
bool value = 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package cline;
|
||||
import "cline/common.proto";
|
||||
option java_package = "bot.cline.proto";
|
||||
option java_multiple_files = true;
|
||||
|
||||
service DictationService {
|
||||
rpc startRecording(EmptyRequest) returns (RecordingResult);
|
||||
rpc stopRecording(EmptyRequest) returns (RecordedAudio);
|
||||
rpc cancelRecording(EmptyRequest) returns (RecordingResult);
|
||||
rpc getRecordingStatus(EmptyRequest) returns (RecordingStatus);
|
||||
rpc transcribeAudio(TranscribeAudioRequest) returns (Transcription);
|
||||
}
|
||||
|
||||
message TranscribeAudioRequest {
|
||||
string audio_base64 = 2;
|
||||
string language = 3;
|
||||
}
|
||||
|
||||
message RecordingResult {
|
||||
bool success = 1;
|
||||
string error = 2;
|
||||
}
|
||||
|
||||
message RecordedAudio {
|
||||
bool success = 1;
|
||||
string audio_base64 = 2;
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
message RecordingStatus {
|
||||
bool is_recording = 1;
|
||||
double duration_seconds = 2;
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
message Transcription {
|
||||
string text = 1;
|
||||
string error = 2;
|
||||
}
|
||||
@@ -50,7 +50,7 @@ service FileService {
|
||||
rpc refreshRules(EmptyRequest) returns (RefreshedRules);
|
||||
|
||||
// Opens a task's conversation history file on disk
|
||||
rpc openTaskHistory(StringRequest) returns (Empty);
|
||||
rpc openDiskConversationHistory(StringRequest) returns (Empty);
|
||||
|
||||
// Toggles a workflow on or off
|
||||
rpc toggleWorkflow(ToggleWorkflowRequest) returns (ClineRulesToggles);
|
||||
|
||||
+121
-49
@@ -32,7 +32,9 @@ service ModelsService {
|
||||
// Refreshes and returns Baseten models
|
||||
rpc refreshBasetenModels(EmptyRequest) returns (OpenRouterCompatibleModelInfo);
|
||||
// Fetches available models from SAP AI Core
|
||||
rpc getSapAiCoreModels(SapAiCoreModelsRequest) returns (StringArray);
|
||||
rpc getSapAiCoreModels(SapAiCoreModelsRequest) returns (SapAiCoreModelsResponse);
|
||||
// Fetches available models from OCA
|
||||
rpc refreshOcaModels(StringRequest) returns (OcaCompatibleModelInfo);
|
||||
}
|
||||
|
||||
// List of VS Code LM models
|
||||
@@ -50,20 +52,20 @@ message LanguageModelChatSelector {
|
||||
|
||||
// Price tier for tiered pricing models
|
||||
message PriceTier {
|
||||
int32 token_limit = 1; // Upper limit (inclusive) of input tokens for this price
|
||||
int64 token_limit = 1; // Upper limit (inclusive) of input tokens for this price
|
||||
double price = 2; // Price per million tokens for this tier
|
||||
}
|
||||
|
||||
// Thinking configuration for models that support thinking/reasoning
|
||||
message ThinkingConfig {
|
||||
optional int32 max_budget = 1; // Max allowed thinking budget tokens
|
||||
optional int64 max_budget = 1; // Max allowed thinking budget tokens
|
||||
optional double output_price = 2; // Output price per million tokens when budget > 0
|
||||
repeated PriceTier output_price_tiers = 3; // Optional: Tiered output price when budget > 0
|
||||
}
|
||||
|
||||
// Model tier for tiered pricing structures
|
||||
message ModelTier {
|
||||
int32 context_window = 1;
|
||||
int64 context_window = 1;
|
||||
optional double input_price = 2;
|
||||
optional double output_price = 3;
|
||||
optional double cache_writes_price = 4;
|
||||
@@ -108,12 +110,67 @@ message SapAiCoreModelsRequest {
|
||||
string resource_group = 6;
|
||||
}
|
||||
|
||||
// SAP AI Core model with deployment information
|
||||
message SapAiCoreModelDeployment {
|
||||
string model_name = 1;
|
||||
string deployment_id = 2;
|
||||
}
|
||||
|
||||
|
||||
// Response for SAP AI Core models with orchestration availability
|
||||
message SapAiCoreModelsResponse {
|
||||
repeated SapAiCoreModelDeployment deployments = 1;
|
||||
bool orchestration_available = 2;
|
||||
}
|
||||
|
||||
// Request for updating API configuration
|
||||
message UpdateApiConfigurationRequest {
|
||||
Metadata metadata = 1;
|
||||
ModelsApiConfiguration api_configuration = 2;
|
||||
}
|
||||
|
||||
// Model info for OCA (OpenAI-compatible) models exposed by the OCA provider
|
||||
message OcaModelInfo {
|
||||
// Maximum completion tokens per request supported by this model
|
||||
optional int64 max_tokens = 1;
|
||||
// Total context window in tokens (input + output)
|
||||
optional int64 context_window = 2;
|
||||
// Whether the model supports image inputs
|
||||
optional bool supports_images = 3;
|
||||
// Whether prompt caching is supported for this model
|
||||
bool supports_prompt_cache = 4;
|
||||
// Price per million input tokens (USD unless otherwise specified by provider)
|
||||
optional double input_price = 5;
|
||||
// Price per million output tokens (USD unless otherwise specified by provider)
|
||||
optional double output_price = 6;
|
||||
// Thinking/reasoning configuration if the model supports it
|
||||
optional ThinkingConfig thinking_config = 7;
|
||||
// Price per million tokens for prompt cache writes
|
||||
optional double cache_writes_price = 9;
|
||||
// Price per million tokens for prompt cache reads
|
||||
optional double cache_reads_price = 10;
|
||||
// Human-readable model description
|
||||
optional string description = 11;
|
||||
// Recommended default temperature for this model
|
||||
optional double temperature = 13;
|
||||
// Optional survey content to display in the UI
|
||||
optional string survey_content = 14;
|
||||
// Identifier for the survey associated with this model
|
||||
optional string survey_id = 15;
|
||||
// Optional banner content (e.g., deprecation or promotion notes)
|
||||
optional string banner = 16;
|
||||
// Canonical model identifier as reported by OCA
|
||||
string model_name = 17;
|
||||
}
|
||||
|
||||
// Aggregated OCA model catalog keyed by model identifier
|
||||
message OcaCompatibleModelInfo {
|
||||
// key: canonical model id as reported by OCA (e.g., "openai/gpt-4o-mini")
|
||||
// value: OcaModelInfo describing that model
|
||||
map<string, OcaModelInfo> models = 1;
|
||||
optional string error = 2;
|
||||
}
|
||||
|
||||
// API Provider enumeration
|
||||
enum ApiProvider {
|
||||
ANTHROPIC = 0;
|
||||
@@ -149,12 +206,15 @@ enum ApiProvider {
|
||||
BASETEN = 30;
|
||||
ZAI = 31;
|
||||
VERCEL_AI_GATEWAY = 32;
|
||||
QWEN_CODE = 33;
|
||||
DIFY = 34;
|
||||
OCA = 35;
|
||||
}
|
||||
|
||||
// Model info for OpenAI-compatible models
|
||||
message OpenAiCompatibleModelInfo {
|
||||
optional int32 max_tokens = 1;
|
||||
optional int32 context_window = 2;
|
||||
optional int64 max_tokens = 1;
|
||||
optional int64 context_window = 2;
|
||||
optional bool supports_images = 3;
|
||||
bool supports_prompt_cache = 4;
|
||||
optional double input_price = 5;
|
||||
@@ -171,8 +231,8 @@ message OpenAiCompatibleModelInfo {
|
||||
|
||||
// Model info for LiteLLM models
|
||||
message LiteLLMModelInfo {
|
||||
optional int32 max_tokens = 1;
|
||||
optional int32 context_window = 2;
|
||||
optional int64 max_tokens = 1;
|
||||
optional int64 context_window = 2;
|
||||
optional bool supports_images = 3;
|
||||
bool supports_prompt_cache = 4;
|
||||
optional double input_price = 5;
|
||||
@@ -224,8 +284,8 @@ message ModelsApiConfiguration {
|
||||
optional string requesty_base_url = 33;
|
||||
optional string together_api_key = 34;
|
||||
optional string fireworks_api_key = 35;
|
||||
optional int32 fireworks_model_max_completion_tokens = 36;
|
||||
optional int32 fireworks_model_max_tokens = 37;
|
||||
optional int64 fireworks_model_max_completion_tokens = 36;
|
||||
optional int64 fireworks_model_max_tokens = 37;
|
||||
optional string qwen_api_key = 38;
|
||||
optional string doubao_api_key = 39;
|
||||
optional string mistral_api_key = 40;
|
||||
@@ -237,31 +297,38 @@ message ModelsApiConfiguration {
|
||||
optional string xai_api_key = 46;
|
||||
optional string sambanova_api_key = 47;
|
||||
optional string cerebras_api_key = 48;
|
||||
optional int32 request_timeout_ms = 49;
|
||||
optional int64 request_timeout_ms = 49;
|
||||
optional string sap_ai_core_client_id = 50;
|
||||
optional string sap_ai_core_client_secret = 51;
|
||||
optional string sap_ai_resource_group = 52;
|
||||
optional string sap_ai_core_token_url = 53;
|
||||
optional string sap_ai_core_base_url = 54;
|
||||
optional string moonshot_api_key = 55;
|
||||
optional string moonshot_api_line = 56;
|
||||
optional string aws_authentication = 57;
|
||||
optional string aws_bedrock_api_key = 58;
|
||||
optional string cline_account_id = 59;
|
||||
optional string groq_api_key = 60;
|
||||
optional string hugging_face_api_key = 61;
|
||||
optional string huawei_cloud_maas_api_key = 62;
|
||||
optional string baseten_api_key = 63;
|
||||
optional string ollama_api_key = 64;
|
||||
optional string zai_api_key = 65;
|
||||
optional string zai_api_line = 66;
|
||||
optional string lm_studio_max_tokens = 67;
|
||||
optional string vercel_ai_gateway_api_key = 68;
|
||||
optional bool sap_ai_core_use_orchestration_mode = 55;
|
||||
optional string moonshot_api_key = 56;
|
||||
optional string moonshot_api_line = 57;
|
||||
optional string aws_authentication = 58;
|
||||
optional string aws_bedrock_api_key = 59;
|
||||
optional string cline_account_id = 60;
|
||||
optional string groq_api_key = 61;
|
||||
optional string hugging_face_api_key = 62;
|
||||
optional string huawei_cloud_maas_api_key = 63;
|
||||
optional string baseten_api_key = 64;
|
||||
optional string ollama_api_key = 65;
|
||||
optional string zai_api_key = 66;
|
||||
optional string zai_api_line = 67;
|
||||
optional string lm_studio_max_tokens = 68;
|
||||
optional string vercel_ai_gateway_api_key = 69;
|
||||
optional string qwen_code_oauth_path = 70;
|
||||
optional string dify_api_key = 71;
|
||||
optional string dify_base_url = 72;
|
||||
optional string oca_base_url = 73;
|
||||
optional string oca_api_key = 74;
|
||||
optional string oca_refresh_token = 75;
|
||||
|
||||
// Plan mode configurations
|
||||
optional ApiProvider plan_mode_api_provider = 100;
|
||||
optional string plan_mode_api_model_id = 101;
|
||||
optional int32 plan_mode_thinking_budget_tokens = 102;
|
||||
optional int64 plan_mode_thinking_budget_tokens = 102;
|
||||
optional string plan_mode_reasoning_effort = 103;
|
||||
optional LanguageModelChatSelector plan_mode_vs_code_lm_model_selector = 104;
|
||||
optional bool plan_mode_aws_bedrock_custom_selected = 105;
|
||||
@@ -279,21 +346,25 @@ message ModelsApiConfiguration {
|
||||
optional string plan_mode_together_model_id = 117;
|
||||
optional string plan_mode_fireworks_model_id = 118;
|
||||
optional string plan_mode_sap_ai_core_model_id = 119;
|
||||
optional string plan_mode_groq_model_id = 120;
|
||||
optional OpenRouterModelInfo plan_mode_groq_model_info = 121;
|
||||
optional string plan_mode_hugging_face_model_id = 122;
|
||||
optional OpenRouterModelInfo plan_mode_hugging_face_model_info = 123;
|
||||
optional string plan_mode_huawei_cloud_maas_model_id = 124;
|
||||
optional OpenRouterModelInfo plan_mode_huawei_cloud_maas_model_info = 125;
|
||||
optional string plan_mode_baseten_model_id = 126;
|
||||
optional OpenRouterModelInfo plan_mode_baseten_model_info = 127;
|
||||
optional string plan_mode_vercel_ai_gateway_model_id = 128;
|
||||
optional OpenRouterModelInfo plan_mode_vercel_ai_gateway_model_info = 129;
|
||||
optional string plan_mode_sap_ai_core_deployment_id = 120;
|
||||
optional string plan_mode_groq_model_id = 121;
|
||||
optional OpenRouterModelInfo plan_mode_groq_model_info = 122;
|
||||
optional string plan_mode_hugging_face_model_id = 123;
|
||||
optional OpenRouterModelInfo plan_mode_hugging_face_model_info = 124;
|
||||
optional string plan_mode_huawei_cloud_maas_model_id = 125;
|
||||
optional OpenRouterModelInfo plan_mode_huawei_cloud_maas_model_info = 126;
|
||||
optional string plan_mode_baseten_model_id = 127;
|
||||
optional OpenRouterModelInfo plan_mode_baseten_model_info = 128;
|
||||
optional string plan_mode_vercel_ai_gateway_model_id = 129;
|
||||
optional OpenRouterModelInfo plan_mode_vercel_ai_gateway_model_info = 130;
|
||||
optional string plan_mode_oca_model_id = 131;
|
||||
optional OcaModelInfo plan_mode_oca_model_info = 132;
|
||||
|
||||
|
||||
// Act mode configurations
|
||||
optional ApiProvider act_mode_api_provider = 200;
|
||||
optional string act_mode_api_model_id = 201;
|
||||
optional int32 act_mode_thinking_budget_tokens = 202;
|
||||
optional int64 act_mode_thinking_budget_tokens = 202;
|
||||
optional string act_mode_reasoning_effort = 203;
|
||||
optional LanguageModelChatSelector act_mode_vs_code_lm_model_selector = 204;
|
||||
optional bool act_mode_aws_bedrock_custom_selected = 205;
|
||||
@@ -311,16 +382,17 @@ message ModelsApiConfiguration {
|
||||
optional string act_mode_together_model_id = 217;
|
||||
optional string act_mode_fireworks_model_id = 218;
|
||||
optional string act_mode_sap_ai_core_model_id = 219;
|
||||
optional string act_mode_groq_model_id = 220;
|
||||
optional OpenRouterModelInfo act_mode_groq_model_info = 221;
|
||||
optional string act_mode_hugging_face_model_id = 222;
|
||||
optional OpenRouterModelInfo act_mode_hugging_face_model_info = 223;
|
||||
optional string act_mode_huawei_cloud_maas_model_id = 224;
|
||||
optional OpenRouterModelInfo act_mode_huawei_cloud_maas_model_info = 225;
|
||||
optional string act_mode_baseten_model_id = 226;
|
||||
optional OpenRouterModelInfo act_mode_baseten_model_info = 227;
|
||||
optional string act_mode_vercel_ai_gateway_model_id = 228;
|
||||
optional OpenRouterModelInfo act_mode_vercel_ai_gateway_model_info = 229;
|
||||
|
||||
repeated string favorited_model_ids = 300;
|
||||
optional string act_mode_sap_ai_core_deployment_id = 220;
|
||||
optional string act_mode_groq_model_id = 221;
|
||||
optional OpenRouterModelInfo act_mode_groq_model_info = 222;
|
||||
optional string act_mode_hugging_face_model_id = 223;
|
||||
optional OpenRouterModelInfo act_mode_hugging_face_model_info = 224;
|
||||
optional string act_mode_huawei_cloud_maas_model_id = 225;
|
||||
optional OpenRouterModelInfo act_mode_huawei_cloud_maas_model_info = 226;
|
||||
optional string act_mode_baseten_model_id = 227;
|
||||
optional OpenRouterModelInfo act_mode_baseten_model_info = 228;
|
||||
optional string act_mode_vercel_ai_gateway_model_id = 229;
|
||||
optional OpenRouterModelInfo act_mode_vercel_ai_gateway_model_info = 230;
|
||||
optional string act_mode_oca_model_id = 231;
|
||||
optional OcaModelInfo act_mode_oca_model_info = 232;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package cline;
|
||||
import "cline/common.proto";
|
||||
option java_package = "bot.cline.proto";
|
||||
option java_multiple_files = true;
|
||||
|
||||
// Service for account-related operations
|
||||
service OcaAccountService {
|
||||
// Handles the user clicking the login link in the UI.
|
||||
// Generates a secure nonce for state validation, stores it in secrets,
|
||||
// and opens the authentication URL in the external browser.
|
||||
rpc ocaAccountLoginClicked(EmptyRequest) returns (String);
|
||||
|
||||
// Handles the user clicking the logout button in the UI.
|
||||
// Clears API keys and user state.
|
||||
rpc ocaAccountLogoutClicked(EmptyRequest) returns (Empty);
|
||||
|
||||
// Subscribe to auth status update events (when authentication state changes)
|
||||
rpc ocaSubscribeToAuthStatusUpdate(EmptyRequest)
|
||||
returns (stream OcaAuthState);
|
||||
|
||||
}
|
||||
|
||||
|
||||
message OcaAuthState {
|
||||
optional OcaUserInfo user = 1;
|
||||
optional string api_key = 2;
|
||||
}
|
||||
|
||||
// User's information
|
||||
message OcaUserInfo {
|
||||
string uid = 1;
|
||||
optional string display_name = 2;
|
||||
optional string email = 3;
|
||||
}
|
||||
+67
-31
@@ -1,6 +1,7 @@
|
||||
syntax = "proto3";
|
||||
package cline;
|
||||
import "cline/common.proto";
|
||||
import "cline/models.proto";
|
||||
option java_package = "bot.cline.proto";
|
||||
option java_multiple_files = true;
|
||||
|
||||
@@ -8,7 +9,6 @@ service StateService {
|
||||
rpc getLatestState(EmptyRequest) returns (State);
|
||||
rpc updateTerminalConnectionTimeout(UpdateTerminalConnectionTimeoutRequest) returns (UpdateTerminalConnectionTimeoutResponse);
|
||||
rpc updateTerminalReuseEnabled(BooleanRequest) returns (Empty);
|
||||
rpc updateDefaultTerminalProfile(StringRequest) returns (TerminalProfileUpdateResponse);
|
||||
rpc getAvailableTerminalProfiles(EmptyRequest) returns (TerminalProfiles);
|
||||
rpc subscribeToState(EmptyRequest) returns (stream State);
|
||||
rpc toggleFavoriteModel(StringRequest) returns (Empty);
|
||||
@@ -18,8 +18,14 @@ service StateService {
|
||||
rpc updateSettings(UpdateSettingsRequest) returns (Empty);
|
||||
rpc updateTelemetrySetting(TelemetrySettingRequest) returns (Empty);
|
||||
rpc setWelcomeViewCompleted(BooleanRequest) returns (Empty);
|
||||
rpc updateInfoBannerVersion(Int64Request) returns (Empty);
|
||||
rpc updateModelBannerVersion(Int64Request) returns (Empty);
|
||||
}
|
||||
message DictationSettings {
|
||||
bool feature_enabled = 1;
|
||||
bool dictation_enabled = 2;
|
||||
string dictation_language = 3;
|
||||
}
|
||||
|
||||
message State {
|
||||
string state_json = 1;
|
||||
}
|
||||
@@ -56,6 +62,7 @@ enum OpenaiReasoningEffort {
|
||||
LOW = 0;
|
||||
MEDIUM = 1;
|
||||
HIGH = 2;
|
||||
MINIMAL = 3;
|
||||
}
|
||||
|
||||
enum McpDisplayMode {
|
||||
@@ -106,6 +113,16 @@ message TelemetrySettingRequest {
|
||||
TelemetrySettingEnum setting = 2;
|
||||
}
|
||||
|
||||
// Browser settings for UpdateSettingsRequest
|
||||
message BrowserSettingsUpdate {
|
||||
optional Viewport viewport = 1;
|
||||
optional string remote_browser_host = 2;
|
||||
optional bool remote_browser_enabled = 3;
|
||||
optional string chrome_executable_path = 4;
|
||||
optional bool disable_tool_use = 5;
|
||||
optional string custom_args = 6;
|
||||
}
|
||||
|
||||
// Message for updating settings
|
||||
message UpdateSettingsRequest {
|
||||
Metadata metadata = 1;
|
||||
@@ -125,6 +142,13 @@ message UpdateSettingsRequest {
|
||||
optional bool strict_plan_mode_enabled = 16;
|
||||
optional FocusChainSettings focus_chain_settings = 17;
|
||||
optional bool use_auto_condense = 18;
|
||||
optional string custom_prompt = 19;
|
||||
optional BrowserSettingsUpdate browser_settings = 20;
|
||||
optional string default_terminal_profile = 21;
|
||||
optional bool yolo_mode_toggled = 22;
|
||||
optional DictationSettings dictation_settings = 23;
|
||||
optional int32 auto_condense_threshold = 24;
|
||||
optional bool multi_root_enabled = 25;
|
||||
}
|
||||
|
||||
// Complete API Configuration message
|
||||
@@ -136,10 +160,10 @@ message ApiConfiguration {
|
||||
optional string lite_llm_base_url = 4;
|
||||
optional string lite_llm_api_key = 5;
|
||||
optional bool lite_llm_use_prompt_cache = 6;
|
||||
optional string openai_headers = 7; // JSON string
|
||||
map<string, string> open_ai_headers = 7;
|
||||
optional string anthropic_base_url = 8;
|
||||
optional string openrouter_api_key = 9;
|
||||
optional string openrouter_provider_sorting = 10;
|
||||
optional string open_router_api_key = 9;
|
||||
optional string open_router_provider_sorting = 10;
|
||||
optional string aws_access_key = 11;
|
||||
optional string aws_secret_key = 12;
|
||||
optional string aws_session_token = 13;
|
||||
@@ -152,14 +176,14 @@ message ApiConfiguration {
|
||||
optional string claude_code_path = 20;
|
||||
optional string vertex_project_id = 21;
|
||||
optional string vertex_region = 22;
|
||||
optional string openai_base_url = 23;
|
||||
optional string openai_api_key = 24;
|
||||
optional string open_ai_base_url = 23;
|
||||
optional string open_ai_api_key = 24;
|
||||
optional string ollama_base_url = 25;
|
||||
optional string ollama_api_options_ctx_num = 26;
|
||||
optional string lm_studio_base_url = 27;
|
||||
optional string gemini_api_key = 28;
|
||||
optional string gemini_base_url = 29;
|
||||
optional string openai_native_api_key = 30;
|
||||
optional string open_ai_native_api_key = 30;
|
||||
optional string deep_seek_api_key = 31;
|
||||
optional string requesty_api_key = 32;
|
||||
optional string requesty_base_url = 33;
|
||||
@@ -192,61 +216,68 @@ message ApiConfiguration {
|
||||
optional string zai_api_line = 60;
|
||||
optional string lm_studio_max_tokens = 61;
|
||||
optional string vercel_ai_gateway_api_key = 62;
|
||||
optional string qwen_code_oauth_path = 63;
|
||||
optional string dify_api_key = 64;
|
||||
optional string dify_base_url = 65;
|
||||
optional string oca_base_url = 66;
|
||||
optional string oca_api_key = 67;
|
||||
optional string oca_refresh_token = 68;
|
||||
|
||||
// Plan mode configurations
|
||||
optional string plan_mode_api_provider = 100;
|
||||
optional ApiProvider plan_mode_api_provider = 100;
|
||||
optional string plan_mode_api_model_id = 101;
|
||||
optional int32 plan_mode_thinking_budget_tokens = 102;
|
||||
optional string plan_mode_reasoning_effort = 103;
|
||||
optional string plan_mode_vscode_lm_model_selector = 104; // JSON string
|
||||
optional LanguageModelChatSelector plan_mode_vs_code_lm_model_selector = 104;
|
||||
optional bool plan_mode_aws_bedrock_custom_selected = 105;
|
||||
optional string plan_mode_aws_bedrock_custom_model_base_id = 106;
|
||||
optional string plan_mode_openrouter_model_id = 107;
|
||||
optional string plan_mode_openrouter_model_info = 108; // JSON string
|
||||
optional string plan_mode_openai_model_id = 109;
|
||||
optional string plan_mode_openai_model_info = 110; // JSON string
|
||||
optional string plan_mode_open_router_model_id = 107;
|
||||
optional OpenRouterModelInfo plan_mode_open_router_model_info = 108;
|
||||
optional string plan_mode_open_ai_model_id = 109;
|
||||
optional OpenAiCompatibleModelInfo plan_mode_open_ai_model_info = 110;
|
||||
optional string plan_mode_ollama_model_id = 111;
|
||||
optional string plan_mode_lm_studio_model_id = 112;
|
||||
optional string plan_mode_lite_llm_model_id = 113;
|
||||
optional string plan_mode_lite_llm_model_info = 114; // JSON string
|
||||
optional LiteLLMModelInfo plan_mode_lite_llm_model_info = 114;
|
||||
optional string plan_mode_requesty_model_id = 115;
|
||||
optional string plan_mode_requesty_model_info = 116; // JSON string
|
||||
optional OpenRouterModelInfo plan_mode_requesty_model_info = 116;
|
||||
optional string plan_mode_together_model_id = 117;
|
||||
optional string plan_mode_fireworks_model_id = 118;
|
||||
optional string plan_mode_sap_ai_core_model_id = 119;
|
||||
optional string plan_mode_huawei_cloud_maas_model_id = 120;
|
||||
optional string plan_mode_huawei_cloud_maas_model_info = 121;
|
||||
optional OpenRouterModelInfo plan_mode_huawei_cloud_maas_model_info = 121;
|
||||
optional string plan_mode_vercel_ai_gateway_model_id = 122;
|
||||
optional string plan_mode_vercel_ai_gateway_model_info = 123;
|
||||
optional OpenRouterModelInfo plan_mode_vercel_ai_gateway_model_info = 123;
|
||||
optional string plan_mode_oca_model_id = 124;
|
||||
optional OcaModelInfo plan_mode_oca_model_info = 125;
|
||||
|
||||
// Act mode configurations
|
||||
optional string act_mode_api_provider = 200;
|
||||
optional ApiProvider act_mode_api_provider = 200;
|
||||
optional string act_mode_api_model_id = 201;
|
||||
optional int32 act_mode_thinking_budget_tokens = 202;
|
||||
optional string act_mode_reasoning_effort = 203;
|
||||
optional string act_mode_vscode_lm_model_selector = 204; // JSON string
|
||||
optional LanguageModelChatSelector act_mode_vs_code_lm_model_selector = 204;
|
||||
optional bool act_mode_aws_bedrock_custom_selected = 205;
|
||||
optional string act_mode_aws_bedrock_custom_model_base_id = 206;
|
||||
optional string act_mode_openrouter_model_id = 207;
|
||||
optional string act_mode_openrouter_model_info = 208; // JSON string
|
||||
optional string act_mode_openai_model_id = 209;
|
||||
optional string act_mode_openai_model_info = 210; // JSON string
|
||||
optional string act_mode_open_router_model_id = 207;
|
||||
optional OpenRouterModelInfo act_mode_open_router_model_info = 208;
|
||||
optional string act_mode_open_ai_model_id = 209;
|
||||
optional OpenAiCompatibleModelInfo act_mode_open_ai_model_info = 210;
|
||||
optional string act_mode_ollama_model_id = 211;
|
||||
optional string act_mode_lm_studio_model_id = 212;
|
||||
optional string act_mode_lite_llm_model_id = 213;
|
||||
optional string act_mode_lite_llm_model_info = 214; // JSON string
|
||||
optional LiteLLMModelInfo act_mode_lite_llm_model_info = 214;
|
||||
optional string act_mode_requesty_model_id = 215;
|
||||
optional string act_mode_requesty_model_info = 216; // JSON string
|
||||
optional OpenRouterModelInfo act_mode_requesty_model_info = 216;
|
||||
optional string act_mode_together_model_id = 217;
|
||||
optional string act_mode_fireworks_model_id = 218;
|
||||
optional string act_mode_sap_ai_core_model_id = 219;
|
||||
optional string act_mode_huawei_cloud_maas_model_id = 220;
|
||||
optional string act_mode_huawei_cloud_maas_model_info = 221;
|
||||
optional OpenRouterModelInfo act_mode_huawei_cloud_maas_model_info = 221;
|
||||
optional string act_mode_vercel_ai_gateway_model_id = 222;
|
||||
optional string act_mode_vercel_ai_gateway_model_info = 223;
|
||||
|
||||
// Favorited model IDs
|
||||
repeated string favorited_model_ids = 300;
|
||||
optional OpenRouterModelInfo act_mode_vercel_ai_gateway_model_info = 223;
|
||||
optional string act_mode_oca_model_id = 224;
|
||||
optional OcaModelInfo act_mode_oca_model_info = 225;
|
||||
|
||||
// Extension fields for Bedrock Api Keys
|
||||
optional string aws_authentication = 301;
|
||||
@@ -264,6 +295,11 @@ message FocusChainSettings {
|
||||
int32 remind_cline_interval = 2;
|
||||
}
|
||||
|
||||
message Viewport {
|
||||
int32 width = 1;
|
||||
int32 height = 2;
|
||||
}
|
||||
|
||||
message UpdateTerminalConnectionTimeoutResponse {
|
||||
optional int32 timeout_ms = 1;
|
||||
}
|
||||
|
||||
+6
-21
@@ -5,18 +5,6 @@ import "cline/common.proto";
|
||||
option java_package = "bot.cline.proto";
|
||||
option java_multiple_files = true;
|
||||
|
||||
// Enum for webview provider types
|
||||
enum WebviewProviderType {
|
||||
SIDEBAR = 0;
|
||||
TAB = 1;
|
||||
}
|
||||
|
||||
// Define a new message type for webview provider info
|
||||
message WebviewProviderTypeRequest {
|
||||
Metadata metadata = 1;
|
||||
WebviewProviderType provider_type = 2;
|
||||
}
|
||||
|
||||
// Enum for ClineMessage type
|
||||
enum ClineMessageType {
|
||||
ASK = 0;
|
||||
@@ -229,13 +217,13 @@ service UiService {
|
||||
rpc onDidShowAnnouncement(EmptyRequest) returns (Boolean);
|
||||
|
||||
// Subscribe to addToInput events (when user adds content via context menu)
|
||||
rpc subscribeToAddToInput(StringRequest) returns (stream String);
|
||||
rpc subscribeToAddToInput(EmptyRequest) returns (stream String);
|
||||
|
||||
// Subscribe to MCP button clicked events
|
||||
rpc subscribeToMcpButtonClicked(WebviewProviderTypeRequest) returns (stream Empty);
|
||||
rpc subscribeToMcpButtonClicked(EmptyRequest) returns (stream Empty);
|
||||
|
||||
// Subscribe to history button click events
|
||||
rpc subscribeToHistoryButtonClicked(WebviewProviderTypeRequest) returns (stream Empty);
|
||||
rpc subscribeToHistoryButtonClicked(EmptyRequest) returns (stream Empty);
|
||||
|
||||
// Subscribe to chat button clicked events (when the chat button is clicked in VSCode)
|
||||
rpc subscribeToChatButtonClicked(EmptyRequest) returns (stream Empty);
|
||||
@@ -244,22 +232,19 @@ service UiService {
|
||||
rpc subscribeToAccountButtonClicked(EmptyRequest) returns (stream Empty);
|
||||
|
||||
// Subscribe to settings button clicked events
|
||||
rpc subscribeToSettingsButtonClicked(WebviewProviderTypeRequest) returns (stream Empty);
|
||||
rpc subscribeToSettingsButtonClicked(EmptyRequest) returns (stream Empty);
|
||||
|
||||
// Subscribe to partial message updates (streaming Cline messages as they're built)
|
||||
rpc subscribeToPartialMessage(EmptyRequest) returns (stream ClineMessage);
|
||||
|
||||
// Subscribe to theme change events
|
||||
rpc subscribeToTheme(EmptyRequest) returns (stream String);
|
||||
|
||||
// Initialize webview when it launches
|
||||
rpc initializeWebview(EmptyRequest) returns (Empty);
|
||||
|
||||
// Subscribe to relinquish control events
|
||||
rpc subscribeToRelinquishControl(EmptyRequest) returns (stream Empty);
|
||||
|
||||
// Subscribe to focus chat input events with client ID
|
||||
rpc subscribeToFocusChatInput(StringRequest) returns (stream Empty);
|
||||
// Subscribe to focus chat input events
|
||||
rpc subscribeToFocusChatInput(EmptyRequest) returns (stream Empty);
|
||||
|
||||
// Subscribe to webview visibility change events
|
||||
rpc subscribeToDidBecomeVisible(EmptyRequest) returns (stream Empty);
|
||||
|
||||
Binary file not shown.
+34
-2
@@ -17,12 +17,44 @@ service EnvService {
|
||||
// Returns a stable machine identifier for telemetry distinctId purposes.
|
||||
rpc getMachineId(cline.EmptyRequest) returns (cline.String);
|
||||
|
||||
// Returns the name and version of the host IDE or environment.
|
||||
rpc getHostVersion(cline.EmptyRequest) returns (GetHostVersionResponse);
|
||||
|
||||
// Returns a URI that will redirect to the host environment.
|
||||
// e.g. vscode://saoudrizwan.claude-dev, idea://, pycharm://, etc.
|
||||
// If the host does not support URIs it should return empty.
|
||||
rpc getIdeRedirectUri(cline.EmptyRequest) returns (cline.String);
|
||||
|
||||
// Returns the telemetry settings of the host environment. This may return UNSUPPORTED
|
||||
// if the host does not specify telemetry settings for the plugin.
|
||||
rpc getTelemetrySettings(cline.EmptyRequest) returns (GetTelemetrySettingsResponse);
|
||||
|
||||
// Returns events when the telemetry settings change.
|
||||
rpc subscribeToTelemetrySettings(cline.EmptyRequest) returns (stream TelemetrySettingsEvent);
|
||||
}
|
||||
|
||||
message GetHostVersionResponse {
|
||||
// The name of the host platform, e.g VSCode
|
||||
// The name of the host platform, e.g VSCode, IntelliJ Ultimate Edition, etc.
|
||||
optional string platform = 1;
|
||||
// The version of the host platform, e.g. 1.103.0
|
||||
// The version of the host platform, e.g. 1.103.0 for VSCode, or 2025.1.1.1 for JetBrains IDEs.
|
||||
optional string version = 2;
|
||||
// The type of the cline host environment, e.g. 'VSCode Extension', 'Cline for JetBrains', 'CLI'
|
||||
// This is different from the platform because there are many JetBrains IDEs, but they all use the same
|
||||
// plugin.
|
||||
optional string cline_type = 3;
|
||||
// The version of the cline host environment, e.g. 33.2.10 for extension, or 1.0.6 for JetBrains.
|
||||
optional string cline_version = 4;
|
||||
}
|
||||
|
||||
enum Setting {
|
||||
UNSUPPORTED = 0; // This host does not support this setting.
|
||||
ENABLED = 1;
|
||||
DISABLED = 2;
|
||||
}
|
||||
message GetTelemetrySettingsResponse {
|
||||
Setting is_enabled = 1;
|
||||
}
|
||||
|
||||
message TelemetrySettingsEvent {
|
||||
Setting is_enabled = 1;
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package host;
|
||||
option java_package = "bot.cline.host.proto";
|
||||
option java_multiple_files = true;
|
||||
|
||||
import "cline/common.proto";
|
||||
|
||||
/**
|
||||
* The watch service is only here as example of a streaming rpc in the host bridge.
|
||||
* This being replaced with a native JS file watcher.
|
||||
*/
|
||||
// WatchService provides methods for watching files in the IDE
|
||||
service WatchService {
|
||||
// Subscribe to file changes
|
||||
rpc subscribeToFile(SubscribeToFileRequest) returns (stream FileChangeEvent);
|
||||
}
|
||||
|
||||
// Request to subscribe to file changes
|
||||
message SubscribeToFileRequest {
|
||||
cline.Metadata metadata = 1;
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
// Event representing a file change
|
||||
message FileChangeEvent {
|
||||
enum ChangeType {
|
||||
CREATED = 0;
|
||||
CHANGED = 1;
|
||||
DELETED = 2;
|
||||
}
|
||||
|
||||
string path = 1;
|
||||
ChangeType type = 2;
|
||||
string content = 3; // Optional content of the file after change
|
||||
}
|
||||
@@ -4,8 +4,6 @@ package host;
|
||||
option java_package = "bot.cline.host.proto";
|
||||
option java_multiple_files = true;
|
||||
|
||||
import "cline/common.proto";
|
||||
|
||||
// Provides methods for working with IDE windows and editors.
|
||||
service WindowService {
|
||||
// Opens a text document in the IDE editor and returns editor information.
|
||||
@@ -40,7 +38,6 @@ service WindowService {
|
||||
}
|
||||
|
||||
message ShowTextDocumentRequest {
|
||||
cline.Metadata metadata = 1;
|
||||
string path = 2;
|
||||
optional ShowTextDocumentOptions options = 3;
|
||||
}
|
||||
@@ -59,7 +56,6 @@ message TextEditorInfo {
|
||||
}
|
||||
|
||||
message ShowOpenDialogueRequest {
|
||||
cline.Metadata metadata = 1;
|
||||
optional bool can_select_many = 2;
|
||||
optional string open_label = 3;
|
||||
optional ShowOpenDialogueFilterOption filters = 4;
|
||||
|
||||
@@ -18,14 +18,18 @@ service WorkspaceService {
|
||||
|
||||
// Get diagnostics from the workspace.
|
||||
rpc getDiagnostics(GetDiagnosticsRequest) returns (GetDiagnosticsResponse);
|
||||
// Returns workspace items (files/folders) matching a query for mention autocomplete
|
||||
rpc searchWorkspaceItems(SearchWorkspaceItemsRequest) returns (SearchWorkspaceItemsResponse);
|
||||
|
||||
// Makes the problems panel/pane visible in the IDE and focuses it.
|
||||
rpc openProblemsPanel(OpenProblemsPanelRequest) returns (OpenProblemsPanelResponse);
|
||||
|
||||
// Opens the IDE file explorer panel and selects a file or directory.
|
||||
rpc openInFileExplorerPanel(OpenInFileExplorerPanelRequest) returns (OpenInFileExplorerPanelResponse);
|
||||
|
||||
// Opens and focuses the Cline sidebar panel in the host IDE.
|
||||
rpc openClineSidebarPanel(OpenClineSidebarPanelRequest) returns (OpenClineSidebarPanelResponse);
|
||||
|
||||
// Opens and focuses the terminal panel.
|
||||
rpc openTerminalPanel(OpenTerminalRequest) returns (OpenTerminalResponse);
|
||||
}
|
||||
|
||||
message GetWorkspacePathsRequest {
|
||||
@@ -81,8 +85,11 @@ message SearchWorkspaceItemsResponse {
|
||||
|
||||
message OpenProblemsPanelRequest {}
|
||||
message OpenProblemsPanelResponse {}
|
||||
|
||||
message OpenInFileExplorerPanelRequest {
|
||||
string path = 1;
|
||||
}
|
||||
message OpenInFileExplorerPanelResponse {}
|
||||
message OpenClineSidebarPanelRequest {}
|
||||
message OpenClineSidebarPanelResponse {}
|
||||
message OpenTerminalRequest {}
|
||||
message OpenTerminalResponse {}
|
||||
+2
-49
@@ -10,7 +10,6 @@ import * as path from "path"
|
||||
import { rmrf } from "./file-utils.mjs"
|
||||
import { main as generateHostBridgeClient } from "./generate-host-bridge-client.mjs"
|
||||
import { main as generateProtoBusSetup } from "./generate-protobus-setup.mjs"
|
||||
import { loadProtoDescriptorSet } from "./proto-utils.mjs"
|
||||
|
||||
const require = createRequire(import.meta.url)
|
||||
const PROTOC = path.join(require.resolve("grpc-tools"), "../bin/protoc")
|
||||
@@ -31,14 +30,13 @@ const TS_PROTO_OPTIONS = [
|
||||
"esModuleInterop=true",
|
||||
"outputServices=generic-definitions", // output generic ServiceDefinitions
|
||||
"outputIndex=true", // output an index file for each package which exports all protos in the package.
|
||||
"useOptionals=messages", // Message fields are optional, scalars are not.
|
||||
"useOptionals=none", // scalar and message fields are required unless they are marked as optional.
|
||||
"useDate=false", // Timestamp fields will not be automatically converted to Date.
|
||||
]
|
||||
|
||||
async function main() {
|
||||
await cleanup()
|
||||
await compileProtos()
|
||||
await checkProtos()
|
||||
await generateProtoBusSetup()
|
||||
await generateHostBridgeClient()
|
||||
}
|
||||
@@ -59,7 +57,7 @@ async function compileProtos() {
|
||||
|
||||
tsProtoc(TS_OUT_DIR, protoFiles, TS_PROTO_OPTIONS)
|
||||
// grpc-js is used to generate service impls for the ProtoBus service.
|
||||
tsProtoc(GRPC_JS_OUT_DIR, protoFiles, ["outputServices=grpc-js,outputClientImpl=false", ...TS_PROTO_OPTIONS])
|
||||
tsProtoc(GRPC_JS_OUT_DIR, protoFiles, ["outputServices=grpc-js", ...TS_PROTO_OPTIONS])
|
||||
// nice-js is used for the Host Bridge client impls because it uses promises.
|
||||
tsProtoc(NICE_JS_OUT_DIR, protoFiles, ["outputServices=nice-grpc,useExactTypes=false", ...TS_PROTO_OPTIONS])
|
||||
|
||||
@@ -187,51 +185,6 @@ function checkAppleSiliconCompatibility() {
|
||||
}
|
||||
}
|
||||
|
||||
const int64TypeNames = ["TYPE_INT64", "TYPE_UINT64", "TYPE_SINT64", "TYPE_FIXED64", "TYPE_SFIXED64"]
|
||||
|
||||
async function checkProtos() {
|
||||
const proto = await loadProtoDescriptorSet()
|
||||
const int64Fields = []
|
||||
|
||||
for (const [packageName, packageDef] of Object.entries(proto)) {
|
||||
for (const [messageName, def] of Object.entries(packageDef)) {
|
||||
// Skip service definitions
|
||||
if (def && typeof def === "object" && "service" in def) {
|
||||
continue
|
||||
}
|
||||
// Check message fields
|
||||
if (def && def.type && def.type.field) {
|
||||
for (const field of def.type.field) {
|
||||
if (int64TypeNames.includes(field.type)) {
|
||||
const name = `${packageName}.${messageName}.${field.name}`
|
||||
int64Fields.push({
|
||||
name: name,
|
||||
type: field.type,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (int64Fields.length > 0) {
|
||||
console.log(chalk.yellow(`\nWarning: Found ${int64Fields.length} fields using 64-bit integer types`))
|
||||
for (const field of int64Fields) {
|
||||
const typeNames = {
|
||||
TYPE_INT64: "int64",
|
||||
TYPE_UINT64: "uint64",
|
||||
TYPE_SINT64: "sint64",
|
||||
TYPE_FIXED64: "fixed64",
|
||||
TYPE_SFIXED64: "sfixed64",
|
||||
}
|
||||
log_verbose(chalk.yellow(` - ${field.name} (${typeNames[field.type]})`))
|
||||
}
|
||||
log_verbose(chalk.yellow("\nWARNING: 64-bit integer fields detected in proto definitions"))
|
||||
log_verbose(chalk.yellow("JavaScript cannot safely represent integers larger than 2^53-1 (Number.MAX_SAFE_INTEGER)."))
|
||||
log_verbose(chalk.yellow("Consider using string representation for large numbers or implementing BigInt support.\n"))
|
||||
}
|
||||
}
|
||||
|
||||
function log_verbose(s) {
|
||||
if (process.argv.includes("-v") || process.argv.includes("--verbose")) {
|
||||
console.log(s)
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
|
||||
/**
|
||||
* Interactive Playwright launcher for the Cline VS Code extension.
|
||||
*
|
||||
* Overview:
|
||||
* - Starts the mock Cline API server (from the e2e test fixtures).
|
||||
* - Downloads a stable build of VS Code (via @vscode/test-electron).
|
||||
* - Creates a temporary VS Code user profile directory.
|
||||
* - Installs and links the Cline extension (from dist/e2e.vsix and the dev path).
|
||||
* - Opens a test workspace and automatically reveals the Cline sidebar.
|
||||
* - Records **all gRPC calls** during the session for later inspection.
|
||||
* - Keeps VS Code running for manual interactive testing until the window is closed or Ctrl+C is pressed.
|
||||
* - Cleans up all resources (mock server, temp profile, Electron process) on exit.
|
||||
*
|
||||
* Usage:
|
||||
* 1. (Optional) Build and install the e2e extension:
|
||||
* npm run test:e2e:build
|
||||
*
|
||||
* 2. From the repo root, start the interactive session:
|
||||
* npm run test:playwright:interactive
|
||||
*
|
||||
* 3. VS Code will launch with the Cline extension loaded and gRPC recording enabled.
|
||||
*
|
||||
* 4. Interact with the extension manually.
|
||||
*
|
||||
* 5. Close the VS Code window or press Ctrl+C to end the session and trigger cleanup.
|
||||
*/
|
||||
|
||||
import { downloadAndUnzipVSCode, SilentReporter } from "@vscode/test-electron"
|
||||
import { mkdtempSync } from "fs"
|
||||
import os from "os"
|
||||
import path from "path"
|
||||
import { _electron } from "playwright"
|
||||
import { ClineApiServerMock } from "../src/test/e2e/fixtures/server"
|
||||
import { E2ETestHelper } from "../src/test/e2e/utils/helpers"
|
||||
|
||||
async function main() {
|
||||
await ClineApiServerMock.startGlobalServer()
|
||||
|
||||
const userDataDir = mkdtempSync(path.join(os.tmpdir(), "vsce-interactive"))
|
||||
const executablePath = await downloadAndUnzipVSCode("stable", undefined, new SilentReporter())
|
||||
|
||||
// launch VSCode
|
||||
const app = await _electron.launch({
|
||||
executablePath,
|
||||
env: {
|
||||
...process.env,
|
||||
TEMP_PROFILE: "true",
|
||||
E2E_TEST: "true",
|
||||
CLINE_ENVIRONMENT: "local",
|
||||
GRPC_RECORDER_ENABLED: "true",
|
||||
GRPC_RECORDER_TESTS_FILTERS_ENABLED: "true",
|
||||
},
|
||||
args: [
|
||||
"--no-sandbox",
|
||||
"--disable-updates",
|
||||
"--disable-workspace-trust",
|
||||
"--disable-extensions",
|
||||
"--skip-welcome",
|
||||
"--skip-release-notes",
|
||||
`--user-data-dir=${userDataDir}`,
|
||||
`--install-extension=${path.join(E2ETestHelper.CODEBASE_ROOT_DIR, "dist", "e2e.vsix")}`,
|
||||
`--extensionDevelopmentPath=${E2ETestHelper.CODEBASE_ROOT_DIR}`,
|
||||
path.join(E2ETestHelper.E2E_TESTS_DIR, "fixtures", "workspace"),
|
||||
],
|
||||
})
|
||||
|
||||
const page = await app.firstWindow()
|
||||
|
||||
await E2ETestHelper.openClineSidebar(page)
|
||||
|
||||
console.log("VSCode with Cline extension is now running!")
|
||||
console.log(`Temporary data directory on: ${userDataDir}`)
|
||||
console.log("You can manually interact with the extension.")
|
||||
console.log("Press Ctrl+C to close when done.")
|
||||
|
||||
async function teardown() {
|
||||
console.log("Cleaning up resources...")
|
||||
try {
|
||||
await app?.close()
|
||||
await ClineApiServerMock.stopGlobalServer?.()
|
||||
await E2ETestHelper.rmForRetries(userDataDir, { recursive: true })
|
||||
} catch (e) {
|
||||
console.log(`We could teardown interactive playwright properly, error:${e}`)
|
||||
}
|
||||
console.log("Finished cleaning up resources...")
|
||||
}
|
||||
|
||||
process.on("SIGINT", async () => {
|
||||
await teardown()
|
||||
process.exit(0)
|
||||
})
|
||||
|
||||
process.on("SIGTERM", async () => {
|
||||
await teardown()
|
||||
process.exit(0)
|
||||
})
|
||||
|
||||
const win = await app.firstWindow()
|
||||
win.on("close", async () => {
|
||||
console.log("VS Code window closed.")
|
||||
await teardown()
|
||||
process.exit(0)
|
||||
})
|
||||
process.stdin.resume()
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error("Failed to start:", err)
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -6,40 +6,102 @@ import fs from "fs"
|
||||
import { cp } from "fs/promises"
|
||||
import { glob } from "glob"
|
||||
import minimatch from "minimatch"
|
||||
import os from "os"
|
||||
import path from "path"
|
||||
import { rmrf } from "./file-utils.mjs"
|
||||
|
||||
const BUILD_DIR = "dist-standalone"
|
||||
const BINARIES_DIR = `${BUILD_DIR}/binaries`
|
||||
const RUNTIME_DEPS_DIR = "standalone/runtime-files"
|
||||
const IS_DEBUG_BUILD = process.env.IS_DEBUG_BUILD === "true"
|
||||
|
||||
// This should match the node version packaged with the JetBrains plugin.
|
||||
const TARGET_NODE_VERSION = "22.15.0"
|
||||
const TARGET_PLATFORMS = [
|
||||
{ platform: "win32", arch: "x64", targetDir: "win-x64" },
|
||||
{ platform: "darwin", arch: "x64", targetDir: "darwin-x64" },
|
||||
{ platform: "darwin", arch: "arm64", targetDir: "darwin-arm64" },
|
||||
{ platform: "linux", arch: "x64", targetDir: "linux-x64" },
|
||||
]
|
||||
const SUPPORTED_BINARY_MODULES = ["better-sqlite3"]
|
||||
|
||||
const UNIVERSAL_BUILD = !process.argv.includes("-s")
|
||||
const IS_VERBOSE = process.argv.includes("-v") || process.argv.includes("--verbose")
|
||||
|
||||
async function main() {
|
||||
await installNodeDependencies()
|
||||
if (UNIVERSAL_BUILD) {
|
||||
console.log("Building universal package for all platforms...")
|
||||
await packageAllBinaryDeps()
|
||||
} else {
|
||||
console.log(`Building package for ${os.platform()}-${os.arch()}...`)
|
||||
}
|
||||
await zipDistribution()
|
||||
}
|
||||
|
||||
async function installNodeDependencies() {
|
||||
// Clean modules from any previous builds
|
||||
await rmrf(path.join(BUILD_DIR, "node_modules"))
|
||||
await rmrf(path.join(BINARIES_DIR))
|
||||
|
||||
await cpr(RUNTIME_DEPS_DIR, BUILD_DIR)
|
||||
|
||||
console.log("Running npm install in distribution directory...")
|
||||
const cwd = process.cwd()
|
||||
process.chdir(BUILD_DIR)
|
||||
execSync("npm install", { stdio: "inherit", cwd: BUILD_DIR })
|
||||
|
||||
try {
|
||||
execSync("npm install", { stdio: "inherit" })
|
||||
// Move the vscode directory into node_modules.
|
||||
// It can't be installed using npm because it will create a symlink which cannot be unzipped correctly on windows.
|
||||
fs.renameSync("vscode", path.join("node_modules", "vscode"))
|
||||
} catch (error) {
|
||||
console.error("Error during setup:", error)
|
||||
// Move the vscode directory into node_modules.
|
||||
// It can't be installed using npm because it will create a symlink which cannot be unzipped correctly on windows.
|
||||
fs.renameSync(`${BUILD_DIR}/vscode`, `${BUILD_DIR}/node_modules/vscode`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads prebuilt binaries for each platform for the modules that include binaries. It uses `npx prebuild-install`
|
||||
* to download the binary.
|
||||
*
|
||||
* The modules are downloaded to dist-standalone/binaries/{os}-{platform}/.
|
||||
* When cline-core is installed, the installer should use the correct module for the current platform.
|
||||
*/
|
||||
async function packageAllBinaryDeps() {
|
||||
// Check for native .node modules.
|
||||
const allNativeModules = await glob("**/*.node", { cwd: path.join(BUILD_DIR, "node_modules"), nodir: true })
|
||||
const isAllowed = (path) => SUPPORTED_BINARY_MODULES.some((allowed) => path.includes(allowed))
|
||||
const blocked = allNativeModules.filter((x) => !isAllowed(x))
|
||||
|
||||
if (blocked.length > 0) {
|
||||
console.error(`Error: Native node modules cannot be included in the standalone distribution:\n\n${blocked.join("\n")}`)
|
||||
console.error(
|
||||
"\nThese modules must support prebuilt-install and be added to the supported list in scripts/package-standalone.mjs",
|
||||
)
|
||||
process.exit(1)
|
||||
} finally {
|
||||
process.chdir(cwd)
|
||||
}
|
||||
|
||||
// Check for native .node modules.
|
||||
const nativeModules = await glob("**/*.node", { cwd: BUILD_DIR, nodir: true })
|
||||
if (nativeModules.length > 0) {
|
||||
console.error("Native node modules cannot be included in the standalone distribution:\n", nativeModules.join("\n"))
|
||||
process.exit(1)
|
||||
for (const module of SUPPORTED_BINARY_MODULES) {
|
||||
console.log(`Installing binaries for ${module}...`)
|
||||
const src = path.join(BUILD_DIR, "node_modules", module)
|
||||
if (!fs.existsSync(src)) {
|
||||
console.warn(`Warning: Trying to install binaries for the module '${module}', but it is not being used by cline.`)
|
||||
continue
|
||||
}
|
||||
|
||||
for (const { platform, arch, targetDir } of TARGET_PLATFORMS) {
|
||||
const binaryDir = `${BINARIES_DIR}/${targetDir}/node_modules`
|
||||
fs.mkdirSync(binaryDir, { recursive: true })
|
||||
|
||||
// Copy the module from the build dir
|
||||
const dest = path.join(binaryDir, module)
|
||||
await cpr(src, dest)
|
||||
|
||||
// Download the binary libs
|
||||
const v = IS_VERBOSE ? "--verbose" : ""
|
||||
const cmd = `npx prebuild-install --platform=${platform} --arch=${arch} --target=${TARGET_NODE_VERSION} ${v}`
|
||||
log_verbose(`${module}: ${cmd}`)
|
||||
execSync(cmd, { cwd: dest, stdio: "inherit" })
|
||||
log_verbose("")
|
||||
}
|
||||
// Remove the original module with the host platform binaries installed directly into node_modules.
|
||||
log_verbose(`Cleaning up host version of ${module}`)
|
||||
await rmrf(src)
|
||||
log_verbose("")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,10 +109,13 @@ async function zipDistribution() {
|
||||
// Zip the build directory (excluding any pre-existing output zip).
|
||||
const zipPath = path.join(BUILD_DIR, "standalone.zip")
|
||||
const output = fs.createWriteStream(zipPath)
|
||||
const archive = archiver("zip", { zlib: { level: 3 } })
|
||||
const startTime = Date.now()
|
||||
const archive = archiver("zip", { zlib: { level: 6 } })
|
||||
|
||||
output.on("close", () => {
|
||||
console.log(`Created ${zipPath} (${(archive.pointer() / 1024 / 1024).toFixed(1)} MB)`)
|
||||
const endTime = Date.now()
|
||||
const duration = (endTime - startTime) / 1000
|
||||
console.log(`Created ${zipPath} (${(archive.pointer() / 1024 / 1024).toFixed(1)} MB) in ${duration.toFixed(2)} seconds`)
|
||||
})
|
||||
archive.on("warning", (err) => {
|
||||
console.warn(`Warning: ${err}`)
|
||||
@@ -73,7 +138,7 @@ async function zipDistribution() {
|
||||
// Add the whole cline directory under "extension", except the for the ignored files.
|
||||
archive.directory(process.cwd(), "extension", (entry) => {
|
||||
if (isIgnored(entry.name)) {
|
||||
log_verbose("Ignoring", entry.name)
|
||||
//log_verbose("Ignoring", entry.name)
|
||||
return false
|
||||
}
|
||||
return entry
|
||||
@@ -145,7 +210,7 @@ function createIsIgnored(standaloneIgnores) {
|
||||
let allIgnore = [...defaultIgnore, ...expandedIgnore, ...standaloneIgnores]
|
||||
|
||||
// Map files need to be included in the debug build. Remove .map ignores when IS_DEBUG_BUILD is set
|
||||
if (process.env.IS_DEBUG_BUILD) {
|
||||
if (IS_DEBUG_BUILD) {
|
||||
allIgnore = allIgnore.filter((pattern) => !pattern.endsWith(".map"))
|
||||
console.log("Debug build: Including .map files in package")
|
||||
}
|
||||
@@ -167,6 +232,7 @@ function createIsIgnored(standaloneIgnores) {
|
||||
|
||||
/* cp -r */
|
||||
async function cpr(source, dest) {
|
||||
log_verbose(`Copying ${source} -> ${dest}`)
|
||||
await cp(source, dest, {
|
||||
recursive: true,
|
||||
preserveTimestamps: true,
|
||||
@@ -175,7 +241,7 @@ async function cpr(source, dest) {
|
||||
}
|
||||
|
||||
function log_verbose(...args) {
|
||||
if (process.argv.includes("-v") || process.argv.includes("--verbose")) {
|
||||
if (IS_VERBOSE) {
|
||||
console.log(...args)
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+377
@@ -0,0 +1,377 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Nightly publish script for VS Code extension
|
||||
* Converts package.json to testing version, packages, publishes, and restores
|
||||
*
|
||||
* This script:
|
||||
* 1. Backs up the original package.json
|
||||
* 2. Updates package.json with:
|
||||
* - New version (major.minor.timestamp format)
|
||||
* - Changes name to "cline-nightly"
|
||||
* - Changes displayName to "Cline (Nightly)"
|
||||
* 3. Packages the extension as a .vsix file
|
||||
* 4. Publishes to VS Code Marketplace (if VSCE_PAT is set)
|
||||
* 5. Publishes to OpenVSX Registry (if OVSX_PAT is set)
|
||||
* 6. Restores the original package.json
|
||||
*
|
||||
* Usage:
|
||||
* npm run publish:marketplace:nightly
|
||||
* npm run publish:marketplace:nightly -- --dry-run
|
||||
*
|
||||
* Environment variables:
|
||||
* VSCE_PAT - Personal Access Token for VS Code Marketplace
|
||||
* OVSX_PAT - Personal Access Token for OpenVSX Registry
|
||||
*
|
||||
* Dependencies:
|
||||
* - vsce (VS Code Extension Manager)
|
||||
* - ovsx (OpenVSX CLI)
|
||||
*/
|
||||
|
||||
import { execFileSync, execSync } from "node:child_process"
|
||||
import fs from "node:fs"
|
||||
import path from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
|
||||
// Get __dirname equivalent in ES modules
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
// ANSI color codes for console output
|
||||
const colors = {
|
||||
reset: "\x1b[0m",
|
||||
red: "\x1b[31m",
|
||||
green: "\x1b[32m",
|
||||
yellow: "\x1b[33m",
|
||||
}
|
||||
|
||||
// Logging utilities
|
||||
const log = {
|
||||
info: (msg) => console.log(`${colors.green}[INFO]${colors.reset} ${msg}`),
|
||||
warn: (msg) => console.log(`${colors.yellow}[WARN]${colors.reset} ${msg}`),
|
||||
error: (msg) => console.error(`${colors.red}[ERROR]${colors.reset} ${msg}`),
|
||||
}
|
||||
|
||||
// Configuration
|
||||
const config = {
|
||||
// The name and display name for the nightly version
|
||||
nightlyName: "cline-nightly",
|
||||
nightlyDisplayName: "Cline (Nightly)",
|
||||
projectRoot: path.join(__dirname, ".."),
|
||||
get packageJsonPath() {
|
||||
return path.join(this.projectRoot, "package.json")
|
||||
},
|
||||
get packageBackupPath() {
|
||||
return path.join(this.projectRoot, "package.json.backup")
|
||||
},
|
||||
get distDir() {
|
||||
return path.join(this.projectRoot, "dist")
|
||||
},
|
||||
get vsixPath() {
|
||||
return path.join(this.distDir, "cline-nightly.vsix")
|
||||
},
|
||||
}
|
||||
|
||||
// Utility class for managing the publish process
|
||||
class NightlyPublisher {
|
||||
constructor() {
|
||||
this.originalPackageJson = null
|
||||
this.hasBackup = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if required dependencies are installed
|
||||
*/
|
||||
checkDependencies() {
|
||||
const dependencies = [
|
||||
{ name: "vsce", check: "vsce --version" },
|
||||
{ name: "npx", check: "npx --version" },
|
||||
]
|
||||
|
||||
const missing = []
|
||||
|
||||
for (const dep of dependencies) {
|
||||
try {
|
||||
execSync(dep.check, { stdio: "ignore" })
|
||||
} catch {
|
||||
missing.push(dep.name)
|
||||
}
|
||||
}
|
||||
|
||||
if (missing.length > 0) {
|
||||
throw new Error(
|
||||
`Missing required dependencies: ${missing.join(", ")}. Please install them before running this script.`,
|
||||
)
|
||||
}
|
||||
|
||||
log.info("All dependencies are installed")
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a command exists
|
||||
*/
|
||||
commandExists(command) {
|
||||
try {
|
||||
execSync(`which ${command}`, { stdio: "ignore" })
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create backup of package.json
|
||||
*/
|
||||
backupPackageJson() {
|
||||
if (!fs.existsSync(config.packageJsonPath)) {
|
||||
throw new Error(`package.json not found at ${config.packageJsonPath}`)
|
||||
}
|
||||
|
||||
log.info("Backing up original package.json")
|
||||
this.originalPackageJson = fs.readFileSync(config.packageJsonPath, "utf-8")
|
||||
fs.writeFileSync(config.packageBackupPath, this.originalPackageJson)
|
||||
this.hasBackup = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore original package.json
|
||||
*/
|
||||
restorePackageJson() {
|
||||
if (this.hasBackup && fs.existsSync(config.packageBackupPath)) {
|
||||
log.info("Restoring original package.json")
|
||||
fs.writeFileSync(config.packageJsonPath, this.originalPackageJson)
|
||||
fs.unlinkSync(config.packageBackupPath)
|
||||
this.hasBackup = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate new version with timestamp
|
||||
* Format: major.minor.timestamp
|
||||
*/
|
||||
generateVersion(currentVersion) {
|
||||
// Extract major.minor from current version (e.g., "3.27.1" -> "3.27")
|
||||
const versionParts = currentVersion.split(".")
|
||||
if (versionParts.length < 2) {
|
||||
throw new Error(`Invalid version format: ${currentVersion}`)
|
||||
}
|
||||
|
||||
const major = versionParts[0]
|
||||
const minor = versionParts[1]
|
||||
const timestamp = Math.floor(Date.now() / 1000)
|
||||
|
||||
return `${major}.${minor}.${timestamp}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Update package.json with nightly configuration
|
||||
*/
|
||||
updatePackageJson() {
|
||||
// Replace any occurrences cline. or claude-dev with nightly name
|
||||
const rawContent = fs.readFileSync(config.packageJsonPath, "utf-8")
|
||||
const content = rawContent.replaceAll("claude-dev", config.nightlyName).replaceAll('"cline.', `"${config.nightlyName}.`)
|
||||
|
||||
const pkg = JSON.parse(content)
|
||||
const currentVersion = pkg.version
|
||||
|
||||
if (!currentVersion) {
|
||||
throw new Error("Could not read version from package.json")
|
||||
}
|
||||
|
||||
log.info(`Current version: ${currentVersion}`)
|
||||
|
||||
const newVersion = this.generateVersion(currentVersion)
|
||||
log.info(`New version: ${newVersion}`)
|
||||
|
||||
// Update package.json fields
|
||||
pkg.version = newVersion
|
||||
pkg.name = config.nightlyName
|
||||
pkg.displayName = config.nightlyDisplayName
|
||||
pkg.contributes.viewsContainers.activitybar.title = config.nightlyDisplayName
|
||||
|
||||
// Save updated package.json
|
||||
log.info("Updating package.json for nightly build")
|
||||
fs.writeFileSync(config.packageJsonPath, JSON.stringify(pkg, null, "\t"))
|
||||
|
||||
return newVersion
|
||||
}
|
||||
|
||||
/**
|
||||
* Package the extension
|
||||
*/
|
||||
packageExtension() {
|
||||
// Ensure dist directory exists
|
||||
if (!fs.existsSync(config.distDir)) {
|
||||
fs.mkdirSync(config.distDir, { recursive: true })
|
||||
}
|
||||
|
||||
log.info("Packaging extension")
|
||||
|
||||
const args = ["package", "--pre-release", "--no-update-package-json", "--no-git-tag-version", "--out", config.vsixPath]
|
||||
|
||||
try {
|
||||
execFileSync("vsce", args, {
|
||||
stdio: "inherit",
|
||||
cwd: config.projectRoot,
|
||||
})
|
||||
log.info(`Package created: ${config.vsixPath}`)
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to package extension: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish to VS Code Marketplace
|
||||
*/
|
||||
publishToVSCodeMarketplace() {
|
||||
const token = process.env.VSCE_PAT
|
||||
|
||||
if (!token) {
|
||||
log.warn("VSCE_PAT not set, skipping VS Code Marketplace publish")
|
||||
return false
|
||||
}
|
||||
|
||||
log.info("Publishing to VS Code Marketplace")
|
||||
|
||||
const args = ["publish", "--pre-release", "--no-git-tag-version", "--packagePath", config.vsixPath]
|
||||
|
||||
try {
|
||||
execFileSync("vsce", args, {
|
||||
env: { ...process.env, VSCE_PAT: token },
|
||||
stdio: "inherit",
|
||||
cwd: config.projectRoot,
|
||||
})
|
||||
log.info("Successfully published to VS Code Marketplace")
|
||||
return true
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to publish to VS Code Marketplace: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish to OpenVSX Registry
|
||||
*/
|
||||
publishToOpenVSX() {
|
||||
const token = process.env.OVSX_PAT
|
||||
|
||||
if (!token) {
|
||||
log.warn("OVSX_PAT not set, skipping OpenVSX Registry publish")
|
||||
return false
|
||||
}
|
||||
|
||||
log.info("Publishing to OpenVSX Registry")
|
||||
|
||||
const args = ["ovsx", "publish", "--pre-release", "--packagePath", config.vsixPath, "--pat", token]
|
||||
|
||||
try {
|
||||
execFileSync("npx", args, {
|
||||
stdio: "inherit",
|
||||
cwd: config.projectRoot,
|
||||
})
|
||||
log.info("Successfully published to OpenVSX Registry")
|
||||
return true
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to publish to OpenVSX Registry: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main execution flow
|
||||
*/
|
||||
async run(isDryRun = false) {
|
||||
try {
|
||||
log.info(`Starting nightly publish process${isDryRun ? " (dry run)" : ""}`)
|
||||
|
||||
// Step 1: Check dependencies
|
||||
this.checkDependencies()
|
||||
|
||||
// Step 2: Backup package.json
|
||||
this.backupPackageJson()
|
||||
|
||||
// Step 3: Update package.json
|
||||
const newVersion = this.updatePackageJson()
|
||||
|
||||
// Step 4: Package extension
|
||||
this.packageExtension()
|
||||
|
||||
// Step 5: Publish to marketplaces (skip if dry run)
|
||||
let vsCodePublished = false
|
||||
let openVSXPublished = false
|
||||
|
||||
if (isDryRun) {
|
||||
log.info("Dry run mode: Skipping marketplace publishing")
|
||||
} else {
|
||||
vsCodePublished = this.publishToVSCodeMarketplace()
|
||||
openVSXPublished = this.publishToOpenVSX()
|
||||
}
|
||||
|
||||
// Summary
|
||||
log.info(`Nightly publish process completed successfully${isDryRun ? " (dry run)" : ""}`)
|
||||
log.info(`Package created for v${newVersion}: ${config.vsixPath}`)
|
||||
|
||||
if (!isDryRun && !vsCodePublished && !openVSXPublished) {
|
||||
log.warn("Extension was packaged but not published to any marketplace")
|
||||
log.warn("Set VSCE_PAT and/or OVSX_PAT environment variables to enable publishing")
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(`Publish failed: ${error.message}`)
|
||||
process.exit(1)
|
||||
} finally {
|
||||
// Always restore package.json
|
||||
this.restorePackageJson()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle cleanup on process exit
|
||||
const publisher = new NightlyPublisher()
|
||||
|
||||
process.on("exit", () => {
|
||||
publisher.restorePackageJson()
|
||||
})
|
||||
|
||||
process.on("SIGINT", () => {
|
||||
log.info("\nInterrupted, cleaning up...")
|
||||
publisher.restorePackageJson()
|
||||
process.exit(130)
|
||||
})
|
||||
|
||||
process.on("SIGTERM", () => {
|
||||
log.info("\nTerminated, cleaning up...")
|
||||
publisher.restorePackageJson()
|
||||
process.exit(143)
|
||||
})
|
||||
|
||||
// Parse command line arguments
|
||||
const args = process.argv.slice(2)
|
||||
const isDryRun = args.includes("--dry-run") || args.includes("-n")
|
||||
const showHelp = args.includes("--help") || args.includes("-h")
|
||||
|
||||
if (showHelp) {
|
||||
console.log(`
|
||||
Nightly publish script for VS Code extension
|
||||
|
||||
Usage:
|
||||
npm run publish:marketplace:nightly [options]
|
||||
|
||||
Options:
|
||||
--dry-run, -n Run without actually publishing (package only)
|
||||
--help, -h Show this help message
|
||||
|
||||
Environment variables:
|
||||
VSCE_PAT Personal Access Token for VS Code Marketplace
|
||||
OVSX_PAT Personal Access Token for OpenVSX Registry
|
||||
|
||||
Examples:
|
||||
npm run publish:marketplace:nightly # Full publish
|
||||
npm run publish:marketplace:nightly -- --dry-run # Package only
|
||||
VSCE_PAT="token" npm run publish:marketplace:nightly # Publish to VS Code only
|
||||
`)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// Run the publisher
|
||||
publisher.run(isDryRun).catch((error) => {
|
||||
log.error(error.message)
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -9,7 +9,7 @@ if [[ "${1:-}" == "-h" ]]; then
|
||||
fi
|
||||
|
||||
CORE_DIR=~/.cline/core
|
||||
INSTALL_DIR=$CORE_DIR/0.0.1
|
||||
INSTALL_DIR=$CORE_DIR/dev-instance/
|
||||
LOG_FILE=~/.cline/cline-core-service.log
|
||||
|
||||
ZIP_FILE=standalone.zip
|
||||
@@ -25,4 +25,6 @@ unp $ZIP_FILE > /dev/null
|
||||
|
||||
pkill -f cline-core.js || true
|
||||
|
||||
echo pwd: $(pwd)
|
||||
set -x
|
||||
NODE_PATH=./node_modules DEV_WORKSPACE_FOLDER=/tmp/ node cline-core.js 2>&1 | tee $LOG_FILE
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
const { execSync } = require("child_process")
|
||||
const process = require("process")
|
||||
|
||||
try {
|
||||
if (process.platform === "linux") {
|
||||
console.log("Detected Linux environment.")
|
||||
|
||||
execSync("which xvfb-run", { stdio: "ignore" })
|
||||
|
||||
console.log("xvfb-run is installed. Running tests with xvfb-run...")
|
||||
execSync("xvfb-run -a npm run test:coverage", { stdio: "inherit" })
|
||||
} else {
|
||||
console.log("Non-Linux environment detected. Running tests normally.")
|
||||
execSync("npm run test:integration", { stdio: "inherit" })
|
||||
}
|
||||
} catch (error) {
|
||||
if (process.platform === "linux") {
|
||||
console.error(
|
||||
`Error: xvfb-run is not installed.\n` +
|
||||
`Please install it using the following command:\n` +
|
||||
` Debian/Ubuntu: sudo apt install xvfb\n` +
|
||||
` RHEL/CentOS: sudo yum install xvfb\n` +
|
||||
` Arch Linux: sudo pacman -S xvfb`,
|
||||
)
|
||||
} else {
|
||||
console.error("Error running tests:", error.message)
|
||||
}
|
||||
process.exit(1)
|
||||
}
|
||||
@@ -3,7 +3,11 @@ import * as grpc from "@grpc/grpc-js"
|
||||
import { ReflectionService } from "@grpc/reflection"
|
||||
import * as health from "grpc-health-check"
|
||||
import * as os from "os"
|
||||
import { host } from "src/generated/grpc-js/index"
|
||||
import { type DiffServiceServer, DiffServiceService } from "../src/generated/grpc-js/host/diff"
|
||||
import { type EnvServiceServer, EnvServiceService } from "../src/generated/grpc-js/host/env"
|
||||
import { type TestingServiceServer, TestingServiceService } from "../src/generated/grpc-js/host/testing"
|
||||
import { type WindowServiceServer, WindowServiceService } from "../src/generated/grpc-js/host/window"
|
||||
import { type WorkspaceServiceServer, WorkspaceServiceService } from "../src/generated/grpc-js/host/workspace"
|
||||
import { getPackageDefinition } from "./proto-utils.mjs"
|
||||
|
||||
export async function startTestHostBridgeServer() {
|
||||
@@ -14,11 +18,11 @@ export async function startTestHostBridgeServer() {
|
||||
healthImpl.addToServer(server)
|
||||
|
||||
// Add host bridge services using the mock implementations
|
||||
server.addService(host.WorkspaceServiceService, createMockService<host.WorkspaceServiceServer>("WorkspaceService"))
|
||||
server.addService(host.WindowServiceService, createMockService<host.WindowServiceServer>("WindowService"))
|
||||
server.addService(host.EnvServiceService, createMockService<host.EnvServiceServer>("EnvService"))
|
||||
server.addService(host.DiffServiceService, createMockService<host.DiffServiceServer>("DiffService"))
|
||||
server.addService(host.WatchServiceService, createMockService<host.WatchServiceServer>("WatchService"))
|
||||
server.addService(WorkspaceServiceService, createMockService<WorkspaceServiceServer>("WorkspaceService"))
|
||||
server.addService(WindowServiceService, createMockService<WindowServiceServer>("WindowService"))
|
||||
server.addService(EnvServiceService, createMockService<EnvServiceServer>("EnvService"))
|
||||
server.addService(DiffServiceService, createMockService<DiffServiceServer>("DiffService"))
|
||||
server.addService(TestingServiceService, createMockService<TestingServiceServer>("TestingService"))
|
||||
|
||||
// Load package definition for reflection service
|
||||
const packageDefinition = await getPackageDefinition()
|
||||
@@ -58,8 +62,9 @@ function createMockService<T extends grpc.UntypedServiceImplementation>(serviceN
|
||||
// Special cases that need specific return values
|
||||
switch (prop) {
|
||||
case "getWorkspacePaths":
|
||||
const workspaceDir = process.env.TEST_HOSTBRIDGE_WORKSPACE_DIR || "/test-workspace"
|
||||
callback(null, {
|
||||
paths: ["/test-workspace"],
|
||||
paths: [workspaceDir],
|
||||
})
|
||||
return
|
||||
|
||||
@@ -69,6 +74,12 @@ function createMockService<T extends grpc.UntypedServiceImplementation>(serviceN
|
||||
})
|
||||
return
|
||||
|
||||
case "getTelemetrySettings":
|
||||
callback(null, {
|
||||
isEnabled: 2, // Setting.DISABLED
|
||||
})
|
||||
return
|
||||
|
||||
case "clipboardReadText":
|
||||
callback(null, {
|
||||
value: "",
|
||||
@@ -115,8 +126,8 @@ function createMockService<T extends grpc.UntypedServiceImplementation>(serviceN
|
||||
})
|
||||
return
|
||||
|
||||
// For streaming methods (like subscribeToFile)
|
||||
case "subscribeToFile":
|
||||
// For streaming methods (like subscribeToTelemetrySettings)
|
||||
case "subscribeToTelemetrySettings":
|
||||
// Just end the stream immediately
|
||||
call.end()
|
||||
return
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
|
||||
/**
|
||||
* Simple Cline gRPC Server
|
||||
*
|
||||
* This script provides a minimal way to run the Cline core gRPC service
|
||||
* without requiring the full installation, while automatically mocking all external services. Simply run:
|
||||
*
|
||||
* # One-time setup (generates protobuf files)
|
||||
* npm run compile-standalone
|
||||
* npm run test:sca-server
|
||||
*
|
||||
* The following components are started automatically:
|
||||
* 1. HostBridge test server
|
||||
* 2. ClineApiServerMock (mock implementation of the Cline API)
|
||||
* 3. AuthServiceMock (activated if E2E_TEST="true")
|
||||
*
|
||||
* Environment Variables for Customization:
|
||||
* PROJECT_ROOT - Override project root directory (default: parent of scripts dir)
|
||||
* CLINE_DIST_DIR - Override distribution directory (default: PROJECT_ROOT/dist-standalone)
|
||||
* CLINE_CORE_FILE - Override core file name (default: cline-core.js)
|
||||
* PROTOBUS_PORT - gRPC server port (default: 26040)
|
||||
* HOSTBRIDGE_PORT - HostBridge server port (default: 26041)
|
||||
* WORKSPACE_DIR - Working directory (default: current directory)
|
||||
* E2E_TEST - Enable E2E test mode (default: true)
|
||||
* CLINE_ENVIRONMENT - Environment setting (default: local)
|
||||
*
|
||||
* Ideal for local development, testing, or lightweight E2E scenarios.
|
||||
*/
|
||||
|
||||
import * as fs from "node:fs"
|
||||
import { mkdtempSync, rmSync } from "node:fs"
|
||||
import * as os from "node:os"
|
||||
import { ChildProcess, execSync, spawn } from "child_process"
|
||||
import * as path from "path"
|
||||
import { ClineApiServerMock } from "../src/test/e2e/fixtures/server/index"
|
||||
|
||||
const PROTOBUS_PORT = process.env.PROTOBUS_PORT || "26040"
|
||||
const HOSTBRIDGE_PORT = process.env.HOSTBRIDGE_PORT || "26041"
|
||||
const WORKSPACE_DIR = process.env.WORKSPACE_DIR || process.cwd()
|
||||
const E2E_TEST = process.env.E2E_TEST || "true"
|
||||
const CLINE_ENVIRONMENT = process.env.CLINE_ENVIRONMENT || "local"
|
||||
const USE_C8 = process.env.USE_C8 === "true"
|
||||
|
||||
// Locate the standalone build directory and core file with flexible path resolution
|
||||
const projectRoot = process.env.PROJECT_ROOT || path.resolve(__dirname, "..")
|
||||
const distDir = process.env.CLINE_DIST_DIR || path.join(projectRoot, "dist-standalone")
|
||||
const clineCoreFile = process.env.CLINE_CORE_FILE || "cline-core.js"
|
||||
const coreFile = path.join(distDir, clineCoreFile)
|
||||
|
||||
const childProcesses: ChildProcess[] = []
|
||||
|
||||
async function main(): Promise<void> {
|
||||
console.log("Starting Simple Cline gRPC Server...")
|
||||
console.log(`Project Root: ${projectRoot}`)
|
||||
console.log(`Workspace: ${WORKSPACE_DIR}`)
|
||||
console.log(`ProtoBus Port: ${PROTOBUS_PORT}`)
|
||||
console.log(`HostBridge Port: ${HOSTBRIDGE_PORT}`)
|
||||
|
||||
console.log(`Looking for standalone build at: ${coreFile}`)
|
||||
|
||||
if (!fs.existsSync(coreFile)) {
|
||||
console.error(`Standalone build not found at: ${coreFile}`)
|
||||
console.error("Available environment variables for customization:")
|
||||
console.error(" PROJECT_ROOT - Override project root directory")
|
||||
console.error(" CLINE_DIST_DIR - Override distribution directory")
|
||||
console.error(" CLINE_CORE_FILE - Override core file name")
|
||||
console.error("")
|
||||
console.error("To build the standalone version, run: npm run compile-standalone")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
try {
|
||||
await ClineApiServerMock.startGlobalServer()
|
||||
console.log("Cline API Server started in-process")
|
||||
} catch (error) {
|
||||
console.error("Failed to start Cline API Server:", error)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const extensionsDir = path.join(distDir, "vsce-extension")
|
||||
const userDataDir = mkdtempSync(path.join(os.tmpdir(), "vsce"))
|
||||
const clineTestWorkspace = mkdtempSync(path.join(os.tmpdir(), "cline-test-workspace-"))
|
||||
|
||||
console.log("Starting HostBridge test server...")
|
||||
const hostbridge: ChildProcess = spawn("npx", ["tsx", path.join(__dirname, "test-hostbridge-server.ts")], {
|
||||
stdio: "pipe",
|
||||
env: {
|
||||
...process.env,
|
||||
TEST_HOSTBRIDGE_WORKSPACE_DIR: clineTestWorkspace,
|
||||
HOST_BRIDGE_ADDRESS: `127.0.0.1:${HOSTBRIDGE_PORT}`,
|
||||
},
|
||||
})
|
||||
childProcesses.push(hostbridge)
|
||||
|
||||
console.log(`Temp user data dir: ${userDataDir}`)
|
||||
console.log(`Temp extensions dir: ${extensionsDir}`)
|
||||
// Extract standalone.zip if needed
|
||||
const standaloneZipPath = path.join(distDir, "standalone.zip")
|
||||
if (!fs.existsSync(standaloneZipPath)) {
|
||||
console.error(`standalone.zip not found at: ${standaloneZipPath}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log("Extracting standalone.zip to extensions directory...")
|
||||
try {
|
||||
if (!fs.existsSync(extensionsDir)) {
|
||||
execSync(`unzip -q "${standaloneZipPath}" -d "${extensionsDir}"`, { stdio: "inherit" })
|
||||
}
|
||||
console.log(`Successfully extracted standalone.zip to: ${extensionsDir}`)
|
||||
} catch (error) {
|
||||
console.error("Failed to extract standalone.zip:", error)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const covDir = path.join(projectRoot, `coverage/coverage-core-${PROTOBUS_PORT}`)
|
||||
|
||||
const baseArgs = ["--enable-source-maps", path.join(distDir, "cline-core.js")]
|
||||
|
||||
const spawnArgs = USE_C8 ? ["c8", "--report-dir", covDir, "node", ...baseArgs] : ["node", ...baseArgs]
|
||||
|
||||
console.log(`Starting Cline Core Service... (useC8=${USE_C8})`)
|
||||
|
||||
const coreService: ChildProcess = spawn("npx", spawnArgs, {
|
||||
cwd: projectRoot,
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_PATH: "./node_modules",
|
||||
DEV_WORKSPACE_FOLDER: WORKSPACE_DIR,
|
||||
PROTOBUS_ADDRESS: `127.0.0.1:${PROTOBUS_PORT}`,
|
||||
HOST_BRIDGE_ADDRESS: `localhost:${HOSTBRIDGE_PORT}`,
|
||||
E2E_TEST,
|
||||
CLINE_ENVIRONMENT,
|
||||
CLINE_DIR: userDataDir,
|
||||
INSTALL_DIR: extensionsDir,
|
||||
},
|
||||
stdio: "inherit",
|
||||
})
|
||||
childProcesses.push(coreService)
|
||||
|
||||
const shutdown = async () => {
|
||||
console.log("\nShutting down services...")
|
||||
|
||||
while (childProcesses.length > 0) {
|
||||
const child = childProcesses.pop()
|
||||
if (child && !child.killed) child.kill("SIGINT")
|
||||
}
|
||||
|
||||
await ClineApiServerMock.stopGlobalServer()
|
||||
|
||||
try {
|
||||
rmSync(userDataDir, { recursive: true, force: true })
|
||||
rmSync(clineTestWorkspace, { recursive: true, force: true })
|
||||
console.log("Cleaned up temporary directories")
|
||||
} catch (err) {
|
||||
console.warn("Failed to cleanup temp directories:", err)
|
||||
}
|
||||
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
process.on("SIGINT", shutdown)
|
||||
process.on("SIGTERM", shutdown)
|
||||
|
||||
coreService.on("exit", (code) => {
|
||||
console.log(`Core service exited with code ${code}`)
|
||||
shutdown()
|
||||
})
|
||||
hostbridge.on("exit", (code) => {
|
||||
console.log(`HostBridge exited with code ${code}`)
|
||||
shutdown()
|
||||
})
|
||||
|
||||
console.log(`Cline gRPC Server is running on 127.0.0.1:${PROTOBUS_PORT}`)
|
||||
console.log("Press Ctrl+C to stop")
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((err) => {
|
||||
console.error("Failed to start simple Cline server:", err)
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
/**
|
||||
* Test Orchestrator
|
||||
*
|
||||
* Automates server lifecycle for running spec files against the standalone server.
|
||||
*
|
||||
* Prerequisites:
|
||||
* Build standalone first: `npm run compile-standalone`
|
||||
*
|
||||
* Usage:
|
||||
* - Single file: `npm run test:tp-orchestrator path/to/spec.json`
|
||||
* - All specs dir: `npm run test:tp-orchestrator tests/specs`
|
||||
*
|
||||
* Flags:
|
||||
* --server-logs Show server logs (hidden by default)
|
||||
* --count=<number> Repeat execution N times (default: 1)
|
||||
* --fix Automatically update spec files with actual responses
|
||||
* --coverage Generate integration test coverage information
|
||||
*
|
||||
*/
|
||||
|
||||
import { ChildProcess, spawn } from "child_process"
|
||||
import fs from "fs"
|
||||
import minimist from "minimist"
|
||||
import net from "net"
|
||||
import path from "path"
|
||||
import kill from "tree-kill"
|
||||
|
||||
let showServerLogs = false
|
||||
let fix = false
|
||||
let coverage = false
|
||||
const WAIT_SERVER_DEFAULT_TIMEOUT = 15000
|
||||
const usedPorts = new Set<number>()
|
||||
|
||||
/**
|
||||
* Find an available TCP port within the given range [min, max].
|
||||
*
|
||||
* - Ports are allocated sequentially (starting at `min`) rather than randomly,
|
||||
* which avoids accidental reuse when running hundreds of tests in a row.
|
||||
* - Each successfully allocated port is tracked in `usedPorts` to guarantee
|
||||
* it is never handed out again within the lifetime of this orchestrator.
|
||||
* - Before returning, the function binds a temporary server to the port to
|
||||
* verify that the OS really considers it available, then immediately closes it.
|
||||
*
|
||||
* This approach makes the orchestrator much more robust on CI (e.g. GitHub Actions),
|
||||
* where a just-terminated server may leave its socket in TIME_WAIT and cause
|
||||
* flakiness if the same port is reallocated too soon.
|
||||
*/
|
||||
async function getAvailablePort(min = 20000, max = 49151): Promise<number> {
|
||||
return new Promise((resolve, _) => {
|
||||
const tryPort = (candidate?: number) => {
|
||||
const port = candidate ?? Math.floor(Math.random() * (max - min + 1)) + min
|
||||
if (usedPorts.has(port)) {
|
||||
// already allocated in this run
|
||||
return tryPort()
|
||||
}
|
||||
const server = net.createServer()
|
||||
server.once("error", () => tryPort())
|
||||
server.once("listening", () => {
|
||||
server.close(() => {
|
||||
usedPorts.add(port) // mark reserved
|
||||
resolve(port)
|
||||
})
|
||||
})
|
||||
server.listen(port, "127.0.0.1")
|
||||
}
|
||||
tryPort()
|
||||
})
|
||||
}
|
||||
|
||||
// Poll until a given TCP port on a host is accepting connections.
|
||||
async function waitForPort(port: number, host = "127.0.0.1", timeout = 10000): Promise<void> {
|
||||
const start = Date.now()
|
||||
const waitForPortSleepMs = 100
|
||||
while (Date.now() - start < timeout) {
|
||||
await new Promise((res) => setTimeout(res, waitForPortSleepMs))
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const socket = net.connect(port, host, () => {
|
||||
socket.destroy()
|
||||
resolve()
|
||||
})
|
||||
socket.on("error", reject)
|
||||
})
|
||||
return
|
||||
} catch {
|
||||
// try again
|
||||
}
|
||||
}
|
||||
throw new Error(`Timeout waiting for ${host}:${port}`)
|
||||
}
|
||||
|
||||
async function startServer(): Promise<{ server: ChildProcess; grpcPort: string }> {
|
||||
const grpcPort = (await getAvailablePort()).toString()
|
||||
const hostbridgePort = (await getAvailablePort()).toString()
|
||||
|
||||
const server = spawn("npx", ["tsx", "scripts/test-standalone-core-api-server.ts"], {
|
||||
stdio: showServerLogs ? "inherit" : "pipe",
|
||||
env: {
|
||||
...process.env,
|
||||
PROTOBUS_PORT: grpcPort,
|
||||
HOSTBRIDGE_PORT: hostbridgePort,
|
||||
USE_C8: coverage ? "true" : "false",
|
||||
},
|
||||
})
|
||||
|
||||
// Wait for either the server to become ready or fail on spawn error
|
||||
await Promise.race([
|
||||
waitForPort(Number(grpcPort), "127.0.0.1", WAIT_SERVER_DEFAULT_TIMEOUT),
|
||||
new Promise((_, reject) => server.once("error", reject)),
|
||||
])
|
||||
|
||||
return { server, grpcPort }
|
||||
}
|
||||
|
||||
function stopServer(server: ChildProcess): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
if (!server.pid) return resolve()
|
||||
|
||||
kill(server.pid, "SIGINT", (err) => {
|
||||
if (err) console.warn("Failed to kill server process:", err)
|
||||
server.once("exit", () => resolve())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function runTestingPlatform(specFile: string, grpcPort: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const testProcess = spawn("npx", ["ts-node", "index.ts", specFile, ...(fix ? ["--fix"] : [])], {
|
||||
cwd: path.join(process.cwd(), "testing-platform"),
|
||||
stdio: "inherit",
|
||||
env: {
|
||||
...process.env,
|
||||
STANDALONE_GRPC_SERVER_PORT: grpcPort,
|
||||
},
|
||||
})
|
||||
|
||||
testProcess.once("error", reject)
|
||||
testProcess.once("exit", (code) => {
|
||||
code === 0 ? resolve() : reject(new Error(`Exit code ${code}`))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function runSpec(specFile: string): Promise<void> {
|
||||
const { server, grpcPort } = await startServer()
|
||||
try {
|
||||
await runTestingPlatform(specFile, grpcPort)
|
||||
console.log(`✅ ${path.basename(specFile)} passed`)
|
||||
} finally {
|
||||
await stopServer(server)
|
||||
}
|
||||
}
|
||||
|
||||
function collectSpecFiles(inputPath: string): string[] {
|
||||
const fullPath = path.resolve(inputPath)
|
||||
if (!fs.existsSync(fullPath)) throw new Error(`Path does not exist: ${fullPath}`)
|
||||
|
||||
const stat = fs.statSync(fullPath)
|
||||
if (stat.isDirectory()) {
|
||||
return fs
|
||||
.readdirSync(fullPath)
|
||||
.filter((f) => f.endsWith(".json"))
|
||||
.map((f) => path.join(fullPath, f))
|
||||
}
|
||||
if (fullPath.endsWith(".json")) return [fullPath]
|
||||
throw new Error("Spec path must be a JSON file or a folder containing JSON files")
|
||||
}
|
||||
|
||||
async function runAll(inputPath: string, count: number) {
|
||||
const specFiles = collectSpecFiles(inputPath)
|
||||
if (specFiles.length === 0) {
|
||||
console.warn(`⚠️ No spec files found in ${inputPath}`)
|
||||
return
|
||||
}
|
||||
|
||||
let success = 0
|
||||
let failure = 0
|
||||
const totalStart = Date.now()
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
console.log(`\n🔁 Run #${i + 1} of ${count}`)
|
||||
for (const specFile of specFiles) {
|
||||
try {
|
||||
await runSpec(specFile)
|
||||
success++
|
||||
} catch (err) {
|
||||
console.error(`❌ run #${i + 1}: ${path.basename(specFile)} failed:`, (err as Error).message)
|
||||
failure++
|
||||
}
|
||||
}
|
||||
|
||||
if (failure > 0) process.exitCode = 1
|
||||
}
|
||||
|
||||
console.log(`✅ Passed: ${success}`)
|
||||
if (failure > 0) console.log(`❌ Failed: ${failure}`)
|
||||
console.log(`📋 Total specs: ${specFiles.length} Total runs: ${specFiles.length * count}`)
|
||||
console.log(`🏁 All runs completed in ${((Date.now() - totalStart) / 1000).toFixed(2)}s`)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const args = minimist(process.argv.slice(2), { default: { count: 1 } })
|
||||
const inputPath = args._[0]
|
||||
const count = Number(args.count)
|
||||
showServerLogs = Boolean(args["server-logs"])
|
||||
fix = Boolean(args["fix"])
|
||||
coverage = Boolean(args["coverage"])
|
||||
|
||||
if (!inputPath) {
|
||||
console.error(
|
||||
"Usage: npx tsx scripts/testing-platform-orchestrator.ts <spec-file-or-folder> [--count=N] [--server-logs] [--fix] [--coverage]",
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
await runAll(inputPath, count)
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((err) => {
|
||||
console.error("❌ Fatal error:", err)
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Validate a PR-specific scenario exists in src/test/scenarios
|
||||
# Rules:
|
||||
# - example.ts is exempt
|
||||
# - Exactly one scenario must match the current PR number
|
||||
# - All non-exempt scenario files must include a valid "GitHub PR" metadata line
|
||||
#
|
||||
# Usage: ./scripts/validate-scenario.sh <PR_NUMBER>
|
||||
|
||||
PR_NUMBER="${1:-}"
|
||||
|
||||
SCENARIOS_DIR="src/test/scenarios"
|
||||
EXEMPT_BASENAMES=("example.ts")
|
||||
|
||||
red() { printf "\033[31m%s\033[0m\n" "$*"; }
|
||||
green() { printf "\033[32m%s\033[0m\n" "$*"; }
|
||||
yellow(){ printf "\033[33m%s\033[0m\n" "$*"; }
|
||||
|
||||
is_exempt() {
|
||||
local base="$1"
|
||||
for ex in "${EXEMPT_BASENAMES[@]}"; do
|
||||
if [[ "$base" == "$ex" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 <PR_NUMBER>" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
if [[ -z "$PR_NUMBER" ]]; then
|
||||
red "Error: PR number is required."
|
||||
usage
|
||||
fi
|
||||
|
||||
if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
|
||||
red "Error: PR number must be numeric. Got: '$PR_NUMBER'"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ ! -d "$SCENARIOS_DIR" ]]; then
|
||||
red "Error: Scenarios directory not found: $SCENARIOS_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
declare -a ALL_FILES=()
|
||||
declare -a MISSING_METADATA=()
|
||||
declare -a MALFORMED_METADATA=()
|
||||
declare -a FOUND_FILES=()
|
||||
declare -a FOUND_PRS=()
|
||||
|
||||
# Find top-level .ts files in scenarios dir
|
||||
while IFS= read -r -d '' file; do
|
||||
ALL_FILES+=("$file")
|
||||
done < <(find "$SCENARIOS_DIR" -maxdepth 1 -type f -name "*.ts" -print0 | sort -z)
|
||||
|
||||
if [[ ${#ALL_FILES[@]} -eq 0 ]]; then
|
||||
red "Error: No scenario files found in $SCENARIOS_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for file in "${ALL_FILES[@]}"; do
|
||||
base="$(basename "$file")"
|
||||
if is_exempt "$base"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Extract metadata line, pattern: // GitHub PR - 123
|
||||
meta_line="$(grep -E -m1 '^[[:space:]]*//[[:space:]]*GitHub[[:space:]]+PR[[:space:]]*-[[:space:]]*[0-9]+[[:space:]]*$' "$file" || true)"
|
||||
|
||||
if [[ -z "$meta_line" ]]; then
|
||||
MISSING_METADATA+=("$file")
|
||||
continue
|
||||
fi
|
||||
|
||||
pr_in_file="$(sed -E 's@.*GitHub[[:space:]]+PR[[:space:]]*-[[:space:]]*([0-9]+).*@\1@' <<< "$meta_line" | tr -d '[:space:]')"
|
||||
|
||||
if ! [[ "$pr_in_file" =~ ^[0-9]+$ ]]; then
|
||||
MALFORMED_METADATA+=("$file")
|
||||
continue
|
||||
fi
|
||||
|
||||
FOUND_FILES+=("$file")
|
||||
FOUND_PRS+=("$pr_in_file")
|
||||
done
|
||||
|
||||
# Fail if any non-exempt file is missing metadata
|
||||
if [[ ${#MISSING_METADATA[@]} -gt 0 ]]; then
|
||||
red "Error: The following scenario files are missing the required metadata line '// GitHub PR - <number>':"
|
||||
for f in "${MISSING_METADATA[@]}"; do
|
||||
echo " - $f"
|
||||
done
|
||||
echo
|
||||
echo "Please add a metadata line like:"
|
||||
echo " // GitHub PR - $PR_NUMBER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Fail if any metadata is malformed
|
||||
if [[ ${#MALFORMED_METADATA[@]} -gt 0 ]]; then
|
||||
red "Error: The following scenario files have a malformed 'GitHub PR' metadata line:"
|
||||
for f in "${MALFORMED_METADATA[@]}"; do
|
||||
echo " - $f"
|
||||
done
|
||||
echo
|
||||
echo "Expected format:"
|
||||
echo " // GitHub PR - $PR_NUMBER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Count matches for this PR
|
||||
matches=0
|
||||
declare -a MATCHED_FILES=()
|
||||
for i in "${!FOUND_FILES[@]}"; do
|
||||
if [[ "${FOUND_PRS[$i]}" == "$PR_NUMBER" ]]; then
|
||||
matches=$((matches + 1))
|
||||
MATCHED_FILES+=("${FOUND_FILES[$i]}")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $matches -eq 0 ]]; then
|
||||
red "Error: No scenario file found for PR #$PR_NUMBER."
|
||||
echo "Scenarios with declared PRs:"
|
||||
if [[ ${#FOUND_FILES[@]} -eq 0 ]]; then
|
||||
echo " (none)"
|
||||
else
|
||||
for i in "${!FOUND_FILES[@]}"; do
|
||||
echo " - ${FOUND_FILES[$i]} (PR: ${FOUND_PRS[$i]})"
|
||||
done
|
||||
fi
|
||||
echo
|
||||
echo "Please add a scenario in $SCENARIOS_DIR with a metadata line:"
|
||||
echo " // GitHub PR - $PR_NUMBER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $matches -gt 1 ]]; then
|
||||
red "Error: Multiple scenario files found for PR #$PR_NUMBER (exactly one required):"
|
||||
for f in "${MATCHED_FILES[@]}"; do
|
||||
echo " - $f"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
green "Success: Exactly one scenario found for PR #$PR_NUMBER:"
|
||||
echo " - ${MATCHED_FILES[0]}"
|
||||
@@ -0,0 +1,293 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { ModelInfo } from "@shared/api"
|
||||
import { ApiHandler } from "../../core/api/index"
|
||||
import { ApiStream } from "../../core/api/transform/stream"
|
||||
|
||||
interface DifyHandlerOptions {
|
||||
difyApiKey?: string
|
||||
difyBaseUrl?: string
|
||||
}
|
||||
|
||||
export class DifyHandler implements ApiHandler {
|
||||
private options: DifyHandlerOptions
|
||||
private baseUrl: string
|
||||
private apiKey: string
|
||||
private conversationId: string | null = null
|
||||
|
||||
constructor(options: DifyHandlerOptions) {
|
||||
this.options = options
|
||||
this.apiKey = options.difyApiKey || ""
|
||||
this.baseUrl = options.difyBaseUrl || ""
|
||||
|
||||
console.log("[DIFY DEBUG] Constructor called with:", {
|
||||
hasApiKey: !!this.apiKey,
|
||||
baseUrl: this.baseUrl,
|
||||
})
|
||||
|
||||
if (!this.apiKey) {
|
||||
throw new Error("Dify API key is required")
|
||||
}
|
||||
if (!this.baseUrl) {
|
||||
throw new Error("Dify base URL is required")
|
||||
}
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
console.log("[DIFY DEBUG] createMessage called with:", {
|
||||
systemPromptLength: systemPrompt?.length || 0,
|
||||
messagesCount: messages?.length || 0,
|
||||
})
|
||||
|
||||
// Convert messages to Dify format
|
||||
const query = this.convertMessagesToQuery(systemPrompt, messages)
|
||||
const requestBody = {
|
||||
inputs: {},
|
||||
query: query,
|
||||
response_mode: "streaming",
|
||||
conversation_id: this.conversationId || "",
|
||||
user: "cline-user", // A unique user identifier
|
||||
files: [],
|
||||
}
|
||||
|
||||
const fullUrl = `${this.baseUrl}/chat-messages`
|
||||
console.log("[DIFY DEBUG] Making request to:", fullUrl)
|
||||
console.log("[DIFY DEBUG] Request body:", JSON.stringify(requestBody, null, 2))
|
||||
console.log("[DIFY DEBUG] Current process environment variables (for proxy debugging):", process.env)
|
||||
|
||||
let response: Response
|
||||
try {
|
||||
response = await fetch(fullUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${this.apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
})
|
||||
} catch (error: any) {
|
||||
console.error("[DIFY DEBUG] Network error during fetch:", error)
|
||||
// Log more detailed error information if available (e.g., from undici)
|
||||
const cause = error.cause ? ` | Cause: ${error.cause}` : ""
|
||||
throw new Error(`Dify API network error: ${error.message}${cause}`)
|
||||
}
|
||||
|
||||
console.log("[DIFY DEBUG] Response status:", response.status)
|
||||
const headersObj: Record<string, string> = {}
|
||||
response.headers.forEach((value, key) => {
|
||||
headersObj[key] = value
|
||||
})
|
||||
console.log("[DIFY DEBUG] Response headers:", headersObj)
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
console.error("[DIFY DEBUG] Error response:", errorText)
|
||||
throw new Error(`Dify API error: ${response.status} ${response.statusText} - ${errorText}`)
|
||||
}
|
||||
|
||||
if (!response.body) {
|
||||
throw new Error("No response body from Dify API")
|
||||
}
|
||||
|
||||
const reader = response.body.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
let buffer = ""
|
||||
let fullText = ""
|
||||
|
||||
console.log("[DIFY DEBUG] Starting to read streaming response...")
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
if (done) {
|
||||
console.log("[DIFY DEBUG] Stream ended naturally")
|
||||
break
|
||||
}
|
||||
|
||||
const chunk = decoder.decode(value, { stream: true })
|
||||
console.log("[DIFY DEBUG] Raw chunk received:", JSON.stringify(chunk))
|
||||
|
||||
buffer += chunk
|
||||
const lines = buffer.split("\n")
|
||||
|
||||
// Keep the last incomplete line in the buffer
|
||||
buffer = lines.pop() || ""
|
||||
|
||||
for (const line of lines) {
|
||||
console.log("[DIFY DEBUG] Processing line:", JSON.stringify(line))
|
||||
|
||||
if (line.startsWith("data: ")) {
|
||||
const data = line.slice(6).trim()
|
||||
console.log("[DIFY DEBUG] Extracted data:", JSON.stringify(data))
|
||||
|
||||
if (data === "[DONE]") {
|
||||
console.log("[DIFY DEBUG] Received [DONE] signal")
|
||||
return // Explicitly return on [DONE]
|
||||
}
|
||||
|
||||
if (data === "") {
|
||||
console.log("[DIFY DEBUG] Empty data line, skipping")
|
||||
continue
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(data)
|
||||
console.log("[DIFY DEBUG] Parsed JSON:", parsed)
|
||||
|
||||
// Capture conversation_id as soon as it's available
|
||||
if (parsed.conversation_id && !this.conversationId) {
|
||||
this.conversationId = parsed.conversation_id
|
||||
console.log("[DIFY DEBUG] Captured conversation_id:", this.conversationId)
|
||||
}
|
||||
|
||||
// Handle different Dify event types based on actual Dify API
|
||||
if (parsed.event === "message") {
|
||||
console.log("[DIFY DEBUG] Message event, answer:", parsed.answer)
|
||||
// Dify sends the full text in each "answer" chunk, so we replace.
|
||||
if (typeof parsed.answer === "string") {
|
||||
fullText = parsed.answer
|
||||
console.log("[DIFY DEBUG] Updated fullText length:", fullText.length)
|
||||
yield {
|
||||
type: "text",
|
||||
text: fullText,
|
||||
}
|
||||
}
|
||||
} else if (parsed.event === "message_replace") {
|
||||
console.log("[DIFY DEBUG] Replace message event:", parsed)
|
||||
if (parsed.answer) {
|
||||
fullText = parsed.answer // Replace instead of append
|
||||
console.log("[DIFY DEBUG] Replaced fullText length:", fullText.length)
|
||||
yield {
|
||||
type: "text",
|
||||
text: fullText,
|
||||
}
|
||||
}
|
||||
} else if (parsed.event === "message_end") {
|
||||
console.log("[DIFY DEBUG] Message end event", parsed)
|
||||
// Message completed. Yield final text if we have any.
|
||||
if (fullText) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: fullText,
|
||||
}
|
||||
}
|
||||
// Yield usage data if available
|
||||
if (parsed.usage) {
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: parsed.usage.prompt_tokens || 0,
|
||||
outputTokens: parsed.usage.completion_tokens || parsed.usage.total_tokens || 0,
|
||||
totalCost: parsed.usage.total_price || 0,
|
||||
}
|
||||
}
|
||||
return // End of stream
|
||||
} else if (parsed.event === "error") {
|
||||
console.error("[DIFY DEBUG] Error event:", parsed)
|
||||
throw new Error(`Dify API error: ${parsed.message || "Unknown error"}`)
|
||||
} else if (parsed.event === "workflow_started" || parsed.event === "workflow_finished") {
|
||||
console.log("[DIFY DEBUG] Workflow event:", parsed.event)
|
||||
// These are informational events, continue processing
|
||||
} else if (parsed.event === "node_started" || parsed.event === "node_finished") {
|
||||
console.log("[DIFY DEBUG] Node event:", parsed.event, parsed.data)
|
||||
// These are informational events, continue processing
|
||||
} else if (parsed.event === "ping") {
|
||||
console.log("[DIFY DEBUG] Ping event received, keeping connection alive.")
|
||||
// Ping event, do nothing
|
||||
} else {
|
||||
console.log("[DIFY DEBUG] Unknown event type:", parsed.event, "Full object:", parsed)
|
||||
// Try to extract text from other possible fields
|
||||
if (parsed.text) {
|
||||
fullText += parsed.text
|
||||
yield {
|
||||
type: "text",
|
||||
text: fullText,
|
||||
}
|
||||
} else if (parsed.content) {
|
||||
fullText += parsed.content
|
||||
yield {
|
||||
type: "text",
|
||||
text: fullText,
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("[DIFY DEBUG] Failed to parse JSON:", data, "Error:", e)
|
||||
}
|
||||
} else if (line.trim() !== "") {
|
||||
console.log(
|
||||
"[DIFY DEBUG] Non-data line (not starting with 'data:'), trying to parse as direct JSON:",
|
||||
JSON.stringify(line),
|
||||
)
|
||||
// Try to parse as direct JSON (fallback for non-SSE responses, though Dify uses SSE)
|
||||
try {
|
||||
const parsed = JSON.parse(line.trim())
|
||||
console.log("[DIFY DEBUG] Parsed direct JSON:", parsed)
|
||||
|
||||
// Handle the same event types as above
|
||||
if (parsed.event === "message" && parsed.answer) {
|
||||
fullText += parsed.answer
|
||||
yield {
|
||||
type: "text",
|
||||
text: fullText,
|
||||
}
|
||||
} else if (parsed.event === "message_end") {
|
||||
if (fullText) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: fullText,
|
||||
}
|
||||
}
|
||||
return
|
||||
} else if (parsed.event === "error") {
|
||||
console.error("[DIFY DEBUG] Direct JSON Error event:", parsed)
|
||||
throw new Error(`Dify API error: ${parsed.message || "Unknown error"}`)
|
||||
}
|
||||
} catch (e) {
|
||||
// Not JSON, continue
|
||||
console.log("[DIFY DEBUG] Line is not direct JSON, continuing")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
reader.releaseLock()
|
||||
console.log("[DIFY DEBUG] Stream reader released")
|
||||
}
|
||||
}
|
||||
|
||||
private convertMessagesToQuery(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): string {
|
||||
// Dify's context is managed by `conversation_id`. The `query` should be the last user message.
|
||||
// The system prompt is typically configured in the Dify App itself.
|
||||
const lastUserMessage = messages.filter((m) => m.role === "user").pop()
|
||||
|
||||
if (!lastUserMessage) {
|
||||
return "" // Should not happen in normal flow
|
||||
}
|
||||
|
||||
const userQuery = Array.isArray(lastUserMessage.content)
|
||||
? lastUserMessage.content.map((c) => ("text" in c ? c.text : "")).join("\n")
|
||||
: (lastUserMessage.content as string)
|
||||
|
||||
// Only prepend the system prompt if it's the very first message of a new conversation.
|
||||
if (!this.conversationId && systemPrompt) {
|
||||
console.log("[DIFY DEBUG] Prepending system prompt for new conversation.")
|
||||
return `${systemPrompt}\n\n---\n\n${userQuery}`
|
||||
}
|
||||
|
||||
return userQuery
|
||||
}
|
||||
|
||||
getModel(): { id: string; info: ModelInfo } {
|
||||
return {
|
||||
id: "dify-workflow",
|
||||
info: {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 128000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Dify workflow - model selection is configured in your Dify application",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
-21
@@ -1,19 +1,23 @@
|
||||
import * as vscode from "vscode"
|
||||
import {
|
||||
migrateCustomInstructionsToGlobalRules,
|
||||
migrateTaskHistoryToFile,
|
||||
migrateWelcomeViewCompleted,
|
||||
migrateWorkspaceToGlobalStorage,
|
||||
} from "./core/storage/state-migrations"
|
||||
import { WebviewProvider } from "./core/webview"
|
||||
import { Logger } from "./services/logging/Logger"
|
||||
import { PostHogClientProvider } from "./services/posthog/PostHogClientProvider"
|
||||
import { EmptyRequest } from "./shared/proto/cline/common"
|
||||
import { WebviewProviderType } from "./shared/webview/types"
|
||||
import "./utils/path" // necessary to have access to String.prototype.toPosix
|
||||
|
||||
import { HostProvider } from "@/hosts/host-provider"
|
||||
import { FileContextTracker } from "./core/context/context-tracking/FileContextTracker"
|
||||
import { telemetryService } from "./services/posthog/PostHogClientProvider"
|
||||
import { ExtensionRegistryInfo } from "./registry"
|
||||
import { audioRecordingService } from "./services/dictation/AudioRecordingService"
|
||||
import { ErrorService } from "./services/error"
|
||||
import { featureFlagsService } from "./services/feature-flags"
|
||||
import { initializeDistinctId } from "./services/logging/distinctId"
|
||||
import { PostHogClientProvider } from "./services/posthog/PostHogClientProvider"
|
||||
import { telemetryService } from "./services/telemetry"
|
||||
import { ShowMessageType } from "./shared/proto/host/window"
|
||||
import { getLatestAnnouncementId } from "./utils/announcements"
|
||||
/**
|
||||
@@ -23,18 +27,15 @@ import { getLatestAnnouncementId } from "./utils/announcements"
|
||||
* @returns The webview provider
|
||||
*/
|
||||
export async function initialize(context: vscode.ExtensionContext): Promise<WebviewProvider> {
|
||||
// Set the distinct ID for logging and telemetry
|
||||
await initializeDistinctId(context)
|
||||
|
||||
// Initialize PostHog client provider
|
||||
let distinctId = context.globalState.get<string>("cline.distinctId")
|
||||
if (!distinctId) {
|
||||
try {
|
||||
const response = await HostProvider.env.getMachineId(EmptyRequest.create({}))
|
||||
distinctId = response.value
|
||||
} catch (e) {
|
||||
Logger.warn(`Failed to get machine ID: ${e instanceof Error ? e.message : String(e)}`)
|
||||
// PostHogProvider will fall back to uuid
|
||||
}
|
||||
}
|
||||
PostHogClientProvider.getInstance(distinctId)
|
||||
PostHogClientProvider.getInstance()
|
||||
|
||||
// Setup the external services
|
||||
await ErrorService.initialize()
|
||||
await featureFlagsService.poll()
|
||||
|
||||
// Migrate custom instructions to global Cline rules (one-time cleanup)
|
||||
await migrateCustomInstructionsToGlobalRules(context)
|
||||
@@ -45,21 +46,24 @@ export async function initialize(context: vscode.ExtensionContext): Promise<Webv
|
||||
// Migrate workspace storage values back to global storage (reverting previous migration)
|
||||
await migrateWorkspaceToGlobalStorage(context)
|
||||
|
||||
// Ensure taskHistory.json exists and migrate legacy state (runs once)
|
||||
await migrateTaskHistoryToFile(context)
|
||||
|
||||
// Clean up orphaned file context warnings (startup cleanup)
|
||||
await FileContextTracker.cleanupOrphanedWarnings(context)
|
||||
|
||||
const sidebarWebview = HostProvider.get().createWebviewProvider(WebviewProviderType.SIDEBAR)
|
||||
const webview = HostProvider.get().createWebviewProvider()
|
||||
|
||||
await showVersionUpdateAnnouncement(context)
|
||||
|
||||
telemetryService.captureExtensionActivated()
|
||||
|
||||
return sidebarWebview
|
||||
return webview
|
||||
}
|
||||
|
||||
async function showVersionUpdateAnnouncement(context: vscode.ExtensionContext) {
|
||||
// Version checking for autoupdate notification
|
||||
const currentVersion = context.extension.packageJSON.version
|
||||
const currentVersion = ExtensionRegistryInfo.version
|
||||
const previousVersion = context.globalState.get<string>("clineVersion")
|
||||
// Perform post-update actions if necessary
|
||||
try {
|
||||
@@ -68,14 +72,14 @@ async function showVersionUpdateAnnouncement(context: vscode.ExtensionContext) {
|
||||
|
||||
// Use the same condition as announcements: focus when there's a new announcement to show
|
||||
const lastShownAnnouncementId = context.globalState.get<string>("lastShownAnnouncementId")
|
||||
const latestAnnouncementId = getLatestAnnouncementId(context)
|
||||
const latestAnnouncementId = getLatestAnnouncementId()
|
||||
|
||||
if (lastShownAnnouncementId !== latestAnnouncementId) {
|
||||
// Focus Cline when there's a new announcement to show (major/minor updates or fresh installs)
|
||||
const message = previousVersion
|
||||
? `Cline has been updated to v${currentVersion}`
|
||||
: `Welcome to Cline v${currentVersion}`
|
||||
await vscode.commands.executeCommand("claude-dev.SidebarProvider.focus")
|
||||
await HostProvider.workspace.openClineSidebarPanel({})
|
||||
await new Promise((resolve) => setTimeout(resolve, 200))
|
||||
HostProvider.window.showMessage({
|
||||
type: ShowMessageType.INFORMATION,
|
||||
@@ -95,8 +99,13 @@ async function showVersionUpdateAnnouncement(context: vscode.ExtensionContext) {
|
||||
* Performs cleanup when Cline is deactivated that is common to all platforms.
|
||||
*/
|
||||
export async function tearDown(): Promise<void> {
|
||||
PostHogClientProvider.getInstance().dispose()
|
||||
// Clean up audio recording service to ensure no orphaned processes
|
||||
audioRecordingService.cleanup()
|
||||
|
||||
PostHogClientProvider.getInstance().dispose()
|
||||
telemetryService.dispose()
|
||||
ErrorService.get().dispose()
|
||||
featureFlagsService.dispose()
|
||||
// Dispose all webview instances
|
||||
await WebviewProvider.disposeAllInstances()
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ export enum Environment {
|
||||
local = "local",
|
||||
}
|
||||
|
||||
interface EnvironmentConfig {
|
||||
export interface EnvironmentConfig {
|
||||
appBaseUrl: string
|
||||
apiBaseUrl: string
|
||||
mcpBaseUrl: string
|
||||
|
||||
+76
-1
@@ -9,6 +9,7 @@ import { CerebrasHandler } from "./providers/cerebras"
|
||||
import { ClaudeCodeHandler } from "./providers/claude-code"
|
||||
import { ClineHandler } from "./providers/cline"
|
||||
import { DeepSeekHandler } from "./providers/deepseek"
|
||||
import { DifyHandler } from "./providers/dify"
|
||||
import { DoubaoHandler } from "./providers/doubao"
|
||||
import { FireworksHandler } from "./providers/fireworks"
|
||||
import { GeminiHandler } from "./providers/gemini"
|
||||
@@ -20,11 +21,13 @@ import { LmStudioHandler } from "./providers/lmstudio"
|
||||
import { MistralHandler } from "./providers/mistral"
|
||||
import { MoonshotHandler } from "./providers/moonshot"
|
||||
import { NebiusHandler } from "./providers/nebius"
|
||||
import { OcaHandler } from "./providers/oca"
|
||||
import { OllamaHandler } from "./providers/ollama"
|
||||
import { OpenAiHandler } from "./providers/openai"
|
||||
import { OpenAiNativeHandler } from "./providers/openai-native"
|
||||
import { OpenRouterHandler } from "./providers/openrouter"
|
||||
import { QwenHandler } from "./providers/qwen"
|
||||
import { QwenCodeHandler } from "./providers/qwen-code"
|
||||
import { RequestyHandler } from "./providers/requesty"
|
||||
import { SambanovaHandler } from "./providers/sambanova"
|
||||
import { SapAiCoreHandler } from "./providers/sapaicore"
|
||||
@@ -36,6 +39,10 @@ import { XAIHandler } from "./providers/xai"
|
||||
import { ZAiHandler } from "./providers/zai"
|
||||
import { ApiStream, ApiStreamUsageChunk } from "./transform/stream"
|
||||
|
||||
export type CommonApiHandlerOptions = {
|
||||
onRetryAttempt?: ApiConfiguration["onRetryAttempt"]
|
||||
}
|
||||
|
||||
export interface ApiHandler {
|
||||
createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream
|
||||
getModel(): ApiHandlerModel
|
||||
@@ -47,6 +54,13 @@ export interface ApiHandlerModel {
|
||||
info: ModelInfo
|
||||
}
|
||||
|
||||
export interface ApiProviderInfo {
|
||||
providerId: string
|
||||
model: ApiHandlerModel
|
||||
customPrompt?: string // "compact"
|
||||
autoCondenseThreshold?: number // 0-1 range
|
||||
}
|
||||
|
||||
export interface SingleCompletionHandler {
|
||||
completePrompt(prompt: string): Promise<string>
|
||||
}
|
||||
@@ -59,6 +73,7 @@ function createHandlerForProvider(
|
||||
switch (apiProvider) {
|
||||
case "anthropic":
|
||||
return new AnthropicHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
apiKey: options.apiKey,
|
||||
anthropicBaseUrl: options.anthropicBaseUrl,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
@@ -67,6 +82,7 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "openrouter":
|
||||
return new OpenRouterHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
openRouterApiKey: options.openRouterApiKey,
|
||||
openRouterModelId: mode === "plan" ? options.planModeOpenRouterModelId : options.actModeOpenRouterModelId,
|
||||
openRouterModelInfo: mode === "plan" ? options.planModeOpenRouterModelInfo : options.actModeOpenRouterModelInfo,
|
||||
@@ -77,6 +93,7 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "bedrock":
|
||||
return new AwsBedrockHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
awsAccessKey: options.awsAccessKey,
|
||||
awsSecretKey: options.awsSecretKey,
|
||||
@@ -98,6 +115,7 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "vertex":
|
||||
return new VertexHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
vertexProjectId: options.vertexProjectId,
|
||||
vertexRegion: options.vertexRegion,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
@@ -109,6 +127,7 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "openai":
|
||||
return new OpenAiHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
openAiApiKey: options.openAiApiKey,
|
||||
openAiBaseUrl: options.openAiBaseUrl,
|
||||
azureApiVersion: options.azureApiVersion,
|
||||
@@ -119,6 +138,7 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "ollama":
|
||||
return new OllamaHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
ollamaBaseUrl: options.ollamaBaseUrl,
|
||||
ollamaApiKey: options.ollamaApiKey,
|
||||
ollamaModelId: mode === "plan" ? options.planModeOllamaModelId : options.actModeOllamaModelId,
|
||||
@@ -127,12 +147,14 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "lmstudio":
|
||||
return new LmStudioHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
lmStudioBaseUrl: options.lmStudioBaseUrl,
|
||||
lmStudioModelId: mode === "plan" ? options.planModeLmStudioModelId : options.actModeLmStudioModelId,
|
||||
lmStudioMaxTokens: options.lmStudioMaxTokens,
|
||||
})
|
||||
case "gemini":
|
||||
return new GeminiHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
vertexProjectId: options.vertexProjectId,
|
||||
vertexRegion: options.vertexRegion,
|
||||
geminiApiKey: options.geminiApiKey,
|
||||
@@ -144,17 +166,20 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "openai-native":
|
||||
return new OpenAiNativeHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
openAiNativeApiKey: options.openAiNativeApiKey,
|
||||
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "deepseek":
|
||||
return new DeepSeekHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
deepSeekApiKey: options.deepSeekApiKey,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "requesty":
|
||||
return new RequestyHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
requestyBaseUrl: options.requestyBaseUrl,
|
||||
requestyApiKey: options.requestyApiKey,
|
||||
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
|
||||
@@ -165,16 +190,19 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "fireworks":
|
||||
return new FireworksHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
fireworksApiKey: options.fireworksApiKey,
|
||||
fireworksModelId: mode === "plan" ? options.planModeFireworksModelId : options.actModeFireworksModelId,
|
||||
})
|
||||
case "together":
|
||||
return new TogetherHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
togetherApiKey: options.togetherApiKey,
|
||||
togetherModelId: mode === "plan" ? options.planModeTogetherModelId : options.actModeTogetherModelId,
|
||||
})
|
||||
case "qwen":
|
||||
return new QwenHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
qwenApiKey: options.qwenApiKey,
|
||||
qwenApiLine:
|
||||
options.qwenApiLine === QwenApiRegions.INTERNATIONAL ? QwenApiRegions.INTERNATIONAL : QwenApiRegions.CHINA,
|
||||
@@ -182,23 +210,33 @@ function createHandlerForProvider(
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
})
|
||||
case "qwen-code":
|
||||
return new QwenCodeHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
qwenCodeOauthPath: options.qwenCodeOauthPath,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "doubao":
|
||||
return new DoubaoHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
doubaoApiKey: options.doubaoApiKey,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "mistral":
|
||||
return new MistralHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
mistralApiKey: options.mistralApiKey,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "vscode-lm":
|
||||
return new VsCodeLmHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
vsCodeLmModelSelector:
|
||||
mode === "plan" ? options.planModeVsCodeLmModelSelector : options.actModeVsCodeLmModelSelector,
|
||||
})
|
||||
case "cline":
|
||||
return new ClineHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
clineAccountId: options.clineAccountId,
|
||||
ulid: options.ulid,
|
||||
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
|
||||
@@ -210,6 +248,7 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "litellm":
|
||||
return new LiteLlmHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
liteLlmApiKey: options.liteLlmApiKey,
|
||||
liteLlmBaseUrl: options.liteLlmBaseUrl,
|
||||
liteLlmModelId: mode === "plan" ? options.planModeLiteLlmModelId : options.actModeLiteLlmModelId,
|
||||
@@ -221,12 +260,14 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "moonshot":
|
||||
return new MoonshotHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
moonshotApiKey: options.moonshotApiKey,
|
||||
moonshotApiLine: options.moonshotApiLine,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "huggingface":
|
||||
return new HuggingFaceHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
huggingFaceApiKey: options.huggingFaceApiKey,
|
||||
huggingFaceModelId: mode === "plan" ? options.planModeHuggingFaceModelId : options.actModeHuggingFaceModelId,
|
||||
huggingFaceModelInfo:
|
||||
@@ -234,33 +275,39 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "nebius":
|
||||
return new NebiusHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
nebiusApiKey: options.nebiusApiKey,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "asksage":
|
||||
return new AskSageHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
asksageApiKey: options.asksageApiKey,
|
||||
asksageApiUrl: options.asksageApiUrl,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "xai":
|
||||
return new XAIHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
xaiApiKey: options.xaiApiKey,
|
||||
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "sambanova":
|
||||
return new SambanovaHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
sambanovaApiKey: options.sambanovaApiKey,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "cerebras":
|
||||
return new CerebrasHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
cerebrasApiKey: options.cerebrasApiKey,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "groq":
|
||||
return new GroqHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
groqApiKey: options.groqApiKey,
|
||||
groqModelId: mode === "plan" ? options.planModeGroqModelId : options.actModeGroqModelId,
|
||||
groqModelInfo: mode === "plan" ? options.planModeGroqModelInfo : options.actModeGroqModelInfo,
|
||||
@@ -268,6 +315,7 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "baseten":
|
||||
return new BasetenHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
basetenApiKey: options.basetenApiKey,
|
||||
basetenModelId: mode === "plan" ? options.planModeBasetenModelId : options.actModeBasetenModelId,
|
||||
basetenModelInfo: mode === "plan" ? options.planModeBasetenModelInfo : options.actModeBasetenModelInfo,
|
||||
@@ -275,6 +323,7 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "sapaicore":
|
||||
return new SapAiCoreHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
sapAiCoreClientId: options.sapAiCoreClientId,
|
||||
sapAiCoreClientSecret: options.sapAiCoreClientSecret,
|
||||
sapAiCoreTokenUrl: options.sapAiCoreTokenUrl,
|
||||
@@ -283,9 +332,13 @@ function createHandlerForProvider(
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
|
||||
deploymentId: mode === "plan" ? options.planModeSapAiCoreDeploymentId : options.actModeSapAiCoreDeploymentId,
|
||||
sapAiCoreUseOrchestrationMode: options.sapAiCoreUseOrchestrationMode,
|
||||
})
|
||||
case "claude-code":
|
||||
return new ClaudeCodeHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
claudeCodePath: options.claudeCodePath,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
thinkingBudgetTokens:
|
||||
@@ -293,14 +346,21 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "huawei-cloud-maas":
|
||||
return new HuaweiCloudMaaSHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
huaweiCloudMaasApiKey: options.huaweiCloudMaasApiKey,
|
||||
huaweiCloudMaasModelId:
|
||||
mode === "plan" ? options.planModeHuaweiCloudMaasModelId : options.actModeHuaweiCloudMaasModelId,
|
||||
huaweiCloudMaasModelInfo:
|
||||
mode === "plan" ? options.planModeHuaweiCloudMaasModelInfo : options.actModeHuaweiCloudMaasModelInfo,
|
||||
})
|
||||
case "dify": // Add Dify.ai handler
|
||||
return new DifyHandler({
|
||||
difyApiKey: options.difyApiKey,
|
||||
difyBaseUrl: options.difyBaseUrl,
|
||||
})
|
||||
case "vercel-ai-gateway":
|
||||
return new VercelAIGatewayHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
vercelAiGatewayApiKey: options.vercelAiGatewayApiKey,
|
||||
vercelAiGatewayModelId:
|
||||
mode === "plan" ? options.planModeVercelAiGatewayModelId : options.actModeVercelAiGatewayModelId,
|
||||
@@ -309,12 +369,27 @@ function createHandlerForProvider(
|
||||
})
|
||||
case "zai":
|
||||
return new ZAiHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
zaiApiLine: options.zaiApiLine,
|
||||
zaiApiKey: options.zaiApiKey,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "oca":
|
||||
return new OcaHandler({
|
||||
ocaBaseUrl: options.ocaBaseUrl,
|
||||
ocaModelId: mode === "plan" ? options.planModeOcaModelId : options.actModeOcaModelId,
|
||||
ocaModelInfo: mode === "plan" ? options.planModeOcaModelInfo : options.actModeOcaModelInfo,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
ocaUsePromptCache:
|
||||
mode === "plan"
|
||||
? options.planModeOcaModelInfo?.supportsPromptCache
|
||||
: options.actModeOcaModelInfo?.supportsPromptCache,
|
||||
taskId: options.ulid,
|
||||
})
|
||||
default:
|
||||
return new AnthropicHandler({
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
apiKey: options.apiKey,
|
||||
anthropicBaseUrl: options.anthropicBaseUrl,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
@@ -337,7 +412,7 @@ export function buildApiHandler(configuration: ApiConfiguration, mode: Mode): Ap
|
||||
const handler = createHandlerForProvider(apiProvider, options, mode)
|
||||
|
||||
const modelInfo = handler.getModel().info
|
||||
if (modelInfo.maxTokens && thinkingBudgetTokens > modelInfo.maxTokens) {
|
||||
if (modelInfo?.maxTokens && modelInfo.maxTokens > 0 && thinkingBudgetTokens > modelInfo.maxTokens) {
|
||||
const clippedValue = modelInfo.maxTokens - 1
|
||||
if (mode === "plan") {
|
||||
options.planModeThinkingBudgetTokens = clippedValue
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import "should"
|
||||
import { ConverseStreamCommand } from "@aws-sdk/client-bedrock-runtime"
|
||||
import { ApiHandlerOptions } from "@shared/api"
|
||||
import { Readable } from "stream"
|
||||
import type { AwsBedrockHandlerOptions } from "../bedrock"
|
||||
import { AwsBedrockHandler } from "../bedrock"
|
||||
|
||||
describe("AwsBedrockHandler", () => {
|
||||
@@ -202,8 +202,8 @@ describe("AwsBedrockHandler", () => {
|
||||
})
|
||||
})
|
||||
|
||||
const mockOptions: ApiHandlerOptions = {
|
||||
actModeApiModelId: "anthropic.claude-3-7-sonnet-20250219-v1:0",
|
||||
const mockOptions: AwsBedrockHandlerOptions = {
|
||||
apiModelId: "anthropic.claude-3-7-sonnet-20250219-v1:0",
|
||||
awsRegion: "us-east-1",
|
||||
awsAccessKey: "test-key",
|
||||
awsSecretKey: "test-secret",
|
||||
@@ -214,9 +214,9 @@ describe("AwsBedrockHandler", () => {
|
||||
awsBedrockUsePromptCache: false,
|
||||
awsUseCrossRegionInference: false,
|
||||
awsBedrockEndpoint: "",
|
||||
actModeAwsBedrockCustomSelected: false,
|
||||
actModeAwsBedrockCustomModelBaseId: undefined,
|
||||
actModeThinkingBudgetTokens: 1600,
|
||||
awsBedrockCustomSelected: false,
|
||||
awsBedrockCustomModelBaseId: undefined,
|
||||
thinkingBudgetTokens: 1600,
|
||||
}
|
||||
|
||||
const mockModelInfo = {
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { afterEach, beforeEach, describe, it } from "mocha"
|
||||
import sinon from "sinon"
|
||||
import "should"
|
||||
import { ClaudeCodeHandler } from "@core/api/providers/claude-code"
|
||||
|
||||
describe("ClaudeCodeHandler", () => {
|
||||
let handler: ClaudeCodeHandler
|
||||
let sandbox: sinon.SinonSandbox
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
handler = new ClaudeCodeHandler({
|
||||
claudeCodePath: "/mock/path",
|
||||
apiModelId: "claude-3-5-sonnet-20241022",
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore()
|
||||
})
|
||||
|
||||
describe("token counting", () => {
|
||||
it("should correctly handle token usage from assistant messages", async () => {
|
||||
// The 'input_tokens' field represents the TOTAL number of input tokens used.
|
||||
// See https://docs.anthropic.com/en/api/messages#usage-object
|
||||
|
||||
// Mock the runClaudeCode function
|
||||
const runClaudeCodeModule = await import("@/integrations/claude-code/run")
|
||||
const runClaudeCodeStub = sandbox.stub(runClaudeCodeModule, "runClaudeCode")
|
||||
|
||||
// Create a proper async generator mock for the Claude Code response
|
||||
async function* mockGenerator() {
|
||||
// First yield the system init
|
||||
yield {
|
||||
type: "system",
|
||||
subtype: "init",
|
||||
apiKeySource: "api",
|
||||
}
|
||||
|
||||
// Yield assistant message with usage data
|
||||
// Example: If base input is 70 tokens, cache read is 20, and cache creation is 10,
|
||||
// then input_tokens from Anthropic API will be 100 (70 + 20 + 10)
|
||||
yield {
|
||||
type: "assistant",
|
||||
message: {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "Test response",
|
||||
},
|
||||
],
|
||||
usage: {
|
||||
input_tokens: 100, // Total including cache (per Anthropic docs)
|
||||
output_tokens: 50,
|
||||
cache_read_input_tokens: 20, // Already included in input_tokens
|
||||
cache_creation_input_tokens: 10, // Already included in input_tokens
|
||||
},
|
||||
stop_reason: "end_turn",
|
||||
},
|
||||
}
|
||||
|
||||
// Yield result with cost
|
||||
yield {
|
||||
type: "result",
|
||||
result: {},
|
||||
total_cost_usd: 0.005,
|
||||
}
|
||||
}
|
||||
|
||||
runClaudeCodeStub.returns(mockGenerator() as any)
|
||||
|
||||
const systemPrompt = "You are a helpful assistant."
|
||||
const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Hello" }]
|
||||
|
||||
const usageData: any[] = []
|
||||
|
||||
// Collect the results
|
||||
for await (const chunk of handler.createMessage(systemPrompt, messages)) {
|
||||
if (chunk.type === "usage") {
|
||||
usageData.push({
|
||||
inputTokens: chunk.inputTokens,
|
||||
outputTokens: chunk.outputTokens,
|
||||
cacheReadTokens: chunk.cacheReadTokens,
|
||||
cacheWriteTokens: chunk.cacheWriteTokens,
|
||||
totalCost: chunk.totalCost,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Verify token counting follows Anthropic API specification
|
||||
usageData.should.have.length(1)
|
||||
usageData[0].should.deepEqual({
|
||||
inputTokens: 100, // Total including cache tokens (per Anthropic API docs)
|
||||
outputTokens: 50,
|
||||
cacheReadTokens: 20, // Tracked separately for reporting
|
||||
cacheWriteTokens: 10, // Tracked separately for reporting
|
||||
totalCost: 0.005,
|
||||
})
|
||||
|
||||
// CRITICAL ASSERTION: Verify that input_tokens is NOT inflated by re-adding cache tokens
|
||||
// The bug would have caused inputTokens to be incorrectly calculated as 130 (100 + 20 + 10)
|
||||
// The fix ensures it remains 100, as per Anthropic's specification
|
||||
usageData[0].inputTokens.should.equal(100) // Correct: matches API response
|
||||
usageData[0].inputTokens.should.not.equal(130) // Would be wrong: double-counting cache tokens
|
||||
})
|
||||
|
||||
it("should handle missing usage fields with nullish coalescing", async () => {
|
||||
// Mock the runClaudeCode function
|
||||
const runClaudeCodeModule = await import("@/integrations/claude-code/run")
|
||||
const runClaudeCodeStub = sandbox.stub(runClaudeCodeModule, "runClaudeCode")
|
||||
|
||||
// Create a proper async generator mock with missing/undefined usage fields
|
||||
async function* mockGenerator() {
|
||||
yield {
|
||||
type: "assistant",
|
||||
message: {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "Test response",
|
||||
},
|
||||
],
|
||||
usage: {
|
||||
input_tokens: 100,
|
||||
output_tokens: 50,
|
||||
// cache fields are undefined/missing
|
||||
},
|
||||
stop_reason: "end_turn",
|
||||
},
|
||||
}
|
||||
|
||||
yield {
|
||||
type: "result",
|
||||
result: {},
|
||||
total_cost_usd: 0.005,
|
||||
}
|
||||
}
|
||||
|
||||
runClaudeCodeStub.returns(mockGenerator() as any)
|
||||
|
||||
const systemPrompt = "You are a helpful assistant."
|
||||
const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Hello" }]
|
||||
|
||||
const usageData: any[] = []
|
||||
|
||||
// Collect the results
|
||||
for await (const chunk of handler.createMessage(systemPrompt, messages)) {
|
||||
if (chunk.type === "usage") {
|
||||
usageData.push({
|
||||
inputTokens: chunk.inputTokens,
|
||||
outputTokens: chunk.outputTokens,
|
||||
cacheReadTokens: chunk.cacheReadTokens,
|
||||
cacheWriteTokens: chunk.cacheWriteTokens,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that undefined cache tokens default to 0
|
||||
usageData.should.have.length(1)
|
||||
usageData[0].should.deepEqual({
|
||||
inputTokens: 100,
|
||||
outputTokens: 50,
|
||||
cacheReadTokens: 0, // Should default to 0
|
||||
cacheWriteTokens: 0, // Should default to 0
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle completely missing usage object", async () => {
|
||||
// Mock the runClaudeCode function
|
||||
const runClaudeCodeModule = await import("@/integrations/claude-code/run")
|
||||
const runClaudeCodeStub = sandbox.stub(runClaudeCodeModule, "runClaudeCode")
|
||||
|
||||
// Create a proper async generator mock with missing usage object
|
||||
async function* mockGenerator() {
|
||||
yield {
|
||||
type: "assistant",
|
||||
message: {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "Test response",
|
||||
},
|
||||
],
|
||||
// usage is undefined
|
||||
usage: undefined,
|
||||
stop_reason: "end_turn",
|
||||
},
|
||||
}
|
||||
|
||||
// Need to yield a result chunk to trigger usage data emission
|
||||
yield {
|
||||
type: "result",
|
||||
result: {},
|
||||
total_cost_usd: 0,
|
||||
}
|
||||
}
|
||||
|
||||
runClaudeCodeStub.returns(mockGenerator() as any)
|
||||
|
||||
const systemPrompt = "You are a helpful assistant."
|
||||
const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Hello" }]
|
||||
|
||||
const usageData: any[] = []
|
||||
|
||||
// Collect the results
|
||||
for await (const chunk of handler.createMessage(systemPrompt, messages)) {
|
||||
if (chunk.type === "usage") {
|
||||
usageData.push({
|
||||
inputTokens: chunk.inputTokens,
|
||||
outputTokens: chunk.outputTokens,
|
||||
cacheReadTokens: chunk.cacheReadTokens,
|
||||
cacheWriteTokens: chunk.cacheWriteTokens,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// All token counts should default to 0 when usage is undefined
|
||||
usageData.should.have.length(1)
|
||||
usageData[0].should.deepEqual({
|
||||
inputTokens: 0,
|
||||
outputTokens: 0,
|
||||
cacheReadTokens: 0,
|
||||
cacheWriteTokens: 0,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("getModel", () => {
|
||||
it("should return the correct model when specified", () => {
|
||||
const handler = new ClaudeCodeHandler({
|
||||
apiModelId: "claude-3-5-sonnet-20241022",
|
||||
})
|
||||
|
||||
const model = handler.getModel()
|
||||
model.id.should.equal("claude-3-5-sonnet-20241022")
|
||||
})
|
||||
|
||||
it("should return default model when not specified", () => {
|
||||
const handler = new ClaudeCodeHandler({})
|
||||
|
||||
const model = handler.getModel()
|
||||
// The default model should be set
|
||||
model.id.should.be.type("string")
|
||||
model.info.should.be.type("object")
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,243 @@
|
||||
import Anthropic from "@anthropic-ai/sdk"
|
||||
import { LiteLlmHandler, type LiteLlmModelInfoResponse } from "@core/api/providers/litellm"
|
||||
import { convertToOpenAiMessages } from "@core/api/transform/openai-format"
|
||||
import { expect } from "chai"
|
||||
import sinon from "sinon"
|
||||
|
||||
const fakeClient = {
|
||||
chat: {
|
||||
completions: {
|
||||
create: sinon.stub(),
|
||||
},
|
||||
},
|
||||
baseURL: "fake",
|
||||
}
|
||||
|
||||
describe("LiteLlmHandler", () => {
|
||||
const originalFetch = global.fetch
|
||||
const mockFetch = sinon.stub()
|
||||
|
||||
const mockModelFetch = (modelInfo: LiteLlmModelInfoResponse["data"][number]) => {
|
||||
mockFetch.resolves({
|
||||
ok: true,
|
||||
json: () =>
|
||||
Promise.resolve({
|
||||
data: [modelInfo],
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
let handler: LiteLlmHandler
|
||||
|
||||
const mockHandlerChat = () => {
|
||||
sinon.stub(handler, "ensureClient" as any).returns(fakeClient)
|
||||
}
|
||||
|
||||
const initializeHandler = (model: string) => {
|
||||
handler = new LiteLlmHandler({
|
||||
liteLlmApiKey: "test-api-key",
|
||||
liteLlmBaseUrl: "http://localhost:4000",
|
||||
liteLlmUsePromptCache: true,
|
||||
liteLlmModelId: model,
|
||||
})
|
||||
|
||||
mockHandlerChat()
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
global.fetch = mockFetch
|
||||
|
||||
// Configure the stub to return a stream that closes immediately with usage data
|
||||
fakeClient.chat.completions.create.resolves(
|
||||
createAsyncIterable([
|
||||
{
|
||||
choices: [{ delta: { content: "test response" } }],
|
||||
},
|
||||
{
|
||||
choices: [{}],
|
||||
usage: {
|
||||
prompt_tokens: 100,
|
||||
completion_tokens: 50,
|
||||
cache_creation_input_tokens: 20,
|
||||
cache_read_input_tokens: 10,
|
||||
},
|
||||
},
|
||||
]),
|
||||
)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
sinon.reset()
|
||||
|
||||
global.fetch = originalFetch
|
||||
})
|
||||
|
||||
const createAsyncIterable = (data: any[] = []) => {
|
||||
return {
|
||||
[Symbol.asyncIterator]: async function* () {
|
||||
yield* data
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
describe("prompt cache", () => {
|
||||
const setModelData = (model: string, supportsPromptCaching: boolean) => {
|
||||
mockModelFetch({
|
||||
model_name: model,
|
||||
litellm_params: {
|
||||
model,
|
||||
},
|
||||
model_info: {
|
||||
supports_prompt_caching: supportsPromptCaching,
|
||||
input_cost_per_token: 0.01,
|
||||
output_cost_per_token: 0.02,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
describe("when the model doesn't support prompt caching", () => {
|
||||
const model = "openai/gpt-5"
|
||||
|
||||
beforeEach(() => {
|
||||
initializeHandler(model)
|
||||
setModelData(model, false)
|
||||
})
|
||||
|
||||
it("sends the system prompt and messages with the openai format", async () => {
|
||||
const systemPrompt = "Test System Prompt"
|
||||
const messages: Anthropic.Messages.MessageParam[] = [
|
||||
{
|
||||
role: "user",
|
||||
content: "first message",
|
||||
},
|
||||
{
|
||||
role: "assistant",
|
||||
content: "first response",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "test",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
text: "second message",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
for await (const _ of handler.createMessage(systemPrompt, messages)) {
|
||||
}
|
||||
|
||||
sinon.assert.calledOnce(fakeClient.chat.completions.create)
|
||||
|
||||
const callArgs = fakeClient.chat.completions.create.getCall(0).args[0]
|
||||
|
||||
const systemPromptMessage = callArgs.messages.shift()
|
||||
expect(systemPromptMessage).to.deep.equal({
|
||||
role: "system",
|
||||
content: systemPrompt,
|
||||
})
|
||||
|
||||
expect(callArgs.messages).to.deep.equal(convertToOpenAiMessages(messages))
|
||||
})
|
||||
})
|
||||
|
||||
describe("when the model supports prompt caching", () => {
|
||||
const model = "anthropic/claude-sonnet-4-20250514"
|
||||
|
||||
beforeEach(() => {
|
||||
initializeHandler(model)
|
||||
|
||||
setModelData(model, true)
|
||||
})
|
||||
|
||||
it("inserts the cache control in the system prompt and the last two user messages", async () => {
|
||||
const systemPrompt = "Test System Prompt"
|
||||
const messages: Anthropic.Messages.MessageParam[] = [
|
||||
{
|
||||
role: "user",
|
||||
content: "first message",
|
||||
},
|
||||
{
|
||||
role: "assistant",
|
||||
content: "first response",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "test",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
text: "second message",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
for await (const _ of handler.createMessage(systemPrompt, messages)) {
|
||||
}
|
||||
|
||||
sinon.assert.calledOnce(fakeClient.chat.completions.create)
|
||||
|
||||
const callArgs = fakeClient.chat.completions.create.getCall(0).args[0]
|
||||
|
||||
expect(callArgs.messages[0]).to.deep.equal({
|
||||
role: "system",
|
||||
content: [
|
||||
{
|
||||
text: systemPrompt,
|
||||
type: "text",
|
||||
cache_control: {
|
||||
type: "ephemeral",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const sentMessages = callArgs.messages
|
||||
expect(sentMessages.length).to.equal(4)
|
||||
|
||||
const firstUserMessage = sentMessages[1]
|
||||
|
||||
expect(firstUserMessage).to.deep.equal({
|
||||
role: "user",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "first message",
|
||||
cache_control: {
|
||||
type: "ephemeral",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const lastUserMessage = sentMessages[3]
|
||||
expect(lastUserMessage.content[0]).to.deep.equal({
|
||||
type: "text",
|
||||
text: "test",
|
||||
})
|
||||
|
||||
const lastContentBlock = lastUserMessage.content[lastUserMessage.content.length - 1]
|
||||
expect(lastContentBlock).to.deep.equal({
|
||||
type: "text",
|
||||
text: "second message",
|
||||
cache_control: {
|
||||
type: "ephemeral",
|
||||
},
|
||||
})
|
||||
|
||||
expect(callArgs.model).to.be.a("string")
|
||||
expect(callArgs.stream).to.equal(true)
|
||||
expect(callArgs.stream_options).to.deep.equal({ include_usage: true })
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user