Compare commits

..
Author SHA1 Message Date
celestial-vault eb842982ff migrate withProgress 2025-07-21 23:15:11 -07:00
2134 changed files with 87787 additions and 635043 deletions
-211
View File
@@ -1,211 +0,0 @@
---
name: create-pull-request
description: Create a GitHub pull request following project conventions. Use when the user asks to create a PR, submit changes for review, or open a pull request. Handles commit analysis, branch management, PR template usage, and PR creation using the gh CLI tool.
---
# Create Pull Request
This skill guides you through creating a well-structured GitHub pull request that follows project conventions and best practices.
## Prerequisites Check
Before proceeding, verify the following:
### 1. Check if `gh` CLI is installed
```bash
gh --version
```
If not installed, inform the user:
> The GitHub CLI (`gh`) is required but not installed. Please install it:
> - macOS: `brew install gh`
> - Other: https://cli.github.com/
### 2. Check if authenticated with GitHub
```bash
gh auth status
```
If not authenticated, guide the user to run `gh auth login`.
### 3. Verify clean working directory
```bash
git status
```
If there are uncommitted changes, ask the user whether to:
- Commit them as part of this PR
- Stash them temporarily
- Discard them (with caution)
## Gather Context
### 1. Identify the current branch
```bash
git branch --show-current
```
Ensure you're not on `main` or `master`. If so, ask the user to create or switch to a feature branch.
### 2. Find the base branch
```bash
git remote show origin | grep "HEAD branch"
```
This is typically `main` or `master`.
### 3. Analyze recent commits relevant to this PR
```bash
git log origin/main..HEAD --oneline --no-decorate
```
Review these commits to understand:
- What changes are being introduced
- The scope of the PR (single feature/fix or multiple changes)
- Whether commits should be squashed or reorganized
### 4. Review the diff
```bash
git diff origin/main..HEAD --stat
```
This shows which files changed and helps identify the type of change.
## Information Gathering
Before creating the PR, you need the following information. Check if it can be inferred from:
- Commit messages
- Branch name (e.g., `fix/issue-123`, `feature/new-login`)
- Changed files and their content
If any critical information is missing, use `ask_followup_question` to ask the user:
### Required Information
1. **Related Issue Number**: Look for patterns like `#123`, `fixes #123`, or `closes #123` in commit messages
2. **Description**: What problem does this solve? Why were these changes made?
3. **Type of Change**: Bug fix, new feature, breaking change, refactor, cosmetic, documentation, or workflow
4. **Test Procedure**: How was this tested? What could break?
### Example clarifying question
If the issue number is not found:
> I couldn't find a related issue number in the commit messages or branch name. What GitHub issue does this PR address? (Enter the issue number, e.g., "123" or "N/A" for small fixes)
## Git Best Practices
Before creating the PR, consider these best practices:
### Commit Hygiene
1. **Atomic commits**: Each commit should represent a single logical change
2. **Clear commit messages**: Follow conventional commit format when possible
3. **No merge commits**: Prefer rebasing over merging to keep history clean
### Branch Management
1. **Rebase on latest main** (if needed):
```bash
git fetch origin
git rebase origin/main
```
2. **Squash if appropriate**: If there are many small "WIP" commits, consider interactive rebase:
```bash
git rebase -i origin/main
```
Only suggest this if commits appear messy and the user is comfortable with rebasing.
### Push Changes
Ensure all commits are pushed:
```bash
git push origin HEAD
```
If the branch was rebased, you may need:
```bash
git push origin HEAD --force-with-lease
```
## Create the Pull Request
**IMPORTANT**: Read and use the PR template at `.github/pull_request_template.md`. The PR body format must **strictly match** the template structure. Do not deviate from the template format.
When filling out the template:
- Replace `#XXXX` with the actual issue number, or keep as `#XXXX` if no issue exists (for small fixes)
- Fill in all sections with relevant information gathered from commits and context
- Mark the appropriate "Type of Change" checkbox(es)
- Complete the "Pre-flight Checklist" items that apply
### Create PR with gh CLI
**Use a temporary file for the PR body** to avoid shell escaping issues, newline problems, and other command-line flakiness:
1. Write the PR body to a temporary file:
```
/tmp/pr-body.md
```
2. Create the PR using the file:
```bash
gh pr create --title "PR_TITLE" --body-file /tmp/pr-body.md --base main
```
3. Clean up the temporary file:
```bash
rm /tmp/pr-body.md
```
For draft PRs:
```bash
gh pr create --title "PR_TITLE" --body-file /tmp/pr-body.md --base main --draft
```
**Why use a file?** Passing complex markdown with newlines, special characters, and checkboxes directly via `--body` is error-prone. The `--body-file` flag handles all content reliably.
## Post-Creation
After creating the PR:
1. **Display the PR URL** so the user can review it
2. **Remind about CI checks**: Tests and linting will run automatically
3. **Suggest next steps**:
- Add reviewers if needed: `gh pr edit --add-reviewer USERNAME`
- Add labels if needed: `gh pr edit --add-label "bug"`
## Error Handling
### Common Issues
1. **No commits ahead of main**: The branch has no changes to submit
- Ask if the user meant to work on a different branch
2. **Branch not pushed**: Remote doesn't have the branch
- Push the branch first: `git push -u origin HEAD`
3. **PR already exists**: A PR for this branch already exists
- Show the existing PR: `gh pr view`
- Ask if they want to update it instead
4. **Merge conflicts**: Branch conflicts with base
- Guide user through resolving conflicts or rebasing
## Summary Checklist
Before finalizing, ensure:
- [ ] `gh` CLI is installed and authenticated
- [ ] Working directory is clean
- [ ] All commits are pushed
- [ ] Branch is up-to-date with base branch
- [ ] Related issue number is identified, or placeholder is used
- [ ] PR description follows the template exactly
- [ ] Appropriate type of change is selected
- [ ] Pre-flight checklist items are addressed
+8
View File
@@ -0,0 +1,8 @@
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
Improve cerebras Qwen model performance by removing thinking tokens from the model input
+11
View File
@@ -0,0 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.0.5/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "restricted",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": minor
---
Change available Cerebras models - limit to Qwen and llama 3.3 70b
+8
View File
@@ -0,0 +1,8 @@
---
"claude-dev": patch
---
Added checkpointTrackerErrorMessage to HistoryItem - restored with task, prevents re-initialization if timed out before
Never re-init checkpoint tracker if it timed out before
Warning at 7s that it's taking awhile, timeout and give up at 15s
Fixed click to open settings - now opens to correct tab
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
fix: mcp servers are not started when disabled
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
Refactor Git commit message generation to support output streaming.
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
Introduce Claude Code support on Windows and fix E2BIG issues
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": minor
---
Change Cerebras Qwen 3 32b context window from 16k to 64k
+26
View File
@@ -0,0 +1,26 @@
changesDir: .changes
unreleasedDir: unreleased
headerPath: header.tpl.md
changelogPath: CHANGELOG.md
versionExt: md
versionFormat: '## {{.Version}} - {{.Time.Format "2006-01-02"}}'
kindFormat: "### {{.Kind}}"
changeFormat: "* {{.Body}}"
kinds:
- label: Added
auto: minor
- label: Changed
auto: major
- label: Deprecated
auto: minor
- label: Removed
auto: major
- label: Fixed
auto: patch
- label: Security
auto: patch
newlines:
afterChangelogHeader: 1
beforeChangelogVersion: 1
endOfVersion: 1
envPrefix: CHANGIE_
-1
View File
@@ -1 +0,0 @@
../../.clinerules/workflows/hotfix-release.md
-1
View File
@@ -1 +0,0 @@
../../.clinerules/workflows/release.md
@@ -1,51 +0,0 @@
#!/bin/bash
set -euo pipefail
# Only run in Claude Code remote environments
if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
exit 0
fi
cd "$CLAUDE_PROJECT_DIR"
echo "=== Claude Code for Web Setup ==="
echo ""
# Install latest gh CLI tool
echo "Installing GitHub CLI..."
GH_VERSION=$(curl -s https://api.github.com/repos/cli/cli/releases/latest | grep '"tag_name"' | cut -d'"' -f4 | sed 's/^v//')
curl -sL "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_amd64.tar.gz" -o /tmp/gh.tar.gz
tar -xzf /tmp/gh.tar.gz -C /tmp
sudo mv "/tmp/gh_${GH_VERSION}_linux_amd64/bin/gh" /usr/local/bin/gh
rm -rf /tmp/gh.tar.gz /tmp/gh_${GH_VERSION}_linux_amd64
echo "Installed gh version: $(gh --version | head -1)"
echo ""
# Check if GITHUB_TOKEN is set and configure gh
if [ -n "${GITHUB_TOKEN:-}" ]; then
echo "GITHUB_TOKEN is configured - gh CLI is ready to use"
echo ""
echo "You can use gh commands directly, for example:"
echo " gh issue list --repo cline/cline --limit 5"
echo " gh pr list --repo cline/cline --state open"
echo " gh issue view 123 --repo cline/cline"
echo ""
else
echo "GITHUB_TOKEN is not set - gh CLI will have limited functionality"
echo ""
echo "To enable full GitHub API access:"
echo "1. Create a Fine-grained Personal Access Token at https://github.com/settings/tokens?type=beta"
echo "2. Add it as GITHUB_TOKEN in your Claude Code environment settings"
echo ""
fi
# Install project dependencies
echo "Installing dependencies..."
npm run install:all
# Generate gRPC/protobuf types (required for TypeScript)
echo "Generating proto types..."
npm run protos
echo ""
echo "Session setup complete!"
-14
View File
@@ -1,14 +0,0 @@
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/claude-code-for-web-setup.sh"
}
]
}
]
}
}
-33
View File
@@ -1,33 +0,0 @@
# CLI Development
The CLI lives in `cli/` and uses React Ink for terminal UI.
- If needed, look at `cli/src/constants/colors.ts` for re-used terminal colors, e.g. `COLORS.primaryBlue` highlight color (selections, spinners, success states).
- Never use `dimColor` with gray (e.g. `<Text color="gray" dimColor>`) - it's too hard to read. Use `color="gray"` for secondary text and normal foreground (no color) for primary text.
- When thinking about how to handle state or messages from core, look at webview for how it communicates with the vs code extension.
- When updating the webview, consider and suggest to the user to update the CLI TUI since we want to provide a similar experience to our terminal users as we do our vs code extension users.
## Adding New API Providers
When adding a new API provider to the extension, you must also update the CLI:
1. **Update `cli/src/components/ModelPicker.tsx`**: Add the provider to the `providerModels` map so `getDefaultModelId()` returns the correct default model. Import the models and default ID from `@shared/api`:
```typescript
import { newProviderDefaultModelId, newProviderModels } from "@/shared/api"
export const providerModels = {
// ...existing providers
"new-provider": { models: newProviderModels, defaultId: newProviderDefaultModelId },
}
```
2. **Use `applyProviderConfig()` for auth flows**: When implementing OAuth or other auth flows for the provider, use the shared utility at `cli/src/utils/provider-config.ts`:
```typescript
import { applyProviderConfig } from "../utils/provider-config"
// After successful auth:
await applyProviderConfig({ providerId: "new-provider", controller })
```
This handles setting provider, default model, API key mapping, state persistence, and rebuilding the API handler.
3. **Provider-specific auth**: If the provider uses OAuth (like `openai-codex`), add handling in `SettingsPanelContent.tsx`'s `handleProviderSelect` callback. See the existing Codex OAuth flow as a reference.
+1 -1
View File
@@ -716,7 +716,7 @@ The Controller class manages MCP servers through the McpHub service:
class Controller {
mcpHub?: McpHub
constructor(context: vscode.ExtensionContext, webviewProvider: WebviewProvider) {
constructor(context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel, webviewProvider: WebviewProvider) {
this.mcpHub = new McpHub(this)
}
-51
View File
@@ -1,51 +0,0 @@
# Debug Harness
HTTP-controlled debugger for the VSCode extension at `src/dev/debug-harness/server.ts`.
## Quick start
```bash
# Build extension first if needed (protos + esbuild):
npm run protos && IS_DEV=true node esbuild.mjs
# Launch (skip-build if already built):
npx tsx src/dev/debug-harness/server.ts --skip-build --auto-launch
# In another terminal:
curl localhost:19229/api -d '{"method":"status"}'
```
## Key commands
All via `POST localhost:19229/api` with `{"method":"...", "params":{...}}`:
- **`launch`** / **`shutdown`** — lifecycle
- **`ui.screenshot`** — screenshot to `/tmp/cline-debug/`; returns `{path}`**use `read_file` on the path to examine, do NOT `open` the file** (Preview.app covers the VSCode window)
- **`ui.open_sidebar`** — open the Cline sidebar
- **`ext.set_breakpoint`** `{file, line, condition?}` — breakpoint by source file (sourcemap-resolved)
- **`ext.evaluate`** `{expression, callFrameId?}` — eval in extension host
- **`ext.resume`** / **`ext.step_over`** / **`ext.step_into`** — stepping
- **`ext.call_stack`** — inspect when paused
- **`web.evaluate`** `{expression}` — eval in webview
- **`web.post_message`** `{message}` — send postMessage to extension host via exposed vsCodeApi
- **`wait_for_pause`** `{timeout?}` — block until breakpoint hit
- **`ui.locator`** `{role?, testId?, text?, action?, frame?}` — Playwright locator (auto-retries on stale sidebar frame)
- **`ui.react_input`** `{text, selector?, clear?, submit?}` — set React textarea value via `execCommand('insertText')`; works reliably across multiple tasks
- **`ui.send_message`** `{text, images?, files?, responseType?}` — send chat message bypassing the textarea entirely (via gRPC postMessage)
- **`ui.command_palette`** `{command}` — run VSCode command
## Caveats
- **⚠️ Dismiss "Introducing Cline Kanban" overlay FIRST**: On fresh launches a full-screen promo overlay blocks the sidebar. **Dismiss it immediately after `ui.open_sidebar`**, before any other interaction or screenshot. Most reliable method:
```bash
curl localhost:19229/api -d '{"method": "ui.open_sidebar"}'
curl localhost:19229/api -d '{"method": "web.evaluate", "params": {"expression": "document.querySelector(\".sr-only\")?.parentElement?.click()"}}'
```
- **Screenshots — don't open the file**: `ui.screenshot` and `ui.sidebar_screenshot` save PNGs to `/tmp/cline-debug/` and return the `{path}`. Use `read_file` on the path to examine screenshots. Running `open <path>` launches Preview.app on macOS which covers the VSCode window.
- **Scripts count = 0 after launch**: CDP connects after extension host starts, so scripts parsed during startup aren't tracked. Breakpoints still work via sourcemap resolution.
- **Port 9230**: Extension host inspector. If another VSCode instance uses this port, the harness will fail to connect. Kill other debug instances first.
- **macOS only** for now (Playwright Electron launch behavior).
- **Webview CDP**: `connect_webview` may fail depending on Electron version. `web.evaluate` still works via Playwright's `frame.evaluate()` fallback.
- **Sourcemap paths**: esbuild outputs relative paths like `../src/extension.ts` in the sourcemap. The resolver handles this, but if a file isn't found, use `ext.source_files` to see exact paths.
See `src/dev/debug-harness/README.md` for full API reference.
-205
View File
@@ -1,205 +0,0 @@
This file is the secret sauce for working effectively in this codebase. It captures tribal knowledge—the nuanced, non-obvious patterns that make the difference between a quick fix and hours of back-and-forth & human intervention.
**When to add to this file:**
- User had to intervene, correct, or hand-hold
- Multiple back-and-forth attempts were needed to get something working
- You discovered something that required reading many files to understand
- A change touched files you wouldn't have guessed
- Something worked differently than you expected
- User explicitly asks to "add this to CLAUDE.md"
**Proactively suggest additions** when any of the above happen—don't wait to be asked.
**What NOT to add:** Stuff you can figure out from reading a few files, obvious patterns, or standard practices. This file should be high-signal, not comprehensive.
## Miscellaneous
- This is a VS Code extension—check `package.json` for available scripts before trying to verify builds (e.g., `npm run compile`, not `npm run build`).
- When creating PRs, contributors should not create changelog-entry files. Maintainers handle release versioning and changelog curation during the release process.
- When adding new feature flags, see this PR as a reference https://github.com/cline/cline/pull/7566
- Additional instructions about making requests: @.clinerules/network.md
## gRPC/Protobuf Communication
The extension and webview communicate via gRPC-like protocol over VS Code message passing.
**Proto files live in `proto/`** (e.g., `proto/cline/task.proto`, `proto/cline/ui.proto`)
- Each feature domain has its own `.proto` file
- For simple data, use shared types in `proto/cline/common.proto` (`StringRequest`, `Empty`, `Int64Request`)
- For complex data, define custom messages in the feature's `.proto` file
- Naming: Services `PascalCaseService`, RPCs `camelCase`, Messages `PascalCase`
- For streaming responses, use `stream` keyword (see `subscribeToAuthCallback` in `account.proto`)
**Run `npm run protos`** after any proto changes—generates types in:
- `src/shared/proto/` - Shared type definitions
- `src/generated/grpc-js/` - Service implementations
- `src/generated/nice-grpc/` - Promise-based clients
- `src/generated/hosts/` - Generated handlers
**Adding new enum values** (like a new `ClineSay` type) requires updating conversion mappings in `src/shared/proto-conversions/cline-message.ts`
**Adding new RPC methods** requires:
- Handler in `src/core/controller/<domain>/`
- Call from webview via generated client: `UiServiceClient.scrollToSettings(StringRequest.create({ value: "browser" }))`
**Example—the `explain-changes` feature touched:**
- `proto/cline/task.proto` - Added `ExplainChangesRequest` message and `explainChanges` RPC
- `proto/cline/ui.proto` - Added `GENERATE_EXPLANATION = 29` to `ClineSay` enum
- `src/shared/ExtensionMessage.ts` - Added `ClineSayGenerateExplanation` type
- `src/shared/proto-conversions/cline-message.ts` - Added mapping for new say type
- `src/core/controller/task/explainChanges.ts` - Handler implementation
- `webview-ui/src/components/chat/ChatRow.tsx` - UI rendering
## Adding a New API Provider
When adding a new provider (e.g., "openai-codex"), you must update the proto conversion layer in THREE places or the provider will silently reset to Anthropic:
1. `proto/cline/models.proto` - Add to the `ApiProvider` enum (e.g., `OPENAI_CODEX = 40;`)
2. `convertApiProviderToProto()` in `src/shared/proto-conversions/models/api-configuration-conversion.ts` - Add case mapping string to proto enum
3. `convertProtoToApiProvider()` in the same file - Add case mapping proto enum back to string
**Why this matters:** Without these, the provider string hits the `default` case and returns `ANTHROPIC`. The webview, provider list, and handler all work fine, but the state silently resets when it round-trips through proto serialization. No error is thrown.
**Other files to update when adding a provider:**
- `src/shared/api.ts` - Add to `ApiProvider` union type, define models
- `src/shared/providers/providers.json` - Add to provider list for dropdown
- `src/core/api/index.ts` - Register handler in `createHandlerForProvider()`
- `webview-ui/src/components/settings/utils/providerUtils.ts` - Add cases in `getModelsForProvider()` and `normalizeApiConfiguration()`
- `webview-ui/src/utils/validate.ts` - Add validation case
- `webview-ui/src/components/settings/ApiOptions.tsx` - Render provider component
## Responses API Providers (OpenAI Codex, OpenAI Native)
Providers using OpenAI's Responses API require native tool calling. XML tools don't work with the Responses API.
**Symptoms of broken native tool calling:**
- Tools get called multiple times (e.g., `ask_followup_question` asks the same question twice)
- Tool arguments get duplicated or malformed
- The model responds but tools aren't recognized
**Root causes to check:**
1. **Provider missing from `isNextGenModelProvider()`** in `src/utils/model-utils.ts`. The native variant matchers (e.g., `native-gpt-5/config.ts`) call this function. If your provider isn't in the list, the matcher returns false and falls back to XML tools.
2. **Model missing `apiFormat: ApiFormat.OPENAI_RESPONSES`** in its model info (`src/shared/api.ts`). This property signals that the model requires native tool calling. The task runner in `src/core/task/index.ts` checks this and forces `enableNativeToolCalls: true` regardless of user settings.
**When adding a new Responses API provider:**
1. Add provider to `isNextGenModelProvider()` list in `src/utils/model-utils.ts`
2. Set `apiFormat: ApiFormat.OPENAI_RESPONSES` on all models that use the Responses API
3. The variant matcher and task runner will handle the rest automatically
## Adding Tools to System Prompt
This is tricky—multiple prompt variants and configs. **Always search for existing similar tools first and follow their pattern.** Look at the full chain from prompt definition → variant configs → handler → UI before implementing.
1. **Add to `ClineDefaultTool` enum** in `src/shared/tools.ts`
2. **Tool definition** in `src/core/prompts/system-prompt/tools/` (create file like `generate_explanation.ts`)
- Define variants for each `ModelFamily` (generic, next-gen, xs, etc.)
- Export variants array (e.g., `export const my_tool_variants = [GENERIC, NATIVE_NEXT_GEN, XS]`)
- **Fallback behavior**: If a variant isn't defined for a model family, `ClineToolSet.getToolByNameWithFallback()` automatically falls back to GENERIC. So you only need to export `[GENERIC]` unless the tool needs model-specific behavior.
3. **Register in `src/core/prompts/system-prompt/tools/init.ts`** - Import and spread into `allToolVariants`
4. **Add to variant configs** - Each model family has its own config in `src/core/prompts/system-prompt/variants/*/config.ts`. Add your tool's enum to the `.tools()` list:
- `generic/config.ts`, `next-gen/config.ts`, `gpt-5/config.ts`, `native-gpt-5/config.ts`, `native-gpt-5-1/config.ts`, `native-next-gen/config.ts`, `gemini-3/config.ts`, `glm/config.ts`, `hermes/config.ts`, `xs/config.ts`
- **Important**: If you add to a variant's config, make sure the tool spec exports a variant for that ModelFamily (or relies on GENERIC fallback)
5. **Create handler** in `src/core/task/tools/handlers/`
6. **Wire up in `ToolExecutor.ts`** if needed for execution flow
7. **Add to tool parsing** in `src/core/assistant-message/index.ts` if needed
8. **If tool has UI feedback**: add `ClineSay` enum in proto, update `src/shared/ExtensionMessage.ts`, update `src/shared/proto-conversions/cline-message.ts`, update `webview-ui/src/components/chat/ChatRow.tsx`
## Modifying System Prompt
**Read these first:** `src/core/prompts/system-prompt/README.md`, `tools/README.md`, `__tests__/README.md`
System prompt is modular: **components** (reusable sections) + **variants** (model-specific configs) + **templates** (with `{{PLACEHOLDER}}` resolution).
**Key directories:**
- `components/` - Shared sections: `rules.ts`, `capabilities.ts`, `editing_files.ts`, etc.
- `variants/` - Model-specific: `generic/`, `next-gen/`, `xs/`, `gpt-5/`, `gemini-3/`, `hermes/`, `glm/`, etc.
- `templates/` - Template engine and placeholder definitions
**Variant tiers (ask user which to modify):**
- **Next-gen** (Claude 4, GPT-5, Gemini 2.5): `next-gen/`, `native-next-gen/`, `native-gpt-5/`, `native-gpt-5-1/`, `gemini-3/`, `gpt-5/`
- **Standard** (default fallback): `generic/`
- **Local/small models**: `xs/`, `hermes/`, `glm/`
**How overrides work:** Variants can override components via `componentOverrides` in their `config.ts`, or provide a custom template in `template.ts` (e.g., `next-gen/template.ts` exports `rules_template`). If no override, the shared component from `components/` is used.
**Example: Adding a rule to RULES section**
1. Check if variant overrides rules: look for `rules_template` in `variants/*/template.ts` or `componentOverrides.RULES` in `config.ts`
2. If shared: modify `components/rules.ts`
3. If overridden: modify that variant's template
4. XS variant is special—has heavily condensed inline content in `template.ts`
**After any changes, regenerate snapshots:**
```bash
UPDATE_SNAPSHOTS=true npm run test:unit
```
Snapshots live in `__tests__/__snapshots__/`. Tests validate across model families and context variations (browser, MCP, focus chain).
## Modifying Default Slash Commands
Three places need updates:
- `src/core/slash-commands/index.ts` - Command definitions
- `src/core/prompts/commands.ts` - System prompt integration
- `webview-ui/src/utils/slash-commands.ts` - Webview autocomplete
## Adding New Global State Keys
Adding a new key to global state requires updates in multiple places. Missing any step causes silent failures.
Required steps:
1. Type definition in `src/shared/storage/state-keys.ts` - Add to `GlobalState` or `Settings` interface
2. Read from globalState in `src/core/storage/utils/state-helpers.ts`:
- Add `const myKey = context.globalState.get<GlobalStateAndSettings["myKey"]>("myKey")` in `readGlobalStateFromDisk()`
- Add to the return object: `myKey: myKey ?? defaultValue,`
3. StateManager handles read/write via `setGlobalState()`/`getGlobalStateKey()` after initialization
Common mistake: Adding only the return value without the `context.globalState.get()` call. This compiles but the value is always `undefined` on load.
Settings plumbing gotcha: if a key is user-toggleable from settings, wire both controller update paths:
- `src/core/controller/state/updateSettings.ts` for webview `updateSetting(...)`
- `src/core/controller/state/updateSettingsCli.ts` for CLI/ACP settings updates
Missing one path causes a toggle to appear to change in one surface while the backend state stays unchanged.
Webview toggle gotcha: settings changes must also round-trip back in state payloads.
- Add the field to `UpdateSettingsRequest` in `proto/cline/state.proto` (for webview update requests), then run `npm run protos`
- Include the key in `Controller.getStateToPostToWebview()` (`src/core/controller/index.ts`)
- Ensure `ExtensionState` and webview defaults include the key (`src/shared/ExtensionMessage.ts`, `webview-ui/src/context/ExtensionStateContext.tsx`)
If this round-trip wiring is missing, the backend value can update but the toggle in webview appears stuck or reverts.
## StateManager Cache vs Direct globalState Access
StateManager uses an in-memory cache populated during `StateManager.initialize(context)` in `common.ts`. For most state, use `controller.stateManager.setGlobalState()`/`getGlobalStateKey()`.
Exception: State needed immediately at extension startup (before cache is ready)
When Window A sets state and immediately opens Window B, the new window's StateManager cache is populated from `context.globalState` during initialization. If you need to read state in Window B right at startup (e.g., in `common.ts` during `initialize()`), read directly from `context.globalState.get()` instead of StateManager's cache.
Example pattern (see `lastShownAnnouncementId` and `worktreeAutoOpenPath`):
```typescript
// Writing (normal pattern)
controller.stateManager.setGlobalState("myKey", value)
// Reading at startup in common.ts (bypass cache)
const value = context.globalState.get<string>("myKey")
```
This is only needed for cross-window state read during the brief startup window before StateManager cache is fully usable. Normal state access after initialization should use StateManager.
## ChatRow Cancelled/Interrupted States
When a ChatRow displays a loading/in-progress state (spinner), you must handle what happens when the task is cancelled. This is non-obvious because cancellation doesn't update the message content—you have to infer it from context.
**The pattern:**
1. A message has a `status` field (e.g., `"generating"`, `"complete"`, `"error"`) stored in `message.text` as JSON
2. When cancelled mid-operation, the status stays `"generating"` forever—no one updates it
3. To detect cancellation, check TWO conditions:
- `!isLast` — if this message is no longer the last message, something else happened after it (interrupted)
- `lastModifiedMessage?.ask === "resume_task" || "resume_completed_task"` — task was just cancelled and is waiting to resume
**Example from `generate_explanation`:**
```tsx
const wasCancelled =
explanationInfo.status === "generating" &&
(!isLast ||
lastModifiedMessage?.ask === "resume_task" ||
lastModifiedMessage?.ask === "resume_completed_task")
const isGenerating = explanationInfo.status === "generating" && !wasCancelled
```
**Why both checks?**
- `!isLast` catches: cancelled → resumed → did other stuff → this old message is stale
- `lastModifiedMessage?.ask === "resume_task"` catches: just cancelled, hasn't resumed yet, this message is still technically "last"
**See also:** `BrowserSessionRow.tsx` uses similar pattern with `isLastApiReqInterrupted` and `isLastMessageResume`.
**Backend side:** When streaming is cancelled, clean up properly (close tabs, clear comments, etc.) by checking `taskState.abort` after the streaming function returns.
-423
View File
@@ -1,423 +0,0 @@
# Cline Hooks Documentation
## Overview
Cline hooks allow you to execute custom scripts at specific points in the agentic workflow. Hooks can be placed in either:
- **Global hooks directory**: `~/Documents/Cline/Hooks/` (applies to all workspaces)
- **Workspace hooks directory**: `.clinerules/hooks/` (applies to the workspace the repo is part of)
Hooks run automatically when enabled.
## Enabling Hooks
1. Open Cline settings in VSCode
2. Navigate to the Feature Settings section
3. Check the "Enable Hooks" checkbox
4. Hooks must be executable files (on Unix/Linux/macOS use `chmod +x hookname`)
## Available Hooks
### TaskStart Hook
- **When**: Runs when a NEW task is started (not when resuming)
- **Purpose**: Initialize task context, validate task requirements, set up environment
- **Global Location**: `~/Documents/Cline/Hooks/TaskStart`
- **Workspace Location**: `.clinerules/hooks/TaskStart`
### TaskResume Hook
- **When**: Runs when an EXISTING task is resumed (after user clicks resume button)
- **Purpose**: Validate resumed task state, restore context, check for changes since last run
- **Global Location**: `~/Documents/Cline/Hooks/TaskResume`
- **Workspace Location**: `.clinerules/hooks/TaskResume`
### TaskCancel Hook
- **When**: Runs when a task is cancelled or a hook is aborted by the user (only if there's actual active work or work was started)
- **Purpose**: Clean up resources, log cancellation, save state
- **Global Location**: `~/Documents/Cline/Hooks/TaskCancel`
- **Workspace Location**: `.clinerules/hooks/TaskCancel`
- **Note**: This hook is NOT cancellable
### TaskComplete Hook (coming soon!)
- **When**: Runs when a task is marked as complete
- **Purpose**: Log completion status, perform final cleanup, generate reports
- **Global Location**: `~/Documents/Cline/Hooks/TaskComplete`
- **Workspace Location**: `.clinerules/hooks/TaskComplete`
### UserPromptSubmit Hook
- **When**: Runs when the user submits a prompt/message (initial task, resume, or feedback)
- **Purpose**: Validate user input, preprocess prompts, add context to user messages
- **Global Location**: `~/Documents/Cline/Hooks/UserPromptSubmit`
- **Workspace Location**: `.clinerules/hooks/UserPromptSubmit`
### PreToolUse Hook
- **When**: Runs BEFORE a tool is executed
- **Purpose**: Validate parameters, block execution, or add context
- **Global Location**: `~/Documents/Cline/Hooks/PreToolUse`
- **Workspace Location**: `.clinerules/hooks/PreToolUse`
### PostToolUse Hook
- **When**: Runs AFTER a tool completes
- **Purpose**: Observe results, track patterns, or add context
- **Global Location**: `~/Documents/Cline/Hooks/PostToolUse`
- **Workspace Location**: `.clinerules/hooks/PostToolUse`
### PreCompact Hook (coming soon!)
- **When**: Runs BEFORE the conversation context is compacted/truncated
- **Purpose**: Observe compaction events, log context management, track token usage
- **Global Location**: `~/Documents/Cline/Hooks/PreCompact`
- **Workspace Location**: `.clinerules/hooks/PreCompact`
## Cross-Platform Hook Format
Cline uses a git-style approach for hooks that works consistently across all platforms:
### Hook Files (All Platforms)
- **No file extensions**: Hooks are named exactly `PreToolUse` or `PostToolUse` (no `.bat`, `.cmd`, `.sh` etc.)
- **Shebang required**: First line must be a shebang (e.g., `#!/usr/bin/env bash` or `#!/usr/bin/env node`)
- **Executable on Unix**: On Unix/Linux/macOS, hooks must be executable: `chmod +x PreToolUse`
- **Windows**: Not currently supported.
### How It Works
Like git hooks, Cline executes hook files through a shell that interprets the shebang line:
- On Unix/Linux/macOS: Native shell execution with shebang support
This means:
- ✅ Same hook script works on all platforms
- ✅ Write once, run anywhere
- ✅ Use any scripting language (bash, node, python, etc.)
### Creating Hooks
**On Unix/Linux/macOS:**
```bash
# Create hook file
nano ~/Documents/Cline/Hooks/PreToolUse
# Make executable
chmod +x ~/Documents/Cline/Hooks/PreToolUse
```
## Context Injection Timing
**IMPORTANT**: Context injected by hooks affects **FUTURE AI decisions**, not the current tool execution.
### Why This Matters
When a hook runs:
1. The AI has already decided what tool to use and with what parameters
2. The hook cannot modify those parameters
3. Context from the hook is added to the conversation
4. The AI sees this context in the **NEXT API request** and can adjust future decisions
### PreToolUse Hook Flow
```
1. AI decides: "I'll use write_to_file with these parameters"
2. PreToolUse hook runs → can block or add context
3. If allowed, tool executes with original parameters
4. Context is added to conversation
5. Next API request includes this context
6. AI adjusts future decisions based on context
```
### PostToolUse Hook Flow
```
1. Tool completes execution
2. PostToolUse hook runs → observes results
3. Hook adds context about the outcome
4. Context is added to conversation
5. Next API request includes this context
6. AI can learn from the results
```
## Hook Input/Output
### Input (via stdin as JSON)
All hooks receive:
```json
{
"clineVersion": "string",
"hookName": "TaskStart" | "TaskResume" | "TaskCancel" | "TaskComplete" | "UserPromptSubmit" | "PreToolUse" | "PostToolUse" | "PreCompact",
"timestamp": "string",
"taskId": "string",
"workspaceRoots": ["string"],
"userId": "string",
"taskStart": { // Only for TaskStart
"taskMetadata": {
"taskId": "string",
"ulid": "string",
"initialTask": "string"
}
},
"taskResume": { // Only for TaskResume
"taskMetadata": {
"taskId": "string",
"ulid": "string"
},
"previousState": {
"lastMessageTs": "string",
"messageCount": "string",
"conversationHistoryDeleted": "string"
}
},
"taskCancel": { // Only for TaskCancel
"taskMetadata": {
"taskId": "string",
"ulid": "string",
"completionStatus": "string"
}
},
"taskComplete": { // Only for TaskComplete
"taskMetadata": {
"taskId": "string",
"ulid": "string"
}
},
"userPromptSubmit": { // Only for UserPromptSubmit
"prompt": "string",
"attachments": ["string"]
},
"preToolUse": { // Only for PreToolUse
"toolName": "string",
"parameters": {}
},
"postToolUse": { // Only for PostToolUse
"toolName": "string",
"parameters": {},
"result": "string",
"success": boolean,
"executionTimeMs": number
},
"preCompact": { // Only for PreCompact
"contextSize": number,
"messagesToCompact": number,
"compactionStrategy": "string"
}
}
```
### Output (via stdout as JSON)
All hooks must return:
```json
{
"cancel": boolean, // Required: false to continue, true to block execution
"contextModification": "string", // Optional: Context for future AI decisions
"errorMessage": "string" // Optional: Error details if blocking
}
```
**Note**: The `cancel` field works as follows:
- `false` (or omitted): Allow execution to continue
- `true`: Block execution and show error message to user
## Hook Execution Limits
- **Timeout**: Hooks must complete within 30 seconds (configurable via `HOOK_EXECUTION_TIMEOUT_MS`)
- **Context Size**: Context modifications are limited to 50KB (configurable via `MAX_CONTEXT_MODIFICATION_SIZE`)
- **Error Handling**: Expected errors (file not found, permission denied, not a directory) are handled silently; unexpected file system errors are propagated
## Common Use Cases
### 1. Validation - Block Invalid Operations
```bash
#!/usr/bin/env bash
input=$(cat)
tool_name=$(echo "$input" | jq -r '.preToolUse.toolName')
path=$(echo "$input" | jq -r '.preToolUse.parameters.path // ""')
if [[ "$tool_name" == "write_to_file" && "$path" == *.js ]]; then
cat <<EOF
{
"cancel": true,
"errorMessage": "Cannot create .js files in TypeScript project",
"contextModification": "Use .ts/.tsx extensions only"
}
EOF
exit 0
fi
echo '{"cancel": false}'
```
### 2. Context Building - Learn from Operations
```bash
#!/usr/bin/env bash
input=$(cat)
tool_name=$(echo "$input" | jq -r '.postToolUse.toolName')
success=$(echo "$input" | jq -r '.postToolUse.success')
path=$(echo "$input" | jq -r '.postToolUse.parameters.path // ""')
if [[ "$tool_name" == "write_to_file" && "$success" == "true" ]]; then
cat <<EOF
{
"cancel": false,
"contextModification": "Created '$path'. Maintain consistency with this file's patterns in future operations."
}
EOF
else
echo '{"cancel": false}'
fi
```
### 3. Performance Monitoring
```bash
#!/usr/bin/env bash
input=$(cat)
execution_time=$(echo "$input" | jq -r '.postToolUse.executionTimeMs')
tool_name=$(echo "$input" | jq -r '.postToolUse.toolName')
if [[ "$execution_time" -gt 5000 ]]; then
cat <<EOF
{
"cancel": false,
"contextModification": "Tool '$tool_name' took ${execution_time}ms. Consider optimizing future similar operations."
}
EOF
else
echo '{"cancel": false}'
fi
```
### 4. Logging and Telemetry
```bash
#!/usr/bin/env bash
input=$(cat)
# Log to file
echo "$input" >> ~/.cline/hook-logs/tool-usage.jsonl
# Allow execution
echo '{"cancel": false}'
```
## Global vs Workspace Hooks
Cline supports two levels of hooks:
### Global Hooks
- **Location**: `~/Documents/Cline/Hooks/` (macOS/Linux)
- **Scope**: Apply to ALL workspaces and projects
- **Use Case**: Organization-wide policies, personal preferences, universal validations
- **Priority**: Order not guaranteed when combined with workspace hooks
### Workspace Hooks
- **Location**: `.clinerules/hooks/` in each workspace root
- **Scope**: Apply only to the specific workspace
- **Use Case**: Project-specific rules, team conventions, repository requirements
- **Priority**: Order not guaranteed when combined with global hooks
### Hook Execution
When multiple hooks exist (global and/or workspace):
- All hooks for a given step are executed **concurrently** using `Promise.all`
- **Execution order is not guaranteed** - hooks run in parallel
- If ALL hooks allow execution (`cancel: false`), the tool proceeds
- If ANY hook blocks (`cancel: true`), execution is blocked
**Result Combination:**
- `cancel`: If ANY hook returns `true`, execution is blocked
- `contextModification`: All context strings are concatenated with double newlines (`\n\n`)
- `errorMessage`: All error messages are concatenated with single newlines (`\n`)
### Setting Up Global Hooks
1. The global hooks directory is automatically created at:
- macOS/Linux: `~/Documents/Cline/Hooks/`
2. Add your hook script:
```bash
# Unix/Linux/macOS
nano ~/Documents/Cline/Hooks/PreToolUse
chmod +x ~/Documents/Cline/Hooks/PreToolUse
```
3. Enable hooks in Cline settings
### Example: Global + Workspace Hooks
**Global Hook** (applies to all projects):
```bash
#!/usr/bin/env bash
# ~/Documents/Cline/Hooks/PreToolUse
# Universal rule: Never delete package.json
input=$(cat)
tool_name=$(echo "$input" | jq -r '.preToolUse.toolName')
path=$(echo "$input" | jq -r '.preToolUse.parameters.path // ""')
if [[ "$tool_name" == "write_to_file" && "$path" == *"package.json"* ]]; then
echo '{"cancel": true, "errorMessage": "Global policy: Cannot modify package.json"}'
exit 0
fi
echo '{"cancel": false}'
```
**Workspace Hook** (applies to specific project):
```bash
#!/usr/bin/env bash
# .clinerules/hooks/PreToolUse
# Project rule: Only TypeScript files
input=$(cat)
tool_name=$(echo "$input" | jq -r '.preToolUse.toolName')
path=$(echo "$input" | jq -r '.preToolUse.parameters.path // ""')
if [[ "$tool_name" == "write_to_file" && "$path" == *.js ]]; then
echo '{"cancel": true, "errorMessage": "Project rule: Use .ts files only"}'
exit 0
fi
echo '{"cancel": false}'
```
**All hooks must allow execution for the tool to proceed.** Hooks may execute concurrently.
## Multi-Root Workspaces
If you have multiple workspace roots, you can place hooks in each root's `.clinerules/hooks/` directory. All hooks (global and workspace) may execute concurrently. Their results will be combined:
- **cancel**: If ANY hook returns `true`, execution is blocked
- **contextModification**: All context modifications are concatenated
- **errorMessage**: All error messages are concatenated
**Note:** No execution order is guaranteed between hooks from different directories.
## Troubleshooting
### Hook Not Running
- Ensure the "Enable Hooks" setting is checked
- Verify the hook file is executable (`chmod +x hookname`)
- Check the hook file has no syntax errors
- Look for errors in VSCode's Output panel (Cline channel)
### Hook Timing Out
- Reduce complexity of the hook script
- Avoid expensive operations (network calls, heavy computations)
- Consider moving complex logic to a background process
### Context Not Affecting Behavior
- Remember: context affects FUTURE decisions, not the current tool
- Ensure context modifications are clear and actionable
- Check that context isn't being truncated (50KB limit)
## Security Considerations
- Hooks run with the same permissions as VSCode
- Be cautious with hooks from untrusted sources
- Review hook scripts before enabling them
- Consider using `.gitignore` to avoid committing sensitive hook logic
- Hooks can access all workspace files and environment variables
## Best Practices
1. **Keep hooks fast** - Aim for <100ms execution time
2. **Make context actionable** - Be specific about what the AI should do
3. **Use structured prefixes** - Help the AI categorize context
4. **Handle errors gracefully** - Always return valid JSON
5. **Log for debugging** - Keep logs of hook executions for troubleshooting
6. **Test incrementally** - Start with simple hooks and add complexity
7. **Document your hooks** - Add comments explaining the purpose and logic
-90
View File
@@ -1,90 +0,0 @@
# Networking & Proxy Support
To ensure Cline works correctly in all environments (VSCode, JetBrains, CLI) and with various network configurations (especially corporate proxies), strictly follow these guidelines for all network activity.
In extension code, do NOT use the global `fetch` or a default `axios` instance. (Note, `shared/net.ts` is exempt from these rules because it sets up the fetch wrappers.) In Webview code, you SHOULD use global `fetch`.
Global `fetch` and default `axios` do not automatically pick up proxy configurations in all environments (specifically JetBrains and CLI). You MUST use the provided utilities in `@/shared/net` which handle proxy agent configuration. In the webview, the browser/embedder handles proxies.
## Guidelines
### 1. Using `fetch`
Instead of `fetch(...)`, import the proxy-aware wrapper:
```typescript
import { fetch } from '@/shared/net'
// Usage is identical to global fetch
const response = await fetch('https://api.example.com/data')
```
### 2. Using `axios`
When using `axios`, you must apply the settings from `getAxiosSettings()`:
```typescript
import axios from 'axios'
import { getAxiosSettings } from '@/shared/net'
const response = await axios.get('https://api.example.com/data', {
headers: { 'Authorization': '...' },
...getAxiosSettings() // <--- CRITICAL: Injects the proxy agent if needed
})
```
### 3. Third-Party Clients (OpenAI, Ollama, etc.)
Most API client libraries allow you to customize the `fetch` implementation. You **MUST** pass the proxy-aware `fetch` to these clients.
**Example (OpenAI):**
```typescript
import OpenAI from "openai"
import { fetch } from "@/shared/net"
this.client = new OpenAI({
apiKey: '...',
fetch, // <--- CRITICAL: Pass our fetch wrapper
})
```
### 4. Tests
Use `mockFetchForTesting` to mock the underlying fetch implementation.
**Example (callback):**
```
import { mockFetchForTesting } from "@/shared/net"
...
let mockFetch = ...
mockFetchForTesting(mockFetch, () => {
// This calls mockFetch
fetch('https://foo.example').then(...)
})
// Original fetch is restored immediately when the call returns.
```
**Example (Promise):**
```
import { mockFetchForTesting } from "@/shared/net"
...
let mockFetch = ...
await mockFetchForTesting(mockFetch, async () => {
await ...
// This calls mockFetch
await fetch('https://foo.example')
...
})
// Original fetch is restored when the Promise from the callback settles
```
## Verification
If you are adding a new network call or integration:
1. Check `@/shared/net.ts` is imported.
2. Ensure `fetch` or `getAxiosSettings` is being used.
3. Verify that third-party clients are configured to use the custom fetch.
-64
View File
@@ -1,64 +0,0 @@
# Storage Architecture
Global settings, secrets and workspace state are stored in **file-backed JSON stores** under `~/.cline/data/`. This is the shared storage layer used by VSCode, CLI, and JetBrains.
## Key Abstractions
### `StorageContext` (src/shared/storage/storage-context.ts)
The entry point. Created via `createStorageContext()` and passed to `StateManager.initialize()`. Contains three `ClineFileStorage` instances:
- `globalState``~/.cline/data/globalState.json`
- `secrets``~/.cline/data/secrets.json` (mode 0o600)
- `workspaceState``~/.cline/data/workspaces/<hash>/workspaceState.json`
### `ClineFileStorage` (src/shared/storage/ClineFileStorage.ts)
Synchronous JSON key-value store backed by a single file. Supports `get()`, `set()`, `setBatch()`, `delete()`. Writes are atomic (write-then-rename).
### `StateManager` (src/core/storage/StateManager.ts)
In-memory cache on top of `StorageContext`. All runtime reads hit the cache; writes update cache immediately and debounce-flush to disk.
## ⚠️ Do NOT Use VSCode's ExtensionContext for Storage
**Do not** read from or write to `context.globalState`, `context.workspaceState`, or `context.secrets` for persistent data. These are VSCode-specific and not available on CLI or JetBrains.
Instead, use:
```typescript
// Reading state
StateManager.get().getGlobalStateKey("myKey")
StateManager.get().getSecretKey("mySecretKey")
StateManager.get().getWorkspaceStateKey("myWsKey")
// Writing state
StateManager.get().setGlobalState("myKey", value)
StateManager.get().setSecret("mySecretKey", value)
StateManager.get().setWorkspaceState("myWsKey", value)
```
Remember that your data may be read by a different client than the one that wrote it. For example, a value written by Cline in JetBrains may be read by Cline CLI.
## VSCode Migration (src/hosts/vscode/vscode-to-file-migration.ts)
On VSCode startup, a migration copies data from VSCode's `ExtensionContext` storage into the file-backed stores. This runs in `src/common.ts` before `StateManager.initialize()`.
- **Sentinel**: `__vscodeMigrationVersion` key in global state and workspace state — prevents re-migration.
- **Merge strategy**: File store wins. Existing values are never overwritten.
- **Safe downgrade**: VSCode storage is NOT cleared, so older extension versions still work.
## Adding New Storage Keys
1. Add to `src/shared/storage/state-keys.ts` (see existing patterns)
2. Read/write via `StateManager` (NOT via `context.globalState`)
3. If adding a secret, add to `SecretKeys` array in `state-keys.ts`
## File Layout
```
~/.cline/
data/
globalState.json # Global settings & state
secrets.json # API keys (mode 0o600)
tasks/
taskHistory.json # Task history (separate file)
workspaces/
<hash>/
workspaceState.json # Per-workspace toggles
```
@@ -1,29 +0,0 @@
# Address PR Comments
Review and address all comments on the current branch's PR.
## Steps
1. Get the current branch name and find the associated PR:
```bash
gh pr view --json number,title,body
```
2. Understand the PR context:
- Get the full diff: `git diff origin/main...HEAD`
- Read the changed files to understand what the PR is doing
- Read related files if needed to understand the broader context
- Understand the intent and spirit of the changes, not just the code
3. Fetch all PR comments:
- Inline comments: `gh api repos/{owner}/{repo}/pulls/{pr_number}/comments`
- General comments: `gh pr view {pr_number} --json comments,reviews`
4. Present a summary of all comments with your recommendation for each (apply, skip, or respond). Ignore bot noise (release automation, CI status, etc.).
5. **Wait for my approval** before proceeding.
6. After approval:
- Apply code changes and commit
- Reply to comments that were addressed or intentionally skipped
- Push commits
+549
View File
@@ -0,0 +1,549 @@
The goal of this workflow is to take a changeset for a release of Cline, an autonomous coding agent extension that plugs right into your IDE, and write the updated announcement component, and the updated changelog.
For reference, here are some examples of how we converted previous changesets to announcement components / changelogs.
- 3.14
<changeset>
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or setup this action to publish automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
claude-dev@3.14.0
Minor Changes
77c9863: create clinerules folder if its currently a file and creating new rule
0ffb7dd: disabling shift hint for now & improving tooltip behavior
79b76fd: Add support for custom model ID in AWS Bedrock provider, enabling use of Application Inference Profile.
eb6e481: Full support for LaTeX rendering
df37f29: Add support for custom API request timeout. Previously, timeouts were hardcoded to 30 seconds for providers like Ollama or 15 seconds for OpenRouter and Cline. Now users can set a custom timeout value in milliseconds through the settings interface.
e4d26be: allow cursorrules and windsurfrules
c5de50f: Fix Handle @withRetry() SyntaxError when running extension locally issue
61d2f42: enabled pricing calculation for gemini and vertex + more robust caching & cache tracking for gemini & vertex
aed152b: add truncation notice when truncating manually
2fe2405: Migrate Cline Tools Section to new docs
19cc8bc: Add a timeout setting for the terminal connection, allowing users to adjust this if they are having timeout issues
03d4410: Added copy button to code blocks.
c78fe23: addressed race condition in terminal command usage
91e222f: add checkpoints after more messages
14230e7: add newrule slash command
1c7d33a: Add remote config with posthog allowing for disabling new features until they're reading, making for a better developer experience.
4196c14: add cache ui for open router and cline provider
d97424f: showing expanded task by default
5294e78: Refactor to not pass a message for showing the MCP View from the servers modal
70cc437: Fix Windows path issue: Correct handling of import.meta.url to avoid leading slash in pathname
4b697d8: Migrate the addRemoteServer to protobus
Patch Changes
c63d9a1: updated drag and drop text to say "drop" instead of "drag"
459adf0: Add markdown copy to chat
74ec823: Minor UX improvement to drag and drop ux
b0961f4: Remove linear pull request action
e9ce384: searchCommits protobus migration
5802b68: createRuleFile protobus migration
df7f9fc: Add dependsOn to more blocks in the tasks.json
41ae732: Fix for git commit mentions in repos with no git commits
7e78445: Adding args to allow Cursor to open workspaces (for checkpoint testing/development)
bdfda6f: feat(bedrock): Introduce Amazon Nova Premier
65243ad: Introduce UI library for future UI development
4565e06: checkIsImageURL migrated to protobus
5a8e9d8: protobus migration for openImage
deeda6e: Lowering Gemini cache TTL time
db0b022: Adding UI to show openrouter balance next to provider
4650ffa: deleteRuleFile protobus migration
d4bd755: fix cost calculation
</changeset>
<changelog>
## [3.14.0]
- Add UI to show openrouter balance next to provider
- Add support for custom model ID in AWS Bedrock provider, enabling use of Application Inference Profile (Thanks @clicube!)
- Add more robust caching & cache tracking for gemini & vertex providers
- Add support for LaTeX rendering
- Add support for custom API request timeout. Timeouts were 15-30s, but can now be configured via settings for OpenRouter/Cline & Ollama (Thanks @WingsDrafterwork!)
- Add truncation notice when truncating manually
- Add a timeout setting for the terminal connection, allowing users to set a time to wait for terminal startup
- Add copy button to code blocks
- Add copy button to markdown blocks (Thanks @weshoke!)
- Add checkpoints to more messages
- Add slash command to create a new rules file (/newrule)
- Add cache ui for open router and cline provider
- Add Amazon Nova Premier model to Bedrock (Thanks @watany!)
- Add support for cursorrules and windsurfrules
- Add support for batch history deletion (Thanks @danix800!)
- Improve Drag & Drop experience
- Create clinerules folder creating new rule if it's needed
- Enable pricing calculation for gemini and vertex providers
- Refactor message handling to not show the MCP View of the server modal
- Migrate the addRemoteServer to protobus (Thanks @DaveFres!)
- Update task header to be expanded by default
- Update Gemini cache TTL time to 15 minutes
- Fix race condition in terminal command usage
- Fix to correctly handle `import.meta.url`, avoiding leading slash in pathname for Windows (Thanks @DaveFres!)
- Fix @withRetry() decoration syntax error when running extension locally (Thanks @DaveFres!)
- Fix for git commit mentions in repos with no git commits
- Fix cost calculation (Thanks @BarreiroT!)
</changelog>
<announcement-component>
const Announcement = ({ version, hideAnnouncement }: AnnouncementProps) => {
const minorVersion = version.split(".").slice(0, 2).join(".") // 2.0.0 -> 2.0
return (
<div style={containerStyle}>
<VSCodeButton appearance="icon" onClick={hideAnnouncement} style={closeIconStyle}>
<span className="codicon codicon-close"></span>
</VSCodeButton>
<h3 style={h3TitleStyle}>
🎉{" "}New in v{minorVersion}
</h3>
<ul style={ulStyle}>
<li>
<b>Gemini prompt caching:</b> Gemini and Vertex providers now support prompt caching and price tracking for
Gemini models.
</li>
<li>
<b>Copy Buttons:</b> Buttons were added to Markdown and Code blocks that allow you to copy their contents
easily.
</li>
<li>
<b>/newrule command:</b> New slash command to have cline write your .clinerules for you based on your
workflow.
</li>
<li>
<b>Drag and drop improvements:</b> Don't forget to hold shift while dragging files!
</li>
<li>Added more checkpoints across the task, allowing you to restore from more than just file changes.</li>
<li>Added support for rendering LaTeX in message responses. (Try asking Cline to show the quadratic formula)</li>
</ul>
<Accordion isCompact className="pl-0">
<AccordionItem
key="1"
aria-label="Previous Updates"
title="Previous Updates:"
classNames={{
trigger: "bg-transparent border-0 pl-0 pb-0 w-fit",
title: "font-bold text-[var(--vscode-foreground)]",
indicator:
"text-[var(--vscode-foreground)] mb-0.5 -rotate-180 data-[open=true]:-rotate-90 rtl:rotate-0 rtl:data-[open=true]:-rotate-90",
}}>
<ul style={ulStyle}>
<li>
<b>Global Cline Rules:</b> store multiple rules files in Documents/Cline/Rules to share between
projects.
</li>
<li>
<b>Cline Rules Popup:</b> New button in the chat area to view workspace and global cline rules files
to plug and play specific rules for the task
</li>
<li>
<b>Slash Commands:</b> Type <code>/</code> in chat to see the list of quick actions, like starting a
new task (more coming soon!)
</li>
<li>
<b>Edit Messages:</b> You can now edit a message you sent previously by clicking on it. Optionally
restore your project when the message was sent!
</li>
</ul>
</AccordionItem>
</Accordion>
{/*
// Leave this here for an example of how to structure the announcement
<ul style={{ margin: "0 0 8px", paddingLeft: "12px" }}>
<li>
OpenRouter now supports prompt caching! They also have much higher rate limits than other providers,
so I recommend trying them out.
<br />
{!apiConfiguration?.openRouterApiKey && (
<VSCodeButtonLink
href={getOpenRouterAuthUrl(vscodeUriScheme)}
style={{
transform: "scale(0.85)",
transformOrigin: "left center",
margin: "4px -30px 2px 0",
}}>
Get OpenRouter API Key
</VSCodeButtonLink>
)}
{apiConfiguration?.openRouterApiKey && apiConfiguration?.apiProvider !== "openrouter" && (
<VSCodeButton
onClick={() => {
vscode.postMessage({
type: "apiConfiguration",
apiConfiguration: { ...apiConfiguration, apiProvider: "openrouter" },
})
}}
style={{
transform: "scale(0.85)",
transformOrigin: "left center",
margin: "4px -30px 2px 0",
}}>
Switch to OpenRouter
</VSCodeButton>
)}
</li>
<li>
<b>Edit Cline's changes before accepting!</b> When he creates or edits a file, you can modify his
changes directly in the right side of the diff view (+ hover over the 'Revert Block' arrow button in
the center to undo "<code>{"// rest of code here"}</code>" shenanigans)
</li>
<li>
New <code>search_files</code> tool that lets Cline perform regex searches in your project, letting
him refactor code, address TODOs and FIXMEs, remove dead code, and more!
</li>
<li>
When Cline runs commands, you can now type directly in the terminal (+ support for Python
environments)
</li>
</ul>*/}
<div style={hrStyle} />
<p style={linkContainerStyle}>
Join us on{" "}
<VSCodeLink style={linkStyle} href="https://x.com/cline">
X,
</VSCodeLink>{" "}
<VSCodeLink style={linkStyle} href="https://discord.gg/cline">
discord,
</VSCodeLink>{" "}
or{" "}
<VSCodeLink style={linkStyle} href="https://www.reddit.com/r/cline/">
r/cline
</VSCodeLink>
for more updates!
</p>
</div>
)
}
</announcement-component>
- 3.13
<changeset>
Minor Changes
2964388: Added copy button to MermaidBlock component
75143a7: Add the ability to fetch from global cline rules files
Patch Changes
a0252e7: convert inline style to tailwind css of file SettingsView.tsx
ab59bd9: Add stream options back to xai provider
7276f50: Icons to indicate an action is occuring outside of the users workspace
0b19ba6: update to NEW model
</changeset>
<changelog>
## [3.13.0]
- Add Cline rules popover under the chat field, allowing you to easily add, enable & disable workspace level or global rule files
- Add new slash command menu letting you type “/“ to do quick actions like creating new tasks
- Add ability to edit past messages, with options to restore your workspace back to that point
- Allow sending a message when selecting an option provided by the question or plan tool
- Add command to jump to Cline's chat input
- Add support for OpenAI o3 & 4o-mini (Thanks @PeterDaveHello and @arafatkatze!)
- Add baseURL option for Google Gemini provider (Thanks @owengo and @olivierhub!)
- Add support for Azure's DeepSeek model. (Thanks @yt3trees!)
- Add ability for models that support it to receive image responses from MCP servers (Thanks @rikaaa0928!)
- Improve search and replace diff editing by making it more flexible with models that fail to follow structured output instructions. (Thanks @chi-cat!)
- Add detection of Ctrl+C termination in terminal, improving output reading issues
- Fix issue where some commands with large output would cause UI to freeze
- Fix token usage tracking issues with vertex provider (Thanks @mzsima!)
- Fix issue with xAI reasoning content not being parsed (Thanks @mrubens!)
</changelog>
<announcement-component>
const Announcement = ({ version, hideAnnouncement }: AnnouncementProps) => {
const minorVersion = version.split(".").slice(0, 2).join(".") // 2.0.0 -> 2.0
return (
<div style={containerStyle}>
<VSCodeButton appearance="icon" onClick={hideAnnouncement} style={closeIconStyle}>
<span className="codicon codicon-close"></span>
</VSCodeButton>
<h3 style={h3TitleStyle}>
🎉{" "}New in v{minorVersion}
</h3>
<ul style={ulStyle}>
<li>
<b>Global Cline Rules:</b> store multiple rules files in Documents/Cline/Rules to share between projects.
</li>
<li>
<b>Cline Rules Popup:</b> New button in the chat area to view workspace and global cline rules files to plug
and play specific rules for the task
</li>
<li>
<b>Slash Commands:</b> Type <code>/</code> in chat to see the list of quick actions, like starting a new task
(more coming soon!)
</li>
<li>
<b>Edit Messages:</b> You can now edit a message you sent previously by clicking on it. Optionally restore
your project when the message was sent!
</li>
</ul>
<h4 style={{ margin: "5px 0 5px" }}>Previous Updates:</h4>
<ul style={ulStyle}>
<li>
<b>Model Favorites:</b> You can now mark your favorite models when using Cline & OpenRouter providers for
quick access!
</li>
<li>
<b>Faster Diff Editing:</b> Improved animation performance for large files, plus a new indicator in chat
showing the number of edits Cline makes.
</li>
<li>
<b>New Auto-Approve Options:</b> Turn off Cline's ability to read and edit files outside your workspace.
</li>
</ul>
{/*
// Leave this here for an example of how to structure the announcement
<ul style={{ margin: "0 0 8px", paddingLeft: "12px" }}>
<li>
OpenRouter now supports prompt caching! They also have much higher rate limits than other providers,
so I recommend trying them out.
<br />
{!apiConfiguration?.openRouterApiKey && (
<VSCodeButtonLink
href={getOpenRouterAuthUrl(vscodeUriScheme)}
style={{
transform: "scale(0.85)",
transformOrigin: "left center",
margin: "4px -30px 2px 0",
}}>
Get OpenRouter API Key
</VSCodeButtonLink>
)}
{apiConfiguration?.openRouterApiKey && apiConfiguration?.apiProvider !== "openrouter" && (
<VSCodeButton
onClick={() => {
vscode.postMessage({
type: "apiConfiguration",
apiConfiguration: { ...apiConfiguration, apiProvider: "openrouter" },
})
}}
style={{
transform: "scale(0.85)",
transformOrigin: "left center",
margin: "4px -30px 2px 0",
}}>
Switch to OpenRouter
</VSCodeButton>
)}
</li>
<li>
<b>Edit Cline's changes before accepting!</b> When he creates or edits a file, you can modify his
changes directly in the right side of the diff view (+ hover over the 'Revert Block' arrow button in
the center to undo "<code>{"// rest of code here"}</code>" shenanigans)
</li>
<li>
New <code>search_files</code> tool that lets Cline perform regex searches in your project, letting
him refactor code, address TODOs and FIXMEs, remove dead code, and more!
</li>
<li>
When Cline runs commands, you can now type directly in the terminal (+ support for Python
environments)
</li>
</ul>*/}
<div style={hrStyle} />
<p style={linkContainerStyle}>
Join us on{" "}
<VSCodeLink style={linkStyle} href="https://x.com/cline">
X,
</VSCodeLink>{" "}
<VSCodeLink style={linkStyle} href="https://discord.gg/cline">
discord,
</VSCodeLink>{" "}
or{" "}
<VSCodeLink style={linkStyle} href="https://www.reddit.com/r/cline/">
r/cline
</VSCodeLink>
for more updates!
</p>
</div>
)
}
</announcement-component>
We have a changeset PR that automatically generated as new unreleased PRs are merged into main, the PR is always called "Changeset version bump" and the author is github-actions.
The Changeset PR description looks something like this:
<changeset-pr-description>
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or [setup this action to publish automatically](https://github.com/changesets/action#with-publishing). If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
# Releases
## claude-dev@3.16.0
### Minor Changes
- c6e8b04: Recent task list is now collapsible, allowing users to hide their recent tasks (e.g. when sharing their screen).
- aabe4ae: Add detection for new users to display special components
- 6c18d51: adds global endpoint for vertex ai users
- 080ed7c: Add Tailwind CSS IntelliSense to the the recommended extensions list
- 5147e28: new workflow feature
### Patch Changes
- c0b3c69: fix eternal loading states when the last message is a checkpoint
- 570ece3: selectImages protos migration
- 8d8452e: askResponse protobus migration
- cd1ff2a: Finishing the migration of Vscode Advanced settings to Settings Webview
</changeset-pr-description>
The changeset pr is ALWAYS on the following branch: `changeset-release/main`.
I have the `gh` command line tool set up and authenticated, so you have everything you need.
The first step is to get the full diff from the changeset PR to look at the changes that were automatically made to the `CHANGELOG.md` file. By default it will automatically add a new section to the changelog.md file with the new version. The problem with the automatically generated section is that it just takes the text that the developers threw into their changeset files for each corresponding PR, and they can be pretty vague and bad. Additionally there's some stuff that is totally irrelevant for the end user, like minor refactoring changes. So I manually typically go in and update this section to be a proper changelog that will show up in our patchnotes. You can look at how the rest of the file is done because those are all good examples of us updating this to use good language for the end user. We usually put new features up top (and the most exciting flagship features at the very top), and then bug fixes/improvements at the bottom. Having some basic organization to the ordering of the bullet points by content is nice. But use common sense.
To handle this process effectively, do the following:
For each of the automatically generated bullet points in the Changelog.md, you should
1. Take the commit hash at the start of the bullet point, and use the `gh` command line tool find the PR that it was associated with.
2. Use the `gh` command to get the PR title/description/discussion to understand the context surrounding the PR.
3. Use the `gh` command line tool to get the full PR diff to fully understand the changes made in the code.
4. Synthesize that knowledge to determine (a) whether or not this change is relevant to end users and (b) what the text & ordering of the line should be.
5. Update the `CHANGELOG.md` accordingly
Do this for every single item in the list from the autogenerated bullet points. We want to be diligent and have a full understanding of every feature so we can make the best changelog ever!
Here are some principles for good changelogs from keepchangelog.com, a handy guide:
<keepachangelog-pinciples-for-good-changelogs>
### Guiding Principles
- Changelogs are for humans, not machines.
- There should be an entry for every single version.
- The same types of changes should be grouped.
- The latest version comes first.
### Bullet points in the changelog should follow these principles:
- Types of changes
- Added for new features.
- Changed for changes in existing functionality.
- Deprecated for soon-to-be removed features.
- Removed for now removed features.
- Fixed for any bug fixes.
- Security in case of vulnerabilities.
</keepachangelog-pinciples-for-good-changelogs>
Lastly, when developers make a PR, they typically make a changeset. And they have 3 options when making the changeset:
1. Patch
2. Minor
3. Major
Sometimes they label something as minor when really it should just be a patch. Or vice versa. Because of this, the automatic version bump may be incorrect. So when starting out this workflow, you should use the <ask_followup_question> tool to confirm with me whether or not this should be a patch bump (show the old version number and what the proposed new version number would be) or a minor bump. Part of the release process is making sure the version in package.json that is automatically changed actually corresponds with what we decided the bump should actually be based on the features. ALL these modifications happen in the `changeset-release/main` branch btw.
<important_note>
Before doing any of this, make sure you check out the `changeset-release/main` and pull the most recent up to date changes. Then perform all this work in that branch.
New announcement banners should ONLY be made for minor version bumps or higher. That's another reason why double checking if the changelog warrants the bump is important.
Also, SUPER important: For any external contributors that aren't part of the cline github organization, we always want to add a (Thanks @username!) at the end of the changelog to attribute them properly. We're an open source project and it's ethical to do this.
</important_note>
Once the changelog looks good, and the version number looks good, we gotta double check that the version number in the changelog has the brackets around it. And as a final step, double check the package.json version number matches the latest number in the changelog. And as the ultimate final step we run `npm run install:all` to make sure the package version number permiates through the lock file.
<detailed_sequence_of_steps>
# Cline Release Process - Detailed Sequence of Steps
## Before Starting
1. First, examine the changeset PR without checking it out:
```bash
gh pr view changeset-release/main
```
2. View the PR diff to see the auto-generated CHANGELOG.md changes:
```bash
gh pr diff changeset-release/main > changeset-diff.txt
cat changeset-diff.txt | grep -A 50 "CHANGELOG.md"
```
## Initial Setup
3. Once you're ready to start, checkout and update the changeset release branch:
```bash
git checkout changeset-release/main
git pull origin changeset-release/main
```
## Analyzing Each Change
4. For each commit hash in the auto-generated changelog entries:
a. Find the PR number associated with a commit hash:
```bash
gh pr list --search "<commit-hash>" --state merged
```
b. Get PR details for better context:
```bash
gh pr view <PR-number>
```
c. Check if the contributor is external to determine if attribution is needed:
```bash
# Extract username from PR
USERNAME=$(gh pr view <PR-number> --json author --jq .author.login)
# Check if user is a member of the Cline organization
# this command is a bit finnicky, but it 100% works.
# if you see a `Error executing command: The command ran successfully, but we couldn't capture its output. Please proceed accordingly.` error, just retry it until you actually get the output
# don't make any assumptions, just retry the command to actually get the output and determine if they're external or not.
# no output means they are an external contributor, otherwise if there is output they are an internal contributor (part of our github org)
gh api "orgs/cline/members" --jq "map(.login)" | grep -i "pashpashpash"
```
d. View the full PR diff to understand code changes:
```bash
gh pr diff <PR-number> > pr-diff-<PR-number>.txt
cat pr-diff-<PR-number>.txt
```
## Updating the Changelog
5. Based on PR analysis, update the CHANGELOG.md with user-friendly descriptions:
- Use the `<replace_in_file>` tool to edit the CHANGELOG.md file
- Group by feature type (Added, Changed, Fixed)
- Put most exciting features at the top
- Move bug fixes and small improvements to the bottom
- Use clear, end-user focused language
- For external contributors, add attribution at the end of the relevant entry: `(Thanks @username!)`
## Version Number Verification
6. Confirm the version bump is appropriate:
- Check package.json to verify the auto-generated version number:
```bash
cat package.json | grep "\"version\""
```
- If the feature set doesn't warrant a minor bump, use the `<replace_in_file>` tool to modify package.json
7. Ensure the version in CHANGELOG.md has brackets around it:
```
## [3.16.0]
```
## Creating the Announcement (for minor/major versions only)
8. If this is a minor version bump, create/update the announcement component:
- Use the `<replace_in_file>` tool to edit the src/views/components/announcement.tsx file
- Update the highlights based on key features
- Move previous version highlights to the "Previous Updates" section
- Use the previous announcement components as reference for structure
## Finalizing the Release
9. Update dependencies with the new version number:
```bash
npm run install:all
```
10. Commit your changes:
```bash
git add CHANGELOG.md package.json package-lock.json src/views/components/announcement.tsx
git commit -m "Update CHANGELOG.md and announcement for version 3.16.0"
```
11. Push your changes to the changeset branch:
```bash
git push origin changeset-release/main
```
12. Check that your changes pushed successfully:
```bash
git status
```
</detailed_sequence_of_steps>
@@ -1,49 +0,0 @@
# Find Best Reviewers for Current Branch
Analyze my current branch to find the best people to review my PR based on **domain expertise** and git history.
## Steps
1. Get the current branch name and verify it's not `main`
2. Get the diff between the current branch and `origin/main`:
- Use `git diff origin/main...HEAD --name-only` to get changed files
- Use `git diff origin/main...HEAD` to understand the nature/spirit of the changes
3. **Identify the domain/feature area** being changed:
- Read the diff carefully to understand WHAT is being changed conceptually (e.g., "slash commands", "authentication", "API client", "UI components")
- This semantic understanding is crucial for finding the right reviewers
4. Find domain experts by searching for related files and their contributors:
- Identify all files related to the feature/domain (not just the ones changed)
- Example: if changing slash commands, find ALL slash-command related files across the codebase
- Use `git log --format="%an <%ae>" -- <related-files-pattern>` to find who has expertise in that domain
5. For additional context, also gather:
- `git blame -L <start>,<end> origin/main -- <file-path>` for exact lines changed
- Recent commit activity on related files
6. Score and rank contributors by:
- **Highest weight: Domain expertise** - who has the most commits to files in this feature area (even files not touched by this PR)
- **Medium weight: Direct file expertise** - commits to the specific files being changed
- **Lower weight: Line-level ownership** - authored the exact lines being modified
7. Exclude myself (check against my git config user.email)
8. Present the top 5 reviewers as an ordered list
## Output Format
Output an ordered list:
1. **Name** - Domain expert: 15 commits to slash-command related files, authored core parsing logic
2. **Name** - 8 commits to affected files, recently added the feature being modified
3. ...
## Commands Reference
```bash
git config user.email
git diff origin/main...HEAD --name-only
git diff origin/main...HEAD
# Find related files for a domain (adjust pattern based on what you learn from the diff)
find . -type f \( -name "*slash-command*" -o -name "*SlashCommand*" \) | head -20
# Get contributors for related files
find . -type f \( -name "*slash-command*" -o -name "*SlashCommand*" \) -print0 | xargs -0 git log --format="%an <%ae>" -- | sort | uniq -c | sort -rn
git log --format="%an <%ae>" -- <file> | sort | uniq -c | sort -rn
git blame -L 10,20 origin/main -- <file>
```
Do NOT ask questions - analyze the changes, identify the domain, and output the reviewer list.
+21 -7
View File
@@ -6,14 +6,28 @@ Analyze the current branch's changes against main to provide informed insights a
## Step 1: Gather Git Information
<important>Do not return any text or conversation other than what is necessary to run these commands</important>
**Run the following command to get the latest changes (bash):**
```bash
B=$(for c in main master origin/main origin/master; do git rev-parse --verify -q "$c" >/dev/null && echo "$c" && break; done); B=${B:-HEAD}; r(){ git branch --show-current; printf "=== STATUS ===\n"; git status --porcelain | cat; printf "=== COMMIT MESSAGES ===\n"; git log "$B"..HEAD --oneline | cat; printf "=== CHANGED FILES ===\n"; git diff "$B" --name-only | cat; printf "=== FULL DIFF ===\n"; git diff "$B" | cat; }; L=$(r | wc -l); if [ "$L" -gt 500 ]; then r > cline-git-analysis.temp && echo "::OUTPUT_FILE=cline-git-analysis.temp"; else r; fi
```
**First, check the expected output size:**
```shell
(git branch --show-current && echo "=== STATUS ===" && git status --porcelain | cat && echo "=== COMMIT MESSAGES ===" && git log main..HEAD --oneline | cat && echo "=== CHANGED FILES ===" && git diff main --name-only | cat && echo "=== FULL DIFF ===" && git diff main | cat) | wc -l
```
```powershell
$B=$null;foreach($c in 'main','master','origin/main','origin/master'){git rev-parse --verify -q $c *> $null;if($LASTEXITCODE -eq 0){$B=$c;break}};if(-not $B){$B='HEAD'};function r([string]$b){git rev-parse --abbrev-ref HEAD; '=== STATUS ==='; git status --porcelain | cat; '=== COMMIT MESSAGES ==='; git log "$b"..HEAD --oneline | cat; '=== CHANGED FILES ==='; git diff "$b" --name-only | cat; '=== FULL DIFF ==='; git diff "$b" | cat};$out=r $B|Out-String;$lines=($out -split "`r?`n").Count;if($lines -gt 500){$out|Set-Content -NoNewline cline-git-analysis.temp; '::OUTPUT_FILE=cline-git-analysis.temp'}else{$out}
```
**If the expected line count is greater than 500 lines, use the file-based approach:**
```shell
git branch --show-current > cline-git-analysis.temp && echo "=== STATUS ===" >> cline-git-analysis.temp && git status --porcelain >> cline-git-analysis.temp && echo "=== COMMIT MESSAGES ===" >> cline-git-analysis.temp && git log main..HEAD --oneline >> cline-git-analysis.temp && echo "=== CHANGED FILES ===" >> cline-git-analysis.temp && git diff main --name-only >> cline-git-analysis.temp && echo "=== FULL DIFF ===" >> cline-git-analysis.temp && git diff main >> cline-git-analysis.temp
```
Then, read the file using the read_file tool. After you have read the file but before you proceed with subsequent steps, delete it:
```shell
rm cline-git-analysis.temp
```
**If the expected line count is 500 lines or fewer, use the direct approach:**
```shell
git branch --show-current && echo "=== STATUS ===" && git status --porcelain | cat && echo "=== COMMIT MESSAGES ===" && git log main..HEAD --oneline | cat && echo "=== CHANGED FILES ===" && git diff main --name-only | cat && echo "=== FULL DIFF ===" && git diff main | cat
```
<important>If using the direct approach, pipe outputs through `cat` to avoid interactive terminals. If the user's shell is not bash/zsh, adjust the command and chaining
syntax accordingly.</important>
## Step 2: Silent, Structured Analysis Phase
- Analyze all git output without providing commentary or narration
-187
View File
@@ -1,187 +0,0 @@
# Hotfix Release
Create a hotfix release by cherry-picking specific commits from main onto the latest release tag.
## Overview
This workflow helps you:
1. Select specific commits from main to include in a hotfix
2. Create a release notes commit on main (changelog + version bump)
3. Cherry-pick everything onto the latest release tag
4. Tag and push the new release
## Step 1: Setup and Gather Information
First, ensure we're on main and up to date:
```bash
git checkout main && git pull origin main
```
Get the latest release tag:
```bash
git tag --sort=-v:refname | head -1
```
## Step 2: Present Commits Since Last Release
Show all commits on main since the last release tag:
```bash
LAST_TAG=$(git tag --sort=-v:refname | head -1)
git log ${LAST_TAG}..HEAD --oneline --format="%h %s (%an)"
```
Also get the commit messages already on the tag (to identify previously cherry-picked commits). Note: Run these as separate commands to avoid shell parsing issues with parentheses in author names:
```bash
LAST_TAG=$(git tag --sort=-v:refname | head -1)
PREV_TAG=$(git tag --sort=-v:refname | head -2 | tail -1)
```
```bash
git log $PREV_TAG..$LAST_TAG --oneline --format="%s"
```
**Present the list** to the user in a numbered format with commit hash, subject, and author. For any commits whose subject line already appears in the tag's history (previously cherry-picked in an earlier hotfix) or are "Release Notes" commits, add `(already in previous hotfix)` or `(release notes - skip)` after them so the user knows to skip those.
Ask which commits to include in the hotfix.
Use the ask_followup_question tool to let the user specify which commits they want (by number or hash).
## Step 3: Analyze Selected Commits
For each selected commit:
1. Get the full commit message: `git show --no-patch --format="%B" <hash>`
2. Get the diff to understand the change: `git show <hash> --stat`
3. Find the associated PR if any: `gh pr list --search "<hash>" --state merged --json number,title --jq '.[0]'`
Build a mental model of what these changes do for the changelog.
## Step 4: Determine New Version Number
Parse the current version from package.json and the last tag:
```bash
LAST_TAG=$(git tag --sort=-v:refname | head -1)
echo "Last release: $LAST_TAG"
cat package.json | grep '"version"'
```
Hotfixes always increment the patch version (e.g., 3.40.0 -> 3.40.1, or 3.40.1 -> 3.40.2).
**Ask the user to confirm the new version number.**
## Step 5: Create Release Notes Commit on Main
On the main branch, create a commit that updates:
1. **CHANGELOG.md** - Add a new section for the hotfix version at the top:
```markdown
## [3.40.1]
- Description of fix 1
- Description of fix 2
```
Write clear, user-friendly descriptions based on your analysis of the commits.
2. **package.json** - Update the version field to the new version
3. No changelog-entry file cleanup is needed. Contributors do not create changelog-entry files in this repo.
**Skip running `npm run install:all`** - release automation handles lockfile consistency as needed.
Commit with message format: `v{VERSION} Release Notes (hotfix)`
In the commit body, mention:
- This is for a hotfix release
- List the cherry-picked commits that will be included
```bash
git add CHANGELOG.md package.json
git commit -m "v3.40.1 Release Notes (hotfix)
Hotfix release including:
- <commit1-hash>: <description>
- <commit2-hash>: <description>
"
```
Push to main:
```bash
git push origin main
```
## Step 6: Build the Hotfix on the Tag
Checkout the last release tag (detached HEAD):
```bash
LAST_TAG=$(git tag --sort=-v:refname | head -1)
git checkout $LAST_TAG
```
Cherry-pick the selected commits in order:
```bash
git cherry-pick <commit1-hash>
git cherry-pick <commit2-hash>
# ... etc
```
Finally, cherry-pick the release notes commit you just pushed to main:
```bash
# Get the hash of the release notes commit (should be HEAD of main)
RELEASE_NOTES_COMMIT=$(git rev-parse main)
git cherry-pick $RELEASE_NOTES_COMMIT
```
## Step 7: Tag and Push
After all cherry-picks are applied successfully:
```bash
# Tag the new release
git tag v{VERSION}
# Push the tag to remote
git push origin v{VERSION}
```
## Step 8: Return to Main and Summary
Return to main branch:
```bash
git checkout main
```
**Copy a Slack announcement message to clipboard** with the version and PR links for each included fix:
```
VS Code Hotfix v{VERSION} Published
- Description of fix 1 https://github.com/cline/cline/pull/{PR_NUMBER}
- Description of fix 2 https://github.com/cline/cline/pull/{PR_NUMBER}
```
Present a final summary:
- New version: v{VERSION}
- Tag pushed: yes
- Commits included: (list them)
- Slack message copied to clipboard: yes
Remind the user to:
1. Manually trigger the publish release GitHub Action at: https://github.com/cline/cline/actions/workflows/publish.yml (paste `v{VERSION}` as the tag)
2. Post the Slack message to announce the hotfix
## Important Notes
- This workflow does NOT create a release branch - only tags
- The release notes commit goes to main first, then gets cherry-picked to the tag
- This keeps main's history accurate while allowing hotfix releases from tags
- If cherry-pick conflicts occur, resolve them before continuing
+2 -3
View File
@@ -219,9 +219,6 @@ EOF
## Basic PR Commands
```bash
# Get current PR number
gh pr view --json number -q .number
# List open PRs
gh pr list
@@ -347,6 +344,8 @@ A few notes:
So until the settings page is update, and this is added to settings in a way that's clean and doesn't confuse new users, I don't think we can merge this. Please bear with us.
</request_changes_comment>
<request_changes_comment>
Also, don't forget to add a changeset since this fixes a user-facing bug.
The architectural change is solid - moving the focus logic to the command handlers makes sense. Just don't want to introduce subtle timing issues by removing those timeouts.
</request_changes_comment>
</example_comments_that_i_have_written_before>
-64
View File
@@ -1,64 +0,0 @@
# Release
Prepare and publish a release directly from `main`.
## Overview
This workflow helps you:
1. Select/confirm the target version
2. Curate `CHANGELOG.md` entries manually for end users
3. Ensure `package.json` version matches the changelog
4. Create and push a release commit + tag
5. Trigger publish workflow
6. Update GitHub release notes and share a summary
## Process
### 1) Sync and determine version
```bash
git checkout main
git pull origin main
cat package.json | grep '"version"'
```
Confirm the release version with the maintainer (patch/minor/major).
### 2) Curate changelog and version
- Edit `CHANGELOG.md` for the target version using human-friendly release notes.
- Ensure version headers use bracket format, e.g. `## [3.66.1]`.
- Update `package.json` version to the same value.
### 3) Commit and tag
```bash
git add CHANGELOG.md package.json package-lock.json
git commit -m "v<version> Release Notes"
git push origin main
git tag v<version>
git push origin v<version>
```
### 4) Trigger publish workflow
Tell the maintainer to run:
https://github.com/cline/cline/actions/workflows/publish.yml
Use `v<version>` as the release tag.
### 5) Update GitHub release notes
After publish completes:
```bash
gh release view v<version> --json body --jq '.body'
gh release edit v<version> --notes "<final curated release notes>"
```
### 6) Final summary
Provide:
- Released version/tag
- Link to release page
- Summary of top end-user changes
+6
View File
@@ -0,0 +1,6 @@
[codespell]
# Ref: https://github.com/codespell-project/codespell#using-a-config-file
skip = .git*,*.svg,package-lock.json,*.css,.codespellrc,locales
check-hidden = true
ignore-regex = (\b(optIn|isTaller)\b|https://\S+)
# ignore-words-list =
-49
View File
@@ -1,49 +0,0 @@
# THIS IS AUTOGENERATED. DO NOT EDIT MANUALLY
version = 1
name = "cline"
[setup]
script = '''
if [ ! -d "node_modules" ]; then
MAIN_WORKTREE="$(git worktree list | head -n1 | awk '{print $1}')"
ln -s "$MAIN_WORKTREE/node_modules" node_modules
ln -s "$MAIN_WORKTREE/webview-ui/node_modules" webview-ui/node_modules
fi
'''
[[actions]]
name = "VS Code"
icon = "run"
command = "chmod +x ./scripts/run-extension-host.sh && ./scripts/run-extension-host.sh production"
[[actions]]
name = "CLI"
icon = "run"
command = '''
npm run cli:build
npm run cli:run
'''
[[actions]]
name = "npm install"
icon = "tool"
command = '''
rm node_modules
rm webview-ui/node_modules
npm run install:all
'''
[[actions]]
name = "pull main"
icon = "tool"
command = '''
git fetch origin main
if ! git merge-base --is-ancestor main origin/main; then
echo "Local main has commits not on origin/main. Aborting..."
exit 1
fi
git update-ref refs/heads/main refs/remotes/origin/main
echo "main updated to $(git rev-parse --short main)"
'''
-134
View File
@@ -1,134 +0,0 @@
# Cline Development Environment Variables
# Copy this file to .env and fill in your actual values
# Values should be obtained from 1Password shared vault for development
# ============================================================================
# DEVELOPMENT FLAGS
# Recomend not changing these unless you know what you're doing they are set by the launch.json normally
# ============================================================================
# IS_DEV=true
# CLINE_ENVIRONMENT=local
# ============================================================================
# POSTHOG TELEMETRY (Existing)
# ============================================================================
# Get these values from 1Password shared vault
TELEMETRY_SERVICE_API_KEY=your-posthog-telemetry-api-key
ERROR_SERVICE_API_KEY=your-posthog-error-tracking-api-key
# ============================================================================
# OPENTELEMETRY (Optional - for advanced telemetry)
# ============================================================================
# OpenTelemetry provides flexible telemetry collection with multiple export options
# Can run alongside PostHog or independently
# Primary focus: Logs (events), with optional metrics support
# Enable OpenTelemetry (set to 1 to enable)
# OTEL_TELEMETRY_ENABLED=1
# Exporters: "console" for local debugging, "otlp" for remote collector
# Logs are the primary signal (recommended)
# OTEL_LOGS_EXPORTER=console
# OTEL_METRICS_EXPORTER=otlp
# OTLP Protocol: "grpc", "http/json", or "http/protobuf"
# OTEL_EXPORTER_OTLP_PROTOCOL=grpc
# OTLP Endpoint (without /v1/logs or /v1/metrics path - auto-appended)
# For gRPC: use "localhost:4317" (no http:// prefix)
# For HTTP: use "http://localhost:4318"
# OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317
# OTLP Headers (for authentication, e.g., bearer tokens)
# OTEL_EXPORTER_OTLP_HEADERS=authorization=Bearer your-token-here
# Use insecure gRPC connections (for local testing only, NOT for production)
# OTEL_EXPORTER_OTLP_INSECURE=true
# Metric export interval in milliseconds (default: 60000)
# OTEL_METRIC_EXPORT_INTERVAL=10000
# Batch configuration for logs (optional)
# OTEL_LOG_BATCH_SIZE=512 # Max logs per batch (default: 512)
# OTEL_LOG_BATCH_TIMEOUT=5000 # Max wait time in ms (default: 5000)
# OTEL_LOG_MAX_QUEUE_SIZE=2048 # Max queue size (default: 2048)
# Enable detailed export diagnostics (for debugging)
# TEL_DEBUG_DIAGNOSTICS=true
# Advanced: Separate endpoints for metrics and logs (optional)
# OTEL_EXPORTER_OTLP_METRICS_PROTOCOL=http/protobuf
# OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://metrics.example.com:4318
# OTEL_EXPORTER_OTLP_LOGS_PROTOCOL=grpc
# OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=logs.example.com:4317
# Example configurations:
#
# Console debugging (logs only):
# OTEL_TELEMETRY_ENABLED=true
# OTEL_LOGS_EXPORTER=console
# TEL_DEBUG_DIAGNOSTICS=true
#
# OTLP with gRPC (insecure, for local testing):
# OTEL_TELEMETRY_ENABLED=true
# OTEL_LOGS_EXPORTER=otlp
# OTEL_EXPORTER_OTLP_PROTOCOL=grpc
# OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317
# OTEL_EXPORTER_OTLP_INSECURE=true
# OTEL_EXPORTER_OTLP_HEADERS=authorization=Bearer your-token
#
# OTLP with HTTP/JSON (production):
# OTEL_TELEMETRY_ENABLED=true
# OTEL_LOGS_EXPORTER=otlp
# OTEL_EXPORTER_OTLP_PROTOCOL=http/json
# OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com
# OTEL_EXPORTER_OTLP_HEADERS=authorization=Bearer your-token
# ============================================================================
# OBJECT STORE CONFIGURATION
# ============================================================================
# TO ENABLE S3 OR R2 STORAGE, UNCOMMENT AND FILL IN THE FOLLOWING:
# CLINE_STORAGE_ADAPTER="s3" # Options: "s3" or "r2"
# CLINE_STORAGE_BUCKET="cline"
# CLINE_STORAGE_ACCESS_KEY_ID="key"
# CLINE_STORAGE_SECRET_ACCESS_KEY="secrets"
#
# [OPTIONAL FIELDS FOR R2]
# CLINE_STORAGE_ACCOUNT_ID = "account-id"
# Default R2 endpoint (if not set): "https://<CLINE_STORAGE_ACCOUNT_ID>.r2.cloudflarestorage.com"
# CLINE_STORAGE_ENDPOINT = "http://localhost:8333"
#
# [OPTIONAL FIELDS FOR S3]
# CLINE_STORAGE_REGION = "us-west-1" # AWS Bucket Region (default: "us-east-1")
# Default S3 endpoint (if not set): "https://s3.<CLINE_STORAGE_REGION>.amazonaws.com"
# CLINE_STORAGE_ENDPOINT = "http://localhost:8333"
#
# [OPTIONAL FIELDS FOR ALL STORAGE TYPES]
# CLINE_STORAGE_SYNC_INTERVAL_MS = 30000 # Interval for sync worker in milliseconds
# CLINE_STORAGE_SYNC_MAX_RETRIES = 5 # Max retries for failed sync operations
# CLINE_STORAGE_SYNC_BATCH_SIZE = 10 # Number of files to sync in each batch
# CLINE_STORAGE_SYNC_BACKFILL_ENABLED = false # Enable backfill of existing data on startup
# ============================================================================
# OPTIONAL DEVELOPMENT SETTINGS
# ============================================================================
# Uncomment and modify as needed for development
# Multi-root workspace debugging
# MULTI_ROOT_TRACE=true
# gRPC recorder for testing
# GRPC_RECORDER_ENABLED=true
# GRPC_RECORDER_FILE_NAME=test-recording
# Test mode
# E2E_TEST=true
# IS_TEST=true
# ============================================================================
# USAGE INSTRUCTIONS
# ============================================================================
# 1. Copy this file: cp .env.example .env
# 2. Get PostHog keys from 1Password shared vault
# 3. Update the values in .env
# 4. The .env file is gitignored for security
+34
View File
@@ -0,0 +1,34 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
},
"plugins": ["@typescript-eslint", "eslint-rules"],
"rules": {
"@typescript-eslint/naming-convention": [
"warn",
{
"selector": "import",
"format": ["camelCase", "PascalCase"]
}
],
"@typescript-eslint/semi": "off",
"curly": "warn",
"eqeqeq": "warn",
"no-throw-literal": "warn",
"semi": "off",
"react-hooks/exhaustive-deps": "off",
"eslint-rules/no-protobuf-object-literals": "error",
"eslint-rules/no-direct-vscode-api": "warn",
"no-restricted-syntax": [
"error",
{
"selector": "VariableDeclarator[id.type=\"ObjectPattern\"][init.object.name=\"process\"][init.property.name=\"env\"]",
"message": "Use process.env.VARIABLE_NAME directly instead of destructuring"
}
]
},
"ignorePatterns": ["out", "dist", "**/*.d.ts"]
}
-2
View File
@@ -1,6 +1,4 @@
demo.gif filter=lfs diff=lfs merge=lfs -text
assets/docs/demo.gif filter=lfs diff=lfs merge=lfs -text
webview-ui/src/assets/cline_kanban_demo.mp4 filter=lfs diff=lfs merge=lfs -text
webview-ui/src/assets/cline_kanban_demo.webm filter=lfs diff=lfs merge=lfs -text
* text=auto eol=lf
+1 -2
View File
@@ -1,2 +1 @@
/.github/ @saoudrizwan @arafatkatze @maxpaulus43 @candieduniverse
/README.md @saoudrizwan @juanpflores
* @saoudrizwan @ocasta181 @NightTrek @pashpashpash @dcbartlett @saito-sv @Garoth
+67 -67
View File
@@ -1,70 +1,70 @@
name: 🐛 Bug Report
description: File a bug report
labels: ['bug']
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
**Important:** All bug reports must be reproducible using Claude Sonnet 4.5. Cline uses complex prompts so less capable models may not work as expected.
- type: dropdown
id: plugin-type
attributes:
label: Plugin Type
description: Which plugin are you reporting a bug for?
options:
- VSCode Extension
- JetBrains Plugin
- CLI
default: 0
validations:
required: true
- type: input
id: cline-version
attributes:
label: Cline Version
description: What version of Cline are you using? (You can find this at the bottom of the Settings view)
placeholder: 'e.g., 1.2.3'
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
description: How do you trigger this bug? Please walk us through it step by step.
value: |
1.
2.
3.
validations:
required: false
- type: input
id: provider-model
attributes:
label: Provider/Model
description: What provider and model were you using when the issue occurred?
placeholder: 'e.g., cline:anthropic/claude-sonnet-4.5, gemini:gemini-2.5-pro-exp-03-25'
validations:
required: false
- type: textarea
id: system-info
attributes:
label: System Information
description: What operating system and hardware are you using?
placeholder: |
Operating System: Windows 11, macOS Sonoma, Ubuntu 22.04, etc.
Hardware: CPU, GPU, RAM specifications if relevant
e.g.,
OS: Windows 11
CPU: Intel Core i7-11700K
GPU: NVIDIA GeForce RTX 3070
RAM: 32GB DDR4
validations:
required: false
- type: markdown
attributes:
value: |
**Important:** All bug reports must be reproducible using Claude 3.5 Sonnet. Cline uses complex prompts so less capable models may not work as expected.
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
description: How do you trigger this bug? Please walk us through it step by step.
value: |
1.
2.
3.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant API REQUEST output
description: Please copy and paste any relevant output. This will be automatically formatted into code, so no need for backticks.
render: shell
- type: input
id: provider-model
attributes:
label: Provider/Model
description: What provider and model were you using when the issue occurred?
placeholder: "e.g., cline:anthropic/claude-3.7-sonnet, gemini:gemini-2.5-pro-exp-03-25"
validations:
required: true
- type: input
id: operating-system
attributes:
label: Operating System
description: What operating system are you using?
placeholder: "e.g., Windows 11, macOS Sonoma, Ubuntu 22.04"
validations:
required: true
- type: textarea
id: system-info
attributes:
label: System Info
description: What system information is relevant to the issue?
placeholder: "e.g., CPU: Intel Core i7-11700K, GPU: NVIDIA GeForce RTX 3070, RAM: 32GB DDR4"
validations:
required: true
- type: input
id: cline-version
attributes:
label: Cline Version
description: What version of Cline are you using? (You can find this at the bottom of the Settings view)
placeholder: "e.g., 1.2.3"
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Add any other context about the problem here, such as screenshots or related issues.
@@ -0,0 +1,116 @@
name: 💡 Feature Proposal & Contribution
description: Propose a new feature or improvement, and optionally offer to implement feature as a contributor
labels: ["proposal"]
body:
- type: markdown
attributes:
value: |
**Feature Proposal & Contribution for Cline**
Thank you for proposing a feature or improvement for Cline! This template helps us understand the problem, evaluate the solution, and coordinate implementation.
**For detailed proposals:** Please provide comprehensive information to enable fast prioritization and discussion.
**For contribution offers:** You can indicate your willingness to implement the feature yourself.
Before submitting:
- Search existing [Issues](https://github.com/cline/cline/issues) and [Discussions](https://github.com/cline/cline/discussions) to avoid duplicates
- Read the [Contributing Guide](https://github.com/cline/cline/blob/main/CONTRIBUTING.md) if you plan to contribute
- Don't start implementation until the proposal is reviewed and approved
- type: textarea
id: problem-description
attributes:
label: What problem does this solve?
description: |
Describe the problem clearly from a user's point of view. Focus on why this matters, who it affects, and when it occurs.
✅ Good examples:
- "LLM provider returns 400 error when nearing the context window instead of truncating"
- "Submit button is invisible in dark mode"
- "Users can't easily share their Cline configurations with team members"
❌ Avoid vague descriptions:
- "Performance is bad"
- "UI needs work"
Your description should include:
- Who is affected?
- When does it happen?
- What's the current vs expected behavior?
- What is the impact?
placeholder: Be specific about the problem, who it affects, and the impact.
validations:
required: true
- type: textarea
id: proposed-solution
attributes:
label: What's the proposed solution?
description: |
Describe how the problem should be solved. Be specific about UX, system behavior, and any flows that would change.
✅ Good examples:
- "Add error handling immediately after attempting to create the llm stream and retry after manually truncating"
- "Update button styling to ensure contrast in all themes"
- "Add export/import functionality in settings with JSON format"
❌ Avoid vague solutions:
- "Improve performance"
- "Fix the bug"
Your solution should include:
- What exactly will change?
- How will users interact with it?
- What's the expected outcome?
placeholder: Describe the proposed changes and how they solve the problem.
validations:
required: false
- type: dropdown
id: contribution-intent
attributes:
label: Are you interested in implementing this?
description: Let us know if you'd like to contribute to this feature
options:
- "No, just proposing the idea"
- "Yes, I'd like to implement this myself"
- "Yes, I'd like to collaborate with others"
- "Maybe, depending on complexity and guidance"
validations:
required: false
- type: textarea
id: implementation-approach
attributes:
label: Implementation approach (if contributing)
description: |
**Only fill this out if you selected "Yes" above.**
How do you plan to implement this? Include:
- High-level technical approach
- Files/components that would be affected
- Any new dependencies required
- Potential challenges or considerations you've identified
This helps us provide better guidance and ensures alignment before you start coding.
placeholder: "My implementation approach would be..."
- type: checkboxes
id: checklist
attributes:
label: Proposal checklist
options:
- label: I've checked for existing issues or related proposals
required: true
- label: I understand this needs review before implementation can start
required: true
- type: checkboxes
id: contribution-checklist
attributes:
label: Contribution checklist (if contributing)
description: Only check these if you plan to contribute
options:
- label: I've read the [Contributing Guide](https://github.com/cline/cline/blob/main/CONTRIBUTING.md)
- label: I'm willing to make changes based on feedback
- label: I understand the code review process and requirements
-58
View File
@@ -1,58 +0,0 @@
# Copilot Instructions for Cline
This is a VS Code extension. Read `.clinerules/general.md` for tribal knowledge and nuanced patterns.
## Architecture
- **Core** (`src/`): `extension.ts``WebviewProvider``Controller` (single source of truth) → `Task` (agent loop).
- **Webview** (`webview-ui/`): React/Vite app. State via `ExtensionStateContext.tsx`, synced through message passing.
- **CLI** (`cli/`): React Ink terminal UI sharing core logic. Update CLI when changing webview features.
- **Communication**: Protobuf-defined gRPC-like protocol over VS Code message passing. Schemas in `proto/`.
- **MCP**: `src/services/mcp/McpHub.ts`.
## Build & Test (Critical — non-obvious commands)
- **Build**: `npm run compile` — NOT `npm run build`.
- **Watch**: `npm run watch` (extension + webview).
- **Protos**: `npm run protos` — run **immediately** after any `.proto` change. Generates into `src/shared/proto/`, `src/generated/`.
- **Tests**: `npm run test:unit`. After prompt/tool changes: `UPDATE_SNAPSHOTS=true npm run test:unit`.
## Protobuf RPC Workflow (4 steps)
1. **Define** in `proto/cline/*.proto`. Naming: `PascalCaseService`, `camelCase` RPCs, `PascalCase` Messages. Use `common.proto` shared types for simple data.
2. **Generate**: `npm run protos`.
3. **Backend handler**: `src/core/controller/<domain>/`.
4. **Frontend call**: `UiServiceClient.myMethod(Request.create({...}))`.
- Adding enums (e.g. `ClineSay`) → also update `src/shared/proto-conversions/cline-message.ts`.
## Adding API Providers (silent failure risk)
Three proto conversion updates are **required** or the provider silently resets to Anthropic:
1. `proto/cline/models.proto` — add to `ApiProvider` enum.
2. `convertApiProviderToProto()` in `src/shared/proto-conversions/models/api-configuration-conversion.ts`.
3. `convertProtoToApiProvider()` in the same file.
Also update: `src/shared/api.ts`, `src/shared/providers/providers.json`, `src/core/api/index.ts`, `webview-ui/.../providerUtils.ts`, `webview-ui/.../validate.ts`, `webview-ui/.../ApiOptions.tsx`, and `cli/src/components/ModelPicker.tsx`.
For Responses API providers: add to `isNextGenModelProvider()` in `src/utils/model-utils.ts` and set `apiFormat: ApiFormat.OPENAI_RESPONSES` on models.
## Adding Tools to System Prompt (5+ file chain)
1. Add enum to `ClineDefaultTool` in `src/shared/tools.ts`.
2. Create definition in `src/core/prompts/system-prompt/tools/` (export `[GENERIC]` minimum).
3. Register in `src/core/prompts/system-prompt/tools/init.ts`.
4. Whitelist in `src/core/prompts/system-prompt/variants/*/config.ts` for each model family.
5. Handler in `src/core/task/tools/handlers/`, wire in `ToolExecutor.ts`.
6. If tool has UI: add `ClineSay` enum in proto → `ExtensionMessage.ts``cline-message.ts``ChatRow.tsx`.
7. Regenerate snapshots: `UPDATE_SNAPSHOTS=true npm run test:unit`.
## Modifying System Prompt
Modular: `components/` (shared) + `variants/` (model-specific) + `templates/` (`{{PLACEHOLDER}}`). Variants override components via `componentOverrides` in `config.ts` or custom `template.ts`. XS variant is heavily condensed inline. Always regenerate snapshots after changes.
## Global State Keys (silent failure risk)
Adding a key requires: type in `src/shared/storage/state-keys.ts`, read via `context.globalState.get()` in `src/core/storage/utils/state-helpers.ts` `readGlobalStateFromDisk()`, and add to return object. Missing the `.get()` call compiles fine but value is always `undefined`.
## Slash Commands (3 places)
- `src/core/slash-commands/index.ts` — definitions.
- `src/core/prompts/commands.ts` — system prompt integration.
- `webview-ui/src/utils/slash-commands.ts` — webview autocomplete.
## Conventions
- **Paths**: Always use `src/utils/path` helpers (`toPosixString`) for cross-platform compatibility.
- **Logging**: `src/shared/services/Logger.ts`.
- **Feature flags**: See PR #7566 as reference pattern.
+6 -4
View File
@@ -2,14 +2,15 @@
Thank you for contributing to Cline!
⚠️ Important: Before submitting this PR, please ensure you have:
- For feature requests: Created a discussion in our Feature Requests discussions board https://github.com/cline/cline/discussions/categories/feature-requests and received approval from core maintainers before implementation
- For all changes: Link the associated issue/discussion in the "Related Issue" section below
- Opened an issue and discussed your proposed changes with the community / contributors
- Received approval from a core Cline contributor prior to proceeding with the implementation
- Link the associated issue in the "Related Issue" section
Limited exceptions:
Small bug fixes, typo corrections, minor wording improvements, or simple type fixes that don't change functionality may be submitted directly without prior discussion.
Small bug fixes, typo corrections, minor wording improvements, or simple type fixes that don't change functionality may be submitted directly.
Why this requirement?
We deeply appreciate all community contributions - they are essential to Cline's success! To ensure the best use of everyone's time and maintain project direction, we use our Feature Requests discussions board to gauge community interest and validate feature ideas before implementation begins. This helps us focus development efforts on features that will benefit the most users.
We deeply appreciate all community contributions - they are the core reason we're able to operate successfully and keep innovating! We welcome community input and want to make it as easy as possible for people to submit quality work. This process helps our core maintainers review new ideas faster and saves contributor time by ensuring you have the go-ahead before spending time on implementation.
-->
### Related Issue
@@ -60,6 +61,7 @@ We're not looking for exhaustive documentation - just evidence that you've thoug
- [ ] Changes are limited to a single feature, bugfix or chore (split larger changes into separate PRs)
- [ ] Tests are passing (`npm test`) and code is formatted and linted (`npm run format && npm run lint`)
- [ ] I have created a changeset using `npm run changeset` (required for user-facing changes)
- [ ] I have reviewed [contributor guidelines](https://github.com/cline/cline/blob/main/CONTRIBUTING.md)
### Screenshots
@@ -0,0 +1,79 @@
"""
This script updates a specific version's release notes section in CHANGELOG.md with new content
or reformats existing content.
The script:
1. Takes a version number, changelog path, and optionally new content as input from environment variables
2. Finds the section in the changelog for the specified version
3. Either:
a) Replaces the content with new content if provided, or
b) Reformats existing content by:
- Removing the first two lines of the changeset format
- Ensuring version numbers are wrapped in square brackets
4. Writes the updated changelog back to the file
Environment Variables:
CHANGELOG_PATH: Path to the changelog file (defaults to 'CHANGELOG.md')
VERSION: The version number to update/format
PREV_VERSION: The previous version number (used to locate section boundaries)
NEW_CONTENT: Optional new content to insert for this version
"""
#!/usr/bin/env python3
import os
CHANGELOG_PATH = os.environ.get("CHANGELOG_PATH", "CHANGELOG.md")
VERSION = os.environ['VERSION']
PREV_VERSION = os.environ.get("PREV_VERSION", "")
NEW_CONTENT = os.environ.get("NEW_CONTENT", "")
def overwrite_changelog_section(changelog_text: str, new_content: str):
# Find the section for the specified version
version_pattern = f"## {VERSION}\n"
unformmatted_prev_version_pattern = f"## {PREV_VERSION}\n"
prev_version_pattern = f"## [{PREV_VERSION}]\n"
print(f"latest version: {VERSION}")
print(f"prev_version: {PREV_VERSION}")
notes_start_index = changelog_text.find(version_pattern) + len(version_pattern)
notes_end_index = changelog_text.find(prev_version_pattern, notes_start_index) if PREV_VERSION and (prev_version_pattern in changelog_text or unformmatted_prev_version_pattern in changelog_text) else len(changelog_text)
if new_content:
return changelog_text[:notes_start_index] + f"{new_content}\n" + changelog_text[notes_end_index:]
else:
changeset_lines = changelog_text[notes_start_index:notes_end_index].split("\n")
filtered_lines = []
for line in changeset_lines:
# If the previous line is a changeset format
if len(filtered_lines) > 1 and filtered_lines[-1].startswith("### "):
# Remove the last two lines from the filted_lines
filtered_lines.pop()
filtered_lines.pop()
else:
filtered_lines.append(line.strip())
# Prepend a new line to the first line of filtered_lines
if filtered_lines:
filtered_lines[0] = "\n" + filtered_lines[0]
# Print filted_lines wiht a "\n" at the end of each line
for line in filtered_lines:
print(line.strip())
parsed_lines = "\n".join(line for line in filtered_lines)
updated_changelog = changelog_text[:notes_start_index] + parsed_lines + changelog_text[notes_end_index:]
return updated_changelog
with open(CHANGELOG_PATH, 'r') as f:
changelog_content = f.read()
new_changelog = overwrite_changelog_section(changelog_content, NEW_CONTENT)
# print("----------------------------------------------------------------------------------")
# print(new_changelog)
# print("----------------------------------------------------------------------------------")
# Write back to CHANGELOG.md
with open(CHANGELOG_PATH, 'w') as f:
f.write(new_changelog)
print(f"{CHANGELOG_PATH} updated successfully!")
+113
View File
@@ -0,0 +1,113 @@
name: Changeset Converter
run-name: Changeset Conversion
on:
workflow_dispatch:
pull_request:
types: [closed]
env:
REPO_PATH: ${{ github.repository }}
GIT_REF: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || 'main' }}
NODE_VERSION: 20.18.1
jobs:
# Job 1: Create version bump PR when changesets are merged to main
changeset-pr-version-bump:
if: |
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'pull_request' &&
github.event.pull_request.merged == true &&
github.event.pull_request.base.ref == 'main' &&
github.actor != 'github-actions'
)
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Check user for team affiliation
id: team_check
if: github.event_name == 'workflow_dispatch'
uses: morfien101/actions-authorized-user@4a3cfbf0bcb3cafe4a71710a278920c5d94bb38b
with:
username: ${{ github.actor }}
org: ${{ github.repository_owner }}
team: "deployer"
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Check if user is authorized
if: github.event_name == 'workflow_dispatch'
run: |
if [ "${{ steps.team_check.outputs.authorized }}" != "true" ]; then
echo "User is not authorized to run this workflow."
exit 1
fi
- name: Git Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ env.GIT_REF }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: Install Dependencies
run: npm install changeset
# Check if there are any new changesets to process
- name: Check for changesets
id: check-changesets
run: |
NEW_CHANGESETS=$(find .changeset -name "*.md" ! -name "README.md" | wc -l | tr -d ' ')
echo "Changesets diff with previous version: $NEW_CHANGESETS"
echo "new_changesets=$NEW_CHANGESETS" >> $GITHUB_OUTPUT
# Create version bump PR using changesets/action if there are new changesets
- name: Create Changeset Pull Request
if: steps.check-changesets.outputs.new_changesets != '0'
uses: changesets/action@v1
with:
commit: "changeset version bump"
title: "Changeset version bump"
version: npm run version-packages # This performs the changeset version bump
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Get current and previous versions to edit changelog entry
- name: Get version
id: get_version
run: |
VERSION=$(git show HEAD:package.json | jq -r '.version')
echo "version=$VERSION" >> $GITHUB_OUTPUT
PREV_VERSION=$(git show origin/main:package.json | jq -r '.version')
echo "prev_version=$PREV_VERSION" >> $GITHUB_OUTPUT
echo "version=$VERSION"
echo "prev_version=$PREV_VERSION"
# Update CHANGELOG.md with proper format
- name: Update Changelog Format
env:
VERSION: ${{ steps.get_version.outputs.version }}
PREV_VERSION: ${{ steps.get_version.outputs.prev_version }}
run: python .github/scripts/overwrite_changeset_changelog.py
# Commit and push changelog updates
- name: Push Changelog updates to Pull Request
run: |
git config user.name "github-actions"
git config user.email github-actions@github.com
echo "Running git add and commit..."
git add CHANGELOG.md
git commit -m "Updating CHANGELOG.md format"
git status
echo "--------------------------------------------------------------------------------"
echo "Pushing to remote..."
echo "--------------------------------------------------------------------------------"
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
git push origin $CURRENT_BRANCH
-83
View File
@@ -1,83 +0,0 @@
name: CLI TUI Tests
on:
pull_request:
branches:
- main
workflow_dispatch:
workflow_call:
permissions:
contents: read
jobs:
cli-tui-tests:
name: CLI TUI Tests
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build CLI
run: npm run cli:build
- name: Run TUI Tests
id: tui_tests
run: |
npm run test:e2e:cli:tui 2>&1 | tee tui-test-output.log
exit_code=${PIPESTATUS[0]}
echo "tui_exit_code=$exit_code" >> $GITHUB_OUTPUT
exit $exit_code
- name: Write failure summary
if: always() && steps.tui_tests.outcome != 'success' && steps.tui_tests.outcome != 'skipped'
run: |
echo "## ❌ CLI TUI Tests Failed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Step outcome:** \`${{ steps.tui_tests.outcome }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Test Output" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
if [ -f tui-test-output.log ]; then
cat tui-test-output.log >> $GITHUB_STEP_SUMMARY
else
echo "(no test output captured — process may have been killed before output was flushed)" >> $GITHUB_STEP_SUMMARY
fi
echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Debugging" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **TUI traces** are attached as artifacts below — download and inspect them to see terminal state at the point of failure." >> $GITHUB_STEP_SUMMARY
echo "- **To view a trace replay/Run a TUI Trace: ** run \`npx tui-test show-trace path/to/trace/file\` in your terminal" >> $GITHUB_STEP_SUMMARY
echo "- **Full test log** is also attached as an artifact." >> $GITHUB_STEP_SUMMARY
echo "- Tests run with \`retries: 2\` so any failure shown is a consistent failure, not a flake." >> $GITHUB_STEP_SUMMARY
- name: Upload TUI traces
if: always() && steps.tui_tests.outcome != 'success' && steps.tui_tests.outcome != 'skipped'
uses: actions/upload-artifact@v4
with:
name: tui-test-traces
path: tests/e2e/cli/tui-traces/
retention-days: 14
if-no-files-found: warn
- name: Upload test log
if: always() && steps.tui_tests.outcome != 'success' && steps.tui_tests.outcome != 'skipped'
uses: actions/upload-artifact@v4
with:
name: tui-test-log
path: tui-test-output.log
retention-days: 14
if-no-files-found: warn
@@ -1,85 +0,0 @@
name: Smoke Tests
on:
push:
branches: [main]
paths:
- 'src/core/**'
- 'src/shared/**'
- 'proto/**'
- 'evals/**'
- '.github/workflows/cline-evals-regression.yml'
pull_request:
paths:
- 'src/core/**'
- 'src/shared/**'
- 'proto/**'
- 'evals/**'
- '.github/workflows/cline-evals-regression.yml'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: smoke-tests-${{ github.ref }}
cancel-in-progress: true
jobs:
smoke-tests:
name: Smoke Tests
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build and install CLI
run: |
npm run protos
cd cli && npm install && npm run build && npm link
echo "$(npm config get prefix)/bin" >> $GITHUB_PATH
- name: Verify CLI
run: cline --version
- name: Run smoke tests
env:
CLINE_API_KEY: ${{ secrets.CLINE_API_KEY }}
run: |
cline auth -p cline -k "$CLINE_API_KEY" -m "anthropic/claude-sonnet-4.5"
max_attempts=3
for attempt in $(seq 1 $max_attempts); do
echo "::group::Attempt $attempt of $max_attempts"
if npx tsx evals/smoke-tests/run-smoke-tests.ts --trials 1 --parallel; then
echo "::endgroup::"
echo "Smoke tests passed on attempt $attempt"
exit 0
fi
echo "::endgroup::"
if [ $attempt -lt $max_attempts ]; then
echo "::warning::Smoke tests failed on attempt $attempt, retrying..."
sleep 10
fi
done
echo "::error::Smoke tests failed after $max_attempts attempts"
exit 1
- name: Generate summary
if: always()
run: cat evals/smoke-tests/results/latest/summary.md >> $GITHUB_STEP_SUMMARY
- name: Upload results
uses: actions/upload-artifact@v4
if: always()
with:
name: smoke-test-results-${{ github.run_id }}
path: evals/smoke-tests/results/latest/
retention-days: 30
+28
View File
@@ -0,0 +1,28 @@
# Codespell configuration is within .codespellrc
---
name: Codespell
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
codespell:
if: false
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Annotate locations with typos
uses: codespell-project/codespell-problem-matcher@v1
- name: Codespell
uses: codespell-project/actions-codespell@v2
with:
only_warn: 1
+2 -5
View File
@@ -80,16 +80,13 @@ jobs:
playwright-browsers-${{ runner.os }}-
- name: Install root dependencies
if: steps.root-cache.outputs.cache-hit != 'true'
run: npm ci
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install webview-ui dependencies
if: steps.webview-cache.outputs.cache-hit != 'true'
run: cd webview-ui && npm ci
- name: Install vsce
run: npm install -g @vscode/vsce
- name: Install xvfb on Linux
if: matrix.runner == 'ubuntu'
run: sudo apt-get update && sudo apt-get install -y xvfb
@@ -1,53 +0,0 @@
name: Auto-label Issues
on:
issues:
types: [opened, edited]
jobs:
label:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- uses: actions/github-script@v7
with:
script: |
const body = context.payload.issue.body || '';
const labels = context.payload.issue.labels.map(l => l.name);
// Check if JetBrains Plugin is selected
if (body.match(/###\s*Plugin Type\s*\n+JetBrains Plugin/i)) {
if (!labels.includes('JetBrains')) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['JetBrains']
});
}
}
// Check if VSCode Extension is selected
if (body.match(/###\s*Plugin Type\s*\n+VSCode Extension/i)) {
if (!labels.includes('VS Code')) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['VS Code']
});
}
}
// Check if CLI is selected
if (body.match(/###\s*Plugin Type\s*\n+CLI/i)) {
if (!labels.includes('CLI')) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['CLI']
});
}
}
-111
View File
@@ -1,111 +0,0 @@
name: Publish NPM Release
on:
workflow_call:
inputs:
confirm_publish:
description: 'Type "publish" to confirm you want to publish to NPM'
required: true
type: string
permissions:
contents: write # Required for pushing tags
id-token: write # Required for npm trusted publishing (OIDC)
checks: write # Required by test workflow
pull-requests: write # Required by test workflow
jobs:
test:
uses: ./.github/workflows/test.yml
publish-npm-release:
needs: test
name: Publish Cline CLI to NPM
if: github.repository == 'cline/cline' && github.ref == 'refs/heads/main' && inputs.confirm_publish == 'publish'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24.x"
registry-url: "https://registry.npmjs.org"
- name: Install root dependencies and CLI dependencies
run: npm ci --include=optional # this will also install cli deps because "cli" in included in root package.json workspaces field
- name: Generate Protos
run: npm run protos
- name: Read release version
id: version
run: |
# Read version from cli/package.json
VERSION=$(node -p "require('./cli/package.json').version")
echo "Release version: $VERSION"
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Build standalone NPM package
env:
TELEMETRY_SERVICE_API_KEY: ${{ secrets.TELEMETRY_SERVICE_API_KEY }}
ERROR_SERVICE_API_KEY: ${{ secrets.ERROR_SERVICE_API_KEY }}
CLINE_ENVIRONMENT: production
OTEL_TELEMETRY_ENABLED: "1"
OTEL_METRICS_EXPORTER: otlp
OTEL_LOGS_EXPORTER: otlp
OTEL_EXPORTER_OTLP_PROTOCOL: ${{ secrets.OTEL_EXPORTER_OTLP_PROTOCOL }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
run: node scripts/package-npm.mjs
- name: Verify build output
run: |
echo "Checking dist-standalone directory..."
ls -la dist-standalone/
echo "Verifying CLI binaries..."
ls -lh cli/bin/cline-* || echo "Warning: CLI binaries not found"
echo "Checking package.json in dist-standalone..."
cat dist-standalone/package.json | grep version
- name: Publish to NPM with latest tag
run: |
echo "Publishing version ${{ steps.version.outputs.version }} to NPM with tag 'latest'..."
cd dist-standalone
npm publish --tag latest --access public
- name: Tag release
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag "v${{ steps.version.outputs.version }}-cli"
git push origin "v${{ steps.version.outputs.version }}-cli"
- name: Summary
run: |
echo "✅ Successfully published cline@${{ steps.version.outputs.version }} to NPM with tag 'latest'"
echo ""
echo "📦 Install with: npm install -g cline"
echo "🔗 NPM: https://www.npmjs.com/package/cline/v/${{ steps.version.outputs.version }}"
- name: Post release to Slack
uses: slackapi/slack-github-action@v3.0.1
with:
method: chat.postMessage
token: ${{ secrets.SLACK_RELEASE_BOT_TOKEN }}
payload: |
channel: "C0APVKGGZFC"
text: "Cline CLI v${{ steps.version.outputs.version }}"
blocks:
- type: "section"
text:
type: "mrkdwn"
text: "*Cline CLI v${{ steps.version.outputs.version }}*"
- type: "context"
elements:
- type: "mrkdwn"
text: "<https://www.npmjs.com/package/cline/v/${{ steps.version.outputs.version }}|View on npm>"
-134
View File
@@ -1,134 +0,0 @@
name: Publish NPM Nightly
on:
workflow_call:
inputs:
force_publish:
description: "Force publish even if there are no commits in the last 24 hours"
required: false
type: boolean
default: false
permissions:
contents: read
id-token: write # Required for npm trusted publishing (OIDC)
checks: write # Required by test workflow
pull-requests: write # Required by test workflow
jobs:
test:
uses: ./.github/workflows/test.yml
publish-npm-nightly:
needs: test
name: Publish Cline CLI (Nightly) to NPM
if: github.repository == 'cline/cline' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Check for recent commits
id: check_commits
run: |
if [ "${{ inputs.force_publish }}" = "true" ]; then
echo "force_publish enabled, proceeding with publish"
echo "skip=false" >> $GITHUB_OUTPUT
exit 0
fi
if [ $(git rev-list --count HEAD --since="24 hours ago") -eq 0 ]; then
echo "No commits in last 24 hours, skipping publish"
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "Found recent commits, proceeding with publish"
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Setup Node.js
if: steps.check_commits.outputs.skip != 'true'
uses: actions/setup-node@v4
with:
node-version: "24.x"
registry-url: "https://registry.npmjs.org"
- name: Install root dependencies and CLI dependencies
if: steps.check_commits.outputs.skip != 'true'
run: npm ci --include=optional # this will also install cli deps because "cli" in included in root package.json workspaces field
- name: Generate Protos
if: steps.check_commits.outputs.skip != 'true'
run: npm run protos
- name: Generate nightly version with timestamp
if: steps.check_commits.outputs.skip != 'true'
id: version
run: |
# Read base version from cli/package.json (e.g., "2.0.0")
BASE_VERSION=$(node -p "require('./cli/package.json').version")
# Generate timestamp (Unix epoch seconds)
TIMESTAMP=$(date +%s)
# Create unique nightly version: 1.0.9-nightly.1736365200
VERSION="${BASE_VERSION}-nightly.${TIMESTAMP}"
echo "Base version: $BASE_VERSION"
echo "Generated nightly version: $VERSION"
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Update cli/package.json with nightly version
if: steps.check_commits.outputs.skip != 'true'
run: |
# Update version with timestamp-based nightly version
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('cli/package.json', 'utf8'));
pkg.version = '${{ steps.version.outputs.version }}';
fs.writeFileSync('cli/package.json', JSON.stringify(pkg, null, '\t'));
"
echo "Using version ${{ steps.version.outputs.version }} for build"
cat cli/package.json | grep '"version"'
- name: Build and package CLI
if: steps.check_commits.outputs.skip != 'true'
env:
TELEMETRY_SERVICE_API_KEY: ${{ secrets.TELEMETRY_SERVICE_API_KEY }}
ERROR_SERVICE_API_KEY: ${{ secrets.ERROR_SERVICE_API_KEY }}
CLINE_ENVIRONMENT: production
OTEL_TELEMETRY_ENABLED: "1"
OTEL_METRICS_EXPORTER: otlp
OTEL_LOGS_EXPORTER: otlp
OTEL_EXPORTER_OTLP_PROTOCOL: ${{ secrets.OTEL_EXPORTER_OTLP_PROTOCOL }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
run: node scripts/package-npm.mjs
- name: Verify build output
if: steps.check_commits.outputs.skip != 'true'
run: |
echo "Checking dist-standalone directory..."
ls -la dist-standalone/
echo "Verifying CLI binaries..."
ls -lh cli/bin/cline-* || echo "Warning: CLI binaries not found"
echo "Checking package.json in dist-standalone..."
cat dist-standalone/package.json | grep version
- name: Publish to NPM with nightly tag
if: steps.check_commits.outputs.skip != 'true'
run: |
echo "Publishing version ${{ steps.version.outputs.version }} to NPM with tag 'nightly'..."
cd dist-standalone
npm publish --tag nightly --access public
- name: Summary
if: steps.check_commits.outputs.skip != 'true'
run: |
echo "✅ Successfully published cline@${{ steps.version.outputs.version }} to NPM with tag 'nightly'"
echo ""
echo "📦 Install with: npm install -g cline@nightly"
echo "🔗 NPM: https://www.npmjs.com/package/cline/v/${{ steps.version.outputs.version }}"
-215
View File
@@ -1,215 +0,0 @@
# Build and Pack CLI
#
# Builds a CLI tarball from any branch/commit and publishes it as a GitHub Release.
# Requires write access to the repository (maintainers/collaborators only).
#
# Security: Split into two jobs to isolate untrusted build code from write tokens.
# The build job runs arbitrary ref code with zero permissions. The release job
# only runs trusted GitHub Actions with write scope.
#
# Usage (helper script, auto-detects current branch):
# ./scripts/build-cli-artifact.sh
# ./scripts/build-cli-artifact.sh feature/my-changes
# ./scripts/build-cli-artifact.sh feature/my-changes 1234 # comments on PR
#
# Usage (gh CLI directly):
# gh workflow run pack-cli.yml -f ref=main
# gh workflow run pack-cli.yml -f ref=abc123 -f pr_number=1234
#
# Install the built CLI (no auth required):
# npm install -g https://github.com/cline/cline/releases/download/cli-build-<sha>/cline-<ver>.tgz
#
# Find releases:
# gh release list --limit 10
name: Build and Pack CLI
permissions:
contents: read
on:
workflow_dispatch:
inputs:
ref:
description: 'Branch, tag, or commit SHA to build (leave empty for default branch)'
required: false
type: string
pr_number:
description: 'PR number to comment on with install instructions (optional)'
required: false
type: number
jobs:
# ── Build job: runs untrusted ref code with ZERO permissions ──
build:
name: Build CLI
runs-on: ubuntu-latest
permissions: {}
outputs:
commit_sha: ${{ steps.commit.outputs.sha }}
tarball: ${{ steps.pack.outputs.tarball }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
persist-credentials: false
- name: Get commit SHA
id: commit
run: |
COMMIT_SHA=$(git rev-parse --short HEAD)
echo "sha=$COMMIT_SHA" >> $GITHUB_OUTPUT
echo "Building from commit: $COMMIT_SHA"
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20.x"
- name: Install dependencies
run: npm ci --include=optional
- name: Generate Protos
run: npm run protos
- name: Build standalone package
run: node scripts/package-npm.mjs
- name: Create Tarball
id: pack
run: |
cd dist-standalone
TARBALL=$(npm pack)
echo "tarball=$TARBALL" >> $GITHUB_OUTPUT
echo "Created tarball: $TARBALL"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: cli-tarball
path: dist-standalone/*.tgz
# ── Release job: only trusted Actions code, with write permissions ──
release:
name: Release CLI
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
steps:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: cli-tarball
path: dist-standalone
- name: Create GitHub Release
id: create_release
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
const commit = '${{ needs.build.outputs.commit_sha }}';
const tarball = '${{ needs.build.outputs.tarball }}';
// Delete existing release/tag if re-running for the same commit
const tagName = `cli-build-${commit}`;
try {
const existing = await github.rest.repos.getReleaseByTag({
owner: context.repo.owner,
repo: context.repo.repo,
tag: tagName
});
await github.rest.repos.deleteRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: existing.data.id
});
await github.rest.git.deleteRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `tags/${tagName}`
});
core.info(`Deleted existing release for ${tagName}`);
} catch (e) {
// Release doesn't exist yet, that's fine
}
// Create a release
const release = await github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: tagName,
name: `CLI Build (${commit})`,
body: `Automated CLI build from commit ${commit}\n\nInstall with:\n\`\`\`bash\nnpm install -g https://github.com/${context.repo.owner}/${context.repo.repo}/releases/download/${tagName}/${tarball}\n\`\`\``,
draft: false,
prerelease: true
});
// Upload the tarball as a release asset
const tarballPath = path.join('dist-standalone', tarball);
const tarballData = fs.readFileSync(tarballPath);
await github.rest.repos.uploadReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: release.data.id,
name: tarball,
data: tarballData
});
const downloadUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/releases/download/${tagName}/${tarball}`;
core.setOutput('release_url', release.data.html_url);
core.setOutput('download_url', downloadUrl);
- name: Comment on PR with download instructions
if: inputs.pr_number != ''
uses: actions/github-script@v7
with:
script: |
const commit = '${{ needs.build.outputs.commit_sha }}';
const releaseUrl = '${{ steps.create_release.outputs.release_url }}';
const downloadUrl = '${{ steps.create_release.outputs.download_url }}';
const prNumber = ${{ inputs.pr_number || 0 }};
if (!prNumber) return;
const comment = `## 📦 CLI Build Ready
A CLI build has been created for commit \`${commit}\`.
### Install Directly from URL (No Authentication Required!)
\`\`\`bash
npm install -g ${downloadUrl}
\`\`\`
### Alternative: Download and Install
\`\`\`bash
curl -L ${downloadUrl} -o cline.tgz
npm install -g ./cline.tgz
\`\`\`
📦 [View Release](${releaseUrl})
`;
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
- name: Summary
run: |
echo "✅ CLI build complete!"
echo ""
echo "📦 Release: ${{ steps.create_release.outputs.release_url }}"
echo "🔗 Download URL: ${{ steps.create_release.outputs.download_url }}"
echo ""
echo "Install from anywhere (no authentication required):"
echo " npm install -g ${{ steps.create_release.outputs.download_url }}"
@@ -1,60 +0,0 @@
name: Publish CLI (Trusted)
on:
schedule:
- cron: "0 12 * * *" # 4 AM PST (UTC-8) = 12 UTC
workflow_dispatch:
inputs:
publish_target:
description: "Which publish flow to run"
required: true
default: "main"
type: choice
options:
- main
- nightly
confirm_publish:
description: 'Required when publish_target=main. Type "publish" to confirm release publish.'
required: false
type: string
force_nightly_publish:
description: "Force nightly publish even with no commits in last 24h"
required: false
type: boolean
default: false
permissions:
id-token: write # Required for npm trusted publishing (OIDC)
contents: write # Required because npm-main creates/pushes git tags
checks: write # Required by nested reusable test workflow
pull-requests: write # Required by nested reusable test workflow
jobs:
cli-tui-tests:
uses: ./.github/workflows/cli-tui-tests.yml
publish-main:
needs: cli-tui-tests
if: |
github.repository == 'cline/cline' && (
github.event_name == 'workflow_dispatch' &&
github.event.inputs.publish_target == 'main' &&
github.event.inputs.confirm_publish == 'publish' &&
!endsWith(github.actor, '[bot]')
)
uses: ./.github/workflows/npm-main.yaml
secrets: inherit
with:
confirm_publish: ${{ github.event.inputs.confirm_publish }}
publish-nightly:
needs: cli-tui-tests
if: |
github.repository == 'cline/cline' && (
github.event_name == 'schedule' ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.publish_target == 'nightly')
)
uses: ./.github/workflows/npm-nightly.yaml
secrets: inherit
with:
force_publish: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.force_nightly_publish == 'true' }}
-77
View File
@@ -1,77 +0,0 @@
name: "Publish Nightly Release"
on:
schedule:
- cron: '0 12 * * *' # 4 AM PST (UTC-8) = 12 UTC
workflow_dispatch:
permissions:
contents: write
packages: write
checks: write
pull-requests: write
jobs:
test:
uses: ./.github/workflows/test.yml
publish:
needs: test
name: Publish Cline (Nightly) Extension
if: github.repository == 'cline/cline'
runs-on: ubuntu-latest
environment: PublishNightly
steps:
- uses: actions/checkout@v4
with:
lfs: true
- 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:
# Keep publish environment aligned with test workflow/tooling lockfile expectations.
# Newer LTS (Node 24 / npm 11) can make `npm list` fail with ELSPROBLEMS during vsce packaging.
node-version: 22
- name: Install root dependencies
run: npm ci --include=optional
- name: Install webview-ui dependencies
run: cd webview-ui && npm ci --include=optional
- name: Install Publishing Tools
run: npm install -g @vscode/vsce ovsx
- name: Verify LFS media assets are resolved
run: |
for FILE in webview-ui/src/assets/cline_kanban_demo.mp4 webview-ui/src/assets/cline_kanban_demo.webm; do
if grep -q "git-lfs.github.com/spec/v1" "$FILE"; then
echo "Error: $FILE is still a Git LFS pointer in CI checkout"
exit 1
fi
done
- 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
# OpenTelemetry production defaults (can be overridden at runtime)
OTEL_TELEMETRY_ENABLED: ${{ secrets.OTEL_TELEMETRY_ENABLED }}
OTEL_LOGS_EXPORTER: otlp
OTEL_METRICS_EXPORTER: otlp
OTEL_EXPORTER_OTLP_PROTOCOL: ${{ secrets.OTEL_EXPORTER_OTLP_PROTOCOL }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
run: npm run publish:marketplace:nightly
+45 -138
View File
@@ -11,13 +11,8 @@ on:
options:
- pre-release
- release
auto_create_tag_from_main:
description: "Auto-create and push the provided tag from the tested main commit (recommended)"
required: true
default: true
type: boolean
tag:
description: "Tag to publish (required in both modes, e.g., v3.1.2)"
description: "Enter existing tag to publish (e.g., v3.1.2)"
required: true
type: string
@@ -40,80 +35,36 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
fetch-tags: true
lfs: true
- name: Resolve Release Tag
id: resolve_tag
run: |
TAG="${{ github.event.inputs.tag }}"
AUTO_CREATE="${{ github.event.inputs.auto_create_tag_from_main }}"
TESTED_SHA="${{ github.sha }}"
WORKFLOW_REF="${{ github.ref }}"
if [[ -z "$TAG" ]]; then
echo "Error: tag input is required"
exit 1
fi
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.]+)?$ ]]; then
echo "Error: tag must match vX.Y.Z (optionally with -suffix or .suffix)"
exit 1
fi
TAG_REF="refs/tags/$TAG"
git fetch origin main --tags
if [[ "$AUTO_CREATE" == "true" ]]; then
if [[ "$WORKFLOW_REF" != "refs/heads/main" ]]; then
echo "Error: auto-create mode requires dispatching from main (current ref: $WORKFLOW_REF)"
exit 1
fi
echo "Auto-create enabled. Using tested workflow SHA: $TESTED_SHA"
if ! git merge-base --is-ancestor "$TESTED_SHA" origin/main; then
echo "Error: tested SHA $TESTED_SHA is not on origin/main"
exit 1
fi
if git show-ref --verify --quiet "$TAG_REF"; then
TAG_SHA=$(git rev-list -n 1 "$TAG_REF^{commit}")
if [[ "$TAG_SHA" != "$TESTED_SHA" ]]; then
echo "Error: tag '$TAG' already exists at $TAG_SHA, not at tested SHA ($TESTED_SHA)"
exit 1
fi
echo "Tag '$TAG' already exists at tested SHA. Continuing."
else
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag "$TAG" "$TESTED_SHA"
git push origin "$TAG_REF"
echo "Created and pushed tag '$TAG' from tested SHA $TESTED_SHA."
fi
else
if ! git show-ref --verify --quiet "$TAG_REF"; then
echo "Error: tag '$TAG' does not exist in the repository"
exit 1
fi
echo "Using existing tag '$TAG'."
fi
git checkout --detach "$TAG_REF^{commit}"
echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "resolved_sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
ref: ${{ github.event.inputs.tag }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
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
run: npm install --include=optional
if: steps.root-cache.outputs.cache-hit != 'true'
run: npm ci --include=optional
- name: Install webview-ui dependencies
run: cd webview-ui && npm install --include=optional
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
@@ -124,42 +75,29 @@ jobs:
VERSION=$(node -p "require('./package.json').version")
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Verify Tag Matches Package Version
- name: Validate Tag
id: validate_tag
run: |
TAG="${{ steps.resolve_tag.outputs.tag }}"
VERSION="v${{ steps.get_version.outputs.version }}"
if [[ "$TAG" != "$VERSION" ]]; then
echo "Error: tag '$TAG' does not match package version '$VERSION'"
TAG="${{ github.event.inputs.tag }}"
echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "Using existing tag: $TAG"
# Verify the tag exists
if ! git rev-parse "$TAG" >/dev/null 2>&1; then
echo "Error: Tag '$TAG' does not exist in the repository"
exit 1
fi
echo "Tag and package version match: $TAG"
- name: Verify LFS media assets are resolved
run: |
for FILE in webview-ui/src/assets/cline_kanban_demo.mp4 webview-ui/src/assets/cline_kanban_demo.webm; do
if grep -q "git-lfs.github.com/spec/v1" "$FILE"; then
echo "Error: $FILE is still a Git LFS pointer in CI checkout"
exit 1
fi
done
echo "Tag '$TAG' validated successfully"
- name: Package and Publish Extension
env:
VSCE_PAT: ${{ secrets.VSCE_PAT }}
OVSX_PAT: ${{ secrets.OVSX_PAT }}
CLINE_ENVIRONMENT: production
TELEMETRY_SERVICE_API_KEY: ${{ secrets.TELEMETRY_SERVICE_API_KEY }}
ERROR_SERVICE_API_KEY: ${{ secrets.ERROR_SERVICE_API_KEY }}
# OpenTelemetry production defaults (can be overridden at runtime)
OTEL_TELEMETRY_ENABLED: ${{ secrets.OTEL_TELEMETRY_ENABLED }}
OTEL_LOGS_EXPORTER: otlp
OTEL_METRICS_EXPORTER: otlp
OTEL_EXPORTER_OTLP_PROTOCOL: ${{ secrets.OTEL_EXPORTER_OTLP_PROTOCOL }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
run: |
# Required to generate the .vsix
vsce package --allow-package-secrets sendgrid --out "cline-${{ steps.get_version.outputs.version }}.vsix"
vsce package --out "cline-${{ steps.get_version.outputs.version }}.vsix"
if [ "${{ github.event.inputs.release-type }}" = "pre-release" ]; then
npm run publish:marketplace:prerelease
@@ -169,53 +107,22 @@ jobs:
echo "Successfully published release version ${{ steps.get_version.outputs.version }} to VS Code Marketplace and Open VSX Registry"
fi
- name: Get Previous Tag
id: prev_tag
run: |
CURRENT_TAG="${{ steps.resolve_tag.outputs.tag }}"
PREV_TAG=$(git describe --tags --abbrev=0 "$CURRENT_TAG^" 2>/dev/null || echo "")
echo "prev_tag=$PREV_TAG" >> $GITHUB_OUTPUT
- name: Get Changelog Entry
id: changelog
run: |
# Get content between first ## [ and second ## [
CONTENT=$(awk '/^## \[/{if(found) exit; found=1; next} found{print}' CHANGELOG.md)
echo "content<<EOF" >> $GITHUB_OUTPUT
echo "$CONTENT" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
# - name: Get Changelog Entry
# id: changelog
# uses: mindsers/changelog-reader-action@v2
# with:
# # This expects a standard Keep a Changelog format
# # "latest" means it will read whichever is the most recent version
# # set in "## [1.2.3] - 2025-01-28" style
# version: latest
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.resolve_tag.outputs.tag }}
tag_name: ${{ steps.validate_tag.outputs.tag }}
files: "*.vsix"
body: |
${{ steps.changelog.outputs.content }}
**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.prev_tag.outputs.prev_tag }}...${{ steps.resolve_tag.outputs.tag }}
# body: ${{ steps.changelog.outputs.content }}
generate_release_notes: true
prerelease: ${{ github.event.inputs.release-type == 'pre-release' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Post release to Slack
uses: slackapi/slack-github-action@v3.0.1
with:
method: chat.postMessage
token: ${{ secrets.SLACK_RELEASE_BOT_TOKEN }}
payload: |
channel: "C0APVKGGZFC"
text: "Cline ${{ steps.resolve_tag.outputs.tag }}"
blocks:
- type: "section"
text:
type: "mrkdwn"
text: "*Cline ${{ steps.resolve_tag.outputs.tag }}*"
- type: "section"
text:
type: "mrkdwn"
text: ${{ toJSON(steps.changelog.outputs.content) }}
- type: "context"
elements:
- type: "mrkdwn"
text: "Full Changelog: https://github.com/${{ github.repository }}/compare/${{ steps.prev_tag.outputs.prev_tag }}...${{ steps.resolve_tag.outputs.tag }}"
+146 -140
View File
@@ -1,9 +1,6 @@
name: Tests
on:
push:
branches:
- main
workflow_dispatch:
pull_request:
branches:
@@ -17,35 +14,7 @@ permissions:
pull-requests: write # Needed to add comments/annotations to PRs
jobs:
quality-checks:
runs-on: ubuntu-latest
name: Quality Checks
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
cache-dependency-path: |
package-lock.json
webview-ui/package-lock.json
- name: Install root dependencies
run: npm ci
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install webview-ui dependencies
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:
@@ -63,63 +32,97 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
cache-dependency-path: |
package-lock.json
webview-ui/package-lock.json
# 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
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
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- 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: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y xvfb
- name: Install local modules on windows
if: runner.os == 'Windows' && steps.root-cache.outputs.cache-hit == 'true'
run: |
npm install eslint-plugin-eslint-rules
cd webview-ui/ && npm install eslint-plugin-eslint-rules
- name: Set up NPM on Windows
if: runner.os == 'Windows'
run: |
npm config set script-shell "C:\\Program Files\\Git\\bin\\bash.exe"
# Build the extension and tests (without redundant checks)
- name: Type Check
run: npm run check-types
- name: ESLint Check
run: npm run lint
- name: Prettier / Format Check
run: npm run format
# Build the extension before running tests
- name: Build Tests and Extension
id: build_step
run: npm run ci:build
run: npm run pretest
- name: Unit Tests with coverage - Linux
id: unit_tests_linux
if: ${{ !cancelled() && steps.build_step.outcome == 'success' && runner.os == 'Linux' }}
# Unit Tests disabled due to module system conflicts between backend and webview-ui
# - name: Unit Tests
# run: npm run test:unit
# Run extension tests with coverage
- name: Extension Tests with Coverage
id: extension_coverage
continue-on-error: true
run: |
npx nyc --nycrc-path .nycrc.unit.json --reporter=lcov npm run test:unit
- name: Unit Tests - Non-Linux
id: unit_tests_non_linux
if: ${{ !cancelled() && steps.build_step.outcome == 'success' && runner.os != 'Linux' }}
run: |
npm run test:unit
- name: Extension Integration Tests - Linux
id: integration_tests_linux
if: ${{ !cancelled() && steps.build_step.outcome == 'success' && runner.os == 'Linux' }}
run: xvfb-run -a npm run test:coverage
- name: Extension Integration Tests - Non-Linux
id: integration_tests_non_linux
if: ${{ !cancelled() && steps.build_step.outcome == 'success' && runner.os != 'Linux' }}
run: npm run test:integration
node ./scripts/test-ci.js > extension_coverage.txt 2>&1
# Default the encoding to UTF-8 - It's not the default on Windows
PYTHONUTF8=1 PYTHONPATH=.github/scripts python -m coverage_check extract-coverage extension_coverage.txt --type=extension --github-output --verbose
# Run webview tests with coverage
- name: Webview Tests with Coverage
id: webview_tests
if: ${{ !cancelled() && steps.build_step.outcome == 'success' }}
id: webview_coverage
continue-on-error: true
run: |
cd webview-ui
npm run test:coverage
- name: CLI Tests
id: cli_tests
if: ${{ !cancelled() && steps.build_step.outcome == 'success' }}
run: cd cli && npm run test:run
# Ensure coverage dependency is installed
npm install --no-save @vitest/coverage-v8
npm run test:coverage > webview_coverage.txt 2>&1
cd ..
# Default the encoding to UTF-8 - It's not the default on Windows
PYTHONUTF8=1 PYTHONPATH=.github/scripts python -m coverage_check extract-coverage webview-ui/webview_coverage.txt --type=webview --github-output --verbose
# Save coverage reports as artifacts (workflow-scoped)
- name: Save Coverage Reports
uses: actions/upload-artifact@v4
# Only upload artifacts on Linux - We only need coverage from one OS
@@ -127,98 +130,101 @@ jobs:
with:
name: pr-coverage-reports
path: |
coverage-unit/lcov.info
webview-ui/coverage/lcov.info
extension_coverage.txt
webview-ui/webview_coverage.txt
retention-period: workflow # Artifacts are automatically deleted when the workflow completes
test-platform-integration:
needs: quality-checks
# Set the check as failed if any of the tests failed
- name: Print test results and check for failures
run: |
echo "Extension Tests Result: ${{ steps.extension_coverage.outcome }}"
cat extension_coverage.txt
echo "Webview Tests Result: ${{ steps.webview_coverage.outcome }}"
cat webview-ui/webview_coverage.txt
# Check if any of the test steps failed
# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#steps-context
if [ "${{ steps.extension_coverage.outcome }}" != "success" ] || [ "${{ steps.webview_coverage.outcome }}" != "success" ]; then
echo "Tests failed."
exit 1
fi
coverage:
needs: test
runs-on: ubuntu-latest
# Only run on PRs to main branch
if: github.event_name == 'pull_request' && github.base_ref == 'main'
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for accurate comparison
# Setup Python for coverage script
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install requests
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
cache-dependency-path: |
package-lock.json
webview-ui/package-lock.json
testing-platform/package-lock.json
# 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
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install webview-ui dependencies
if: steps.webview-cache.outputs.cache-hit != 'true'
run: cd webview-ui && npm ci
- name: Download ripgrep binaries
run: npm run download-ripgrep
# Build the extension before running tests
- name: Build Extension
run: npm run compile
- name: Compile Standalone
run: npm run compile-standalone
- name: Install testing platform dependencies
run: cd testing-platform && npm ci
- name: Running testing platform integration spec tests
timeout-minutes: 7
run: npm run test:tp-orchestrator -- tests/specs/ --count=1 --coverage
- name: Save Coverage Reports
uses: actions/upload-artifact@v4
with:
name: test-platform-integration-core-coverage
path: coverage/**/lcov.info
qlty:
needs: [test, test-platform-integration]
runs-on: ubuntu-latest
# Run on PRs to main, pushes to main, and manual dispatches
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download unit tests coverage reports
# Download coverage artifacts from test job
- name: Download Coverage Reports
uses: actions/download-artifact@v4
with:
name: pr-coverage-reports
path: .
path: . # Download to root directory to match expected paths
- name: Upload core unit tests coverage to Qlty
uses: qltysh/qlty-action/coverage@v2
with:
token: ${{ secrets.QLTY_COVERAGE_TOKEN }}
# we can merge multiple files if necessary
files: |
coverage-unit/lcov.info
tag: unit:core
# Process coverage workflow
- name: Process coverage workflow
id: coverage
run: |
# Extract PR number from GITHUB_REF
PR_NUMBER=$(echo "$GITHUB_REF" | sed -e 's/refs\/pull\///' -e 's/\/merge//')
- name: Upload webview-ui unit tests coverage to Qlty
uses: qltysh/qlty-action/coverage@v2
with:
token: ${{ secrets.QLTY_COVERAGE_TOKEN }}
# we can merge multiple files if necessary
files: |
webview-ui/coverage/lcov.info
tag: unit:webview-ui
add-prefix: webview-ui/
- name: Download test platform integration core coverage artifact
uses: actions/download-artifact@v4
continue-on-error: true
id: download-integration-coverage
with:
name: test-platform-integration-core-coverage
path: integration-core-coverage-reports
- name: Upload core integration tests coverage to Qlty
if: steps.download-integration-coverage.outcome == 'success'
uses: qltysh/qlty-action/coverage@v2
with:
token: ${{ secrets.QLTY_COVERAGE_TOKEN }}
files: integration-core-coverage-reports/**/lcov.info
tag: integration:core
# Run the coverage workflow from root directory
PYTHONPATH=.github/scripts python -m coverage_check process-workflow \
--base-branch ${{ github.base_ref }} \
--pr-number $PR_NUMBER \
--repo $GITHUB_REPOSITORY \
--token ${{ secrets.GITHUB_TOKEN }} \
--verbose
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -1,98 +0,0 @@
name: Trigger Jetbrains Plugin <-> Cline Tests
on:
pull_request_target:
types: [opened, reopened]
issue_comment:
types: [created]
permissions:
contents: read
pull-requests: read
concurrency:
group: jetbrains-trigger-${{ github.event.pull_request.number || github.event.issue.number }}
cancel-in-progress: true
jobs:
trigger-integration-test:
name: Run Tests
runs-on: ubuntu-latest
# Run on PR open/reopen, or when someone comments /test-jetbrains on a PR
if: |
github.event_name == 'pull_request_target' ||
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
contains(github.event.comment.body, '/test-jetbrains') &&
contains(fromJSON('["MEMBER","OWNER","COLLABORATOR"]'), github.event.comment.author_association))
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: Get PR details (for issue_comment trigger)
id: pr-details
if: github.event_name == 'issue_comment'
env:
GH_TOKEN: ${{ github.token }}
run: |
PR_DATA=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.issue.number }})
echo "head_ref=$(echo "$PR_DATA" | jq -r '.head.ref')" >> $GITHUB_OUTPUT
echo "head_sha=$(echo "$PR_DATA" | jq -r '.head.sha')" >> $GITHUB_OUTPUT
echo "title=$(echo "$PR_DATA" | jq -r '.title')" >> $GITHUB_OUTPUT
echo "html_url=$(echo "$PR_DATA" | jq -r '.html_url')" >> $GITHUB_OUTPUT
- name: Sanitize untrusted inputs
id: sanitize
env:
RAW_BRANCH_NAME: ${{ github.event_name == 'pull_request_target' && github.head_ref || steps.pr-details.outputs.head_ref }}
RAW_PR_TITLE: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.title || steps.pr-details.outputs.title }}
run: |
# Sanitize branch name for JSON
BRANCH_NAME_JSON=$(jq -n --arg b "$RAW_BRANCH_NAME" '$b')
echo "branch_name=$BRANCH_NAME_JSON" >> $GITHUB_OUTPUT
# Sanitize PR title for JSON
PR_TITLE_JSON=$(jq -n --arg t "$RAW_PR_TITLE" '$t')
echo "pr_title=$PR_TITLE_JSON" >> $GITHUB_OUTPUT
- name: Trigger IntelliJ Plugin Integration Test
env:
BRANCH_NAME: ${{ steps.sanitize.outputs.branch_name }}
PR_TITLE: ${{ steps.sanitize.outputs.pr_title }}
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
PR_SHA: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || steps.pr-details.outputs.head_sha }}
PR_URL: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.html_url || steps.pr-details.outputs.html_url }}
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": "$PR_NUMBER",
"branch_name": $BRANCH_NAME,
"action": "${{ github.event.action }}",
"sha": "$PR_SHA",
"pr_title": $PR_TITLE,
"pr_url": "$PR_URL"
}
}
EOF
- name: Log trigger details
env:
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
PR_SHA: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || steps.pr-details.outputs.head_sha }}
run: |
echo "Triggered IntelliJ Plugin integration test for:"
echo " PR #$PR_NUMBER"
echo " Trigger: ${{ github.event_name }}"
echo " Action: ${{ github.event.action }}"
echo " SHA: $PR_SHA"
+5 -28
View File
@@ -8,51 +8,28 @@ tmp
.DS_Store
.idea
.husky/_/
pnpm-lock.yaml
.clineignore
.venv
.actrc
CLAUDE.local.md
webview-ui/src/**/*.js
webview-ui/src/**/*.js.map
# Ignore coverage directories and files
coverage
coverage-unit
.nyc_output
# But don't ignore the coverage scripts in .github/scripts/
!.github/scripts/coverage/
*evals.env
.env
.secrets
.github/act/.secrets
.worktrees
## Generated files ##
src/generated/
src/shared/proto/
src/core/controller/*/methods.ts
src/core/controller/*/index.ts
src/core/controller/grpc-service-config.ts
src/shared/proto/*.ts
src/shared/proto/host/*.ts
webview-ui/src/services/grpc-client.ts
*.tsbuildinfo
# E2E Tests
test-results
/.github/act
/pkg
.secrets
*.tsbuildinfo
# Smoke test results (generated)
evals/smoke-tests/results/
.tui-test
secrets.json
tui-traces
tests/**/cache
-3
View File
@@ -1,3 +0,0 @@
[submodule "evals/cline-bench"]
path = evals/cline-bench
url = https://github.com/cline/cline-bench.git
Regular → Executable
+17 -1
View File
@@ -1 +1,17 @@
lint-staged
echo "Running pre-commit checks..."
# Run ESLint
echo "Running ESLint..."
npm run lint || {
echo "❌ ESLint check failed. Please fix the errors and try committing again."
exit 1
}
# Run Prettier
echo "Running Prettier..."
npx lint-staged --verbose || {
echo "❌ Prettier failed. Please fix the errors and try committing again."
exit 1
}
echo "✅ All checks passed!"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+4 -17
View File
@@ -1,19 +1,6 @@
{
"extension": [
"ts"
],
"spec": [
"src/**/__tests__/*.ts",
"src/test/services/**/*.test.ts"
],
"ignore": [
"src/sdk/**"
],
"require": [
"ts-node/register",
"source-map-support/register",
"./src/test/requires.ts"
],
"recursive": true,
"exit": true
"extension": ["ts"],
"spec": ["src/**/__tests__/*.ts", "eslint-rules/__tests__/**/*.test.ts"],
"require": ["ts-node/register", "source-map-support/register", "./src/test/requires.ts"],
"recursive": true
}
-48
View File
@@ -1,48 +0,0 @@
{
"all": true,
"check-coverage": false,
"reporter": [
"text",
"lcov"
],
"include": [
"src/**/*.ts"
],
"exclude": [
"**/*.d.ts",
"**/*.{test,spec}.{js,jsx,ts,tsx,mjs,cjs}",
"**/__tests__/**",
"**/test/**",
"**/tests/**",
"**/.nyc_output/**",
"**/.vscode-test/**",
"**/tests-results/**",
"src/test/**",
"src/generated/**",
"**/node_modules/**",
"**/dist/**",
"**/out/**",
"**/build/**",
"**/coverage/**",
"**/coverage-unit/**",
"**/proto/**",
"**/*.{config,setup}.{js,ts,mjs,cjs}",
"**/vite-env.d.ts",
"**/*.{css,scss,sass,less,styl}",
"**/*.{svg,png,jpg,jpeg,gif,ico}",
"**/*.{json,yaml,yml}"
],
"extension": [
".ts",
".js"
],
"cache": true,
"sourceMap": true,
"instrument": true,
"report-dir": "./coverage-unit"
}
+10
View File
@@ -0,0 +1,10 @@
dist/
node_modules
webview-ui/build/
*.md
package-lock.json
src/core/prompts/system.ts
src/core/prompts/model_prompts/claude4.ts
evals/
docs/
out/
+8
View File
@@ -0,0 +1,8 @@
{
"tabWidth": 4,
"useTabs": true,
"printWidth": 130,
"semi": false,
"bracketSameLine": true,
"endOfLine": "lf"
}
+2 -2
View File
@@ -2,9 +2,9 @@
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"dbaeumer.vscode-eslint",
"connor4312.esbuild-problem-matchers",
"ms-vscode.extension-test-runner",
"bradlc.vscode-tailwindcss",
"biomejs.biome"
"bradlc.vscode-tailwindcss"
]
}
+20 -155
View File
@@ -6,78 +6,21 @@
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension (production)",
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--disable-workspace-trust",
"--disable-extension",
"saoudrizwan.claude-dev", // Avoid conflicts with installed Cline
"--disable-extension",
"saoudrizwan.cline-nightly", // Avoid conflicts with installed Cline Nightly
"${workspaceFolder}",
"--disable-extensions"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"args": ["--extensionDevelopmentPath=${workspaceFolder}", "--disable-workspace-trust", "${workspaceFolder}"],
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
"preLaunchTask": "${defaultBuildTask}",
"envFile": "${workspaceFolder}/.env",
"env": {
"IS_DEV": "true",
"DEV_WORKSPACE_FOLDER": "${workspaceFolder}",
// Use the environment variable to determine the backend URL
// Options: "production", "staging", "local"
// Require the extension to reload to apply changes
"CLINE_ENVIRONMENT": "production"
}
},
{
"name": "Run Extension (staging)",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--disable-workspace-trust",
"--disable-extension",
"saoudrizwan.claude-dev", // Avoid conflicts with installed Cline
"--disable-extension",
"saoudrizwan.cline-nightly", // Avoid conflicts with installed Cline Nightly
"${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}",
"envFile": "${workspaceFolder}/.env",
"env": {
"IS_DEV": "true",
"DEV_WORKSPACE_FOLDER": "${workspaceFolder}",
"CLINE_ENVIRONMENT": "staging"
}
},
{
"name": "Run Extension (local)",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--disable-workspace-trust",
"--disable-extension",
"saoudrizwan.claude-dev", // Avoid conflicts with installed Cline
"--disable-extension",
"saoudrizwan.cline-nightly", // Avoid conflicts with installed Cline Nightly
"${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}",
"envFile": "${workspaceFolder}/.env",
"env": {
"IS_DEV": "true",
"DEV_WORKSPACE_FOLDER": "${workspaceFolder}",
"CLINE_ENVIRONMENT": "local"
}
},
{
"name": "Run Extension (Fresh Install Mode)",
"type": "extensionHost",
@@ -87,20 +30,14 @@
"--user-data-dir=${workspaceFolder}/dist/tmp/user",
"--profile-temp",
"--sync=off",
"--disable-extension",
"saoudrizwan.claude-dev", // Avoid conflicts with installed Cline
"--disable-extension",
"saoudrizwan.cline-nightly", // Avoid conflicts with installed Cline Nightly
"--disable-extensions",
"--extensionDevelopmentPath=${workspaceFolder}",
"${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
"preLaunchTask": "clean-tmp-user",
"internalConsoleOptions": "openOnSessionStart",
"postDebugTask": "stop",
"envFile": "${workspaceFolder}/.env",
"env": {
"IS_DEV": "true",
"TEMP_PROFILE": "true",
@@ -111,94 +48,22 @@
{
"type": "node",
"request": "launch",
"name": "Debug Test Standalone Core Api Server (test:sca-server)",
"skipFiles": [
"<node_internals>/**"
],
"name": "Run Standalone Service",
"skipFiles": ["<node_internals>/**"],
"sourceMaps": true,
"resolveSourceMapLocations": [
"${workspaceFolder}/**",
"!**/node_modules/**"
],
"cwd": "${workspaceFolder}",
"outFiles": [
"${workspaceFolder}/dist/**/*.js",
"${workspaceFolder}/dist-standalone/**/*.js"
],
"resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"],
"cwd": "${workspaceFolder}/dist-standalone",
"outFiles": ["${workspaceFolder}/dist-standalone/**/*.js"],
"preLaunchTask": "compile-standalone",
"runtimeExecutable": "npx",
"runtimeArgs": [
"tsx"
],
"program": "scripts/test-standalone-core-api-server.ts",
"envFile": "${workspaceFolder}/.env",
"env": {
"PROTOBUS_PORT": "26040",
"HOSTBRIDGE_PORT": "26041",
"WORKSPACE_DIR": "${workspaceFolder}",
"E2E_TEST": "true",
"CLINE_ENVIRONMENT": "local"
// Turns on grpc debug log.
//"GRPC_TRACE": "all",
//"GRPC_VERBOSITY": "DEBUG",
"NODE_PATH": "${workspaceFolder}/dist-standalone/node_modules",
"HOST_BRIDGE_ADDRESS": "localhost:50052"
},
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},
{
"type": "node",
"request": "launch",
"name": "Debug Current Test File",
"skipFiles": [
"<node_internals>/**"
],
"sourceMaps": true,
"resolveSourceMapLocations": [
"${workspaceFolder}/**",
"!**/node_modules/**"
],
"cwd": "${workspaceFolder}",
"runtimeExecutable": "npx",
"runtimeArgs": [
"mocha"
],
"args": [
"--require",
"ts-node/register",
"--require",
"source-map-support/register",
"--require",
"./src/test/requires.ts",
"--exit",
"${file}"
],
"envFile": "${workspaceFolder}/.env",
"env": {
"TS_NODE_PROJECT": "./tsconfig.unit-test.json",
"NODE_ENV": "test",
"IS_DEV": "true",
"CLINE_ENVIRONMENT": "local"
},
"console": "integratedTerminal",
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": "Open Storybook",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"storybook"
],
"cwd": "${workspaceFolder}/webview-ui",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"serverReadyAction": {
"pattern": "Local:.*http://localhost:([0-9]+)",
"uriFormat": "http://localhost:%s",
"action": "openExternally"
},
"env": {
"IS_DEV": "true"
}
"program": "standalone.js"
}
]
}
+2 -22
View File
@@ -6,28 +6,8 @@
},
"search.exclude": {
"out": true, // set this to false to include "out" folder in search results
"dist": true, // set this to false to include "dist" folder in search results,
"node_modules": true,
"dist-standalone": true
"dist": true // set this to false to include "dist" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off",
"typescript.preferences.quoteStyle": "double",
// Protobuf settings
"protoc": {
"options": [
"--proto_path=proto"
]
},
// Enable Lint and format using Biome
"biome.enabled": true,
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"source.fixAll.biome": "explicit",
"source.removeUnused.biome": "always",
"source.removeUnusedImports": "always",
"source.organizeImports.biome": "always"
},
// Disable auto-forwarding ports to prevent Simple Browser from opening the Vite dev server
"remote.autoForwardPorts": false
"typescript.tsc.autoDetect": "off"
}
+10 -56
View File
@@ -30,13 +30,7 @@
},
{
"label": "watch",
"dependsOn": [
"npm: protos",
"npm: build:webview",
"npm: dev:webview",
"npm: watch:tsc",
"npm: watch:esbuild"
],
"dependsOn": ["npm: protos", "npm: build:webview", "npm: dev:webview", "npm: watch:tsc", "npm: watch:esbuild"],
"presentation": {
"reveal": "always"
},
@@ -66,9 +60,7 @@
"problemMatcher": [],
"isBackground": true,
"label": "npm: build:webview",
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"group": "watch",
"reveal": "always"
@@ -86,9 +78,7 @@
"problemMatcher": [],
"isBackground": true,
"label": "npm: build:webview:test",
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"group": "watch",
"reveal": "always"
@@ -123,9 +113,7 @@
],
"isBackground": true,
"label": "npm: dev:webview",
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"group": "watch",
"reveal": "always"
@@ -161,9 +149,7 @@
},
"isBackground": true,
"label": "npm: watch:esbuild",
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"group": "watch",
"reveal": "always"
@@ -199,9 +185,7 @@
},
"isBackground": true,
"label": "npm: watch:esbuild:test",
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"group": "watch",
"reveal": "always"
@@ -220,9 +204,7 @@
"problemMatcher": "$tsc-watch",
"isBackground": true,
"label": "npm: watch:tsc",
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"group": "watch",
"reveal": "always"
@@ -233,9 +215,7 @@
"script": "watch-tests",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"dependsOn": [
"npm: protos"
],
"dependsOn": ["npm: protos"],
"presentation": {
"reveal": "always",
"group": "watchers"
@@ -244,11 +224,7 @@
},
{
"label": "tasks: watch-tests",
"dependsOn": [
"npm: protos",
"npm: watch",
"npm: watch-tests"
],
"dependsOn": ["npm: protos", "npm: watch", "npm: watch-tests"],
"problemMatcher": []
},
{
@@ -259,30 +235,8 @@
{
"label": "clean-tmp-user",
"type": "shell",
"dependsOn": [
"watch"
],
"dependsOn": ["watch"],
"command": "rm -rf ${workspaceFolder}/dist/tmp/user && mkdir -p ${workspaceFolder}/dist/tmp/user"
},
{
"type": "npm",
"script": "storybook",
"group": "build",
"problemMatcher": [],
"isBackground": false,
"label": "npm: storybook",
"dependsOn": [
"npm: protos",
"npm: build:webview"
],
"presentation": {
"reveal": "always"
},
"options": {
"env": {
"IS_DEV": "true"
}
}
}
],
"inputs": [
+3 -13
View File
@@ -1,8 +1,6 @@
# Default
.vscode/**
.vscode-test/**
.worktrees/**
CLAUDE.local.md
out/
dist-standalone/
node_modules/
@@ -20,10 +18,6 @@ tsconfig*.json
eslint-rules/**
.github/**
.husky/**
.env
# cli
cli/**
# Custom
**/demo.gif
@@ -35,9 +29,11 @@ cli/**
eslint-rules/
old_docs/
evals/
.changie.yaml
.codespellrc
.mocharc.json
buf.yaml
.changeset/
.clinerules/
# Ignore all webview-ui files except the build directory (https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/frameworks/hello-world-react-cra/.vscodeignore)
@@ -65,12 +61,6 @@ old_docs/**
!assets/icons/**
# Ignore E2E build files
e2e-build.mjs
e2e-build.js
e2e.vsix
test-results/
# Ignore Storybook files
**/*.stories.tsx
*storybook.log
storybook-static
**/StorybookDecorator.tsx
-1
View File
@@ -1 +0,0 @@
.gitignore
-940
View File
@@ -1,940 +0,0 @@
# SDK Migration — Architecture & Design
Evergreen reference for the Cline SDK migration project. For the
living implementation plan, see `migration.md`.
## References
### Code References
Cline SDK is at ~/clients/cline/sdk-wip
Cline (core, classic VSCode extension, CLI) is at ~/clients/cline/cline
JetBrains Plugin is at ~/clients/cline/intellij-plugin
IntelliJ open source reference is at ~/clients/cline/intellij-community
JCEF (Java-Chromium embedded framework reference) is at ~/clients/cline/jcef
You can use kb_search with these identifiers to understand the
existing code and the SDK code:
cline - Cline core, classic VSCode extension, CLI
sdk - Cline SDK
plugin - JetBrains plugin
vscode - Visual Studio Code opens source
ij - IntelliJ open source
jcef - JCEF IntelliJ's embedded Chromium layer
Prototype VSCode extension on SDK is at ~/clients/cline/sdk-vscode-sample
Prototype JetBrains plugin on SDK is at ~/clients/cline/sdk-intellij-plugin-sample
These are prototypes with features missing and added, so refer to them
as examples, but don't overindex on them.
### Documentation references
See the ~/clients/cline/cline/docs for extension product documentation
and ~/clients/cline/sdk-wip/*.md for SDK documentation.
### Background on the products & architecture
There's a VSCode extension in cline/src. A large part of its UI is a
React-based webview in cline/webview-ui.
There's a JetBrains plugin in the intellij-plugin repo. It packages
the core of the VSCode extension, including the webview, and
communicates with it with protobufs. There's a bunch of stuff in the
cline repo called "standalone" which is what JetBrains communicates
with.
In cline/cli there's a CLI and Kanban tool. Those use the SDK/are
being ported separately to the SDK, so you don't need to worry about
them. It is OK if you have to break them. Just ignore them.
Note, there was an earlier, failed attempt at a cli in go. The go cli
used to use "standalone" like JetBrains. If there's any old go support
cluttering up the repo, it is fine to delete it and clean it up.
The source code and docs mentioned above are the best reference to the
product architecture, behavior, etc. Feel free to ask clarifying
questions when necessary.
---
## Features
### Features to remove
Terminal integration: There is legacy code in the VSCode extension,
and stubs in the RPC system for JetBrains, which used the IDE's
integrated terminals. We have decided we don't need these old modes
and they should be removed. Instead we will rely on "background
terminal". This literally means the node code forks and execs a shell
and uses pipes to communicate with it.
Browser automation: Remove the system that uses Playwright to automate
browsers. These use cases are now well served by third-party MCP
tools.
"Shadow git" checkpointing system. This is too slow, especially on
Windows. The way the Kanban project uses the existing git repo to
store references, and only after each user message, is better. So we
will drop the "shadow copy" git checkpointing system.
Memory bank, structured context: multi-file documentation
(projectbrief, productContext, activeContext, systemPatterns,
techContext, progress.)
Memory bank, persistence: cross-session context preservation.
Focus chain, task tracking: Auto-generated to-do list with real-time
progress indicators.
Focus chain, integration: Editable focus chain integration with deep
planning and reminders.
Deep planning exploration, output and the /deep-planning command.
Workflows (definition, natural language + XML tool syntax, MCP tools
and user input prompts) ... these have been superceded by SKILLS
moving forward.
Slash commands no longer necessary:
/deep-planning (codebase investigation + plan... we have plan/act mode)
/reportbug (bug reporting with diagnostics)
Custom workflows (/workflow.md for user-defined workflows... we have "skills" now.)
### Core features
These must work:
File operations: read, write, search, replace, list files, inspect
code definitions (functions, classes, methods)
Terminal integration: "Background terminal" must work. The agent
relies on this to run npm, git, docker, etc.
Multi-provider AI models: 30+ providers with seamless
switching. There's one provider of note: VSCode has a provider which
hooks up to Copilot using the VSCode LM Provider API. It would be good
to support this *if possible.*
Auto-approve & YOLO mode
- Granular per-tool permission controls
- YOLO mode for maximum automation
- Monitoring, notifications for long-running commands
Auto-compaction
- Summarization automatically compresses conversations when context fills
- Model support for Claude, Gemini, GPT-5, Grok, etc.
Subagents
- Parallel execution of independent research agents
- Isolation with separate context windows
- Cost tracking for task usage per subagent
Web search and web fetch
Worktrees
- git worktrees for parallel sessions
- branch management and .worktreeinclude support
- conflict resolution and merging
Workspaces
- "multi-root" workspaces/projects with multiple root folders
- @workspace:path scoped references
Jupyter Notebooks
- Generate, explain, and improve notebook cells
Cline Rules
- project-specific .cline/rules and global instructions.
- Conditional logic: Path-based activation of rules.
- Compatibility: Works with Cursor Rules, Windsurf rules, AGENTS.md
Skills
- SKILL.md format with YAML frontmatter
- Loading levels: Metadata, instructions and resources
- Scope: Global and project-specific; toggleable
Hooks
- Events: Task lifecycle + tool events (TaskStart, PreToolUse, etc.)
- Runtimes: bash, powershell for Windows
- IO: JSON
- Context injection: Be able to modify or inject context dynamically
.clineignore
- Exclusion rules, gitignore-style file/directory exclusion
- Exceptions: ! prefix for overrides
- Override behavior: Explicit @ mentions bypass ignore rules
MCP (Model Context Protocol)
- Server management: Discovery, enable/disable, restart, config editing
- Transport: stdio (local) and SSE (remote)
- ...all the typical use cases for MCP: APIs, browser automation, db queries, etc.
### Core workflows
These must work:
Task Management
Task lifecycle - create and resume tasks; view task history
Cost tracking - token using and cost monitoring per task
Plan & Act Mode
Plan mode - Explore and investigate without modifying files
Act mode - Implementation with approval gates
Model config - Separate model configuration for plan and act mode if
the user desires
State persistence - Mode switching, task switching preserves history
File context (@-mentions)
Context referencing - Reference files, folders, terminal output, git
changes, URLs, commits via @
Slash commands
/newtask (new task)
/smol (compress history)
/newrule (create rules)
### Model Configuration
We want to continue supporting our 30+ providers (Anthropic, OpenAI,
OpenAI Codex, OpenRouter, Google Gemini, AWS Bedrock, DeepSeek,
Cerebras, Qwen, Mistral, Groq, Fireworks, Together, xAI Grok,
Moonshot, Nebius, HuggingFace, LiteLLM, Ollama, LM Studio, and more.)
THE MOST IMPORTANT REQUIREMENT HERE, after continuing to support them,
is to USE THE CREDENTIALS, MODEL NAMES, CONFIGS, etc. WE HAVE
SAVED. Logging people out of their providers is really annoying to
users; regenerating API keys is painful for them.
VSCode LM API provider may be an interesting/unusual provider out of
this set; it only works in VSCode by calling a specific API.
We must continue supporting local models like Ollama and LM Studio.
We must support the Cline provider with unified auth (open a
webbrowser, handle the SSO redirect), built-in billing and credit
display, banners advertising new or free models, stealth/early access
models, organization switching.
### Enterprise Features
Security and governance
- Client-side execution only (no data transmission outside of limited
Telemetry and inference; no remote codebase indexing)
- SSO role-based access control (member, admin, owner)
- Model and tool controls per team
- Remote configuration downloaded and applied by the extension
Observability
- OpenTelemetry, Datadog, Grafana, Splunk integrations
- Real-time analytics, cost breakdown by team, selective audit logging
Infrastructure
- AWS Bedrock, Google Vertex AI, Azure OpenAI integration
- Bring-your-own-inference with custom endpoints
### Priority "P1" (mid priority) items
Checkpoints - automatic file snapshots after each change. Note, the
snapshot system in the VSCode extension and JetBrains plugin which
copies the whole repository is slow, *especially on Windows*, so we
should replace it with one that writes refs directly into the local
git repo. Look at the way the kanban project does it; this is
preferred (and maybe we should extract and share this code.)
Diffing - compare changes between checkpoints
Restore - restore files, task to a point, or both
MCP Marketplace - we could get rid of this, but ultimately we do want
this feature with major improvements like allowing remote install. For
now, consider removing it, but if it is easier to keep it around let's
do that to lay the groundwork for improvements.
### Priority "P2" (lower priority) items
Task organization - favorites for task grouping and management
File context - Drag and drop files to add to context
File context - actions - context menus to add to Cline, fix, explain, improve
Slash commands
/explain-changes (git diff explanation)
---
## Detailed Design
### Naming: "Sdk..." considered harmful
Do not name types "SdkFoo" or folders "sdk". If you need to use SdkFoo
as a way to keep two classes around in parallel while you're porting,
that's OK, but when this project is done we want to have one clean,
simple codebase; the SDK backing is an implementation detail so just
use simple noun phrases for classes, etc. and don't litter "Sdk" all
over identifiers and folders.
### Proto deprecation and removal
We don't need proto files to describe webview messages. The webview
and extension backend are both in TypeScript and are versioned and
shipped together. We just need to use shared TypeScript interfaces
between them.
We *also* don't need proto to describe JetBrains <--> node
exchanges. We just need something typed and in sync between Kotlin and
TypeScript that we can serialize. JSON probably makes sense. Protos
are OK but we have had problems with that setup creating a ton of GC
pressure on the Kotlin side, hit maximum message size limits, etc.
There are proto build steps which we can remove, as we use proto less.
protos are useful for state which is serialized. If there are files
that are persisted described by protos, it is ok/good to keep
them. Don't expand the use of protos to places protos are not already
used.
### Web View UI
The Webview UI is very dependent on state arising from implementation
details of the pre-SDK implementation. At the same time, we don't want
to build a new UI from scratch right now because it may be forcing too
many changes upon our users at once. So we aim to reuse the existing
webview, but with radical simplificiation in its state management now
that we will have a cleaner architecture in the extension "backend"
with the layering enforced by the SDK.
The webview UI had defects like showing the wrong keybindings for
JetBrains, or using tons of memory or CPU cycles by spamming state
updates really rapidly or sending n^2 state updates as they streamed
in. The first principle of this migration to the SDK is not get worse,
but at the same time, we expect the state clean-up necessary in the
webview will lead to radical simplifications which make some
low-hanging fruit available in performance. It's great to go make
those improvements where they are available.
We don't need this UI to be pixel perfect identical. We need it to be
FAMILIAR, NOT WORSE and preferably BETTER than the status quo.
### Data formats, settings
We MUST pick up existing on-disk state for settings, etc. We don't
want to log users out of their inference providers as we make this
change to the SDK.
The CLI, VSCode extension and JetBrains extension largely share state
on disk. We should continue that situation. If data migrations are
necessary, that's fine, but design them with care. In particular, we
want the long term to be fast, so we should write breadcrumbs
indicating when migration is done. In addition, users can upgrade and
downgrade their extension versions, etc. and we want to be robust to
that in addition to all kinds of failures. For example, in the past we
had problems where we overwrote a JSON settings file, perhaps racily,
and left trailing }s in the file and this caused the product to
totally fail. That's a very serious issue for our users so pay extra
effort and attention to what is happening on disk. (We want PRACTICAL
solutions and robustness and not performative solutions that just add
tons of code and complexity with no real benefit.)
Invalidating old checkpoints is acceptable, unless it is particularly
cheap to support the classic checkpoints. We won't be authoring those
checkpoints any more, and it would be heavy to migrate them.
We want to move from .clinerules (old style) to .cline/rules (new style.)
### Telemetry
We generally want to continue sending the same Telemetry events. If
that is hard, make a detailed report and we can follow up with our
backend team. Note some enterprise features depend on OTEL
observability.
### Code Sharing
In general we should share code between IDEs where there are benefits
to do so. However trivial tools, or tools specific to a given IDE, can
be wired up directly from the extension through to the SDK. (This is
something that was hard to do in the old architecture and we would
like to make easier.)
---
## Research Findings
### SDK Session Backend Extensibility
**Question**: Does the SDK's `SessionBackend` interface support
storing arbitrary per-task data (e.g., tool settings, hook
configuration, auto-approve preferences per task)?
**Answer**: Partially. The `SessionRow` has a `metadata:
Record<string, unknown> | null` field that can store arbitrary
key-value data per session. This is sufficient for per-task settings
like auto-approve preferences, tool configuration, etc.
The SDK supports three backend implementations:
1. `SqliteSessionStore` — SQLite-backed (default, preferred)
2. `FileSessionService` — JSON file-backed (fallback when SQLite
unavailable)
3. `RpcCoreSessionService` — delegates to an RPC server
For our migration, we'll use either `FileSessionService` or provide a
custom `SessionPersistenceAdapter` that reads/writes our existing task
history format. The `ClineCoreOptions.sessionService` field accepts
any backend implementing `CoreSessionService | RpcCoreSessionService |
FileSessionService`.
**Key finding**: The `SessionPersistenceAdapter` interface is the
cleanest extension point. It requires implementing: `ensureSessionsDir`,
`upsertSession`, `getSession`, `listSessions`, `updateSession`,
`deleteSession`, `enqueueSpawnRequest`, `claimSpawnRequest`. Our
`LegacySessionBackend` adapter wraps the existing
`~/.cline/data/tasks/` directory and `taskHistory` JSON array in
`globalState.json`, mapping between `SessionRow` fields and our
`HistoryItem` type:
```
HistoryItem.id → SessionRow.sessionId
HistoryItem.ts → SessionRow.startedAt (ISO string)
HistoryItem.task → SessionRow.prompt
HistoryItem.tokensIn → metadata.tokensIn
HistoryItem.tokensOut → metadata.tokensOut
HistoryItem.totalCost → metadata.totalCost
HistoryItem.modelId → SessionRow.model
HistoryItem.isFavorited → metadata.isFavorited
```
Per-task files (`api_conversation_history.json`, `ui_messages.json`)
map to `SessionRow.messagesPath` and `SessionRow.transcriptPath`.
**Decision**: We will provide a custom `SessionPersistenceAdapter`
that translates between our existing format and the SDK's interface.
No need for a separate sidecar storage layer. The `metadata` field
handles all per-task extensions.
### Telemetry Event Mapping
The extension currently emits telemetry events via a PostHog-based
`TelemetryService`. The SDK has its own `TelemetryService` with
pluggable adapters (`OpenTelemetryAdapter`, `LoggerTelemetryAdapter`).
**Mapping of current extension events → SDK events:**
| Extension Event | SDK CORE_TELEMETRY_EVENTS | Notes |
|---|---|---|
| `user.extension_activated` | `CLIENT.STARTED` ("extension.activated") | ✅ Same event name |
| `user.auth_started` | `USER.AUTH_STARTED` | ✅ Direct match |
| `user.auth_succeeded` | `USER.AUTH_SUCCEEDED` | ✅ Direct match |
| `user.auth_failed` | `USER.AUTH_FAILED` | ✅ Direct match |
| `user.auth_logged_out` | `USER.AUTH_LOGGED_OUT` | ✅ Direct match |
| `task.created` | `TASK.CREATED` | ✅ Direct match |
| `task.restarted` | `TASK.RESTARTED` | ✅ Direct match |
| `task.completed` | `TASK.COMPLETED` | ✅ Direct match |
| `task.conversation_turn` | `TASK.CONVERSATION_TURN` | ✅ Direct match |
| `task.tokens` | `TASK.TOKEN_USAGE` | ✅ Direct match |
| `task.mode` | `TASK.MODE_SWITCH` | ✅ Direct match |
| `task.tool_used` | `TASK.TOOL_USED` | ✅ Direct match |
| `task.skill_used` | `TASK.SKILL_USED` | ✅ Direct match |
| `task.diff_edit_failed` | `TASK.DIFF_EDIT_FAILED` | ✅ Direct match |
| `task.provider_api_error` | `TASK.PROVIDER_API_ERROR` | ✅ Direct match |
| `task.mention_used` | `TASK.MENTION_USED` | ✅ Direct match |
| `task.mention_failed` | `TASK.MENTION_FAILED` | ✅ Direct match |
| `task.mention_search_results` | `TASK.MENTION_SEARCH_RESULTS` | ✅ Direct match |
| `task.subagent_started` | `TASK.SUBAGENT_STARTED` | ✅ Direct match |
| `task.subagent_completed` | `TASK.SUBAGENT_COMPLETED` | ✅ Direct match |
| `hooks.discovery_completed` | `HOOKS.DISCOVERY_COMPLETED` | ✅ Direct match |
| `session.started` | `SESSION.STARTED` | ✅ Direct match |
| `session.ended` | `SESSION.ENDED` | ✅ Direct match |
**Extension events with NO SDK equivalent (need adapter-layer emit):**
| Extension Event | Action |
|---|---|
| `user.opt_out` / `user.opt_in` | Emit via SDK's `captureRequired()` |
| `user.telemetry_enabled` | Emit via SDK's `capture()` |
| `user.extension_storage_error` | Emit via SDK's `capture()` |
| `user.onboarding_progress` | Emit via SDK's `capture()` |
| `workspace.*` (initialized, vcs_detected, etc.) | Emit via SDK's `capture()` |
| `task.feedback` | Emit via SDK's `capture()` |
| `task.option_selected` / `task.options_ignored` | Emit via SDK's `capture()` |
| `task.checkpoint_used` | Emit via SDK's `capture()` |
| `task.mcp_tool_called` | Emit via SDK's `capture()` |
| `task.historical_loaded` | Emit via SDK's `capture()` |
| `task.retry_clicked` | Emit via SDK's `capture()` |
| `task.slash_command_used` | Emit via SDK's `capture()` |
| `task.feature_toggled` | Emit via SDK's `capture()` |
| `task.rule_toggled` | Emit via SDK's `capture()` |
| `task.auto_condense_toggled` | Emit via SDK's `capture()` |
| `task.yolo_mode_toggled` | Emit via SDK's `capture()` |
| `task.terminal_*` (execution, output_failure, hang) | Emit via SDK's `capture()` |
| `task.initialization` | Emit via SDK's `capture()` |
| `task.summarize_task` | Emit via SDK's `capture()` |
| `ui.*` (model_selected, button_clicked, etc.) | Emit via SDK's `capture()` |
| `hooks.enabled` / `hooks.disabled` | Emit via SDK's `capture()` |
| `hooks.cancel_requested` | Emit via SDK's `capture()` |
| `hooks.context_modified` | Emit via SDK's `capture()` |
| `worktree.*` | Emit via SDK's `capture()` |
| `host.detected` | Emit via SDK's `capture()` |
**Extension events being REMOVED (features deleted):**
| Extension Event | Reason |
|---|---|
| `task.browser_tool_start/end/error` | Browser automation removed |
| `task.focus_chain_*` (6 events) | Focus chain removed |
| `task.workspace_search_pattern` | Folded into SDK search |
| `task.subagent_enabled/disabled` | Toggle events; SDK manages directly |
| `task.cline_web_tools_toggled` | Feature simplified |
| `cline.grpc.response.size_bytes` | gRPC being removed |
**Metrics (OTEL counters/histograms):**
The extension has ~30 OTEL metrics (`cline.turns.total`,
`cline.tokens.input.total`, `cline.api.ttft.seconds`, etc.). The SDK
telemetry service supports `recordCounter`, `recordHistogram`, and
`recordGauge`. We will emit these same metrics from the adapter layer
using `telemetry.recordCounter()` / `telemetry.recordHistogram()`.
The metric names can stay the same.
**Decision**: The SDK's `ITelemetryService.capture()` is a generic
event emitter — we can emit ALL extension events through it. The
adapter layer will create a thin telemetry wrapper that provides
the same `captureTaskCreated()`, `captureToolUsage()`, etc. methods
but delegates to the SDK's telemetry service. Events where the SDK
already has a helper function (listed in the first table) use those
directly. Others use `capture({ event, properties })`. No backend
team coordination needed for the initial migration.
### JetBrains IPC Design
#### Current Architecture
```
┌── Kotlin Plugin ──────────────────────────────┐
│ │
│ CoreProcessManager │
│ └─ launches Node.js process (cline-core) │
│ └─ communicates via gRPC ProtoBus │
│ (port 26040-26340) │
│ │
│ HostBridgeService (gRPC server, port 26041) │
│ ├─ DiffService │
│ ├─ WindowService (show file, open dialog) │
│ ├─ WorkspaceService (paths, diagnostics) │
│ ├─ EnvService │
│ └─ TestingService (get webview HTML) │
│ │
│ ProtoBusProxyService │
│ └─ proxies webview ↔ cline-core gRPC │
│ │
│ JsPostMessageHandler │
│ └─ injects JS bridge into JCEF webview │
│ └─ converts postMessage → gRPC request │
│ │
│ WebViewManager │
│ └─ loads webview HTML in JCEF │
│ └─ receives gRPC responses → postMessage │
└────────────────────────────────────────────────┘
```
Problems with this architecture:
- **Proto size limits**: gRPC messages hit 256MB limits with large
conversations. The `ProtoBusProxyService` logs warnings at 10MB+.
- **Java heap pressure**: Serializing/deserializing large proto
messages stresses the JVM heap.
- **Build complexity**: Proto compilation required for both
TypeScript and Java/Kotlin.
- **Stateless-in-theory**: The design is somewhat stateless but we
haven't leveraged restart-for-reliability because state
reconstruction is expensive.
#### Target Architecture
```
┌── Kotlin Plugin ──────────────────────────────┐
│ │
│ CoreProcessManager │
│ └─ launches SDK sidecar (Node.js) │
│ └─ communicates via JSON-RPC over stdio │
│ │
│ HostCallbackService (JSON-RPC server) │
│ ├─ showTextDocument, openDialog │
│ ├─ getWorkspacePaths, getDiagnostics │
│ ├─ getEnvVars, clipboard │
│ └─ (extensible for PSI, run configs, etc.) │
│ │
│ WebviewBridge │
│ └─ receives JSON messages from sidecar │
│ └─ forwards to JCEF via executeJavaScript │
│ └─ receives postMessage from JCEF │
│ └─ forwards to sidecar via stdio │
│ │
│ WebViewManager │
│ └─ loads adapted webview in JCEF │
└────────────────────────────────────────────────┘
┌── SDK Sidecar (Node.js) ──────────────────────┐
│ │
│ SidecarMain │
│ └─ JSON-RPC over stdio (bidirectional) │
│ └─ imports @clinebot/core │
│ └─ shares SDK adapter layer with VSCode │
│ │
│ ClineCore instance │
│ └─ session management │
│ └─ tool execution │
│ └─ provider handling │
│ │
│ HostCallbackClient │
│ └─ calls back to Kotlin for IDE ops │
│ └─ registered as tool executors in SDK │
│ │
│ WebviewBridge │
│ └─ translates SDK events → webview messages │
│ └─ same code as VSCode adapter │
└────────────────────────────────────────────────┘
```
#### IPC Mechanism: JSON-RPC over stdio
**Why JSON-RPC over stdio instead of gRPC:**
- **No message size limits**: JSON over stdio has no inherent size
cap. Conversations with 100K+ tokens serialize to ~5-20MB JSON
which flows fine over pipes.
- **No heap pressure**: No proto serialization on the Java side.
Kotlin reads/writes JSON strings directly. JCEF already works
with JSON.
- **No proto compilation**: Eliminates the Java protobuf dependency
and the dual TypeScript/Java proto generation step.
- **Simple**: Well-understood protocol. Easy to debug (just read
the pipe).
**Protocol**: JSON-RPC 2.0 over stdin/stdout with newline-delimited
JSON messages. The sidecar reads from stdin and writes to stdout.
Stderr is reserved for logging.
```
→ {"jsonrpc":"2.0","method":"session/start","params":{...},"id":1}
← {"jsonrpc":"2.0","result":{"sessionId":"..."},"id":1}
← {"jsonrpc":"2.0","method":"webview/message","params":{"type":"assistant_delta","text":"..."}}
```
**Notifications** (no `id`) are used for streaming events
(assistant deltas, tool events, state updates). The Kotlin plugin
processes these and forwards them to the JCEF webview.
**Callbacks** from sidecar → Kotlin (host operations) use
JSON-RPC requests in the reverse direction:
```
← {"jsonrpc":"2.0","method":"host/showTextDocument","params":{"path":"..."},"id":100}
→ {"jsonrpc":"2.0","result":{"success":true},"id":100}
```
#### Code Sharing Between VSCode, JetBrains, and CLI
The shared SDK adapter layer contains:
```
src/sdk-adapter/
index.ts — ClineSdkHost (creates ClineCore instance)
session-backend.ts — LegacySessionBackend adapter
webview-bridge.ts — SDK events → webview message translation
provider-migration.ts — Legacy provider settings migration
approval-adapter.ts — Auto-approve settings → SDK tool policies
telemetry-adapter.ts — Extension telemetry → SDK telemetry
types.ts — WebviewInbound, WebviewOutbound types
```
Each host then has a thin integration layer:
- **VSCode** (`src/hosts/vscode/sdk-extension.ts`): In-process.
Creates `ClineSdkHost`, registers VSCode LM handler, manages
webview lifecycle. Uses `postMessage` for webview communication.
- **JetBrains** (`src/sidecar/main.ts`): Separate process. Creates
`ClineSdkHost`, reads/writes JSON-RPC on stdio. Registers
`HostCallbackClient` for IDE operations. The webview bridge code
is identical — it just sends messages over stdio instead of
`postMessage`.
#### Statefulness and Reliability
The sidecar is **stateful** — it holds the `ClineCore` instance with
active sessions in memory. However, it is designed for **graceful
restart**:
- **Session persistence**: All session state is written to disk
after each turn (messages, manifest, transcript). On restart, the
sidecar re-reads the session index and can resume.
- **Crash detection**: The Kotlin plugin monitors the sidecar
process. If it exits unexpectedly, the plugin restarts it after a
brief delay (same as current `CoreProcessManager.RESTART_DELAY`).
- **Smaller messages**: Because the protocol is JSON-RPC with
incremental streaming (notifications for each delta), the
messages are much smaller than the current gRPC approach which
sends full state snapshots. This eliminates the heap pressure
that made the current system unreliable.
- **Interrupted operations**: If the sidecar crashes mid-turn, the
next startup detects the unfinished session (status = "running"
but no live process) and marks it as interrupted, just like the
current task resumption flow.
#### JetBrains-Specific Tools
The HostCallback pattern makes it easy to add JetBrains-specific
capabilities without changing shared code:
1. **Registration**: The sidecar's `HostCallbackClient` declares
what capabilities the host supports (e.g., `"psi"`, `"runConfigs"`).
2. **Tool Executors**: JetBrains-specific tool executors are
registered in `ClineCoreOptions.defaultToolExecutors` when the
sidecar starts. For example, a `getDiagnostics` executor that
calls `host/getDiagnostics` via JSON-RPC to get IntelliJ's PSI
analysis results.
3. **No shared code changes**: Adding a new JetBrains capability
requires:
- Implementing the handler in Kotlin (`HostCallbackService`)
- Adding a JSON-RPC method in the sidecar's `HostCallbackClient`
- Optionally registering a custom tool executor
Example for exposing JetBrains PSI:
```kotlin
// Kotlin side
"host/getPsiStructure" -> {
val file = PsiManager.getInstance(project).findFile(virtualFile)
// ... extract structure
respondWithJson(result)
}
```
```typescript
// Sidecar side - registered as a custom tool executor
defaultToolExecutors: {
list_code_definition_names: async (args) => {
// Call back to JetBrains for richer PSI-based results
const result = await hostCallback.call("host/getPsiStructure", { path: args.path });
return result;
}
}
```
---
## Architecture Overview
### Current Architecture
```
┌─── VSCode Extension ──┐ ┌── JetBrains Plugin ──┐ ┌──── CLI ────┐
│ WebviewProvider │ │ Kotlin Plugin │ │ React Ink │
│ Controller │ │ CoreProcessManager │ │ ClineAgent │
│ Task │ │ ProtoBusProxy │ │ │
│ API providers (30+) │ │ JCEF WebView │ │ │
│ McpHub │ │ │ │ │
│ Webview (React) │ │ ↓ gRPC │ │ │
│ │ │ cline-core │ │ │
│ proto/cline/*.proto │ │ (standalone Node) │ │ │
└────────────────────────┘ └──────────────────────┘ └─────────────┘
```
### Target Architecture
```
┌─── VSCode Extension ──┐ ┌── JetBrains Plugin ──┐ ┌──── CLI ────┐
│ SDK Adapter Layer │ │ Kotlin Plugin │ │ React Ink │
│ @clinebot/core │ │ │ │ TUI │
│ (in-process) │ │ ↓ JSON-RPC/stdio │ │ │
│ Webview (adapted) │ │ SDK sidecar (Node) │ │ │
│ │ │ @clinebot/core │ │ │
│ registerHandler │ │ │ │ │
│ ("vscode-lm", ...) │ │ Webview (adapted) │ │ │
└────────────────────────┘ └──────────────────────┘ └─────────────┘
All clients backed by:
@clinebot/core → @clinebot/agents → @clinebot/llms
↓ ↓ ↓
Sessions Tools/Hooks Providers
Storage MCP Bridge Model Catalog
Telemetry Teams/Spawn Handler Registry
```
---
## What the SDK Already Provides
These capabilities exist in the SDK and do not need to be rebuilt:
1. **Legacy provider settings migration**
`migrateLegacyProviderSettings()` reads `globalState.json` +
`secrets.json`, writes to `providers.json`. Handles Anthropic,
OpenAI, OpenAI Codex OAuth, OpenRouter, Bedrock, custom
OpenAI-compatible endpoints, etc. Existing providers are never
overwritten. Migrated entries are tagged `tokenSource: "migration"`.
2. **30+ provider handlers** — Anthropic, OpenAI (chat + responses
API), Google Gemini, AWS Bedrock, Vertex AI, DeepSeek, Ollama,
LM Studio, Mistral, Groq, Fireworks, Together, xAI, Cerebras,
LiteLLM, Nebius, HuggingFace, and more.
3. **Custom handler registry**`registerHandler(id, factory)` and
`registerAsyncHandler(id, factory)` for providers that need
host-specific dependencies (e.g., VSCode LM API).
4. **MCP management**`InMemoryMcpManager` with stdio, SSE, and
streamableHttp transports. Config loader reads from
`~/.cline/data/settings/mcp.json` with Zod validation. Supports
legacy format migration.
5. **Tool framework** — 8 built-in tools: `read_files`,
`search_codebase`, `run_commands`, `editor`, `apply_patch`,
`fetch_web_content`, `skills`, `ask_question`. Preset system with
`development` (act mode) and `readonly` (plan mode) presets.
Per-tool enable/disable. Policy-based approval (auto-approve,
require-approval, per-tool overrides). Model-aware tool routing
(e.g., OpenAI models use `apply_patch` instead of `editor`).
6. **Session lifecycle**`ClineCore.create()``host.start()` /
`host.send()` / `host.abort()` / `host.stop()` / `host.subscribe()`
Interactive mode with prompt queueing (`queue`/`steer` delivery).
Event subscription for streaming.
7. **Telemetry**`TelemetryService` with pluggable adapters:
`OpenTelemetryAdapter` (for enterprise OTEL), `LoggerTelemetryAdapter`.
Standard events: `session.started`, `session.ended`,
`task.created`, `task.conversation_turn`, `task.tool_used`, etc.
See "Telemetry Event Mapping" above for full mapping.
8. **Rules & Skills** — Discovery from `.clinerules/`,
`~/Documents/Cline/Rules`, `~/.cline/data/settings/rules/`.
SKILL.md format with YAML frontmatter. Global and project scopes.
9. **Hooks**`HookEngine` with lifecycle events. Node subprocess
hook helpers for bash/powershell execution.
10. **Subagents/Teams**`AgentTeamsRuntime`, spawn tools, team
coordination with concurrent teammate agents.
11. **System prompt generation**`getClineDefaultSystemPrompt()`
with platform-aware customization.
12. **OAuth token management**`RuntimeOAuthTokenManager` handles
automatic token refresh during sessions for OAuth providers
(Cline, OpenAI Codex).
13. **Storage isolation**`CLINE_DIR`, `CLINE_DATA_DIR`,
`CLINE_SESSION_DATA_DIR` environment variables plus
`setClineDir()` / `setHomeDir()` APIs for test isolation.
---
## Test Strategy
See `migration.md` for the phase-by-phase test plan. This section
covers the evergreen test infrastructure and classification.
### Test Infrastructure
**Extension unit tests** use Mocha with a custom `requires.ts` that
mocks `vscode` and `@integrations/checkpoints` modules. Config in
`.mocharc.json`. These tests run without VSCode.
**Webview tests** use Vitest with React Testing Library. Independent
from the extension — they test React components in isolation.
**E2E tests** use Playwright to drive a real VSCode instance with
the extension loaded. They test chat, auth, diff editing, and editor
integration against a mock API server on localhost:7777.
**SDK adapter tests** use Vitest (simpler setup, better TypeScript
support, no need for vscode-mock since adapter layer is
VSCode-independent). Config in `vitest.config.sdk.ts`.
### SDK Storage Isolation for Tests
The SDK fully supports isolated test environments via environment
variables and API calls:
```typescript
import { setClineDir, setHomeDir } from "@clinebot/shared/storage";
const tempHome = mkdtempSync(join(tmpdir(), "test-home-"));
process.env.HOME = tempHome;
process.env.CLINE_DIR = join(tempHome, ".cline");
process.env.CLINE_DATA_DIR = join(tempHome, ".cline", "data");
setHomeDir(tempHome);
setClineDir(process.env.CLINE_DIR);
```
### Test Framework Decisions
- **Keep Mocha** for extension unit tests (existing infrastructure)
- **Keep Vitest** for webview and CLI tests
- **Keep Playwright** for VSCode E2E tests
- **Add Vitest** for new SDK adapter tests
- **Isolated home directories** for all new tests touching storage
---
## Manual QA Guide
This section is for the QA team. It describes what has been removed
(so you don't file bugs for missing features) and what areas carry
the most regression risk after the SDK migration.
### Removed Features — Do Not File Bugs
- **Browser automation** — The built-in Playwright browser tool is
gone. Users should use third-party MCP browser tools instead.
- **IDE terminal integration** — Commands now run exclusively in a
"background terminal" (headless shell). No terminal tab opens.
- **Shadow-git checkpoints** — Existing checkpoints are invalidated.
- **Memory bank / structured context** — All memory bank files and
UI removed.
- **Focus chain** — No focus chain panel or inline indicators.
- **Deep planning / `/deep-planning`** — Plan/Act mode remains as
the replacement.
- **`/reportbug`** — Removed.
- **Workflows** — Skills (SKILL.md format) are the replacement.
- **Custom workflow slash commands** — Skills replace this.
### Risk Areas — VSCode Extension
1. **Provider credentials & model selection** — Verify existing API
keys survive the upgrade and downgrade.
2. **Cline provider OAuth / SSO** — Test sign-in, sign-out, token
refresh, org switching.
3. **Chat streaming & message display** — Watch for missing/duplicated
messages, broken streaming, performance regressions.
4. **Tool approval flow** — Verify auto-approve, YOLO mode, per-tool
permissions.
5. **Plan/Act mode** — Verify toggling, separate model configs,
state persistence.
6. **Task history & resume** — Old tasks appear, can be resumed; new
tasks are saved.
7. **MCP servers** — Existing configs picked up, tools work.
8. **VSCode LM provider (Copilot)** — Verify it still works.
9. **Settings UI** — All toggles and inputs persist correctly.
10. **Webview performance** — Long conversations should not cause
sluggishness.
### Risk Areas — JetBrains Extension
1. **Sidecar process lifecycle** — Starts reliably, auto-restarts,
shuts down cleanly.
2. **Webview communication** — Messages arrive, state is fresh.
3. **Large conversations** — 100K+ tokens without OOM.
4. **Host operations** — Open file, diagnostics, clipboard all work.
5. **Keybindings** — Correct for the JetBrains platform.
### Risk Areas — CLI
1. **Agent backend replacement** — Core loop works in TUI and
headless modes.
2. **Provider & model picker** — All providers appear, defaults
correct.
3. **Shared state with IDE clients** — Credentials and history
visible across clients.
4. **Slash commands** — Removed commands don't appear; remaining
ones work.
5. **Worktrees & `--cwd`** — Function correctly.
6. **ACP (Agent Communication Protocol)** — Programmatic usage works.
-208
View File
@@ -1,208 +0,0 @@
# SDK Migration Caveats & Known Issues
Tracking issues found during the migration from the legacy inference system to the ClineCore SDK.
## Status Legend
- 🔴 **Blocker** — prevents core functionality
- 🟡 **Minor** — cosmetic or UX annoyance
- 🟢 **Fixed** — resolved
NOTE:
1. Use your debugging tool (DEBUG-HARNESS.md) to reproduce issues.
2. Use your debugging tool to validate your fixes.
3. Commit one verified change together.
4. Work on these in any order you prefer.
---
🟢 Under accounts, the when logged in the "current balance" is ---- and
the reload button does nothing. **Fixed:** getUserCredits handler fetches
balance from Cline API using stored auth token.
🟢 Under accounts, the "cline environment" dropdown doesn't change from
production when you select "staging" or "local". **Fixed:** state-builder
now reads `clineEnv` from globalState and maps to Environment enum;
updateSettings handler persists clineEnv and clears auth on change.
🟢 Under accounts, the logout button does nothing. **Fixed:**
accountLogoutClicked handler clears auth credentials from disk.
🟢 Reportedly under accounts you can't sign in. **Fixed:**
accountLoginClicked handler (was STUB) now opens the Cline login page
in the browser.
🔴 When you have a low credit balance, even after you change accounts
(for example from one "org" to another) or refreshing you keep getting
an error "Insufficient balance. Your Cline Credits balance ..."
🔴 In chat, a chat response has a "copy" button that is
obscured/partially obscured by the last generated code block. In the
classic extension, this appears with enough space around it to be
visible.
🟢 Changing the model during a conversation does not, *apparently*,
change the model used for inference. **Fixed:** updateSettings now
updates the in-memory apiConfiguration (not just disk) so
model/provider changes take effect immediately for subsequent sessions.
🔴 The OpenAI compatible provider produces "404 404 page not found"
errors.
🔴 When running tools (for example, prompt the agent to use kb_status)
output rectangles appear but they are blank.
🔴 When prompted with multiple-step work (like 1. Do this 2. Do that)
the chat displays "0/0 TODOs".
🟡 Checkpoints appear in options, but checkpoints don't appear in
chats; we need to overhaul the checkpoints system anyway see
ARCHITECTURE.md.
🟢 In the history section, you can't mark chats as favorites.
🟡 Banners (for example "Try Claude Sonnet 4.6") can be dismissed, but
there are no < and > buttons visible to page between them.
🟢 "Add to Cline" right click menu (use the command to trigger it)
does not do anything. **Fixed:** sendAddToInputEvent now falls back to
the SDK bridge's pushAddToInput when no classic gRPC subscriptions are
active; WebviewGrpcBridge handles subscribeToAddToInput streaming and
sends via both gRPC response and typed message.
🟢 When a task is cancelled, you can't enter a new chat and send that
chat in addition. (The repro is: Run a task, click cancel relatively
quickly, type a new prompt, try to hit enter/click the arrow.) **Fixed:**
cancelTask now clears currentSession after abort so subsequent
askResponse calls start a new task instead of sending to the aborted
session.
🟢 MCP Servers tab never finishes loading (may be a workos: token
prefix problem?) **Fixed:** subscribeToMcpServers now sends initial
server data as a typed message (mcpServers) instead of only via gRPC
streaming response, which the webview's dual-listen pattern picks up.
🟢 Attached images (via drag and drop or the + icon to attach an image
file) aren't submitted to models. **Fixed:** newTask and askResponse
now include the images array in ClineMessage objects so attached images
appear in the chat UI and are passed to the SDK session.
🔴 Changing the account profile in the accounts tab (for example from
Cline External, which has budget, to Cline Internal Testing Org, which
doesn't) doesn't switch to that profile for inference.
🟡 Account panel may show logged-out state on launch despite being
logged in. Inference still works. The `subscribeToAuthStatusUpdate`
streaming subscription in the webview may not be established before
the bridge pushes initial auth data, causing a race condition. On most
launches the auth state loads correctly (verified via debug harness),
but the user reports intermittent occurrences.
🔴 "Sign up with Cline" button does not do the IDE login flow — it
opens the dashboard (`https://app.cline.bot/login`) instead. In
origin/main, `accountLoginClicked` calls
`AuthService.createAuthRequest()` which starts a local HTTP server for
the OAuth callback, calls the Cline API auth endpoint with the
callback URL, and opens the resulting OAuth redirect URL. The SDK does
not have access to `AuthService` or `HostProvider.getCallbackUrl()`,
so it falls back to opening the dashboard URL directly. Users who are
not logged in cannot authenticate through the extension UI.
**Requires:** SDK support for OAuth callback flows (see
SDK-FEATURE-REQUESTS.md).
🔴 Buttons in the MCP Servers popup do nothing. The restart (🔄),
enable/disable toggle, and delete (🔴) buttons on individual MCP
servers are all no-ops. The gRPC handler stubs these methods:
`restartMcpServer`, `deleteMcpServer`, `toggleMcpServer`,
`toggleToolAutoApprove`, `authenticateMcpServer`, `updateMcpTimeout`.
In origin/main these go through `controller.mcpHub` which manages live
MCP server connections. The SDK reads MCP settings from disk but does
not expose server lifecycle management to the webview. See SDK-MCP.md
for details, we need to implement much more elaborate MCP support
client side to work with the SDK, via a custom RuntimeBuilder and tool
client factory that supports streamable HTTP; watches the file for
changes and either restarts a session or causes the tool definitions
to change; etc.
🔴 Buttons in the MCP Servers → Configure tab do nothing. Same root
cause as above — the configure tab shows servers (e.g. "linear",
"kamibiki") with restart/toggle/delete controls, but all interactions
are stubbed. The "Configure MCP Servers" and "Advanced MCP Settings"
links also depend on `openMcpSettings` which may or may not be wired.
🟡 MCP Marketplace never loads. The Marketplace tab shows "No MCP
servers found in the marketplace". **Partial fix applied:**
`subscribeToMcpMarketplaceCatalog` in `webview-grpc-bridge.ts` now
reads from the disk cache (`~/.cline/data/cache/mcp_marketplace_catalog.json`)
via `readMcpMarketplaceCatalogFromCache()` and pushes the catalog to
the webview as a streaming response. This works if the cache was
previously populated by the classic extension. However,
`refreshMcpMarketplace` (which fetches fresh data from the API) is
still stubbed because it requires an authenticated API call to
`https://api.cline.bot/v1/mcp/marketplace`. If no cache file exists
(fresh install), the marketplace will remain empty.
**Note:** Could not validate with debug harness since it runs the
classic extension, not the SDK adapter.
🔴 Refreshing OpenRouter and Vercel AI Gateway models fails on startup
with `TypeError: Cannot convert undefined or null to object` at
`Object.entries` in `typeConversion.ts:159` (`fromProtobufModels`).
The protobuf response likely returns `undefined` instead of an object,
and `fromProtobufModels` calls `Object.entries()` without a null guard.
🔴 "Cline Wants to execute this command" indicator remains in
"running" state after the command has completed. A cancel button is
shown but does nothing. The webview is not receiving or processing the
tool completion event from the SDK session.
🔴 "Cline read X files" and most other tool-use summaries show tool
names as empty strings. In the main extension, file names are shown
and clickable. The tool name and file path fields are likely not being
mapped from the SDK's tool-use events to the webview message format.
🔴 After a task finishes, typing a follow-up message and pressing
enter creates a new conversation instead of continuing the existing
one. The finished task's session is likely being discarded or the
`askResponse` path is creating a new task instead of resuming.
🔴 Cline does not ask for user approval when executing actions, even
when auto-approve toggles are turned off for most categories. The
approval gate logic from the classic extension is either not wired
into the SDK session flow or the settings are not being read correctly.
🔴 Console floods with `Failed to process partial message: TypeError:
Cannot read properties of undefined (reading 'length')` at
`convertProtoToClineMessage` (`cline-message.ts:251`) after asking a
question. The streaming response handler is receiving partial protobuf
messages with missing fields that `convertProtoToClineMessage` doesn't
guard against.
🔴 Can get intqo a state where messages can no longer be sent in a
conversation. Observed after asking Cline to describe a few files. The
session may be stuck in an unrecoverable state (e.g. waiting for a
response that was dropped or an approval that was never requested).
🟡 Excessive token usage for trivial tasks. A single prompt ("append
'Sahh dude' to the Readme") resulted in a `find` command, a file
edit, 2 file reads, a `tail` command, 116k tokens, and $1.90 cost on
Opus 4.6. The SDK session may not be sending efficient context or may
be over-fetching file contents.
🔴 Dashboard "Usage History" page errors with `Failed to fetch credit
balance: TypeError: Cannot read properties of undefined (reading
'map')` at `convertProtoUsageTransactions` (`helpers.ts:52`). The
protobuf response for usage transactions is returning `undefined`
where an array is expected; `convertProtoUsageTransactions` needs a
null guard.
🔴 Resuming a task from history does not work. The past conversation
is displayed, but once the user types a new message the old
conversation disappears and a new one takes its place. The context
from the previous conversation is lost. The history resume flow is
likely not restoring the SDK session state or conversation messages.
🔴 Auto-approve settings are not respected — related to the approval
gate issue above but specifically: even with auto-approve toggles
explicitly turned off, Cline proceeds without asking. This may be a
separate settings-read bug or the SDK session may not have an approval
callback wired in at all.
+552 -1653
View File
File diff suppressed because it is too large Load Diff
-3
View File
@@ -1,3 +0,0 @@
@.clinerules/general.md
@.clinerules/network.md
@.clinerules/cli.md
+36 -49
View File
@@ -14,11 +14,14 @@ Bug reports help make Cline better for everyone! Before creating a new issue, pl
## Before Contributing
All contributions must begin with a GitHub Issue, unless the change is for small bug fixes, typo corrections, minor wording improvements, or simple type fixes that don't change functionality.
**For features and contributions**:
- First check the [Feature Requests discussions board](https://github.com/cline/cline/discussions/categories/feature-requests) for similar ideas
- If your idea is new, create a new feature request
- Wait for approval from core maintainers before starting implementation
- Once approved, feel free to begin working on a PR with the help of our community!
- **Check existing issues**: Search [GitHub Issues](https://github.com/cline/cline/issues).
- **Create an issue**: Use appropriate templates:
- **Contributions:** Use the "Contribution Request" template to propose what you'd like to work on.
- **Bugs:** "Bug Report" template for reporting issues.
- **Features:** "Detailed Feature Proposal" template for suggesting new features.
- **Wait for approval**: A core Cline contributor must approve your contribution request before you start implementation.
- **Claim issues**: Once approved, the issue will be assigned to you.
**PRs without approved issues may be closed.**
@@ -46,24 +49,35 @@ We also welcome contributions to our [documentation](https://github.com/cline/cl
```bash
npm run install:all
```
4. Generate Protocol Buffer files (required before first build):
```bash
npm run protos
```
5. Launch by pressing `F5` (or `Run`->`Start Debugging`) to open a new VSCode window with the extension loaded. (You may need to install the [esbuild problem matchers extension](https://marketplace.visualstudio.com/items?itemName=connor4312.esbuild-problem-matchers) if you run into issues building the project.)
4. Launch by pressing `F5` (or `Run`->`Start Debugging`) to open a new VSCode window with the extension loaded. (You may need to install the [esbuild problem matchers extension](https://marketplace.visualstudio.com/items?itemName=connor4312.esbuild-problem-matchers) if you run into issues building the project.)
### Creating a Pull Request
1. Commit your changes.
1. Before creating a PR, generate a changeset entry:
```bash
npm run changeset
```
This will prompt you for:
- Type of change (major, minor, patch)
- `major` → breaking changes (1.0.0 → 2.0.0)
- `minor` → new features (1.0.0 → 1.1.0)
- `patch` → bug fixes (1.0.0 → 1.0.1)
- Description of your changes
2. Push your branch and create a PR on GitHub. Our CI will:
2. Commit your changes and the generated `.changeset` file
3. Push your branch and create a PR on GitHub. Our CI will:
- Run tests and checks
3. Testing
- Changesetbot will create a comment showing the version impact
- When merged to main, changesetbot will create a Version Packages PR
- When the Version Packages PR is merged, a new release will be published
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
@@ -75,10 +89,8 @@ We also welcome contributions to our [documentation](https://github.com/cline/cl
2. **Local Development**
- Run `npm run install:all` to install dependencies
- Run `npm run protos` to generate Protocol Buffer files (required before first build)
- Run `npm run test` to run tests locally
- Run → Start Debugging or `>Debug: Select and Start Debugging` and wait for a new VS Code instance to open
- **Terminal Workflow**: Use `npm run dev` (generates protos + runs watch mode) or `npm run watch` (if protos already generated)
- Before submitting PR, run `npm run format:fix` to format your code
3. **Linux-specific Setup**
@@ -138,7 +150,7 @@ Anyone can contribute code to Cline, but we ask that you follow these guidelines
- Run `npm run lint` to check code style
- Run `npm run format` to automatically format code
- All PRs must pass CI checks which include both linting and formatting
- Address any warnings or errors from linter before submitting
- Address any ESLint warnings or errors before submitting
- Follow TypeScript best practices and maintain type safety
3. **Testing**
@@ -148,40 +160,15 @@ 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**
4. **Versioning & Changelog Notes**
- Contributors do not need to create changelog-entry files as part of PRs.
- Maintainers handle release versioning and changelog curation during the release process.
- Create a changeset for any user-facing changes using `npm run changeset`
- Choose the appropriate version bump:
- `major` for breaking changes (1.0.0 → 2.0.0)
- `minor` for new features (1.0.0 → 1.1.0)
- `patch` for bug fixes (1.0.0 → 1.0.1)
- Write clear, descriptive changeset messages that explain the impact
- Documentation-only changes don't require changesets
5. **Commit Guidelines**
-134
View File
@@ -1,134 +0,0 @@
# E2E Debugging Visibility
This is a sub-project of the project described in migration.md. We are
engaging in a big change to the VSCode extension. You gain visibility
into the extension through tests, but sometimes that is not enough.
Your goal is to create way where you can launch the VSCode extension
and have access to the node debugger and webview debugger so that you
can set break points, evaluate expressions, inject input (consider
Microsoft's work with Playwright in VSCode, but anything that works is
fine) step, etc. so that you can observe execution and find and fix
problems without the tedious cycle off adding print statements,
running a test which may hang, fixing something, removing the print
statements, etc.
For this step to be complete, you need to demonstrate you have the
ability to:
1. Build and run the VSCode extension in an unminified form, including
the webview unminified.
2. Add and remove breakpoints, including conditional breakpoints, on
the extension side.
3. Add and remove breakpoints, including conditional breakpoints, on
the webview side.
4. Evaluate expressions at breakpoints. You should be able to refer to
local variables, that is, the extension code should be
unminified. (Concatenated is fine as long as you can find your way
around.)
5. Run, step at breakpoints.
6. Generate UI actions like opening the Cline sidebar, focusing
elements, typing, etc.
7. Take screenshots that you can view.
You need to use this tool inside your agentic loop, that is, you will
need to drive both of these debugees simultaneously from one loop, so
you may need to write yourself a tool which blocks until one of the
debugees hits a breakpoint; can use a timeout and let you break and
examine isolates and stacks; things of that nature.
We are working on macOS, it is fine if this tool just works on macOS
for now.
## Caveats
- **`CLINE_DIR` environment variable**: Because the debug harness
spawns a fresh VSCode instance that runs the Cline extension, and
because *you* (the agent) share state with that extension (API keys,
provider settings, task history), you **must** set `CLINE_DIR=~/.cline`
when launching the harness. Without it the debugee uses an isolated
data directory and won't have your API keys or provider configuration,
causing inference to fail silently (requests hang or error).
```bash
CLINE_DIR=~/.cline npx tsx src/dev/debug-harness/server.ts --skip-build --auto-launch
```
- **⚠️ "Introducing Cline Kanban" promotion — DISMISS FIRST**: On
fresh launches, a full-screen promotional overlay ("Introducing Cline
Kanban") may appear in the sidebar webview. It obscures all other UI
elements, so screenshots will show only the promo and interactions
with the chat input, settings buttons, etc. will fail. **You must
dismiss it immediately after opening the sidebar, before doing
anything else.** This is easy to forget — if your screenshots look
wrong or interactions fail, this is almost certainly why.
**Method 1 — Click the close button via DOM** (most reliable):
```bash
curl localhost:19229/api -d '{"method": "ui.open_sidebar"}'
curl localhost:19229/api -d '{
"method": "web.evaluate",
"params": {"expression": "document.querySelector(\".sr-only\")?.parentElement?.click()"}
}'
```
This finds the `<span class="sr-only">Close</span>` element and
clicks its parent `<button>`.
**Method 2 — Press ESC** (simpler but less reliable):
```bash
curl localhost:19229/api -d '{"method": "ui.open_sidebar"}'
curl localhost:19229/api -d '{
"method": "web.evaluate",
"params": {"expression": "document.activeElement.dispatchEvent(new KeyboardEvent(\"keydown\", {key: \"Escape\", code: \"Escape\", keyCode: 27, bubbles: true}))"}
}'
```
If neither works, take a screenshot (`ui.screenshot`) to see what's
on screen and identify the current dismiss control.
- **Screenshots**: `ui.screenshot` and `ui.sidebar_screenshot` save
PNG files to `/tmp/cline-debug/` and return `{path}` in the JSON
response. **Do NOT open the screenshot file with `open`** — on macOS
this launches Preview.app which covers the VSCode window you're
debugging. Use `read_file` on the returned path to examine the image
without disrupting the debuggee.
- **Debuggee launch delay**: The post-launch activation delay is 1
second. If the extension hasn't fully loaded by the time you interact
with it, just retry — `ui.open_sidebar` and `findSidebar` have their
own internal polling with timeouts.
- **Top toolbar buttons**: The "new task", "mcp servers", "history",
"accounts", and "settings" toolbar buttons are not in the webview DOM
(they're VSCode UI chrome). Instead of trying to click them, run the
associated VSCode commands directly:
- New Task: `cline.plusButtonClicked`
- MCP Servers: `cline.showMcpServers`
- History: `cline.showHistory`
- Accounts: `cline.showAccount`
- Settings: `cline.openSettings`
Example:
```bash
curl localhost:19229/api -d '{
"method": "ui.command_palette",
"params": {"command": "cline.openSettings"}
}'
```
- **CDP disconnects after window reload**: If you use
`workbench.action.reloadWindow` (e.g., to pick up a rebuilt
webview), the extension host CDP connection drops. You must do a full
`shutdown` + relaunch of the debug harness to reconnect.
## References
You can see the vscode source code in ~/clients/cline/vscode and
search it with kb_search vscode
You can search the cline source code (snapshot) with kb_search cline.
File diff suppressed because it is too large Load Diff
-237
View File
@@ -1,237 +0,0 @@
These are issues the agent claims to have fixed, but should be verified:
## Fixed
### 1. 🟢 Remote inference fails with ECONNREFUSED (localhost:4000)
**File:** `src/sdk/cline-session-factory.ts`
**Symptom:** Sending any message with the Cline provider fails after 6 retries with "Cannot connect to API" / ECONNREFUSED to `http://localhost:4000/v1/chat/completions`.
**Root cause:** Base URL overrides (`openAiBaseUrl`, `openRouterBaseUrl`, `liteLlmBaseUrl`) were applied unconditionally to ALL providers, clobbering the Cline API URL. A stale `openAiBaseUrl: "http://localhost:4000/v1"` in `~/.cline/data/globalState.json` overwrote `https://api.cline.bot/api/v1`.
**Fix:** Guard each base URL override with a provider check so it only applies to its respective provider.
---
### 2. 🟢 Task history not persisted after completion
**File:** `src/sdk/SdkController.ts`
**Symptom:** After a task completes successfully, the task did NOT appear in the RECENT section when returning to the home screen.
**Root cause:** `newTask()` created a `currentTaskItem` but never pushed it to `this.taskHistory[]`. `clearTask()` discarded it without saving. No disk persistence implementation existed.
**Fix:** `SdkController` now persists tasks on three paths: (1) `done` event updates `currentTaskItem` with final usage and calls `persistCurrentTask()`, (2) `clearTask()` calls `persistCurrentTask()` before resetting, (3) `cancelTask()` persists the in-progress task. `LegacyStateReader` gained `saveTaskHistory()`, `saveUiMessages()`, and `deleteTaskDirectory()` methods for disk I/O.
### 3. 🟢 Task resumption not implemented
**File:** `src/sdk/SdkController.ts`
**Symptom:** Cannot resume a previous task from history.
**Fix:** `showTaskWithId()` now finds the task in history, loads saved UI messages via `legacyState.readUiMessages()`, restores them into the translator, and sets `currentTaskItem`. The task view renders with full message history.
### 6. 🟢 Settings persistence is best-effort / incomplete
**File:** `src/sdk/SdkController.ts`
**Symptom:** `updateSettings()` was a no-op stub with a TODO comment.
**Fix:** `updateSettings()` now persists settings to `globalState.json` via `legacyState.saveApiConfiguration()`. `updateAutoApprovalSettings()` also persists via the same mechanism.
### 7. 🟢 Completed task not appearing in RECENT section
**Where:** Home screen → RECENT section
**Symptom:** After completing a task and clicking "New Task", the completed task did not appear in the RECENT history list.
**Fix:** Resolved by issue #2 fix — tasks are now persisted to `taskHistory` on completion, so they appear in RECENT.
### 8. 🟢 Top bar buttons are non-functional
**Where:** Header bar — accounts, settings, new chat, history buttons
**Symptom:** Clicking any of the top bar buttons (accounts icon, settings gear, new chat +, task history) does nothing. No navigation occurs, no panels open.
**Root cause:** gRPC stub. The webview subscribes to `subscribeToSettingsButtonClicked`, etc. — these are event streams pushed from the extension host when VSCode title bar buttons are clicked.
**Fix:** Extension.ts button commands now send typed `navigate` messages via `WebviewGrpcBridge.navigate()`, bypassing gRPC streaming subscriptions. Plus button also calls `clearSdkTask()` to reset the SDK session.
### 9. 🟢 @ mentions / autocomplete not working
**Where:** Chat input textarea
**Symptom:** Typing `@` in the chat input does not trigger any autocomplete dropdown. No filename suggestions, no context items offered.
**Root cause:** gRPC stub. The `@` autocomplete calls `FileServiceClient.searchFiles()` to get matching file paths.
**Fix:** Implemented `searchFiles` handler in grpc-handler.ts that delegates to `SdkController.searchFiles()`, which does a real filesystem walk of the workspace directory (max depth 8, skips node_modules/.git/etc). Returns results with `mentionsRequestId` for proper request correlation.
### 10. 🟢 Add files/images button (+) does nothing
**Where:** Bottom bar, "+" button next to chat input
**Symptom:** Clicking the "+" button to add files and images produces no response — no file picker, no dropdown, no action.
**Root cause:** gRPC stub. The button calls `FileServiceClient.selectFiles()` which opens a native file picker dialog.
**Fix:** Implemented `selectFiles` handler that returns `StringArrays` format (`values1` = image data URLs, `values2` = file paths). VscodeWebviewProvider callback reads image files as base64 data URLs and returns relative paths for non-images.
### 11. 🟢 Cannot switch from Plan mode back to Act mode
**Where:** Bottom bar Plan/Act toggle
**Symptom:** Clicking "Plan" successfully switches to Plan mode. However, clicking "Act" after that does NOT switch back to Act mode.
**Root cause:** Proto enum conversion bug — the webview sends numeric enum values (0=PLAN, 1=ACT) but the handler expected string values.
**Fix:** `handleTogglePlanActMode` now converts proto enum values: `0/"PLAN" → "plan"`, `1/"ACT" → "act"`, with fallback for already-converted string values.
### 12. 🟢 "Manage cline rules and workflows" still mentions workflows
**Where:** ClineRulesToggleModal tooltip and aria-label
**Symptom:** The tooltip and aria-label still said "Manage Cline Rules & Workflows".
**Fix:** Updated tooltip to "Manage Cline Rules" and aria-label to "Show/Hide Cline Rules". Also simplified chat placeholder text to remove "workflows" mention.
### 4. 🟢 Input text not cleared immediately on send
**Where:** Webview chat input
**Symptom:** After typing a message and pressing send/enter, the text remains visible in the input field briefly before clearing. Creates a feeling of lag.
**Root cause:** In `useMessageHandlers.ts`, `setInputValue("")` was called AFTER `await TaskServiceClient.newTask(...)` or `await TaskServiceClient.askResponse(...)` completed. The network round-trip caused visible delay before the input cleared.
**Fix:** Moved `setInputValue("")`, `setActiveQuote(null)`, `setSelectedImages([])`, `setSelectedFiles([])` to execute immediately when `hasContent` is true, before any async gRPC calls. React schedules a re-render synchronously, clearing the input before the network round-trip.
### 5. 🟢 api_req_started fires with zeroed token counts
**Where:** Message stream / ChatRow rendering
**Symptom:** An `api_req_started` partial message fires with `{"tokensIn":0,"tokensOut":0,"cost":0}` before real counts arrive, causing a brief flash of "0 / 200.0k" in the token usage bar.
**Root cause:** `ContextWindow.tsx` rendered the token bar whenever `tokenData` existed (i.e., when `contextWindow > 0`), regardless of whether `lastApiReqTotalTokens` was 0.
**Fix:** Added `tokenData.used === 0` guard to the null-return check in `ContextWindow.tsx`. The token bar now only renders when real (non-zero) token data is available.
### 14. 🟢 "Delete chat" button shows placeholder size
**Where:** Task history → delete button tooltip / label
**Symptom:** The "Delete chat" button tooltip displays `Delete Task (size: --)` when task size data is unavailable.
**Root cause:** `DeleteTaskButton.tsx` unconditionally rendered `(size: ${taskSize ? formatSize(taskSize) : "--"})`, showing "--" when `taskSize` is undefined.
**Fix:** Changed to conditionally include size: `taskSize ? \`Delete Task (${formatSize(taskSize)})\` : "Delete Task"`. The tooltip now shows just "Delete Task" when size is unavailable, or "Delete Task (12.4 KB)" when it is.
### 13. 🟢 Terminal settings navigates to blank/stuck webview
**Where:** Settings → Terminal tab
**Symptom:** Opening terminal settings causes React to crash, leaving a blank webview.
**Root cause:** `getAvailableTerminalProfiles` was a gRPC stub returning `{data:{}}`. The webview called `setAvailableTerminalProfiles(response.profiles)` where `response.profiles` was `undefined`, overwriting the default `[]`. Then `TerminalSettingsSection` called `profilesToShow.map()` on `undefined`, crashing React.
**Fix:** Implemented real `handleGetAvailableTerminalProfiles()` handler in grpc-handler.ts that calls `getAvailableTerminalProfiles()` from `utils/shell.ts`, returning platform-specific profiles (Default, zsh, bash on macOS). Also added `availableTerminalProfiles: []` to state-builder.ts as a safety net, and wired `scrollToSettings` to fire `navigate("settings", { targetSection })` via the bridge.
**Verified:** Debug harness confirmed handler returns `{data:{profiles:[{id:"default",...},{id:"zsh",...},{id:"bash",...}]}}`, Settings → Terminal tab renders "Default Terminal Profile" dropdown with all 3 options, shell integration timeout, and terminal reuse settings.
### 16. 🟢 Cline Rules popup still has a "Workflows" tab
**Where:** Scales-of-justice icon → Cline Rules modal
**Symptom:** The "Manage Cline Rules" popup contains a "Workflows" tab. Issue #12 fixed the tooltip text, but the tab itself still exists inside the modal.
**Root cause:** The `ClineRulesToggleModal` component had a full "Workflows" tab with toggle lists for global, local, and remote workflows, plus a description section. Workflows are no longer a feature.
**Fix:** Removed the Workflows tab button, workflows description text, workflows content section (remote/global/local workflow toggle lists), and the remote workflows banner condition from `ClineRulesToggleModal.tsx`. The `currentView` state type was narrowed from `"rules" | "workflows" | "hooks" | "skills"` to `"rules" | "hooks" | "skills"`.
### 17. 🟢 Account pane shows "Sign up with Cline" despite being logged in
**Where:** Account panel / pane
**Symptom:** Even when the user is already authenticated and logged in, the account pane still displays "Sign up with Cline" and other sign-up prompts as if the user were not authenticated.
**Root cause:** `subscribeToAuthStatusUpdate` is a streaming subscription. The bridge's `handleStreamingRequest()` fell into the `default` no-op case, so auth state was never pushed to the webview.
**Fix:** Added explicit `subscribeToAuthStatusUpdate` case in `handleStreamingRequest()` that reads auth credentials from disk and pushes them. Added `roles` to org data and null safety in `isAdminOrOwner()`.
### 18. 🟢 "Sign up with Cline" button does nothing (moot)
**Where:** Account pane → Sign up button
**Fix:** Resolved by #17 — the sign-up button is no longer shown when the user is already authenticated.
### 19. 🟢 Terminal settings still shows "Terminal Execution Mode" option
**Where:** Settings → Terminal
**Fix:** Removed the Terminal Execution Mode dropdown, its handler, and unused imports from `TerminalSettingsSection.tsx`.
### 20. 🟢 Cline provider model type-ahead search does not work
**Where:** Settings → Model selector (Cline provider)
**Root cause:** `refreshClineModelsRpc` was a gRPC stub returning `{}`. The webview never received any model data.
**Fix:** Implemented `handleRefreshClineModels()` in grpc-handler.ts that reads from disk cache first, then falls back to fetching from the Cline API using `globalThis.fetch`. Converts API response to `ModelInfo` records and returns in protobuf format.
### 21. 🟢 Cline provider recommends possibly outdated model
**Where:** Settings → Model selector (Cline provider)
**Fix:** Updated fallback recommendation text in `ClineModelPicker.tsx` from `anthropic/claude-sonnet-4.5` to `anthropic/claude-sonnet-4.6`.
### 22. 🟢 "Use different models for Plan and Act" checkbox immediately unchecks
**Where:** Settings → Model configuration
**Root cause:** `updateSettings()` was writing raw settings instead of merging individual known keys.
**Fix:** `updateSettings()` now iterates known settings keys and writes each one individually. `buildExtensionState()` reads `planActSeparateModels` from `globalState`.
### 23. 🟢 MCP settings Configure tab crashes React
**Where:** MCP Servers → Configure tab
**Root cause:** `refreshMcpMarketplace` stub returns `{}`, replacing the default `{ items: [] }` state, causing `items.find()` to crash.
**Fix:** Added optional chaining (`?.items?.find`) in `getMcpServerDisplayName()`.
### 24. 🟢 History tab is empty and search does nothing
**Where:** History tab (task history list)
**Root cause:** `handleGetTaskHistory()` returned `{ data: { history } }` but webview reads `response.tasks`.
**Fix:** Changed return to `{ data: { tasks, totalCount } }`. Implemented server-side filtering/sorting.
### 25. 🟢 Auto-approve options immediately uncheck when toggled
**Where:** Auto-approve options flyout
**Root cause:** Same as #22 — `updateAutoApprovalSettings()` was not persisting properly.
**Fix:** Fixed alongside #22.
---
### 15. 🟢 MCP tools are missing / not visible to the agent
**Where:** Agent tool execution
**Symptom:** MCP tools that should be available to the agent are not discovered or listed. The agent cannot see or use any MCP-provided tools during task execution.
**Root cause:** `ClineCoreSession` in `cline-session-factory.ts` didn't pass MCP configuration through `coreConfig` when calling `host.start()`. The MCP settings file existed at `~/.cline/data/settings/cline_mcp_settings.json` but the session factory never wired MCP servers into the ClineCore session.
**Fix:** Added `getOrCreateMcpManager()` to `cline-session-factory.ts` that reads MCP server registrations via `resolveMcpServerRegistrations()`, creates an `InMemoryMcpManager` with a client factory using `@modelcontextprotocol/sdk` (supporting stdio, streamableHttp, and SSE transports), connects to all non-disabled servers, generates `Tool[]` via `createMcpTools()`, and passes them as `extraTools` in `coreConfig`. The MCP manager is cached across sessions (servers are long-lived processes). Connection has a 30s timeout to avoid blocking session start. Individual server connection failures are logged but don't prevent other servers or the session from starting.
**Verified:** Debug harness confirmed agent lists `kamibiki__kb_search`, `kamibiki__kb_status`, `kamibiki__kb_index` from the kamibiki MCP server, and successfully invoked `kamibiki__kb_status` returning real indexing data (6 repos, 1M+ embeddings).
---
### 27. 🟢 Banners (e.g., "Try Claude Sonnet 4.6") can't be dismissed
**Where:** Home screen → banner carousel
**Symptom:** Clicking the X dismiss button on any banner does nothing — the banner remains visible and reappears on reload.
**Root cause:** Two issues: (1) `state-builder.ts` hardcoded `dismissedBanners: undefined` instead of reading from globalState, so dismissed banners were never communicated to the webview. (2) `grpc-handler.ts` wrote dismissed banner IDs as plain strings instead of the `{ bannerId, dismissedAt }` objects the webview expects.
**Fix:** State builder now reads `dismissedBanners` from globalState with `normalizeDismissedBanners()` that handles both legacy plain strings and new objects. Handler writes proper `{ bannerId, dismissedAt }` objects and normalizes legacy entries on read.
**Verified:** Debug harness confirmed banners dismiss correctly — carousel shrinks as each banner is dismissed and stays dismissed across reloads.
### 28. 🟢 Can't mark chats as favorites in history
**Where:** History tab → star button on task items
**Symptom:** Clicking the star icon on a history item does nothing — the favorite state never changes.
**Root cause:** Proto field name mismatch in `handleToggleTaskFavorite()`: handler read `request.params?.id` and `request.params?.isFavorite`, but the webview sends `taskId` and `isFavorited` (proto field names from `TaskFavoriteRequest`).
**Fix:** Handler now reads both proto names (`taskId`/`isFavorited`) with fallback to legacy names (`id`/`isFavorite`).
### 29. 🟢 Copy button obscured by last code block in chat
**Where:** Chat response text with code blocks
**Symptom:** The response copy button overlaps with the last code block, making it hard to see and click.
**Root cause:** `CopyButton.tsx` positioned the bottom-right copy button at `bottom-1` (4px from bottom edge), which overlapped with code block content. No padding existed between the markdown content and the button.
**Fix:** Changed position to `bottom-2.5` (10px clearance) and added `pb-4` padding to the chat text content wrapper for code block clearance.
### 30. 🟢 Current balance shows "----" / reload button does nothing
**Where:** Account pane → credit balance display
**Symptom:** The current balance always shows "----" and the reload button has no effect.
**Root cause:** `getUserCredits` handler returned `{ credits: undefined }` instead of calling the Cline API. The webview reads `response.balance.currentBalance` which was always undefined.
**Fix:** `getUserCredits` and `getOrganizationCredits` now fetch real balance data from the Cline API using the stored auth token (`Bearer` header). Includes 10s timeout and error handling.
**Tested:** Integration tests with mock HTTP server verify real balance data flows through correctly (7 tests).
### 31. 🟢 Logout button does nothing
**Where:** Account pane → logout button
**Symptom:** Clicking logout has no effect — the user remains logged in.
**Root cause:** `accountLogoutClicked` was a STUB (silent no-op) in grpc-handler.
**Fix:** Implemented `handleAccountLogout()` that calls `LegacyStateReader.clearClineAuthInfo()` to remove `cline:clineAccountId` from secrets.json, then pushes state update so the webview shows the sign-in view.
**Tested:** Integration test verifies credentials are cleared from disk and auth status shows unauthenticated after logout.
### 32. 🟢 Low credit balance persists after account switching
**Where:** Account pane after switching organizations
**Symptom:** After switching from a low-balance org to a high-balance org, the "Insufficient balance" error persists.
**Root cause:** `setUserOrganization` was a STUB. The active org was never updated on disk, so credit queries always returned the same org's data.
**Fix:** Implemented `handleSetUserOrganization()` that calls `LegacyStateReader.setActiveOrganization()` to update the `active` flag on orgs in stored credentials. Each credit fetch is a fresh API call keyed by org ID, so switching orgs correctly fetches the new org's balance.
**Tested:** Integration test with mock server verifies: switch from low-balance org → high-balance org returns correct (high) balance, not stale (low) balance.
## Open Issues
---
### 26. 🟢 Clicking history items does not open them
**Where:** History tab → clicking any task item; also RECENT section on home screen
**Symptom:** History items display correctly in the History view, but clicking on them does nothing — the view stays on the History tab instead of navigating to the chat view with the loaded task.
**Root cause:** `handleShowTaskWithId()` in `grpc-handler.ts` called `this.delegate.showTaskWithId(id)` to load the task data and push state, but never fired `this.onNavigateCallback?.("chat")` to tell the webview to navigate from the History view to the Chat view.
**Fix:** Added `this.onNavigateCallback?.("chat")` after `showTaskWithId()` completes in `grpc-handler.ts`. This sends a typed `navigate` message to the webview, which triggers `navigateToChat()` — hiding the History view and revealing the Chat view with the loaded task.
**Verified:** Debug harness confirmed clicking items in both the History tab and RECENT section on the home screen now navigates to the chat view with full message history loaded.
---
## Observations (not bugs, just notes)
### UI Rendering — Task Completion View
The completed task view renders correctly:
- Task header with cost badge (e.g. "$0.0072")
- Token usage bar (e.g. "1.4k / 200.0k")
- Response text displayed properly
- "Task Completed" card with green checkmark and the result
- "Start New Task" button appears below the chat
- Input area changes to "Type a message..." (follow-up mode)
### Feature Card Carousel
The home screen shows a rotating feature card carousel (1/4 through 4/4) promoting:
- Claude Sonnet 4.6
- MiniMax M2.5
- ChatGPT integration
- Jupyter Notebooks
Each with a dismiss (X) button per-card.
### Model Selector
Bottom bar correctly shows `cline:anthropic/claud...` (truncated) with Plan/Act toggle. Act mode is the default.
### Debug Harness: `ui.send_message` and `ui.react_input(submit:true)` Don't Start Tasks
Both `ui.send_message` (gRPC postMessage) and `ui.react_input` with `submit:true` report success but don't actually start a new task—the webview stays on the home screen. The workaround is to use `ui.react_input` (without submit) to set the text, then dispatch a KeyboardEvent via `web.evaluate`:
```
curl -s localhost:19229/api -d '{"method":"ui.react_input","params":{"text":"your message","clear":true}}'
curl -s localhost:19229/api -d '{"method":"web.evaluate","params":{"expression":"(() => { const ta = document.querySelector(\"textarea\"); ta.focus(); ta.dispatchEvent(new KeyboardEvent(\"keydown\",{key:\"Enter\",code:\"Enter\",keyCode:13,which:13,bubbles:true})); return \"ok\"; })()"}}'
```
### Debug Harness Limitations (Fixed)
All three limitations below have been addressed:
- ~~Programmatic textarea input doesn't reliably trigger React state updates after the first task.~~ **Fixed**: Two new commands added:
- `ui.react_input` — Uses `document.execCommand('insertText')` which fires real InputEvents that React's onChange handler processes correctly, even after multiple tasks.
- `ui.send_message` — Bypasses the textarea entirely by sending gRPC requests via `postMessage` directly to the extension host.
- ~~The `web.evaluate` context can't access the VS Code API.~~ **Fixed**: The webview now exposes the VS Code API as `window.__clineVsCodeApi`, and a new `web.post_message` command lets the harness send arbitrary messages to the extension host through it.
- ~~The `ui.locator` Playwright actions don't reliably target elements inside the webview iframe.~~ **Fixed**: `findSidebar()` now validates cached frame references (checking for both detached and stale frames), `getTarget()` accepts a `forceRefresh` flag, and `ui.locator` automatically retries with frame re-discovery when targeting sidebar elements.
+1 -1
View File
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2026 Cline Bot Inc.
Copyright 2025 Cline Bot Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+8 -13
View File
@@ -2,7 +2,7 @@
English | <a href="https://github.com/cline/cline/blob/main/locales/es/README.md" target="_blank">Español</a> | <a href="https://github.com/cline/cline/blob/main/locales/de/README.md" target="_blank">Deutsch</a> | <a href="https://github.com/cline/cline/blob/main/locales/ja/README.md" target="_blank">日本語</a> | <a href="https://github.com/cline/cline/blob/main/locales/zh-cn/README.md" target="_blank">简体中文</a> | <a href="https://github.com/cline/cline/blob/main/locales/zh-tw/README.md" target="_blank">繁體中文</a> | <a href="https://github.com/cline/cline/blob/main/locales/ko/README.md" target="_blank">한국어</a>
</sub></div>
# Cline
# Cline \#1 on OpenRouter
<p align="center">
<img src="https://media.githubusercontent.com/media/cline/cline/main/assets/docs/demo.gif" width="100%" />
@@ -30,9 +30,9 @@ English | <a href="https://github.com/cline/cline/blob/main/locales/es/README.md
</table>
</div>
Meet Cline, an AI assistant that can use your **CLI** a**N**d **E**ditor.
Meet Cline (pronounced /klaɪn/, like "Klein"), an AI assistant that can use your **CLI** a**N**d **E**ditor.
Thanks to [Claude Sonnet's agentic coding capabilities](https://www.anthropic.com/claude/sonnet), Cline can handle complex software development tasks step-by-step. With tools that let him create & edit files, explore large projects, use the browser, and execute terminal commands (after you grant permission), he can assist you in ways that go beyond code completion or tech support. Cline can even use the Model Context Protocol (MCP) to create new tools and extend his own capabilities. While autonomous AI scripts traditionally run in sandboxed environments, this extension provides a human-in-the-loop GUI to approve every file change and terminal command, providing a safe and accessible way to explore the potential of agentic AI.
Thanks to [Claude 3.7 Sonnet's agentic coding capabilities](https://www.anthropic.com/claude/sonnet), Cline can handle complex software development tasks step-by-step. With tools that let him create & edit files, explore large projects, use the browser, and execute terminal commands (after you grant permission), he can assist you in ways that go beyond code completion or tech support. Cline can even use the Model Context Protocol (MCP) to create new tools and extend his own capabilities. While autonomous AI scripts traditionally run in sandboxed environments, this extension provides a human-in-the-loop GUI to approve every file change and terminal command, providing a safe and accessible way to explore the potential of agentic AI.
1. Enter your task and add images to convert mockups into functional apps or fix bugs with screenshots.
2. Cline starts by analyzing your file structure & source code ASTs, running regex searches, and reading relevant files to get up to speed in existing projects. By carefully managing what information is added to context, Cline can provide valuable assistance even for large, complex projects without overwhelming the context window.
@@ -43,7 +43,7 @@ Thanks to [Claude Sonnet's agentic coding capabilities](https://www.anthropic.c
4. When a task is completed, Cline will present the result to you with a terminal command like `open -a "Google Chrome" index.html`, which you run with a click of a button.
> [!TIP]
> Follow [this guide](https://docs.cline.bot/features/customization/opening-cline-in-sidebar) to open Cline on the right side of your editor. This lets you use Cline side-by-side with your file explorer, and see how he changes your workspace more clearly.
> Use the `CMD/CTRL + Shift + P` shortcut to open the command palette and type "Cline: Open In New Tab" to open the extension as a tab in your editor. This lets you use Cline side-by-side with your file explorer, and see how he changes your workspace more clearly.
---
@@ -87,7 +87,7 @@ All changes made by Cline are recorded in your file's Timeline, providing an eas
### Use the Browser
With Claude Sonnet's new [Computer Use](https://www.anthropic.com/news/3-5-models-and-computer-use) capability, Cline can launch a browser, click elements, type text, and scroll, capturing screenshots and console logs at each step. This allows for interactive debugging, end-to-end testing, and even general web use! This gives him autonomy to fixing visual bugs and runtime issues without you needing to handhold and copy-pasting error logs yourself.
With Claude 3.5 Sonnet's new [Computer Use](https://www.anthropic.com/news/3-5-models-and-computer-use) capability, Cline can launch a browser, click elements, type text, and scroll, capturing screenshots and console logs at each step. This allows for interactive debugging, end-to-end testing, and even general web use! This gives him autonomy to fixing visual bugs and runtime issues without you needing to handhold and copy-pasting error logs yourself.
Try asking Cline to "test the app", and watch as he runs a command like `npm run dev`, launches your locally running dev server in a browser, and performs a series of tests to confirm that everything works. [See a demo here.](https://x.com/sdrzn/status/1850880547825823989)
@@ -129,9 +129,9 @@ Thanks to the [Model Context Protocol](https://github.com/modelcontextprotocol),
### Checkpoints: Compare and Restore
As Cline works through a task, the extension can take an internal snapshot of your workspace at each step. You can use the 'Compare' button to see a diff between the snapshot and your current workspace, and the 'Restore' button to roll back to that point.
As Cline works through a task, the extension takes a snapshot of your workspace at each step. You can use the 'Compare' button to see a diff between the snapshot and your current workspace, and the 'Restore' button to roll back to that point.
For example, when working with a local web server, you can use 'Restore Workspace Only' to quickly test different versions of your app, then use 'Restore Task and Workspace' when you find the version you want to continue building from. This lets you safely explore different approaches without losing progress while the current checkpoint system is available.
For example, when working with a local web server, you can use 'Restore Workspace Only' to quickly test different versions of your app, then use 'Restore Task and Workspace' when you find the version you want to continue building from. This lets you safely explore different approaches without losing progress.
<!-- Transparent pixel to create line break after floating image -->
@@ -141,11 +141,6 @@ For example, when working with a local web server, you can use 'Restore Workspac
To contribute to the project, start with our [Contributing Guide](CONTRIBUTING.md) to learn the basics. You can also join our [Discord](https://discord.gg/cline) to chat with other contributors in the `#contributors` channel. If you're looking for full-time work, check out our open positions on our [careers page](https://cline.bot/join-us)!
## Enterprise
Get the same Cline experience with enterprise-grade controls: SSO (SAML/OIDC), global policies and configuration, observability with audit trails, private networking (VPC/private link), and self-hosted or on-prem deployments, and enterprise support. Learn more at our [enterprise page](https://cline.bot/enterprise) or [talk to us](https://cline.bot/contact-sales).
## License
[Apache 2.0 © 2026 Cline Bot Inc.](./LICENSE)
[Apache 2.0 © 2025 Cline Bot Inc.](./LICENSE)
-436
View File
@@ -1,436 +0,0 @@
# Cline SDK — MCP Server Management Reference
This document describes how the Cline SDK handles MCP (Model Context Protocol) server lifecycle, configuration, and what is — and isn't — exposed for client integration. It is intended for client developers building UI around MCP server management.
---
## Summary: The Claim That "The SDK Lacks Hooks" Is Wrong
The SDK **does** provide a full MCP manager with lifecycle operations. The `McpManager` interface in `@clinebot/core` supports:
- `registerServer()` / `unregisterServer()` — add or remove servers
- `connectServer()` / `disconnectServer()` — start or stop connections
- `setServerDisabled()` — toggle enable/disable
- `listServers()` — get snapshots of all servers with status
- `refreshTools()` — force-refresh tool lists from a server
- `dispose()` — shut down all servers
The **actual gap** is narrower: there is no built-in file-watcher that auto-reloads `cline_mcp_settings.json` when it changes, and the RPC layer (`@clinebot/rpc`) does not currently expose MCP management endpoints. This means clients that manage MCP settings through the settings file must bridge the gap between file edits and runtime state themselves.
---
## SDK Architecture for MCP
### Layer 1: Settings File (`cline_mcp_settings.json`)
The SDK reads MCP server configuration from a JSON settings file:
```json
{
"mcpServers": {
"docs": {
"transport": { "type": "stdio", "command": "node", "args": ["./mcp.js"] }
},
"remote": {
"transport": { "type": "streamableHttp", "url": "https://mcp.example.com" },
"disabled": true
}
}
}
```
**Location resolution** (`resolveDefaultMcpSettingsPath()`):
- `CLINE_MCP_SETTINGS_PATH` env var (if set)
- Otherwise defaults to the platform-specific Cline data directory
**SDK utilities** for this file (all exported from `@clinebot/core`):
- `resolveDefaultMcpSettingsPath()` — get the path
- `hasMcpSettingsFile()` — check if it exists
- `loadMcpSettingsFile()` — parse and validate with Zod
- `resolveMcpServerRegistrations()` — parse file → `McpServerRegistration[]`
- `registerMcpServersFromSettingsFile(manager)` — parse file and register all servers into a manager
### Layer 2: McpManager (`InMemoryMcpManager`)
`packages/core/src/extensions/mcp/manager.ts` — the runtime MCP lifecycle manager.
```typescript
interface McpManager extends McpToolProvider {
registerServer(registration: McpServerRegistration): Promise<void>;
unregisterServer(serverName: string): Promise<void>;
connectServer(serverName: string): Promise<void>;
disconnectServer(serverName: string): Promise<void>;
setServerDisabled(serverName: string, disabled: boolean): Promise<void>;
listServers(): readonly McpServerSnapshot[];
refreshTools(serverName: string): Promise<readonly McpToolDescriptor[]>;
callTool(request: McpToolCallRequest): Promise<McpToolCallResult>;
dispose(): Promise<void>;
}
```
Key behaviors:
- **Lazy connection**: Servers are registered in disconnected state; connection happens on first `listTools()` or `callTool()`.
- **Transport change detection**: If `registerServer()` is called with a changed transport config, the existing connection is torn down and the client is recreated.
- **Exclusive locking**: Per-server operation locks prevent concurrent connect/disconnect races.
- **Tool caching**: `listTools()` caches results for `toolsCacheTtlMs` (default 5 seconds). Use `refreshTools()` to force a refresh.
- **Disable = disconnect**: Calling `setServerDisabled(name, true)` immediately disconnects the server.
### Layer 3: McpServerClient (Transport Layer)
`packages/core/src/extensions/mcp/client.ts` — the actual MCP protocol client.
The default factory (`createDefaultMcpServerClientFactory()`) creates `StdioMcpClient` instances:
- Spawns child processes for `stdio` transport
- Implements MCP JSON-RPC protocol (both newline-delimited and framed modes)
- Auto-negotiates protocol mode by trying newline first, then framed
- Protocol version: `2024-11-05`
- Connect timeout: 1.5s, request timeout: 5s
```typescript
interface McpServerClient {
connect(): Promise<void>;
disconnect(): Promise<void>;
listTools(): Promise<readonly McpToolDescriptor[]>;
callTool(request: { name: string; arguments?: Record<string, unknown> }): Promise<McpToolCallResult>;
}
type McpServerClientFactory = (registration: McpServerRegistration) => Promise<McpServerClient> | McpServerClient;
```
**Transport types supported**:
| Type | Status |
|---|---|
| `stdio` | ✅ Fully implemented in `StdioMcpClient` |
| `sse` | ⚠️ Type defined, but no built-in client (factory only creates `StdioMcpClient`) |
| `streamableHttp` | ⚠️ Type defined, but no built-in client |
Clients needing SSE or StreamableHTTP support must provide a custom `McpServerClientFactory`.
### Layer 4: Tool Bridge
`packages/core/src/extensions/mcp/tools.ts` via `createMcpTools()` — converts MCP server tools into the SDK's `Tool` type for use in the agent loop.
```typescript
interface CreateMcpToolsOptions {
serverName: string;
provider: McpToolProvider; // Usually the McpManager
nameTransform?: McpToolNameTransform;
timeoutMs?: number;
retryable?: boolean;
maxRetries?: number;
}
```
Default name transform: `{serverName}__{toolName}` (e.g. `docs__search`).
---
## How the Runtime Builder Uses MCP
`packages/core/src/runtime/runtime-builder.ts``loadConfiguredMcpTools()`:
1. Resolves the MCP settings file path
2. Creates a fresh `InMemoryMcpManager`
3. Calls `registerMcpServersFromSettingsFile()` to load all servers
4. Creates `Tool[]` via `createMcpTools()` for each non-disabled server
5. Returns the tools + a `shutdown()` callback that calls `manager.dispose()`
**Critical limitation**: This is done once at session build time. There is **no file watcher** that reloads MCP settings when they change during a session. If the settings file is edited mid-session, the running session won't see the changes.
---
## How Existing Apps Handle MCP Settings
### Tauri Apps (`apps/code`, `apps/desktop`)
Both Tauri apps implement MCP settings management **entirely in Rust** at the Tauri command level, bypassing the SDK's McpManager:
```rust
// apps/code/src-tauri/src/main.rs (identical pattern in apps/desktop)
fn list_mcp_servers() -> Result<McpServersResponse, String>
fn set_mcp_server_disabled(name, disabled) -> Result<McpServersResponse, String>
fn upsert_mcp_server(input) -> Result<McpServersResponse, String>
fn delete_mcp_server(name) -> Result<McpServersResponse, String>
```
These commands:
- Read/write `cline_mcp_settings.json` directly
- Return the full server list after each mutation
- Do **not** interact with any running `McpManager` instance
The frontend (`apps/code/components/views/settings/mcp-view.tsx`) calls these Tauri commands:
- `list_mcp_servers` — refresh the displayed server list
- `set_mcp_server_disabled` — toggle enable/disable
- `upsert_mcp_server` — add or edit a server
- `delete_mcp_server` — remove a server
### Node.js Host (`apps/code/host/commands.ts`)
The Code app's Node.js host also implements MCP CRUD directly:
```typescript
// Direct file reads/writes, not using McpManager
function readMcpServersResponse(): JsonRecord // reads cline_mcp_settings.json
function writeMcpServersMap(servers: JsonRecord) // writes cline_mcp_settings.json
function ensureMcpSettingsFile(): string // ensures file exists
```
Commands: `list_mcp_servers`, `set_mcp_server_disabled`, `upsert_mcp_server`, `delete_mcp_server`, `ensure_mcp_settings_file`
### CLI (`apps/cli`)
The CLI has `clite config mcp` / `clite list mcp` for listing configured MCP servers. It uses the SDK's `resolveMcpServerRegistrations()` to read the settings file.
---
## What the SDK DOES Expose (Exported from `@clinebot/core`)
### Full Type & Implementation Exports
```typescript
// Manager
export { InMemoryMcpManager } from "./extensions/mcp";
export type { McpManager, McpManagerOptions } from "./extensions/mcp";
// Client factory
export { createDefaultMcpServerClientFactory } from "./extensions/mcp";
export type { McpServerClient, McpServerClientFactory } from "./extensions/mcp";
// Config loading
export { hasMcpSettingsFile, loadMcpSettingsFile, registerMcpServersFromSettingsFile,
resolveDefaultMcpSettingsPath, resolveMcpServerRegistrations } from "./extensions/mcp";
export type { LoadMcpSettingsOptions, McpSettingsFile, RegisterMcpServersFromSettingsOptions } from "./extensions/mcp";
// Types
export type { McpServerRegistration, McpServerSnapshot, McpConnectionStatus,
McpServerTransportConfig, McpStdioTransportConfig, McpSseTransportConfig,
McpStreamableHttpTransportConfig } from "./extensions/mcp";
// Tool bridge
export { createMcpTools } from "./extensions/mcp";
export type { CreateMcpToolsOptions, McpToolCallRequest, McpToolCallResult,
McpToolDescriptor, McpToolNameTransform, McpToolProvider } from "./extensions/mcp";
// Policies
export { createDisabledMcpToolPolicies, createDisabledMcpToolPolicy } from "./extensions/mcp";
```
---
## What's Missing / The Actual Gaps
### 1. No RPC Endpoints for MCP Management
`packages/rpc/src` has **zero** MCP-related code. There are no gRPC/RPC methods for:
- Listing MCP servers
- Registering/unregistering servers
- Connecting/disconnecting servers
- Toggling server disabled state
- Refreshing tools
This means RPC-backed clients cannot manage MCP through the RPC layer.
### 2. No Settings File Watcher
The SDK has a `UnifiedConfigFileWatcher` for agents, skills, rules, and workflows — but **not for MCP settings**. When another client edits `cline_mcp_settings.json`, running sessions don't see the change.
### 3. No Live Manager Exposure to Clients
The runtime builder creates an `InMemoryMcpManager` internally during `loadConfiguredMcpTools()`, but it's encapsulated — only the resulting `Tool[]` and a `shutdown()` callback are returned. The manager itself is not exposed to the caller, so clients can't call `connectServer()`, `disconnectServer()`, etc. on a running session's MCP manager.
### 4. SSE/StreamableHTTP Client Not Implemented
The transport types are defined, but the default client factory only produces `StdioMcpClient`. Clients needing SSE or StreamableHTTP must provide their own `McpServerClientFactory`.
---
## What a Client Needs to Do Today
To implement full MCP server management UI:
### Settings CRUD (Works Now)
Read and write `cline_mcp_settings.json` directly. The SDK provides:
- `resolveDefaultMcpSettingsPath()` — find the file
- `loadMcpSettingsFile()` — parse it
- Write it yourself (it's just JSON with `{ mcpServers: { ... } }`)
This is exactly what the Tauri apps and Node.js host do today.
### Runtime Lifecycle (Partial)
For a new session, MCP tools are automatically loaded from the settings file by the runtime builder.
For mid-session changes (restart, delete, toggle), clients currently have two options:
1. **Edit the settings file and restart the session** — the next session build will pick up the changes
2. **Create and manage your own `InMemoryMcpManager`** — the SDK exports everything needed:
```typescript
const manager = new InMemoryMcpManager({
clientFactory: createDefaultMcpServerClientFactory(),
});
await manager.registerServer({ name: "docs", transport: { type: "stdio", command: "node", args: ["./mcp.js"] } });
await manager.connectServer("docs");
const tools = await manager.listTools("docs");
await manager.disconnectServer("docs");
await manager.unregisterServer("docs");
```
### Cross-Client Sync (Not Built)
If multiple clients share the same settings file, there is no notification mechanism. Clients would need their own file watcher (e.g. `fs.watch()` / `chokidar`) on `cline_mcp_settings.json`.
---
## How MCP Tools Become Visible to the Agent (and the Client)
### MCP Tools Are Injected as Regular SDK Tools
The `createMcpTools()` function converts each MCP tool descriptor into a standard `Tool` object (from `@clinebot/shared`). These tools are **indistinguishable** from built-in tools once created — they have a `name`, `description`, `inputSchema`, and an `execute` function.
```typescript
// packages/core/src/extensions/mcp/tools.ts
export async function createMcpTools(options: CreateMcpToolsOptions): Promise<Tool[]> {
const descriptors = await options.provider.listTools(options.serverName);
return descriptors.map((descriptor) => createTool({
name: nameTransform({ serverName, toolName: descriptor.name }), // e.g. "docs__search"
description: descriptor.description || `Execute MCP tool "${descriptor.name}" from server "${serverName}".`,
inputSchema: descriptor.inputSchema,
execute: async (input, context) => options.provider.callTool({
serverName, toolName: descriptor.name, arguments: input, context,
}),
}));
}
```
### The Runtime Builder Merges MCP Tools with Built-in Tools
In `DefaultRuntimeBuilder.build()` (line ~460-476):
```typescript
if (normalized.enableTools) {
tools.push(...createBuiltinToolsList(...)); // SDK built-in tools
const mcpRuntime = await loadConfiguredMcpTools(); // MCP tools
tools.push(...mcpRuntime.tools);
mcpShutdown = mcpRuntime.shutdown;
}
```
The resulting `tools: Tool[]` array — containing **both** built-in and MCP tools — is returned in the `BuiltRuntime`:
```typescript
interface BuiltRuntime {
tools: Tool[]; // ← includes MCP tools
hooks?: AgentHooks;
shutdown: (reason: string) => Promise<void> | void;
// ...
}
```
### The Agent Receives All Tools (Including MCP) Uniformly
The `Agent` (from `@clinebot/agents`) receives the merged `tools` array. It doesn't know or care which tools came from MCP vs built-in. The LLM sees all tools in its tool definitions and can call any of them.
### Client Control Over MCP Tools
Clients **can** control MCP tools through the same mechanisms they use for any tool:
1. **Tool Policies** — Enable/disable or require approval per tool name:
```typescript
toolPolicies: {
"docs__search": { enabled: true, autoApprove: true },
"docs__write": { enabled: true, autoApprove: false }, // requires approval
"risky__delete": { enabled: false }, // completely disabled
}
```
2. **MCP-specific disable policies** — The SDK provides helpers to disable all tools from a specific MCP server:
```typescript
import { createDisabledMcpToolPolicies } from "@clinebot/core";
const policies = createDisabledMcpToolPolicies({
serverName: "risky-server",
toolNames: ["delete", "modify", "drop"],
});
// → { "risky-server__delete": { enabled: false }, ... }
```
3. **CLI flags** — `--tool-enable <name>` and `--tool-disable <name>` work for MCP tools too (they operate on the transformed name like `docs__search`).
4. **Tool approval callback** — When `autoApprove: false`, the agent calls `requestToolApproval()` before executing the tool, giving the client a chance to approve/reject each call.
5. **`enableTools: false`** — Disables ALL tools including MCP.
### What Clients Can See
The `BuiltRuntime.tools` array is visible to the caller of `runtimeBuilder.build()`. The session manager and host apps can inspect it to know exactly which tools (including MCP tools) are available.
MCP tools follow the naming convention `{serverName}__{toolName}` by default, so clients can identify which tools came from which MCP server by parsing the name prefix.
---
## Remote MCP Servers (StreamableHTTP / SSE)
### The SDK's Design Intent
The SDK clearly **intends** to support remote MCP servers. The evidence:
1. **Transport types are fully defined and validated**:
```typescript
interface McpStreamableHttpTransportConfig {
type: "streamableHttp";
url: string;
headers?: Record<string, string>;
}
interface McpSseTransportConfig {
type: "sse";
url: string;
headers?: Record<string, string>;
}
```
2. **Config loader validates all three transports** — The Zod schemas accept `stdio`, `sse`, and `streamableHttp` equally. Legacy formats (`url` without explicit type) default to `sse`; `transportType: "http"` maps to `streamableHttp`.
3. **Manager is transport-agnostic** — The `McpManager` uses `McpServerClientFactory` to create clients. It doesn't care about transport type; that's the factory's job.
4. **Tests use `streamableHttp` registrations** — The manager test suite registers servers with `transport: { type: "streamableHttp", url: "https://mcp.example.test" }` and they work fine (with a mock client factory).
5. **Settings file and UI accept all transports** — Both Tauri apps and the Code app UI offer `stdio`, `sse`, and `streamableHttp` as choices.
### What's Actually Implemented vs Not
| Concern | Status |
|---|---|
| Transport type definitions | ✅ Complete |
| Settings file parsing for all transports | ✅ Complete |
| Settings file CRUD (UI/Tauri/CLI) for all transports | ✅ Complete |
| `McpManager` lifecycle for all transports | ✅ Complete (transport-agnostic) |
| `StdioMcpClient` (spawns child process) | ✅ Complete |
| HTTP/SSE client (connects to remote URL) | ❌ Not in default factory |
### The Gap for Remote Servers
The **only** thing missing is that `createDefaultMcpServerClientFactory()` returns a `StdioMcpClient` unconditionally — it doesn't check `registration.transport.type` and will fail for `sse` or `streamableHttp` transports.
A client can fix this by providing a custom factory:
```typescript
const manager = new InMemoryMcpManager({
clientFactory: async (registration) => {
if (registration.transport.type === "stdio") {
return createDefaultMcpServerClientFactory()(registration);
}
if (registration.transport.type === "streamableHttp") {
return new MyStreamableHttpMcpClient(registration);
}
if (registration.transport.type === "sse") {
return new MySseMcpClient(registration);
}
throw new Error(`Unsupported transport: ${registration.transport.type}`);
},
});
```
The client just needs to implement the `McpServerClient` interface (4 methods: `connect`, `disconnect`, `listTools`, `callTool`).
---
## Recommendation for Improvement
To close the gap, the SDK could:
1. **Add MCP settings to the config watcher system** — create an `McpConfigDefinition` for `UnifiedConfigFileWatcher` to auto-detect changes to `cline_mcp_settings.json`
2. **Expose the McpManager from the runtime builder** — return it alongside the tool list so clients can call lifecycle methods
3. **Add MCP management to the RPC layer** — implement gRPC methods that proxy to `McpManager`
4. **Implement SSE/StreamableHTTP clients** — extend the default client factory
-251
View File
@@ -1,251 +0,0 @@
# Cline SDK — Provider Credentials & OAuth Reference
This document describes how the Cline SDK publishes inference provider metadata, handles credential resolution, and orchestrates OAuth authentication flows. It is intended for client developers integrating with `@clinebot/llms` and `@clinebot/core`.
---
## Provider Catalog
The SDK owns the canonical list of inference providers. It is **not** produced by clients.
### Where Providers Are Defined
| Layer | Location | What It Owns |
|---|---|---|
| `@clinebot/llms` | `packages/llms/src/gateway/builtins.ts` | `BUILTIN_SPECS` array — every built-in provider's `id`, `name`, `description`, `family`, `capabilities`, `apiKeyEnv`, `defaultModelId`, default `baseUrl` |
| `@clinebot/llms` | `packages/llms/src/provider/ids.ts` | `BUILT_IN_PROVIDER` enum and `BUILT_IN_PROVIDER_IDS` array |
| `@clinebot/shared` | `packages/shared/src/llms/gateway.ts` | `GatewayProviderManifest` type — the runtime shape clients receive |
| `@clinebot/llms` | `packages/llms/src/gateway/provider-keys.ts` | Mapping from external `modelsDevKey` identifiers to runtime/generated provider IDs |
### BuiltinSpec Shape
Each built-in provider is declared as a `BuiltinSpec`:
```typescript
interface BuiltinSpec {
id: string; // e.g. "anthropic", "openai-native", "cline"
name: string; // Human-readable name
description: string;
family: ProviderFamily; // Protocol family: "openai-compatible", "anthropic", "google", etc.
protocol?: ProviderProtocol;
client?: ProviderClient;
capabilities?: ProviderCapability[]; // "reasoning" | "prompt-cache" | "tools" | "oauth" | "temperature" | "files"
modelsProviderId?: string;
defaultModelId?: string;
modelsFactory?: () => Record<string, ModelInfo>;
env?: readonly ("browser" | "node")[];
apiKeyEnv?: readonly string[]; // Environment variable names for API key resolution
docsUrl?: string;
defaults?: GatewayProviderSettings; // Includes default baseUrl
}
```
### GatewayProviderManifest (Runtime Shape)
`toManifest()` converts a `BuiltinSpec` into a `GatewayProviderManifest`, which is what clients interact with at runtime:
```typescript
interface GatewayProviderManifest {
id: string;
name: string;
description?: string;
defaultModelId: string;
models: readonly GatewayModelDefinition[];
env?: readonly ("browser" | "node")[];
api?: string; // Default base URL
apiKeyEnv?: readonly string[]; // Env var names for credential resolution
docsUrl?: string;
metadata?: Record<string, JsonValue | undefined>;
}
```
---
## Credential Resolution
### API Key Resolution Order
The SDK resolves credentials in `packages/llms/src/gateway/http.ts` via `resolveApiKey()`:
1. **Explicit `apiKey`** — passed directly in provider config
2. **`apiKeyResolver()`** — async callback (e.g. fetch from keychain)
3. **`apiKeyEnv`** — iterate environment variable names from the provider manifest; first non-empty value wins
If all fail, `getMissingApiKeyError()` produces a message naming the expected env vars:
> `Missing API key for provider "anthropic". Set apiKey explicitly or one of: ANTHROPIC_API_KEY.`
### Per-Provider Credential Metadata Examples
| Provider | `apiKeyEnv` |
|---|---|
| `anthropic` | `["ANTHROPIC_API_KEY"]` |
| `openai-native` | `["OPENAI_API_KEY"]` |
| `gemini` | `["GOOGLE_GENERATIVE_AI_API_KEY", "GEMINI_API_KEY"]` |
| `vertex` | `["GCP_PROJECT_ID", "GOOGLE_CLOUD_PROJECT", "GOOGLE_APPLICATION_CREDENTIALS", "GEMINI_API_KEY", "GOOGLE_API_KEY"]` |
| `bedrock` | `["AWS_REGION", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"]` |
| `sapaicore` | `["AICORE_SERVICE_KEY", "VCAP_SERVICES"]` |
| `cline` | `["CLINE_API_KEY"]` |
| `openrouter` | `["OPENROUTER_API_KEY"]` |
| `deepseek` | `["DEEPSEEK_API_KEY"]` |
Most OpenAI-compatible providers follow the pattern `["{PROVIDER}_API_KEY"]`.
### Provider-Specific Settings
Some providers need additional configuration beyond an API key:
- **Vertex/GCP**: `gcpProjectId`, `gcpRegion`
- **Bedrock/AWS**: `awsAuthentication` (`"iam" | "api-key" | "profile"`), `awsRegion`, `awsAccessKey`, `awsSecretKey`, `awsSessionToken`, `awsProfile`
These are passed through `ProviderSelectionConfig.settings` rather than `apiKeyEnv`.
---
## OAuth Authentication
### Which Providers Support OAuth
Only providers with `"oauth"` in their `capabilities` array support OAuth:
| Provider | OAuth Implementation |
|---|---|
| `cline` | `packages/core/src/auth/cline.ts` — Cline API OAuth |
| `openai-codex` | `packages/core/src/auth/codex.ts` — ChatGPT/OpenAI Codex OAuth with PKCE |
| `oca` | `packages/core/src/auth/oca.ts` — Oracle Code Assist OAuth with PKCE |
The CLI confirms this in `apps/cli/src/commands/auth.ts`:
```typescript
// Only these three providers support CLI OAuth flow
if (providerId === "cline") return oauthApi.loginClineOAuth(...)
if (providerId === "oca") return oauthApi.loginOcaOAuth(...)
if (providerId === "openai-codex") return oauthApi.loginOpenAICodex(...)
throw new Error(`Provider "${providerId}" does not support CLI OAuth flow`)
```
### Responsibility Split: SDK vs Client
| Concern | Owner | Details |
|---|---|---|
| Spawn local callback server | **SDK** | `startLocalOAuthServer()` in `packages/core/src/auth/server.ts` |
| Build authorization URL | **SDK** | Each auth module constructs the URL with redirect_uri, state, etc. |
| Open browser / present URL | **Client** | SDK calls `callbacks.onAuth({ url, instructions })` — client decides how to handle |
| Collect redirect code | **SDK** | Local HTTP server parses `?code=&state=` from redirect |
| Exchange code for tokens | **SDK** | Each auth module handles the token exchange |
| Prompt for manual code input | **Client** | SDK calls `callbacks.onPrompt()` or `callbacks.onManualCodeInput()` as fallback |
### The SDK Does NOT Open Browsers
The SDK never calls `open()` or launches a browser. It uses a callback-based interface:
```typescript
// packages/core/src/auth/types.ts
interface OAuthLoginCallbacks {
onAuth: (info: { url: string; instructions?: string }) => void; // SDK emits URL here
onPrompt: (prompt: OAuthPrompt) => Promise<string>; // SDK asks for input here
onProgress?: (message: string) => void;
onManualCodeInput?: () => Promise<string>; // Fallback if redirect fails
}
```
### The SDK DOES Spawn the Local Callback Server
`packages/core/src/auth/server.ts` exports `startLocalOAuthServer()`:
- Creates a `node:http` server on `127.0.0.1`
- Tries a list of candidate ports in order, skipping `EADDRINUSE`
- Listens on a configured callback path (e.g. `/callback`)
- Extracts `code`, `state`, `provider`, `error` from the redirect URL query params
- Returns a success HTML page to the browser ("Authentication Successful — You can close this window")
- Auto-closes after 3 seconds via embedded `<script>`
- Times out after 5 minutes by default
```typescript
interface LocalOAuthServer {
callbackUrl: string; // e.g. "http://127.0.0.1:54321/callback"
waitForCallback: () => Promise<OAuthCallbackPayload>; // Resolves when redirect arrives
cancelWait: () => void;
close: () => void;
}
```
### OAuth Redirect URLs Are NOT in Provider Metadata
Redirect/callback URLs are **dynamically constructed at runtime**, not published in the provider manifest:
- **Cline**: Dynamic port → `http://localhost:{port}/callback`
- **OpenAI Codex**: Hardcoded `http://localhost:1455/auth/callback` (fixed port, fixed client ID `app_EMoamEEZ73f0CkXaXp7hrann`)
- **OCA**: Dynamic port with configurable path, default `/oauth/callback`
### Client Integration Helper
`packages/core/src/auth/client.ts` provides a convenience adapter:
```typescript
interface OAuthClientCallbacksOptions {
onPrompt: (prompt: OAuthPrompt) => Promise<string>;
onOutput?: (message: string) => void;
openUrl?: (url: string) => void | Promise<void>; // Client provides browser-open function
onOpenUrlError?: (context: { url: string; error: unknown }) => void;
}
function createOAuthClientCallbacks(options): OAuthLoginCallbacks
```
The `openUrl` field is where a CLI passes its `open` implementation, a Tauri app passes shell open, etc.
### End-to-End OAuth Flow
```
1. Client calls SDK login function (e.g. loginClineOAuth)
2. SDK → startLocalOAuthServer() → binds to 127.0.0.1:{port}
3. SDK → builds authorization URL with redirect_uri = callback server URL
4. SDK → callbacks.onAuth({ url, instructions })
5. Client → opens browser (or displays URL to user)
6. User → authenticates in browser
7. Provider → redirects to http://127.0.0.1:{port}/callback?code=...&state=...
8. SDK's local server → captures code and state, renders success page
9. SDK → exchanges authorization code for tokens (provider-specific)
10. SDK → returns OAuthCredentials { access, refresh, expires, accountId?, email? }
```
If the local server redirect times out or fails, the SDK falls back to:
- `onManualCodeInput()` — ask user to paste code
- `onPrompt({ message: "Paste the authorization code (or full redirect URL):" })` — final fallback
- `parseAuthorizationInput()` can handle both raw codes and full URLs with query params
### OAuthCredentials Shape
```typescript
interface OAuthCredentials {
access: string; // Access token
refresh: string; // Refresh token
expires: number; // Expiration timestamp (ms since epoch)
accountId?: string; // Provider-specific account ID
email?: string; // For display/telemetry
metadata?: Record<string, unknown>;
}
```
### Provider-Specific OAuth Details
**Cline OAuth** (`packages/core/src/auth/cline.ts`):
- Authorization URL: `{apiBaseUrl}/auth/authorize?client_type=extension&callback_url=...&state=...`
- Token endpoint: `{apiBaseUrl}/auth/token`
- Default API base: `https://api.cline.bot`
- Supports provider passthrough (callback can include `?provider=google` etc.)
**OpenAI Codex OAuth** (`packages/core/src/auth/codex.ts`):
- Uses PKCE (code challenge + verifier)
- Authorization: `https://auth.openai.com/oauth/authorize`
- Token: `https://auth.openai.com/oauth/token`
- Client ID: `app_EMoamEEZ73f0CkXaXp7hrann`
- Fixed redirect: `http://localhost:1455/auth/callback`
- Scopes: `openid profile email offline_access`
- JWT claim path: `https://api.openai.com/auth`
**OCA OAuth** (`packages/core/src/auth/oca.ts`):
- Uses PKCE (S256 code challenge)
- Supports `internal` and `external` mode with separate IDCS URLs and client IDs
- Authorization: `{idcsUrl}/oauth2/v1/authorize`
- Token: `{idcsUrl}/oauth2/v1/token`
- Configurable callback ports and path
-27
View File
@@ -1,27 +0,0 @@
# Security Policy
## Supported Versions
We actively patch only the most recent minor release of Cline. Older versions receive fixes at our discretion.
## Reporting a Vulnerability
We appreciate your efforts to responsibly disclose your findings and will make every effort to acknowledge your contributions.
To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/cline/cline/security/advisories/new) tab.
The team will send a response indicating the next steps in handling your report. After the initial reply, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
When reporting, please include:
- A short summary of the issue
- Steps to reproduce or a proof of concept
- Any logs, stack traces, or screenshots that might help us understand the problem
We acknowledge reports within 48 hours and aim to release a fix or mitigation within 30 days. While we work on a resolution, please keep the details private.
## Escalation
If you do not receive an acknowledgement of your report within 5 business days, you may send an email to security@cline.bot.
Thank you for helping us keep Cline users safe.
-30
View File
@@ -1,30 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>
<json>
<![CDATA[
{
"fontFamily": "cline-bot",
"majorVersion": 1,
"minorVersion": 0,
"fontURL": "https://cline.bot",
"designerURL": "https://cline.bot",
"licenseURL": "https://cline.bot",
"version": "Version 1.0",
"fontId": "cline-bot",
"psName": "cline-bot",
"subFamily": "Regular",
"fullName": "cline-bot",
"description": "Font generated by IcoMoon."
}
]]>
</json>
</metadata>
<defs>
<font id="cline-bot" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe900;" glyph-name="cline" data-tags="cline" horiz-adv-x="977" d="M964.553 383.11l-60.285 121.406v69.495c0 115.545-92.939 209.321-207.647 209.321h-102.986c7.536 15.071 11.722 32.654 11.722 51.074 0 64.471-51.912 116.383-115.545 116.383s-115.545-51.912-115.545-116.383 4.186-35.166 11.722-51.074h-102.986c-114.708 0-207.647-93.776-207.647-209.321v-69.495l-61.959-121.406c-5.861-11.722-5.861-26.793 0-38.515l61.959-119.732v-69.495c0-115.545 92.939-209.321 207.647-209.321h415.294c114.708 0 207.647 93.776 207.647 209.321v69.495l60.285 119.732c5.861 11.722 5.861 25.956 0 38.515v0zM426.178 284.311c0-52.749-42.702-95.451-94.613-95.451s-94.613 42.702-94.613 95.451v169.132c0 52.749 42.702 95.451 94.613 95.451s94.613-42.702 94.613-95.451v-169.132zM731.787 284.311c0-52.749-42.702-95.451-94.613-95.451s-94.613 42.702-94.613 95.451v169.132c0 52.749 42.702 95.451 94.613 95.451s94.613-42.702 94.613-95.451v-169.132z" />
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.
Binary file not shown.
-12
View File
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 512 535">
<!-- Generator: Adobe Illustrator 29.8.5, SVG Export Plug-In . SVG Version: 2.1.1 Build 2) -->
<defs>
<style>
.st0 {
fill: #fff;
}
</style>
</defs>
<path class="st0" d="M500.6,300.5c-9-20.7-17.9-41.4-26.9-62.1-.7-2-.3-4.4-.3-6.4.4-9,1.1-18,1.4-27,2.8-28.4-6.5-58-25.2-79.6-15.1-18.1-36.6-30.7-59.6-35.5-8.1-1.8-16.6-1.6-25-2.1-10-.7-20-1-30-1.7,2-11.9,1-24.1-3.7-35.3-5.8-14.1-16.8-25.9-30.6-32.5-14.4-7-31.5-8.2-46.7-3.1-16,5.2-29.5,17-36.8,32.1-4.9,10-6.8,21.2-6.1,32.2-19.7-1-39.4-2.2-59.1-3.1-26.8.5-53,11.7-72,30.6-20.2,19.5-31.7,47-32.3,75-.5,9.3-1,18.7-1.5,28-.2,2.1,0,4.1-1.2,6-9.8,16.8-19.5,33.7-29.4,50.6-2.2,4.1-4.9,8-6.6,12.3-2,5.7-1.2,12.2,1.3,17.6,8.9,19.5,17.6,39.2,26.5,58.7.8,1.9,1.5,3.7,1.3,5.8-.6,10.3-1.1,20.7-1.7,31-1.5,21.2,3,42.6,13.5,61.1,8.8,15.8,21.6,29.4,37.1,38.9,13.9,8.7,29.7,13.9,46,15.4,72,3.9,144,7.7,216,11.5,20.1,1.8,40.8-2.8,58.5-12.5,18.8-10.1,34.2-26,44.1-44.9,6.5-12.6,10.5-26.4,11.7-40.5.7-12.4,1.2-24.7,2-37.1,0-3.3,1.9-5.5,3.3-8.2,6.6-11.8,13.5-23.4,20.1-35.2,3.7-6.9,8.1-13.4,11.6-20.4,3.2-6.1,3.2-13.5.3-19.7ZM218.5,316.5c-9.7,7.1-21.3,12.3-33.5,12.5-17.6,1-35.1-5.3-49-16-4.6-3.2-8.1-7.5-9.6-13,0-1.8-.7-3.6,1.7-3.8,4,1,7.9,2.6,12,3.5,22.8,5.6,47.6,5.9,71,4.8,6.5-.2,13-1.3,19.5-.9-2.7,5.6-7.1,9.2-12,12.9ZM276,449.7c-14,.5-28,.1-42-.2-2.1,0-4.3,0-6.4-.4-.9-2.1.6-3.2,1.7-4.8,4.8-5.9,11-11,18.7-12.4,8.4-1.6,16.5,1.2,23.5,5.5,4.7,3,9.2,6.3,12.6,10.8-2.6,1.1-5.3,1.4-8.1,1.4ZM390.4,319.4c-16.4,14.2-38.8,21.8-60.4,18.4-13.2-1.6-24.7-8.6-34.1-17.7-3-3-6.2-6.5-8.1-10.4.5-1,1.2-1.6,2.2-1.6,2.8-.2,5.7.7,8.5,1.1,16,2.9,32.3,4.9,48.5,5.5,14.3.4,28.2-.2,42.2-3.6,2.2-.6,3.7-.3,5.8.5-1.1,2.9-2.2,5.7-4.6,7.8Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

-3
View File
@@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.317 4.15557C18.7873 3.45369 17.147 2.93658 15.4319 2.6404C15.4007 2.63469 15.3695 2.64897 15.3534 2.67754C15.1424 3.05276 14.9087 3.54225 14.7451 3.927C12.9004 3.65083 11.0652 3.65083 9.25832 3.927C9.09465 3.5337 8.85248 3.05276 8.64057 2.67754C8.62449 2.64992 8.59328 2.63564 8.56205 2.6404C6.84791 2.93563 5.20756 3.45275 3.67693 4.15557C3.66368 4.16129 3.65233 4.17082 3.64479 4.18319C0.533392 8.83155 -0.31895 13.3657 0.0991801 17.8436C0.101072 17.8655 0.11337 17.8864 0.130398 17.8997C2.18321 19.4073 4.17171 20.3225 6.12328 20.9291C6.15451 20.9386 6.18761 20.9272 6.20748 20.9015C6.66913 20.2711 7.08064 19.6063 7.43348 18.9073C7.4543 18.8664 7.43442 18.8178 7.39186 18.8016C6.73913 18.554 6.1176 18.2521 5.51973 17.9093C5.47244 17.8816 5.46865 17.814 5.51216 17.7816C5.63797 17.6873 5.76382 17.5893 5.88396 17.4902C5.90569 17.4721 5.93598 17.4683 5.96153 17.4797C9.88928 19.273 14.1415 19.273 18.023 17.4797C18.0485 17.4674 18.0788 17.4712 18.1015 17.4893C18.2216 17.5883 18.3475 17.6873 18.4742 17.7816C18.5177 17.814 18.5149 17.8816 18.4676 17.9093C17.8697 18.2588 17.2482 18.554 16.5945 18.8006C16.552 18.8168 16.533 18.8664 16.5538 18.9073C16.9143 19.6054 17.3258 20.2701 17.7789 20.9005C17.7978 20.9272 17.8319 20.9386 17.8631 20.9291C19.8241 20.3225 21.8126 19.4073 23.8654 17.8997C23.8834 17.8864 23.8948 17.8664 23.8967 17.8445C24.3971 12.6676 23.0585 8.17064 20.3482 4.18414C20.3416 4.17082 20.3303 4.16129 20.317 4.15557ZM8.02002 15.117C6.8375 15.117 5.86313 14.0313 5.86313 12.6981C5.86313 11.3648 6.8186 10.2791 8.02002 10.2791C9.23087 10.2791 10.1958 11.3743 10.1769 12.6981C10.1769 14.0313 9.22141 15.117 8.02002 15.117ZM15.9947 15.117C14.8123 15.117 13.8379 14.0313 13.8379 12.6981C13.8379 11.3648 14.7933 10.2791 15.9947 10.2791C17.2056 10.2791 18.1705 11.3743 18.1516 12.6981C18.1516 14.0313 17.2056 15.117 15.9947 15.117Z" fill="#FAFAFA"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

-3
View File
@@ -1,3 +0,0 @@
<svg viewBox="0 0 24 24" fill="black" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2C6.477 2 2 6.477 2 12C2 16.418 4.865 20.166 8.84 21.49C9.34 21.58 9.52 21.27 9.52 21C9.52 20.77 9.51 20.14 9.51 19.31C6.73 19.91 6.14 17.97 6.14 17.97C5.68 16.81 5.03 16.5 5.03 16.5C4.12 15.88 5.1 15.9 5.1 15.9C6.1 15.97 6.63 16.93 6.63 16.93C7.5 18.45 8.97 18 9.54 17.76C9.63 17.11 9.89 16.67 10.17 16.42C7.95 16.17 5.62 15.31 5.62 11.5C5.62 10.39 6 9.5 6.65 8.79C6.55 8.54 6.2 7.5 6.75 6.15C6.75 6.15 7.59 5.88 9.5 7.17C10.29 6.95 11.15 6.84 12 6.84C12.85 6.84 13.71 6.95 14.5 7.17C16.41 5.88 17.25 6.15 17.25 6.15C17.8 7.5 17.45 8.54 17.35 8.79C18 9.5 18.38 10.39 18.38 11.5C18.38 15.32 16.04 16.16 13.81 16.41C14.17 16.72 14.5 17.33 14.5 18.26C14.5 19.6 14.49 20.68 14.49 21C14.49 21.27 14.67 21.59 15.17 21.49C19.14 20.16 22 16.42 22 12C22 6.477 17.523 2 12 2Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 902 B

-10
View File
@@ -1,10 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2001_1428)">
<path d="M22.2234 0H1.77187C0.792187 0 0 0.773438 0 1.72969V22.2656C0 23.2219 0.792187 24 1.77187 24H22.2234C23.2031 24 24 23.2219 24 22.2703V1.72969C24 0.773438 23.2031 0 22.2234 0ZM7.12031 20.4516H3.55781V8.99531H7.12031V20.4516ZM5.33906 7.43438C4.19531 7.43438 3.27188 6.51094 3.27188 5.37187C3.27188 4.23281 4.19531 3.30937 5.33906 3.30937C6.47813 3.30937 7.40156 4.23281 7.40156 5.37187C7.40156 6.50625 6.47813 7.43438 5.33906 7.43438ZM20.4516 20.4516H16.8937V14.8828C16.8937 13.5562 16.8703 11.8453 15.0422 11.8453C13.1906 11.8453 12.9094 13.2937 12.9094 14.7891V20.4516H9.35625V8.99531H12.7687V10.5609H12.8156C13.2891 9.66094 14.4516 8.70938 16.1813 8.70938C19.7859 8.70938 20.4516 11.0813 20.4516 14.1656V20.4516Z" fill="#FAFAFA"/>
</g>
<defs>
<clipPath id="clip0_2001_1428">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 989 B

-3
View File
@@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.0512 4.07466C15.3113 5.17727 16.301 5.99866 17.4829 5.99866C18.8627 5.99866 19.9813 4.87965 19.9813 3.49933C19.9813 2.11902 18.8627 1 17.4829 1C16.2764 1 15.2703 1.85537 15.036 2.99314C13.0155 3.20991 11.4378 4.92417 11.4378 7.00167C11.4378 7.00636 11.4378 7.00988 11.4378 7.01456C9.24041 7.10713 7.23397 7.73284 5.641 8.72062C5.04949 8.26247 4.30688 7.98945 3.50102 7.98945C1.5672 7.98945 0 9.55725 0 11.4918C0 12.8955 0.824597 14.1048 2.01581 14.6637C2.13177 18.7297 6.56047 22 12.0082 22C17.4559 22 21.8905 18.7261 22.0006 14.6567C23.1824 14.0942 24 12.8885 24 11.493C24 9.55842 22.4328 7.99063 20.499 7.99063C19.6966 7.99063 18.9575 8.2613 18.3672 8.71594C16.7602 7.72113 14.7315 7.09541 12.5119 7.01222C12.5119 7.0087 12.5119 7.00636 12.5119 7.00285C12.5119 5.51473 13.6176 4.27971 15.0512 4.077V4.07466ZM5.50044 13.7146C5.559 12.4444 6.40234 11.4695 7.38272 11.4695C8.3631 11.4695 9.11274 12.4995 9.05417 13.7697C8.99561 15.0398 8.26354 15.5015 7.28199 15.5015C6.30044 15.5015 5.44187 14.9848 5.50044 13.7146ZM16.6348 11.4695C17.6164 11.4695 18.4597 12.4444 18.5171 13.7146C18.5757 14.9848 17.716 15.5015 16.7356 15.5015C15.7552 15.5015 15.022 15.041 14.9634 13.7697C14.9048 12.4995 15.6533 11.4695 16.6348 11.4695ZM15.4682 16.6533C15.6521 16.6721 15.7693 16.8631 15.6978 17.0341C15.0946 18.4766 13.6703 19.4901 12.0082 19.4901C10.3461 19.4901 8.92299 18.4766 8.31859 17.0341C8.24714 16.8631 8.36427 16.6721 8.54817 16.6533C9.62577 16.5444 10.7912 16.4846 12.0082 16.4846C13.2252 16.4846 14.3895 16.5444 15.4682 16.6533Z" fill="#FAFAFA"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

-3
View File
@@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.3263 1.90393H21.6998L14.3297 10.3274L23 21.7899H16.2112L10.894 14.838L4.80995 21.7899H1.43443L9.31743 12.78L1 1.90393H7.96111L12.7674 8.25826L18.3263 1.90393ZM17.1423 19.7707H19.0116L6.94539 3.81706H4.93946L17.1423 19.7707Z" fill="#FAFAFA"/>
</svg>

Before

Width:  |  Height:  |  Size: 358 B

-203
View File
@@ -1,203 +0,0 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true,
"defaultBranch": "main"
},
"assist": {
"enabled": true,
"actions": {
"source": {
"organizeImports": "on",
"useSortedAttributes": "on"
}
}
},
"linter": {
"enabled": true,
"domains": {
"react": "recommended"
},
// Ideally we would want to turn on all the rules that are currently off,
// keeping them off currently to make sure only changes on the migrations
// are included in the initial PR before we apply the format and lint changes.
// TODO: turn on all rules that are currently off if applicable.
// TODO: Remove --diagnostic-level=error from CI commands.
"rules": {
"recommended": true,
"correctness": {
"useExhaustiveDependencies": "info",
"noUndeclaredVariables": "off",
"noEmptyPattern": "info",
"useJsxKeyInIterable": "off",
"noInnerDeclarations": "off",
"useHookAtTopLevel": "info",
"useYield": "info",
"noConstructorReturn": "off",
"noInvalidPositionAtImportRule": "off",
"noSwitchDeclarations": "off",
"noUnusedImports": "error"
},
"a11y": "info",
"style": {
"useNodejsImportProtocol": "off",
"useImportType": "off",
"useBlockStatements": "off",
"useNamingConvention": "off",
"useThrowOnlyError": "info",
"useConsistentArrayType": "off",
"noParameterAssign": "off",
"useAsConstAssertion": "off",
"useDefaultParameterLast": "off",
"noNonNullAssertion": "info",
"useEnumInitializers": "off",
"useSelfClosingElements": "info",
"useSingleVarDeclarator": "off",
"useNumberNamespace": "info",
"noInferrableTypes": "info",
"useTemplate": "info",
"noUselessElse": "info"
},
"suspicious": {
"noDoubleEquals": "warn",
"noImplicitAnyLet": "info",
"noThenProperty": "off",
"noAsyncPromiseExecutor": "info",
"noImportAssign": "off",
"noExplicitAny": "info",
"noControlCharactersInRegex": "warn",
"noShadowRestrictedNames": "off",
"noArrayIndexKey": "info",
"noAssignInExpressions": "info",
"useIterableCallbackReturn": "info"
},
"complexity": {
"noUselessConstructor": "info",
"useOptionalChain": "info",
"noBannedTypes": "warn",
"useLiteralKeys": "info",
"noUselessCatch": "info",
"noUselessSwitchCase": "info",
"noStaticOnlyClass": "info"
},
"security": {
"noDangerouslySetInnerHtml": "info"
}
}
},
"formatter": {
"enabled": true,
"indentStyle": "tab",
"indentWidth": 4,
"lineWidth": 130,
"lineEnding": "lf",
"formatWithErrors": true
},
"css": {
"parser": {
"tailwindDirectives": true
}
},
"javascript": {
"formatter": {
"semicolons": "asNeeded",
"arrowParentheses": "always",
"bracketSameLine": true,
"bracketSpacing": true,
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"trailingCommas": "all"
}
},
"json": {
"formatter": {
"trailingCommas": "none",
"expand": "always"
}
},
"files": {
"ignoreUnknown": true,
"includes": [
"**",
// explicitly force files to be ignored by the scanner with !!
"!!**/dist",
"!!**/dist-*",
"!!**/out",
"!!**/evals",
"!!**/playwright",
"!!**/test-results",
"!!**/node_modules",
"!!**/webview-ui/build",
"!!**/generated",
"!!**/proto",
"!!**/tests/specs"
]
},
"plugins": [
"src/dev/grit/process-env.grit"
],
"overrides": [
{
"includes": [
"**",
"!!**/dist",
"!!**/hosts/vscode/**",
"!!**/test/**",
"!!**/*.test.ts",
"!!src/dev/**",
"!!src/extension.ts",
"!!src/integrations/git/commit-message-generator.ts",
"!!src/integrations/terminal/**",
"!!src/core/controller/ui/openWalkthrough.ts"
],
"plugins": [
"src/dev/grit/vscode-api.grit"
]
},
{
// Do not use console logging directly, use the Logger service instead.
"plugins": [
"src/dev/grit/console-log.grit"
],
"includes": [
"**",
"!!**/esbuild.*",
"!!**/*.mts",
"!!**/webview-ui/**",
"!!**/evals/**",
"!!**/standalone/**",
"!!**/cli/**",
"!!**/e2e/**",
"!!**/test/**",
"!!**/__tests__/**",
"!!**/*.test.ts",
"!!**/*.stories.ts",
"!!src/dev/**",
"!!**/*.mjs",
"!!**/*.js",
"!!**/scripts/**",
"!!**/*.tsx",
"!!**/testing-platform/**",
// ACP mode must redirect console to stderr - this is intentional
"!!cli/src/acp/index.ts"
]
},
{
"includes": [
"**",
"!!src/core/storage/state-migrations.ts",
"!!src/core/storage/FileContextTracker.ts",
"!!src/core/context/context-tracking/FileContextTracker.ts",
"!!src/common.ts",
"!!src/services/logging/distinctId.ts",
"!!src/core/storage/utils/state-helpers.ts",
"!!src/extension.ts"
],
"plugins": [
"src/dev/grit/use-cache-service.grit"
]
}
]
}
+1
View File
@@ -9,6 +9,7 @@ lint:
except: # Add exceptions for current patterns that contradict STANDARD settings
- RPC_PASCAL_CASE # rpcs are camel case (start with lowercase)
- PACKAGE_DIRECTORY_MATCH # the protos in the cline package are not in a dir named cline.
- RPC_REQUEST_RESPONSE_UNIQUE # request messages are not unique.
- RPC_REQUEST_STANDARD_NAME # request messages dont all end with Request
- RPC_RESPONSE_STANDARD_NAME # response messages dont all end with Response
-256
View File
@@ -1,256 +0,0 @@
# cline
## [2.12.0]
### Added
- `read_file` tool now supports chunked reading for targeted file access
### Fixed
- Exclude `new_task` tool from system prompt in yolo/headless mode
### Changed
- Polish `Notification` hook functionality
## [2.9.0]
### Added
- Latency improvements for remote workspaces
## [2.8.2]
### Fixed
- Use `kanban@latest` in `cline kanban` to always fetch the newest version
## [2.8.1]
### Added
- Implement dynamic free model detection for Cline API
- Add file read deduplication cache to prevent repeated reads
- Add feature tips tooltip during thinking state
### Fixed
- Fix flaky CLI Enter-key handling across Windows/test environments
- Replace error message when not logged in to Cline
- Align ClineRulesToggleModal padding with ServersToggleModal
- Skip WebP for GLM and Devstral models running through llama.cpp
- Respect user-configured context window in LiteLLM getModel()
- Honor explicit model IDs outside static catalog in W&B provider
- Add missing Fireworks serverless models and pricing
## [2.8.0]
### Added
- Added W&B Inference by CoreWeave as a new API provider with 17 models including DeepSeek-V3.1, Llama 4, and Qwen3-Coder
- Added CLI TUI end-to-end test suite
### Fixed
- Claude Code: handle rate limit events, empty content arrays, error results, and unknown content types without crashing
- CLI: `/q` and `/exit` slash commands now execute immediately on Enter without requiring the slash menu to be visible
- CLI: slash command filtering now prioritizes exact and prefix matches over fuzzy matches
## [2.7.0]
### Added
- Added MCP add shortcuts for stdio and HTTP servers
- Added `--continue` for the current directory
- Added `--auto-condense` flag for AI-powered context compaction
- Added `--hooks-dir` flag for runtime hook injection
- Enabled error autocapture
- Prompt rules now include test verification guidance and make `CLI_RULES` language-agnostic
### Fixed
- Fixed remount behavior so TUI remounts only on width resize
- Fixed startup prompt replay on resize remount
- Fixed task flags so they are applied before the welcome TUI mounts
### Changed
- Hooks: reintroduced feature toggle
## [2.6.1]
### Added
- Added GPT-5.4 models for ChatGPT subscription users
- Hooks: Added a `Notification` hook for attention and completion boundaries
- Added `--hooks-dir` CLI flag for runtime hook injection
- Added `--auto-approve-all` CLI flag for interactive mode
### Fixed
- Handle streamable HTTP MCP reconnects more reliably
## [2.6.0]
### Added
- Hook payloads now include `model.provider` and `model.slug`
- Token/cost updates now happen immediately as usage chunks arrive, not after tool execution
### Fixed
- Improve subagent context compaction logic
- Subagent stream retry delay increased to reduce noise from transient failures
- State serialization errors are now caught and logged instead of crashing
- Removed incorrect `max_tokens` from OpenRouter requests
## [2.5.2]
### Added
- Added Windows PowerShell support for hooks (execution, resolution, and management), improving hook behavior on Windows for CLI and shared core workflows.
### Fixed
- Restored GPT-OSS native file editing for OpenAI-compatible models used through shared core tooling.
- Improved OpenRouter context overflow error handling so auto-compaction triggers correctly for wrapped 400 errors.
- Hardened checkpoint recovery by retrying nested git restore and preventing silent `.git_disabled` leftovers.
- Added a User-Agent header for requests to the Cline back-end to improve request handling consistency.
## [2.5.1]
### Added
- Expanded CLI markdown rendering support (headings, lists, blockquotes, fenced code blocks, links, and nested lists).
### Fixed
- Fixed CLI headless auth provider model metadata loading for Cline and Vercel AI Gateway by fetching model info from API with cache fallback.
- Increased flaky CLI import test timeout on Windows CI to reduce intermittent test failures.
## [2.5.0]
### Added
- Added Cline SDK API interface for programmatic access to Cline features and tools, enabling integration into custom applications.
- Added Codex 5.3 model support
### Fixed
- Fix OpenAI Codex by setting `store` to `false`
- Use `isLocatedInPath()` instead of string matching for path containment checks
## [2.4.3]
### Added
- Add /q command to quit CLI
- Fetch featured models from backend with local fallback
### Fixed
- Fix auth check for ACP mode
- Fix Cline auth with ACP flag
- Fix yolo mode to not persist yolo setting to disk
## [2.4.2]
### Added
- Gemini-3.1 Pro Preview
### Patch Changes
- VSCode uses shared files for global, workspace and secret state.
## [2.4.1]
### Fixed
- Fix infinite retry loop when write_to_file fails with missing content parameter. Provides progressive guidance to the model, escalating from suggestions to hard stops, with context window awareness to break the loop.
## [2.4.0]
### Added
- Adding Anthropic Sonnet 4.6
- Allows users to enter custom aws region when selecting bedrock as a provider in CLI
- Keep reasoning rows visible when low-stakes tool groups start immediately after reasoning.
- Restore reasoning trace visibility in chat and improve the thinking row UX so streamed reasoning is visible, then collapsible after completion.
### Fixed
- Banners now display immediately when opening the extension instead of requiring user interaction first
- Resolved 17 security vulnerabilities including high-severity DoS issues in dependencies (body-parser, axios, qs, tar, and others)
## [2.2.2]
- Allows users to enter custom aws region when selecting bedrock as a provider
- Prevent Parent Container Scrolling In Dropdowns
## [2.2.1]
- Added Minimax 2.5 Free Promo
- Fixed Response chaining for OpenAI's Responses API
## [2.2.0]
### Added
- Subagent: replace legacy subagents with the native `use_subagents` tool
- Bundle `endpoints.json` support so packaged distributions can ship required endpoints out-of-the-box
- Amazon Bedrock: support parallel tool calling
- New "double-check completion" experimental feature to verify work before marking tasks complete
- CLI: new task controls/flags including custom `--thinking` token budget and `--max-consecutive-mistakes` for yolo runs
- Remote config: new UI/options (including connection/test buttons) and support for syncing deletion of remotely configured MCP servers
- Vertex / Claude Code: add 1M context model options for Claude Opus 4.6
- ZAI/GLM: add GLM-5
### Fixed
- CLI: handle stdin redirection correctly in CI/headless environments
- CLI: preserve OAuth callback paths during auth redirects
- VS Code Web: generate auth callback URLs via `vscode.env.asExternalUri` (OAuth callback reliability)
- Terminal: surface command exit codes in results and improve long-running `execute_command` timeout behavior
- UI: add loading indicator and fix `api_req_started` rendering
- Task streaming: prevent duplicate streamed text rows after completion
- API: preserve selected Vercel model when model metadata is missing
- Telemetry: route PostHog networking through proxy-aware shared fetch and ensure telemetry flushes on shutdown
- CI: increase Windows E2E test timeout to reduce flakiness
### Changed
- Settings/model UX: move "reasoning effort" into model configuration and expose it in settings
- CLI provider selection: limit provider list to those remotely configured
- UI: consolidate ViewHeader component/styling across views
- Tools: add auto-approval support for `attempt_completion` commands
- Remotely configured MCP server schema now supports custom headers
## [2.1.0]
### Minor Changes
- 42ce100: Add Generate API Key on Hicap Provider selection
### Patch Changes
- 195294f: Add support for bundled endpoints.json in enterprise distributions. Extensions can now include a pre-configured endpoints.json file that automatically switches Cline to self-hosted mode. Includes packaging scripts for VSIX, NPM, and JetBrains plugins.
- a1f2601: Replace the LiteLLM model list with a selector
- 739d75a: Add Claude Code provider support for Claude Opus 4.6 and Sonnet 4.5 1M variants via both full model names and aliases (`opus[1m]`, `sonnet[1m]`), and align the `opus` alias with Opus 4.6.
- 8440380: Add GitHub Actions workflow to build CLI from any commit for testing
- b1a8db2: fix(cli): prevent hang when spawned without TTY
- 7c87017: Add Claude Opus 4.6 model support
- d116ac5: Supports rendering markdown table in chat view.
- 6d8fb85: Fix CLI crashing in CI environments and with stdin redirection (e.g., `cline "prompt" < /dev/null`). Now checks both stdin and stdout TTY status before using Ink, and only errors on empty stdin when no prompt is provided.
- 70a9904: Fix JetBrains sign-in regression by adding fallback for openExternal RPC
- f440f3a: fix: use vscode.env.openExternal for auth in remote environments
Fixes OAuth authentication in VS Code Server and remote environments by routing browser URL opening through VS Code's native openExternal API instead of the npm 'open' package.
- 70a9904: fix: use vscode.env.asExternalUri for auth callback URLs only in VS Code Web
Fixes OAuth callback redirect in VS Code Web (`code serve-web`, Codespaces) by using `vscode.env.asExternalUri()` to resolve the callback URI. This is gated behind a `vscode.env.uiKind === UIKind.Web` check so regular desktop VS Code continues to use the `vscode://` URI directly. The `getCallbackUrl` API now accepts a `path` parameter so the full callback URI (including route) is resolved correctly, and callers pass their path directly instead of appending after.
- 5308ded: Updating script documentation and removing unnecessary continue on error
- b514f18: Prevent duplicate streamed text rows when a partial text update arrives after the same text was already finalized.
- 26391c9: Fix Bedrock model id
- d19a877: Unify ViewHeader Styles Across All Views
- 5dcaa8c: Add Vertex Claude Opus 4.6 1M model option and global endpoint support, and pass the 1M beta header for Vertex Claude requests.
-365
View File
@@ -1,365 +0,0 @@
# Cline CLI
The official CLI for Cline. Run Cline tasks directly from the terminal with the same underlying functionality as the VS Code extension.
## Features
- **Reuses Core Codebase**: Shares the same Controller, Task, and API handling as the VS Code extension
- **Terminal Output**: Displays Cline messages directly in your terminal with colored output
- **Task History**: Access your task history from the command line
- **Configurable**: Use custom configuration directories and working directories
- **Image Support**: Attach images to your prompts using file paths or inline references
## Prerequisites
- Node.js 20.x or later
- npm or yarn
- The parent Cline project dependencies installed
## Installation
From the repository root:
```bash
# Install all dependencies first
npm run install:all
# Ensure protos are generated
npm run protos
# Build and link the CLI globally
npm run cli:link
```
## Usage
### Interactive Mode (Default)
When you run `cline` without any command, it launches an interactive welcome prompt:
```bash
# Launch interactive mode
cline
# Or run a task directly
cline "Create a hello world function in Python"
# With options
cline -v --thinking "Analyze this codebase"
```
### Commands
#### `task` (alias: `t`)
Run a new task with a prompt.
```bash
cline task "Create a hello world function in Python"
cline t "Create a hello world function"
```
**Options:**
| Option | Description |
|--------|-------------|
| `-a, --act` | Run in act mode |
| `-p, --plan` | Run in plan mode |
| `-y, --yolo` | Enable yolo mode (auto-approve actions) |
| `-m, --model <model>` | Model to use for the task |
| `-i, --images <paths...>` | Image file paths to include with the task |
| `-v, --verbose` | Show verbose output including reasoning |
| `-c, --cwd <path>` | Working directory for the task |
| `--config <path>` | Path to Cline configuration directory |
| `-t, --thinking` | Enable extended thinking (1024 token budget) |
**Examples:**
```bash
# Run in plan mode with verbose output
cline task -p -v "Design a REST API"
# Use a specific model with yolo mode
cline task -m claude-sonnet-4-5-20250929 -y "Refactor this function"
# Include images with your prompt
cline task -i screenshot.png diagram.jpg "Fix the UI based on these images"
# Or use inline image references in the prompt
cline task "Fix the layout shown in @./screenshot.png"
# Enable extended thinking for complex tasks
cline task -t "Architect a microservices system"
# Specify working directory
cline task -c /path/to/project "Add unit tests"
```
#### `history` (alias: `h`)
List task history with pagination support.
```bash
cline history
cline h
```
**Options:**
| Option | Description |
|--------|-------------|
| `-n, --limit <number>` | Number of tasks to show (default: 10) |
| `-p, --page <number>` | Page number, 1-based (default: 1) |
| `--config <path>` | Path to Cline configuration directory |
**Examples:**
```bash
# Show last 10 tasks (default)
cline history
# Show 20 tasks
cline history -n 20
# Show page 2 with 5 tasks per page
cline history -n 5 -p 2
```
#### `config`
Show current configuration including global and workspace state.
```bash
cline config
```
**Options:**
| Option | Description |
|--------|-------------|
| `--config <path>` | Path to Cline configuration directory |
#### `auth`
Authenticate a provider and configure what model is used.
```bash
cline auth
```
**Options:**
| Option | Description |
|--------|-------------|
| `-p, --provider <id>` | Provider ID for quick setup (e.g., openai-native, anthropic) |
| `-k, --apikey <key>` | API key for the provider |
| `-m, --modelid <id>` | Model ID to configure (e.g., gpt-4o, claude-sonnet-4-5-20250929) |
| `-b, --baseurl <url>` | Base URL (optional, only for openai provider) |
| `-v, --verbose` | Show verbose output |
| `-c, --cwd <path>` | Working directory for the task |
| `--config <path>` | Path to Cline configuration directory |
**Examples:**
```bash
# Interactive authentication
cline auth
# Quick setup with provider and API key
cline auth -p anthropic -k sk-ant-xxxxx
# Full quick setup with model
cline auth -p openai-native -k sk-xxxxx -m gpt-4o
# OpenAI-compatible provider with custom base URL
cline auth -p openai -k your-api-key -b https://api.example.com/v1
```
### Global Options
These options are available for the default command (running a task directly):
| Option | Description |
|--------|-------------|
| `-v, --verbose` | Show verbose output |
| `-c, --cwd <path>` | Working directory |
| `--config <path>` | Configuration directory |
| `--thinking` | Enable extended thinking (1024 token budget) |
## Development
### Quick Start
```bash
# 1. Install all dependencies (root, webview-ui, cli)
npm run install:all
# 2. Build and link globally so you can run `cline` from anywhere
npm run cli:link
# 3. Test it
cline --help
```
### Scripts
Run these from the repository root:
| Script | Description |
|--------|-------------|
| `npm run install:all` | Install deps for root, webview-ui, and cli |
| `npm run cli:build` | Generate protos and build CLI |
| `npm run cli:build:production` | Production build (minified) |
| `npm run cli:link` | Build and `npm link` so you can run `cline` from anywhere |
| `npm run cli:unlink` | Remove the global `cline` symlink |
| `npm run cli:dev` | Link + watch mode for development |
| `npm run cli:watch` | Watch mode only (no initial build) |
| `npm run cli:test` | Run CLI tests |
### Development Workflow
1. Run `npm run cli:dev` - this links the CLI globally and starts watch mode
2. Make changes to files in `cli/src/`
3. The build automatically rebuilds on save
4. Test your changes by running `cline` in another terminal
5. When done, run `npm run cli:unlink` to clean up
### Proto Generation
The CLI uses proto-generated types for message passing (same as the VS Code extension). If you modify any `.proto` files, run:
```bash
npm run protos
```
This generates TypeScript types in `src/generated/` that both the CLI and extension use.
## Publish
#### 1. Publish to npm
```bash
npm publish
```
#### 2. Update the Homebrew formula
```bash
npm run update-brew-formula
```
#### 3. Test the formula locally
```bash
# Create a local tap
brew tap-new cline/local
cp ./cli/cline.rb "$(brew --repository)/Library/Taps/cline/homebrew-local/Formula/cline.rb"
# Build from Source
brew install --build-from-source cline/local/cline
# Install from your local tap
brew install cline/local/cline
# Clean up when done
brew untap cline/local
```
#### 4. If using a tap, commit and push
```bash
git add cline.rb
git commit -m "Update cline to v2.0.0"
git push
```
## Architecture
### How It Works
The CLI directly imports and reuses the core Cline TypeScript codebase (the same code that powers the VS Code extension). This means feature parity is easy to maintain - when core gets updated, the CLI automatically benefits.
```
┌─────────────────────────────────────────────────────────┐
│ CLI (cli/) │
│ - React Ink terminal UI │
│ - Command parsing (commander) │
│ - Terminal-specific adapters │
└─────────────────────────────────────────────────────────┘
│ direct imports
┌─────────────────────────────────────────────────────────┐
│ Core (src/core/) │
│ - Controller: task lifecycle, state management │
│ - Task: AI API calls, tool execution │
│ - StateManager: persistent storage │
│ - Proto types: message definitions │
└─────────────────────────────────────────────────────────┘
```
Unlike a client-server architecture, the CLI runs everything in a single Node.js process. The "host bridge" pattern provides terminal-appropriate implementations for things the VS Code extension would handle differently (clipboard, file dialogs, etc.).
### Key Files
| File | Purpose |
|------|---------|
| `src/index.ts` | Entry point, command definitions |
| `src/components/App.tsx` | Main React Ink app |
| `src/components/ChatView.tsx` | Task conversation UI |
| `src/controllers/CliWebviewProvider.ts` | Bridges core messages to terminal output |
| `src/vscode-context.ts` | Mock VS Code extension context for core compatibility |
| `src/vscode-shim.ts` | Shims for VS Code APIs that core depends on |
| `src/constants/colors.ts` | Terminal color definitions |
### React Ink
The CLI uses [React Ink](https://github.com/vadimdemedes/ink) for its terminal UI. This lets us build the interface with React components that render to the terminal. Key patterns:
- Components in `src/components/` render terminal UI
- Hooks in `src/hooks/` manage terminal-specific state (size, scrolling)
- The `useStateSubscriber` hook subscribes to core state changes
## Configuration
The CLI stores its data in `~/.cline/data/` by default:
- `globalState.json`: Global settings and state
- `secrets.json`: API keys and secrets
- `workspace/`: Workspace-specific state
- `tasks/`: Task history and conversation data
Override with the `--config` option or `CLINE_DIR` environment variable.
## Troubleshooting
### Build Errors
If you encounter build errors:
```bash
# Make sure all deps are installed
npm run install:all
# Regenerate proto types
npm run protos
# Then rebuild
npm run cli:build
```
### "command not found: cline"
The CLI isn't linked globally. Run:
```bash
npm run cli:link
```
### Changes Not Reflected
If your code changes aren't showing up:
1. Make sure watch mode is running (`npm run cli:dev`)
2. Check for TypeScript errors in the watch output
3. Try unlinking and relinking: `npm run cli:unlink && npm run cli:link`
### Import Errors from Core
The CLI imports from `@core/`, `@shared/`, etc. These paths are defined in the root `tsconfig.json`. If you see import errors, make sure you're building from the repo root, not from inside `cli/`.
-81
View File
@@ -1,81 +0,0 @@
# Cline
<p align="center">
<img src="https://github.com/user-attachments/assets/7123f9d1-afeb-48d5-93fa-e750dec0ebba" width="70%" />
</p>
<div align="center">
<table>
<tbody>
<td align="center">
<a href="https://www.npmjs.com/package/cline" target="_blank"><strong>NPM</strong></a>
</td>
<td align="center">
<a href="https://discord.gg/cline" target="_blank"><strong>Discord</strong></a>
</td>
<td align="center">
<a href="https://www.reddit.com/r/cline/" target="_blank"><strong>r/cline</strong></a>
</td>
<td align="center">
<a href="https://github.com/cline/cline/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop" target="_blank"><strong>Feature Requests</strong></a>
</td>
<td align="center">
<a href="https://docs.cline.bot/getting-started/for-new-coders" target="_blank"><strong>Getting Started</strong></a>
</td>
</tbody>
</table>
</div>
Meet Cline, an AI assistant that lives in your terminal.
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.
```bash
npm i -g cline
# cd into your project and run:
cline
```
> Move your mouse around under the Cline icon for a surprise!
---
<img align="right" width="340" src="https://github.com/user-attachments/assets/ceb74224-08aa-4b8b-a3e7-b438ac3d160a">
### Use any API and Model
Cline supports API providers like ChatGPT, Anthropic, OpenAI, Google Gemini, AWS Bedrock, Azure, GCP Vertex, Cerebras, Groq, and Moonshot. You can also configure any OpenAI compatible API, or use a local model through LM Studio/Ollama. If you're using a Cline Account, you'll always have access to the newest models as soon as they're available.
<!-- Transparent pixel to create line break after floating image -->
<img width="2000" height="0" src="https://github.com/user-attachments/assets/ee14e6f7-20b8-4391-9091-8e8e25561929"><br>
<img align="left" width="370" src="https://github.com/user-attachments/assets/cad091f6-6c0f-4e4b-97ea-a1ff67e39b9b">
### Stay in Control with Human-in-the-Loop
Cline asks for your approval before running commands, editing files, or taking any action. Review each step and approve or reject as you go—or enable auto-approve to let Cline work autonomously to completion.
<!-- Transparent pixel to create line break after floating image -->
<img width="2000" height="0" src="https://github.com/user-attachments/assets/cad091f6-6c0f-4e4b-97ea-a1ff67e39b9b"><br>
<img align="right" width="400" src="https://github.com/user-attachments/assets/4f264a0c-3802-49a7-8e5e-13d97beb659e">
### Plan & Act Modes
Toggle to Plan Mode to discuss implementation and architecture with Cline. He'll ask clarifying questions, explore your codebase, and present a plan for you to align on. Once you're satisfied, switch to Act Mode and let Cline execute the plan.
<!-- Transparent pixel to create line break after floating image -->
<img width="2000" height="0" src="https://github.com/user-attachments/assets/4f264a0c-3802-49a7-8e5e-13d97beb659e"><br>
## Enterprise
Get the same Cline experience with enterprise-grade controls: SSO (SAML/OIDC), global policies and configuration, observability with audit trails, private networking (VPC/private link), and self-hosted or on-prem deployments, and enterprise support. Learn more at our [enterprise page](https://cline.bot/enterprise) or [talk to us](https://cline.bot/contact-sales).
## License
[Apache 2.0 © 2026 Cline Bot Inc.](./LICENSE)
-21
View File
@@ -1,21 +0,0 @@
# IMPORTANT: `npm run postpublish` to update this file after publishing a new version of the package
class Cline < Formula
desc "Autonomous coding agent CLI - capable of creating/editing files, running commands, and more"
homepage "https://cline.bot"
url "https://registry.npmjs.org/cline/-/cline-2.0.0.tgz" # GET from https://registry.npmjs.org/cline/latest tarball URL
sha256 "65bae90401191aeeabfbbc0b315e816aea96742043ba85b90671bf5e19d0761e"
license "Apache-2.0"
depends_on "node@20"
depends_on "ripgrep"
def install
system "npm", "install", *std_npm_args(prefix: false)
bin.install_symlink Dir["#{libexec}/bin/*"]
end
test do
# Test that the binary exists and is executable
assert_match version.to_s, shell_output("#{bin}/cline --version")
end
end

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