| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 0 | 9 | 6 | 0% |
| Commands | 1 | 7 | 19 | 4% |
| Section tags | 2 | 4 | 4 | 20% |
What each file covers
Sections
0 shared · 9 only in A · 6 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
- + Cloud Agent Instructions
- + Cline CLI
- + Build / Lint / test
- + GUI display
- + VS Code extension (`apps/vscode`, package `claude-dev`)
- + Desktop app (`apps/examples/desktop-app`, package `@cline/code`)
Commands
1 shared · 7 only in A · 19 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 cli
- + bun run cli -i
- + bun run cli doctor
- + bun run cli version
- + bun run build:sdk
- + bun -F @cline/cli test:e2e
- + bun run build:webview
- + bun esbuild.mjs
- + bun run package
- + bun run test:unit
- + bun run test:integration
- + bun run test:e2e
- + bun run download-ripgrep
- + bun run dev:sidecar
- + bun run dev:web
- + bun run dev
- + cargo
- + bun run typecheck
- + bun run test:chat-ui
- bun run protos
Section tags
2 shared · 4 only in A · 4 only in B- − setup
- − architecture
- − security
- − deployment
- + test
- + lint-format
- + monorepo
- + agent-behaviour
- build
- code-style
Line diff
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 · AGENTS.md
@@ +1 @@
1This is the **Cline** monorepo. Toolchain is **Bun 1.3.13** (package manager + task runner) with **Node >=22** as the runtime. Do not use npm/yarn/pnpm.
2
3## Cloud Agent Instructions
4
5### Cline CLI
6- Run from source: `bun run cli` (interactive: `bun run cli -i`; one-shot: append a prompt). This resolves to `apps/cli` and **auto-spawns the `@cline/cline-hub` daemon** — you do not start the hub separately.
7- Inspect local health with `bun run cli doctor`; `bun run cli version` prints the version.
8- An actual agent turn requires an **LLM provider credential**. With no credentials the default `cline` provider fails fast with an `Unauthorized` error and the interactive TUI shows a provider sign-in screen. Configure via `cline auth` or provider env vars (e.g. `ANTHROPIC_API_KEY`, `CLINE_API_KEY`, `OPENROUTER_API_KEY`); see `apps/cli/README.md`.
9
10### Build / Lint / test
11- SDK packages (`@cline/shared|llms|agents|core|sdk`) resolve each other through compiled `dist/` (their `exports` point only at `dist/`, with no `development` source condition). You **must** run `bun run build:sdk` after changing SDK dependencies/source before running the CLI or SDK tests, otherwise imports fail with missing `@cline/*` / missing `dist/` errors. Running processes do **not** hot-reload SDK source changes — rebuild and restart.\
12- Known cloud-env test artifact: `@cline/core` test `src/services/workspace/workspace-manifest.test.ts > readGitWorkspaceState > prefers origin and returns the current branch` fails because cloud VMs configure git `insteadOf` rules that rewrite GitHub remotes to `https://x-access-token:...@github.com/...`. This is an environment artifact, not a code bug.
13- Some `@cline/cli` e2e assertions (`bun -F @cline/cli test:e2e`) may fail on exact tool-listing string formats; treat as pre-existing test drift, not an environment problem.
14
15### GUI display
16- A virtual X display is live at **`DISPLAY=:1`** (the same desktop used for screenshots). GUI apps (VS Code, the Tauri desktop window) launched with `DISPLAY=:1` render there and can be screenshotted — no need to start your own `xvfb`. Prefer starting long-running GUI/dev processes in a `tmux` session (see the tmux guidance) so they survive.
17
18### VS Code extension (`apps/vscode`, package `claude-dev`)
19Toolchain is pre-installed and persisted in the VM: generated gRPC/proto code, the bundled `ripgrep` binaries (`apps/vscode/bin/`), the built webview (`webview-ui/build`), the esbuild bundle (`dist/extension.js`), VS Code itself (`/usr/bin/code`), and the GUI system libraries its tests need.
20- **Codegen prerequisite:** `bun run protos` (from `apps/vscode`) regenerates `src/generated/*` and the webview grpc client. The `dev`, `build:webview`, and `check-types` scripts already run it, so proto changes are picked up by those commands; run it manually only if you edit `.proto` files without a full build.
21- **Build:** `bun run build:webview` (webview UI, ~15s) then `bun esbuild.mjs` (extension bundle). `bun run package` does the full production build.
22- **Run it (dev host):** `DISPLAY=:1 code --no-sandbox --user-data-dir=/tmp/vscode-userdata --extensionDevelopmentPath=/workspace/apps/vscode <some-folder>`, then click the Cline icon in the Activity Bar to open the webview. (`--no-sandbox` is required in this container.)
23- **Test:** `bun run test:unit` (bun-based, ~984 tests, no VS Code host needed). `bun run test:integration` (`@vscode/test-electron`, downloads a VS Code build, runs under the GUI libs) and `bun run test:e2e` (Playwright) exercise a real extension host — heavier, and the GUI libs for them are already installed.
24- One-time deps (already installed, listed here in case they must be recreated): ripgrep via `bun run download-ripgrep`; VS Code test GUI libs per `CONTRIBUTING.md` (`libnss3`, `libatk*`, `libgbm1`, `xvfb`, etc.).
25
26### Desktop app (`apps/examples/desktop-app`, package `@cline/code`)
27A Tauri v2 (Rust) shell + Next.js webview + a Bun "sidecar" backend. Rust and the Tauri Linux system libs are pre-installed and persisted.
28- **Headless (no Rust/window):** run the backend and UI separately — `bun run dev:sidecar` (Bun backend on `127.0.0.1:3126`, serves `ws://.../transport`) and `bun run dev:web` (Next.js UI on `http://localhost:3125`).
29- **Native window:** `bun run dev` (`tauri dev`) — its `beforeDevCommand` builds the sidecar binary and starts `dev:web` (`:3125`), then Rust `main.rs` spawns the sidecar; so free ports `3125`/`3126` first. Launch with `DISPLAY=:1` to see the window. A `libEGL: DRI3 error` warning is benign (software rendering) — the WebKitGTK window still renders.
30- **Rust version caveat:** the crate graph needs Cargo's `edition2024` feature, so **Rust ≥1.85** is required (the VM's base 1.83 fails with "feature `edition2024` is required"). The toolchain here was updated via `rustup default stable` (currently 1.97). First `cargo` build downloads/compiles the full Tauri crate graph (a few minutes); subsequent builds are cached.
31- **System libs (already installed):** `libwebkit2gtk-4.1-dev`, `libgtk-3-dev`, `libayatana-appindicator3-dev`, `librsvg2-dev`, `libxdo-dev`, `libssl-dev`, `build-essential`.
32- **Test/typecheck:** `bun run typecheck`, `bun run test:chat-ui` (Vitest). Both trigger `build:ui` first.
33
@@ −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+This is the **Cline** monorepo. Toolchain is **Bun 1.3.13** (package manager + task runner) with **Node >=22** as the runtime. Do not use npm/yarn/pnpm.
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+## Cloud Agent Instructions
104
11−**Proactively suggest additions** when any of the above happen—don't wait to be asked.
5+### Cline CLI
6+- Run from source: `bun run cli` (interactive: `bun run cli -i`; one-shot: append a prompt). This resolves to `apps/cli` and **auto-spawns the `@cline/cline-hub` daemon** — you do not start the hub separately.
7+- Inspect local health with `bun run cli doctor`; `bun run cli version` prints the version.
8+- An actual agent turn requires an **LLM provider credential**. With no credentials the default `cline` provider fails fast with an `Unauthorized` error and the interactive TUI shows a provider sign-in screen. Configure via `cline auth` or provider env vars (e.g. `ANTHROPIC_API_KEY`, `CLINE_API_KEY`, `OPENROUTER_API_KEY`); see `apps/cli/README.md`.
129
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.
10+### Build / Lint / test
11+- SDK packages (`@cline/shared|llms|agents|core|sdk`) resolve each other through compiled `dist/` (their `exports` point only at `dist/`, with no `development` source condition). You **must** run `bun run build:sdk` after changing SDK dependencies/source before running the CLI or SDK tests, otherwise imports fail with missing `@cline/*` / missing `dist/` errors. Running processes do **not** hot-reload SDK source changes — rebuild and restart.\
12+- Known cloud-env test artifact: `@cline/core` test `src/services/workspace/workspace-manifest.test.ts > readGitWorkspaceState > prefers origin and returns the current branch` fails because cloud VMs configure git `insteadOf` rules that rewrite GitHub remotes to `https://x-access-token:...@github.com/...`. This is an environment artifact, not a code bug.
13+- Some `@cline/cli` e2e assertions (`bun -F @cline/cli test:e2e`) may fail on exact tool-listing string formats; treat as pre-existing test drift, not an environment problem.
1414
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
15+### GUI display
16+- A virtual X display is live at **`DISPLAY=:1`** (the same desktop used for screenshots). GUI apps (VS Code, the Tauri desktop window) launched with `DISPLAY=:1` render there and can be screenshotted — no need to start your own `xvfb`. Prefer starting long-running GUI/dev processes in a `tmux` session (see the tmux guidance) so they survive.
2317
24−## Searching the Codebase — Avoiding Build Output
18+### VS Code extension (`apps/vscode`, package `claude-dev`)
19+Toolchain is pre-installed and persisted in the VM: generated gRPC/proto code, the bundled `ripgrep` binaries (`apps/vscode/bin/`), the built webview (`webview-ui/build`), the esbuild bundle (`dist/extension.js`), VS Code itself (`/usr/bin/code`), and the GUI system libraries its tests need.
20+- **Codegen prerequisite:** `bun run protos` (from `apps/vscode`) regenerates `src/generated/*` and the webview grpc client. The `dev`, `build:webview`, and `check-types` scripts already run it, so proto changes are picked up by those commands; run it manually only if you edit `.proto` files without a full build.
21+- **Build:** `bun run build:webview` (webview UI, ~15s) then `bun esbuild.mjs` (extension bundle). `bun run package` does the full production build.
22+- **Run it (dev host):** `DISPLAY=:1 code --no-sandbox --user-data-dir=/tmp/vscode-userdata --extensionDevelopmentPath=/workspace/apps/vscode <some-folder>`, then click the Cline icon in the Activity Bar to open the webview. (`--no-sandbox` is required in this container.)
23+- **Test:** `bun run test:unit` (bun-based, ~984 tests, no VS Code host needed). `bun run test:integration` (`@vscode/test-electron`, downloads a VS Code build, runs under the GUI libs) and `bun run test:e2e` (Playwright) exercise a real extension host — heavier, and the GUI libs for them are already installed.
24+- One-time deps (already installed, listed here in case they must be recreated): ripgrep via `bun run download-ripgrep`; VS Code test GUI libs per `CONTRIBUTING.md` (`libnss3`, `libatk*`, `libgbm1`, `xvfb`, etc.).
2525
26−Several directories contain build output or generated code that produces
27−noisy 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−```
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"`.
46−
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−```
51−
52−### When you must search minified files
53−
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:
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
68−The 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
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:
124−```typescript
125−// Writing (normal pattern)
126−controller.stateManager.setGlobalState("myKey", value)
127−
128−// Reading after initialization
129−const value = controller.stateManager.getGlobalStateKey("myKey")
130−```
131−
132−Use `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
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.
136−
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
143−
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
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−
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−
173−```
174−.../Visual Studio Code.app/Contents/MacOS/Code: bad option: --extensionDevelopmentPath=...
175−Error: Process failed to launch! (Playwright _electron.launch)
176−```
177−
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
187−```
188−
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.
191−
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−
26+### Desktop app (`apps/examples/desktop-app`, package `@cline/code`)
27+A Tauri v2 (Rust) shell + Next.js webview + a Bun "sidecar" backend. Rust and the Tauri Linux system libs are pre-installed and persisted.
28+- **Headless (no Rust/window):** run the backend and UI separately — `bun run dev:sidecar` (Bun backend on `127.0.0.1:3126`, serves `ws://.../transport`) and `bun run dev:web` (Next.js UI on `http://localhost:3125`).
29+- **Native window:** `bun run dev` (`tauri dev`) — its `beforeDevCommand` builds the sidecar binary and starts `dev:web` (`:3125`), then Rust `main.rs` spawns the sidecar; so free ports `3125`/`3126` first. Launch with `DISPLAY=:1` to see the window. A `libEGL: DRI3 error` warning is benign (software rendering) — the WebKitGTK window still renders.
30+- **Rust version caveat:** the crate graph needs Cargo's `edition2024` feature, so **Rust ≥1.85** is required (the VM's base 1.83 fails with "feature `edition2024` is required"). The toolchain here was updated via `rustup default stable` (currently 1.97). First `cargo` build downloads/compiles the full Tauri crate graph (a few minutes); subsequent builds are cached.
31+- **System libs (already installed):** `libwebkit2gtk-4.1-dev`, `libgtk-3-dev`, `libayatana-appindicator3-dev`, `librsvg2-dev`, `libxdo-dev`, `libssl-dev`, `build-essential`.
32+- **Test/typecheck:** `bun run typecheck`, `bun run test:chat-ui` (Vitest). Both trigger `build:ui` first.
20633
