RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Diff/cline-cline-clinerules-general ↔ cline-cline-clinerules-network

Comparison

A · Cline rules · cline/clineB · Cline rules · cline/cline
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections0970%
Commands0800%
Section tags15213%

What each file covers

Sections

0 shared · 9 only in A · 7 only in B
  • − Miscellaneous
  • − Searching the Codebase — Avoiding Build Output
  • − How to skip build output
  • − When you must search minified files
  • − gRPC/Protobuf Communication
  • − Adding New Global State Keys
  • − StateManager Cache vs Direct globalState Access
  • − ChatRow Cancelled/Interrupted States
  • − Debug Harness: clear inherited VSCode/Electron env vars before launching
  • + Networking & Proxy Support
  • + Guidelines
  • + 1. Using `fetch`
  • + 2. Using `axios`
  • + 3. Third-Party Clients (OpenAI, Ollama, etc.)
  • + 4. Tests
  • + Verification

Commands

0 shared · 8 only in A · 0 only in B
  • − bun src/dev/debug-harness/server.ts --auto-launch --skip-build
  • − bun run X
  • − bun install
  • − bunx <bin>
  • − bun file.ts
  • − bun run compile
  • − bun run build
  • − bun run protos

Section tags

1 shared · 5 only in A · 2 only in B
  • − setup
  • − build
  • − architecture
  • − security
  • − deployment
  • + testing-strategy
  • + dependencies
  •   code-style

Line diff

+58 added−173 removed33 unchanged16.0% identical
cline/cline · .clinerules/general.md
@@ −1 @@
1This 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.
2 
3**When to add to this file:**
4- User had to intervene, correct, or hand-hold
5- Multiple back-and-forth attempts were needed to get something working
6- You discovered something that required reading many files to understand
7- A change touched files you wouldn't have guessed
8- Something worked differently than you expected
9- User explicitly asks to "add this to CLAUDE.md"
10 
11**Proactively suggest additions** when any of the above happen—don't wait to be asked.
12 
13**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.
14 
15## Miscellaneous
16- The whole repo (including `apps/vscode`) uses **bun** for package management and task running. Emit `bun run X` / `bun install` / `bunx <bin>` / `bun file.ts`, never npm/npx. Node remains the *runtime* (VS Code's extension host and the standalone cline-core are Node), so Node-runtime tokens are legitimate and must not be "fixed" to bun — see @.clinerules/bun-and-node.md for the keep-list vs rewrite-list.
17- Avoid provider-specific string matching / hardcoded provider branches when fixing provider/config plumbing. Prefer provider metadata, shared catalog/defaults, explicit protocol/client capabilities, or centralized normalization utilities that apply by data shape rather than `providerId === "..."`. If a provider exception seems necessary, stop and explain why instead of adding ad-hoc string matching.
18- This is a VS Code extension—check `package.json` for available scripts before trying to verify builds (e.g., `bun run compile`, not `bun run build`).
19- When reading a configuration files that users may edit, use `readFileStrippingUtf8Bom`, `readFileSyncStrippingUtf8Bom`, or `stripUtf8Bom` from `@cline/shared/node`. DON'T strip byte order marks of user files handled by tools/passed to models.
20- When creating PRs, contributors should not create changelog-entry files. Maintainers handle release versioning and changelog curation during the release process.
21- When adding new feature flags, see this PR as a reference https://github.com/cline/cline/pull/7566
22- Additional instructions about making requests: @.clinerules/network.md
23 
24## Searching the Codebase — Avoiding Build Output
25 
26Several directories contain build output or generated code that produces
27noisy or unusable results with `search_files` / `grep`:
28 
29| Directory | What it is | Why it's a problem |
30|-----------|-----------|-------------------|
31| `out/` | esbuild bundle output | Mirrors `src/` structure as minified JS — every search gets duplicate hits on single-line files |
32| `dist/` | Packaged extension | Entire extension bundled into one minified `extension.js` (~1 long line) |
33| `dist-standalone/` | Standalone build output | Same minification issue |
34| `src/generated/` | Generated protobuf code | Auto-generated from `proto/`; not the source of truth |
35| `src/shared/proto/` | Generated proto type defs | Auto-generated from `proto/`; not the source of truth |
36| `node_modules/` | Dependencies | Huge, not project source |
37 
38### How to skip build output
39 
40**`search_files`** — Point at `src/` (not the project root) and use `file_pattern`:
41```
42search_files(path="src/core", regex="myFunction", file_pattern="*.ts")
43```
44The `file_pattern` parameter is the most effective filter — e.g. `"*.ts"`,
45`"*.tsx"`, `"*.proto"`.
46 
47**`grep` directly** — Exclude build dirs and restrict to source extensions:
48```bash
49grep -rn "myFunction" src/ --include="*.ts" --exclude-dir={out,dist,node_modules,generated}
50```
51 
52### When you must search minified files
53 
54Sometimes you need to verify what got bundled (e.g., checking if a change
55made it into the build). Minified files are typically one long line, so
56normal `grep` shows the entire file as context. Use these approaches:
57 
58- **`grep -oP`** to extract just the match with limited surrounding context:
59 ```bash
60 grep -oP '.{0,40}myFunction.{0,40}' dist/extension.js
61 ```
62- **`read_file`** on files in `out/src/` — these have source maps and are
63 more readable than `dist/extension.js` (which is the fully bundled output).
64- **Source maps** — `out/src/*.js.map` and `dist/extension.js.map` can be
65 used to trace minified output back to original source locations.
66 
67## gRPC/Protobuf Communication
68The extension and webview communicate via gRPC-like protocol over VS Code message passing.
69 
70**Proto files live in `proto/`** (e.g., `proto/cline/task.proto`, `proto/cline/ui.proto`)
71- Each feature domain has its own `.proto` file
72- For simple data, use shared types in `proto/cline/common.proto` (`StringRequest`, `Empty`, `Int64Request`)
73- For complex data, define custom messages in the feature's `.proto` file
74- Naming: Services `PascalCaseService`, RPCs `camelCase`, Messages `PascalCase`
75- For streaming responses, use `stream` keyword (see `subscribeToAuthCallback` in `account.proto`)
76 
77**Run `bun run protos`** after any proto changes—generates types in:
78- `src/shared/proto/` - Shared type definitions
79- `src/generated/grpc-js/` - Service implementations
80- `src/generated/nice-grpc/` - Promise-based clients
81- `src/generated/hosts/` - Generated handlers
82 
83**Adding new enum values** (like a new `ClineSay` type) requires updating conversion mappings in `src/shared/proto-conversions/cline-message.ts`
84 
85**Adding new RPC methods** requires:
86- Handler in `src/core/controller/<domain>/`
87- Call from webview via generated client: `UiServiceClient.scrollToSettings(StringRequest.create({ value: "browser" }))`
88 
89**Example—the `explain-changes` feature touched:**
90- `proto/cline/task.proto` - Added `ExplainChangesRequest` message and `explainChanges` RPC
91- `proto/cline/ui.proto` - Added `GENERATE_EXPLANATION = 29` to `ClineSay` enum
92- `src/shared/ExtensionMessage.ts` - Added `ClineSayGenerateExplanation` type
93- `src/shared/proto-conversions/cline-message.ts` - Added mapping for new say type
94- `src/core/controller/task/explainChanges.ts` - Handler implementation
95- `webview-ui/src/components/chat/ChatRow.tsx` - UI rendering
96 
97## Adding New Global State Keys
98Adding a new key to global state requires updates in multiple places. Missing any step causes silent failures.
99 
100Required steps:
1011. Type definition in `src/shared/storage/state-keys.ts` - Add to `GlobalState` or `Settings` interface
1022. Add any default value or transform in `src/shared/storage/state-keys.ts` if the key needs one
1033. Read and write the value through `StateManager` (`setGlobalState()` / `getGlobalStateKey()`) after initialization
104 
105Persistent state is file-backed through `StateManager`; do not add new runtime reads or writes against VS Code `ExtensionContext` storage. That storage is only a legacy migration source.
106 
107Settings plumbing gotcha: if a key is user-toggleable from settings, wire both controller update paths:
108- `src/core/controller/state/updateSettings.ts` for webview `updateSetting(...)`
109- `src/core/controller/state/updateSettingsCli.ts` for CLI/ACP settings updates
110Missing one path causes a toggle to appear to change in one surface while the backend state stays unchanged.
111 
112Webview toggle gotcha: settings changes must also round-trip back in state payloads.
113- Add the field to `UpdateSettingsRequest` in `proto/cline/state.proto` (for webview update requests), then run `bun run protos`
114- Include the key in `Controller.getStateToPostToWebview()` (`src/core/controller/index.ts`)
115- Ensure `ExtensionState` and webview defaults include the key (`src/shared/ExtensionMessage.ts`, `webview-ui/src/context/ExtensionStateContext.tsx`)
116If this round-trip wiring is missing, the backend value can update but the toggle in webview appears stuck or reverts.
117 
118## StateManager Cache vs Direct globalState Access
119StateManager uses an in-memory cache populated during `StateManager.initialize()` from file-backed storage. For most state, use `controller.stateManager.setGlobalState()`/`getGlobalStateKey()`.
120 
121Exception: host migration code may read legacy VS Code storage before file-backed storage is initialized.
122 
123Example pattern:
124```typescript
125// Writing (normal pattern)
126controller.stateManager.setGlobalState("myKey", value)
127 
128// Reading after initialization
129const value = controller.stateManager.getGlobalStateKey("myKey")
 
 
130```
131 
132Use `context.globalState` only in VS Code migration code that copies legacy ExtensionContext values into the shared file-backed stores.
133 
134## ChatRow Cancelled/Interrupted States
135When 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.
136 
137**The pattern:**
1381. A message has a `status` field (e.g., `"generating"`, `"complete"`, `"error"`) stored in `message.text` as JSON
1392. When cancelled mid-operation, the status stays `"generating"` forever—no one updates it
1403. To detect cancellation, check TWO conditions:
141 - `!isLast` — if this message is no longer the last message, something else happened after it (interrupted)
142 - `lastModifiedMessage?.ask === "resume_task" || "resume_completed_task"` — task was just cancelled and is waiting to resume
143 
144**Example from `generate_explanation`:**
145```tsx
146const wasCancelled =
147 explanationInfo.status === "generating" &&
148 (!isLast ||
149 lastModifiedMessage?.ask === "resume_task" ||
150 lastModifiedMessage?.ask === "resume_completed_task")
151const isGenerating = explanationInfo.status === "generating" && !wasCancelled
152```
 
153 
154**Why both checks?**
155- `!isLast` catches: cancelled → resumed → did other stuff → this old message is stale
156- `lastModifiedMessage?.ask === "resume_task"` catches: just cancelled, hasn't resumed yet, this message is still technically "last"
 
 
 
 
 
157 
158**See also:** `BrowserSessionRow.tsx` uses similar pattern with `isLastApiReqInterrupted` and `isLastMessageResume`.
159 
160**Backend side:** When streaming is cancelled, clean up properly (close tabs, clear comments, etc.) by checking `taskState.abort` after the streaming function returns.
161 
162## Debug Harness: clear inherited VSCode/Electron env vars before launching
163 
164The debug harness (`apps/vscode/src/dev/debug-harness/server.ts`) launches a child
165VSCode via Playwright's `_electron.launch({ env: { ...process.env, ... } })`. If you
166run the harness from a process that was itself spawned by VSCode (e.g. the Cline
167extension host, an integrated terminal, or an agent running inside VSCode), the
168parent's VSCode/Electron env vars leak into the child and break the launch.
169 
170The fatal one is **`ELECTRON_RUN_AS_NODE=1`**: it makes the child VSCode binary run
171as plain Node, so it rejects every VSCode CLI flag. Symptom:
172 
173```
174.../Visual Studio Code.app/Contents/MacOS/Code: bad option: --extensionDevelopmentPath=...
175Error: Process failed to launch! (Playwright _electron.launch)
176```
177 
178This is NOT the macOS Playwright flakiness mentioned in the harness README — it's
179env inheritance. Fix: strip the inherited vars before starting the harness:
180 
181```bash
182env -u ELECTRON_RUN_AS_NODE -u ELECTRON_NO_ATTACH_CONSOLE \
183 -u VSCODE_CLI -u VSCODE_CODE_CACHE_PATH -u VSCODE_CRASH_REPORTER_PROCESS_TYPE \
184 -u VSCODE_CWD -u VSCODE_ESM_ENTRYPOINT -u VSCODE_HANDLES_UNCAUGHT_ERRORS \
185 -u VSCODE_IPC_HOOK -u VSCODE_NLS_CONFIG -u VSCODE_PID -u VSCODE_L10N_BUNDLE_LOCATION \
186 bun src/dev/debug-harness/server.ts --auto-launch --skip-build
187```
188 
189Check your own env with `env | grep -iE 'electron|vscode_'` first; `ELECTRON_RUN_AS_NODE=1`
190present means you must scrub before launching.
191 
192Other harness notes confirmed in practice:
193- The extension host is **ESM** (`VSCODE_ESM_ENTRYPOINT`), so `ext.evaluate` has no
194 `require` and module-internal functions aren't reachable as globals. To inspect
195 internal builders (e.g. `buildBedrockProviderConfig`), set a breakpoint with
196 `ext.set_breakpoint` and read locals via `ext.evaluate` with the paused `callFrameId`
197 — don't try to `require()` the bundle.
198- `web.evaluate` wraps the expression as a single returned expression; multi-statement
199 snippets must be an IIFE `(() => { ...; return x; })()`, otherwise you get
200 `SyntaxError: Unexpected token ';'`.
201- Webview settings inputs are `vscode-text-field` web components with debounced React
202 onChange. Setting `.value` + dispatching events via `web.evaluate` is unreliable for
203 some fields; focus the inner shadow `input` then use real keystrokes (`ui.type` +
204 `ui.press Tab`, or click the dropdown option) to make the value persist.
205 
206 
cline/cline · .clinerules/network.md
@@ +1 @@
1# Networking & Proxy Support
2 
3To 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.
 
 
 
 
 
 
4 
5In 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`.
6 
7Global `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.
8 
9## Guidelines
 
 
 
 
 
 
 
10 
11### 1. Using `fetch`
12 
13Instead of `fetch(...)`, import the proxy-aware wrapper:
 
14 
15```typescript
16import { fetch } from '@/shared/net'
 
 
 
 
 
 
17 
18// Usage is identical to global fetch
19const response = await fetch('https://api.example.com/data')
 
20```
 
 
 
 
21 
22### 2. Using `axios`
 
 
 
23 
24When using `axios`, you must apply the settings from `getAxiosSettings()`:
25 
26```typescript
27import axios from 'axios'
28import { getAxiosSettings } from '@/shared/net'
29 
30const response = await axios.get('https://api.example.com/data', {
31 headers: { 'Authorization': '...' },
32 ...getAxiosSettings() // <--- CRITICAL: Injects the proxy agent if needed
33})
34```
 
 
 
35 
36### 3. Third-Party Clients (OpenAI, Ollama, etc.)
 
37 
38Most API client libraries allow you to customize the `fetch` implementation. You **MUST** pass the proxy-aware `fetch` to these clients.
 
 
 
 
 
39 
40**Example (OpenAI):**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41```typescript
42import OpenAI from "openai"
43import { fetch } from "@/shared/net"
44 
45this.client = new OpenAI({
46 apiKey: '...',
47 fetch, // <--- CRITICAL: Pass our fetch wrapper
48})
49```
50 
51### 4. Tests
52 
53Use `mockFetchForTesting` to mock the underlying fetch implementation.
 
54 
55**Example (callback):**
 
 
 
 
 
56 
 
 
 
 
 
 
 
 
57```
58import { mockFetchForTesting } from "@/shared/net"
59 
60...
61 let mockFetch = ...
62 mockFetchForTesting(mockFetch, () => {
63 // This calls mockFetch
64 fetch('https://foo.example').then(...)
65 })
66 // Original fetch is restored immediately when the call returns.
67```
68 
69**Example (Promise):**
70 
 
 
 
 
 
 
 
 
 
 
 
 
 
71```
72import { mockFetchForTesting } from "@/shared/net"
 
 
73 
74...
75 let mockFetch = ...
76 await mockFetchForTesting(mockFetch, async () => {
77 await ...
78 // This calls mockFetch
79 await fetch('https://foo.example')
80 ...
81 })
82 // Original fetch is restored when the Promise from the callback settles
83```
84 
85## Verification
 
86 
87If you are adding a new network call or integration:
881. Check `@/shared/net.ts` is imported.
892. Ensure `fetch` or `getAxiosSettings` is being used.
903. Verify that third-party clients are configured to use the custom fetch.
 
 
 
 
 
 
 
 
 
 
91 
@@ −1 +1 @@
1−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.
1+# Networking & Proxy Support
22  
3−**When to add to this file:**
4−- User had to intervene, correct, or hand-hold
5−- Multiple back-and-forth attempts were needed to get something working
6−- You discovered something that required reading many files to understand
7−- A change touched files you wouldn't have guessed
8−- Something worked differently than you expected
9−- User explicitly asks to "add this to CLAUDE.md"
3+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.
104  
11−**Proactively suggest additions** when any of the above happen—don't wait to be asked.
5+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`.
126  
13−**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.
7+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.
148  
15−## Miscellaneous
16−- The whole repo (including `apps/vscode`) uses **bun** for package management and task running. Emit `bun run X` / `bun install` / `bunx <bin>` / `bun file.ts`, never npm/npx. Node remains the *runtime* (VS Code's extension host and the standalone cline-core are Node), so Node-runtime tokens are legitimate and must not be "fixed" to bun — see @.clinerules/bun-and-node.md for the keep-list vs rewrite-list.
17−- Avoid provider-specific string matching / hardcoded provider branches when fixing provider/config plumbing. Prefer provider metadata, shared catalog/defaults, explicit protocol/client capabilities, or centralized normalization utilities that apply by data shape rather than `providerId === "..."`. If a provider exception seems necessary, stop and explain why instead of adding ad-hoc string matching.
18−- This is a VS Code extension—check `package.json` for available scripts before trying to verify builds (e.g., `bun run compile`, not `bun run build`).
19−- When reading a configuration files that users may edit, use `readFileStrippingUtf8Bom`, `readFileSyncStrippingUtf8Bom`, or `stripUtf8Bom` from `@cline/shared/node`. DON'T strip byte order marks of user files handled by tools/passed to models.
20−- When creating PRs, contributors should not create changelog-entry files. Maintainers handle release versioning and changelog curation during the release process.
21−- When adding new feature flags, see this PR as a reference https://github.com/cline/cline/pull/7566
22−- Additional instructions about making requests: @.clinerules/network.md
9+## Guidelines
2310  
24−## Searching the Codebase — Avoiding Build Output
11+### 1. Using `fetch`
2512  
26−Several directories contain build output or generated code that produces
27−noisy or unusable results with `search_files` / `grep`:
13+Instead of `fetch(...)`, import the proxy-aware wrapper:
2814  
29−| Directory | What it is | Why it's a problem |
30−|-----------|-----------|-------------------|
31−| `out/` | esbuild bundle output | Mirrors `src/` structure as minified JS — every search gets duplicate hits on single-line files |
32−| `dist/` | Packaged extension | Entire extension bundled into one minified `extension.js` (~1 long line) |
33−| `dist-standalone/` | Standalone build output | Same minification issue |
34−| `src/generated/` | Generated protobuf code | Auto-generated from `proto/`; not the source of truth |
35−| `src/shared/proto/` | Generated proto type defs | Auto-generated from `proto/`; not the source of truth |
36−| `node_modules/` | Dependencies | Huge, not project source |
15+```typescript
16+import { fetch } from '@/shared/net'
3717  
38−### How to skip build output
39− 
40−**`search_files`** — Point at `src/` (not the project root) and use `file_pattern`:
18+// Usage is identical to global fetch
19+const response = await fetch('https://api.example.com/data')
4120 ```
42−search_files(path="src/core", regex="myFunction", file_pattern="*.ts")
43−```
44−The `file_pattern` parameter is the most effective filter — e.g. `"*.ts"`,
45−`"*.tsx"`, `"*.proto"`.
4621  
47−**`grep` directly** — Exclude build dirs and restrict to source extensions:
48−```bash
49−grep -rn "myFunction" src/ --include="*.ts" --exclude-dir={out,dist,node_modules,generated}
50−```
22+### 2. Using `axios`
5123  
52−### When you must search minified files
24+When using `axios`, you must apply the settings from `getAxiosSettings()`:
5325  
54−Sometimes you need to verify what got bundled (e.g., checking if a change
55−made it into the build). Minified files are typically one long line, so
56−normal `grep` shows the entire file as context. Use these approaches:
26+```typescript
27+import axios from 'axios'
28+import { getAxiosSettings } from '@/shared/net'
5729  
58−- **`grep -oP`** to extract just the match with limited surrounding context:
59− ```bash
60− grep -oP '.{0,40}myFunction.{0,40}' dist/extension.js
61− ```
62−- **`read_file`** on files in `out/src/` — these have source maps and are
63− more readable than `dist/extension.js` (which is the fully bundled output).
64−- **Source maps** — `out/src/*.js.map` and `dist/extension.js.map` can be
65− used to trace minified output back to original source locations.
30+const response = await axios.get('https://api.example.com/data', {
31+ headers: { 'Authorization': '...' },
32+ ...getAxiosSettings() // <--- CRITICAL: Injects the proxy agent if needed
33+})
34+```
6635  
67−## gRPC/Protobuf Communication
68−The extension and webview communicate via gRPC-like protocol over VS Code message passing.
36+### 3. Third-Party Clients (OpenAI, Ollama, etc.)
6937  
70−**Proto files live in `proto/`** (e.g., `proto/cline/task.proto`, `proto/cline/ui.proto`)
71−- Each feature domain has its own `.proto` file
72−- For simple data, use shared types in `proto/cline/common.proto` (`StringRequest`, `Empty`, `Int64Request`)
73−- For complex data, define custom messages in the feature's `.proto` file
74−- Naming: Services `PascalCaseService`, RPCs `camelCase`, Messages `PascalCase`
75−- For streaming responses, use `stream` keyword (see `subscribeToAuthCallback` in `account.proto`)
38+Most API client libraries allow you to customize the `fetch` implementation. You **MUST** pass the proxy-aware `fetch` to these clients.
7639  
77−**Run `bun run protos`** after any proto changes—generates types in:
78−- `src/shared/proto/` - Shared type definitions
79−- `src/generated/grpc-js/` - Service implementations
80−- `src/generated/nice-grpc/` - Promise-based clients
81−- `src/generated/hosts/` - Generated handlers
82− 
83−**Adding new enum values** (like a new `ClineSay` type) requires updating conversion mappings in `src/shared/proto-conversions/cline-message.ts`
84− 
85−**Adding new RPC methods** requires:
86−- Handler in `src/core/controller/<domain>/`
87−- Call from webview via generated client: `UiServiceClient.scrollToSettings(StringRequest.create({ value: "browser" }))`
88− 
89−**Example—the `explain-changes` feature touched:**
90−- `proto/cline/task.proto` - Added `ExplainChangesRequest` message and `explainChanges` RPC
91−- `proto/cline/ui.proto` - Added `GENERATE_EXPLANATION = 29` to `ClineSay` enum
92−- `src/shared/ExtensionMessage.ts` - Added `ClineSayGenerateExplanation` type
93−- `src/shared/proto-conversions/cline-message.ts` - Added mapping for new say type
94−- `src/core/controller/task/explainChanges.ts` - Handler implementation
95−- `webview-ui/src/components/chat/ChatRow.tsx` - UI rendering
96− 
97−## Adding New Global State Keys
98−Adding a new key to global state requires updates in multiple places. Missing any step causes silent failures.
99− 
100−Required steps:
101−1. Type definition in `src/shared/storage/state-keys.ts` - Add to `GlobalState` or `Settings` interface
102−2. Add any default value or transform in `src/shared/storage/state-keys.ts` if the key needs one
103−3. Read and write the value through `StateManager` (`setGlobalState()` / `getGlobalStateKey()`) after initialization
104− 
105−Persistent state is file-backed through `StateManager`; do not add new runtime reads or writes against VS Code `ExtensionContext` storage. That storage is only a legacy migration source.
106− 
107−Settings plumbing gotcha: if a key is user-toggleable from settings, wire both controller update paths:
108−- `src/core/controller/state/updateSettings.ts` for webview `updateSetting(...)`
109−- `src/core/controller/state/updateSettingsCli.ts` for CLI/ACP settings updates
110−Missing one path causes a toggle to appear to change in one surface while the backend state stays unchanged.
111− 
112−Webview toggle gotcha: settings changes must also round-trip back in state payloads.
113−- Add the field to `UpdateSettingsRequest` in `proto/cline/state.proto` (for webview update requests), then run `bun run protos`
114−- Include the key in `Controller.getStateToPostToWebview()` (`src/core/controller/index.ts`)
115−- Ensure `ExtensionState` and webview defaults include the key (`src/shared/ExtensionMessage.ts`, `webview-ui/src/context/ExtensionStateContext.tsx`)
116−If this round-trip wiring is missing, the backend value can update but the toggle in webview appears stuck or reverts.
117− 
118−## StateManager Cache vs Direct globalState Access
119−StateManager uses an in-memory cache populated during `StateManager.initialize()` from file-backed storage. For most state, use `controller.stateManager.setGlobalState()`/`getGlobalStateKey()`.
120− 
121−Exception: host migration code may read legacy VS Code storage before file-backed storage is initialized.
122− 
123−Example pattern:
40+**Example (OpenAI):**
12441 ```typescript
125−// Writing (normal pattern)
126−controller.stateManager.setGlobalState("myKey", value)
42+import OpenAI from "openai"
43+import { fetch } from "@/shared/net"
12744  
128−// Reading after initialization
129−const value = controller.stateManager.getGlobalStateKey("myKey")
45+this.client = new OpenAI({
46+ apiKey: '...',
47+ fetch, // <--- CRITICAL: Pass our fetch wrapper
48+})
13049 ```
13150  
132−Use `context.globalState` only in VS Code migration code that copies legacy ExtensionContext values into the shared file-backed stores.
51+### 4. Tests
13352  
134−## ChatRow Cancelled/Interrupted States
135−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.
53+Use `mockFetchForTesting` to mock the underlying fetch implementation.
13654  
137−**The pattern:**
138−1. A message has a `status` field (e.g., `"generating"`, `"complete"`, `"error"`) stored in `message.text` as JSON
139−2. When cancelled mid-operation, the status stays `"generating"` forever—no one updates it
140−3. To detect cancellation, check TWO conditions:
141− - `!isLast` — if this message is no longer the last message, something else happened after it (interrupted)
142− - `lastModifiedMessage?.ask === "resume_task" || "resume_completed_task"` — task was just cancelled and is waiting to resume
55+**Example (callback):**
14356  
144−**Example from `generate_explanation`:**
145−```tsx
146−const wasCancelled =
147− explanationInfo.status === "generating" &&
148− (!isLast ||
149− lastModifiedMessage?.ask === "resume_task" ||
150− lastModifiedMessage?.ask === "resume_completed_task")
151−const isGenerating = explanationInfo.status === "generating" && !wasCancelled
15257 ```
58+import { mockFetchForTesting } from "@/shared/net"
15359  
154−**Why both checks?**
155−- `!isLast` catches: cancelled → resumed → did other stuff → this old message is stale
156−- `lastModifiedMessage?.ask === "resume_task"` catches: just cancelled, hasn't resumed yet, this message is still technically "last"
60+...
61+ let mockFetch = ...
62+ mockFetchForTesting(mockFetch, () => {
63+ // This calls mockFetch
64+ fetch('https://foo.example').then(...)
65+ })
66+ // Original fetch is restored immediately when the call returns.
67+```
15768  
158−**See also:** `BrowserSessionRow.tsx` uses similar pattern with `isLastApiReqInterrupted` and `isLastMessageResume`.
69+**Example (Promise):**
15970  
160−**Backend side:** When streaming is cancelled, clean up properly (close tabs, clear comments, etc.) by checking `taskState.abort` after the streaming function returns.
161− 
162−## Debug Harness: clear inherited VSCode/Electron env vars before launching
163− 
164−The debug harness (`apps/vscode/src/dev/debug-harness/server.ts`) launches a child
165−VSCode via Playwright's `_electron.launch({ env: { ...process.env, ... } })`. If you
166−run the harness from a process that was itself spawned by VSCode (e.g. the Cline
167−extension host, an integrated terminal, or an agent running inside VSCode), the
168−parent's VSCode/Electron env vars leak into the child and break the launch.
169− 
170−The fatal one is **`ELECTRON_RUN_AS_NODE=1`**: it makes the child VSCode binary run
171−as plain Node, so it rejects every VSCode CLI flag. Symptom:
172− 
17371 ```
174−.../Visual Studio Code.app/Contents/MacOS/Code: bad option: --extensionDevelopmentPath=...
175−Error: Process failed to launch! (Playwright _electron.launch)
176−```
72+import { mockFetchForTesting } from "@/shared/net"
17773  
178−This is NOT the macOS Playwright flakiness mentioned in the harness README — it's
179−env inheritance. Fix: strip the inherited vars before starting the harness:
180− 
181−```bash
182−env -u ELECTRON_RUN_AS_NODE -u ELECTRON_NO_ATTACH_CONSOLE \
183− -u VSCODE_CLI -u VSCODE_CODE_CACHE_PATH -u VSCODE_CRASH_REPORTER_PROCESS_TYPE \
184− -u VSCODE_CWD -u VSCODE_ESM_ENTRYPOINT -u VSCODE_HANDLES_UNCAUGHT_ERRORS \
185− -u VSCODE_IPC_HOOK -u VSCODE_NLS_CONFIG -u VSCODE_PID -u VSCODE_L10N_BUNDLE_LOCATION \
186− bun src/dev/debug-harness/server.ts --auto-launch --skip-build
74+...
75+ let mockFetch = ...
76+ await mockFetchForTesting(mockFetch, async () => {
77+ await ...
78+ // This calls mockFetch
79+ await fetch('https://foo.example')
80+ ...
81+ })
82+ // Original fetch is restored when the Promise from the callback settles
18783 ```
18884  
189−Check your own env with `env | grep -iE 'electron|vscode_'` first; `ELECTRON_RUN_AS_NODE=1`
190−present means you must scrub before launching.
85+## Verification
19186  
192−Other harness notes confirmed in practice:
193−- The extension host is **ESM** (`VSCODE_ESM_ENTRYPOINT`), so `ext.evaluate` has no
194− `require` and module-internal functions aren't reachable as globals. To inspect
195− internal builders (e.g. `buildBedrockProviderConfig`), set a breakpoint with
196− `ext.set_breakpoint` and read locals via `ext.evaluate` with the paused `callFrameId`
197− — don't try to `require()` the bundle.
198−- `web.evaluate` wraps the expression as a single returned expression; multi-statement
199− snippets must be an IIFE `(() => { ...; return x; })()`, otherwise you get
200− `SyntaxError: Unexpected token ';'`.
201−- Webview settings inputs are `vscode-text-field` web components with debounced React
202− onChange. Setting `.value` + dispatching events via `web.evaluate` is unreliable for
203− some fields; focus the inner shadow `input` then use real keystrokes (`ui.type` +
204− `ui.press Tab`, or click the dropdown option) to make the value persist.
205− 
87+If you are adding a new network call or integration:
88+1. Check `@/shared/net.ts` is imported.
89+2. Ensure `fetch` or `getAxiosSettings` is being used.
90+3. Verify that third-party clients are configured to use the custom fetch.
20691  
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack