# Cline 源码分析：一个住在 IDE 里、也能跑在终端里的开源编程 Agent

> **分析对象**：cline（`github.com/cline/cline`），Apache-2.0，本分析基于 **main 分支 2026-08 检出**。仓库无统一版本号：`apps/cli` 为 **v3.0.49**（下文提到的 v3.0.49 均指 CLI），`apps/vscode`（包名 `claude-dev`）为 **4.1.3**，`sdk/packages/*`（shared/llms/agents/core）同为 **0.0.69**，根 `package.json`（`@cline/packages`）不带 version。
> **代码规模**：稀疏检出核心 27MB / 1749 个 `.ts` + 67 个 `.tsx` = 1816 个 TS 源文件。`@cline/core` 引擎约 14 万行，`@cline/llms` 约 11.9 万行（含 8.7 万行自动生成的模型目录），VS Code 扩展约 12.8 万行，CLI 约 7.1 万行。
> **一句话定位**：曾经的"VS Code 插件 Agent"，如今重构为**引擎（SDK）与界面（CLI/VS Code 扩展）分离的 monorepo**——核心是一个进程内、可嵌入、无状态循环的 `AgentRuntime`，外面套三层：会话编排、宿主驱动、应用界面。它和 Claude Code 共享"模型→工具→再模型"的主循环，但用**显式而扁平的声明式工具目录 + per-model 路由**取代了 Claude Code 的"连续前缀缓存排序"。
> **读者对象**：已经读过本系列至少一份分析的读者。本文沿用统一框架，标注 `文件:行号`，可回源码核对。

---

## 目录

1. [项目概览：从 VS Code 插件到"引擎 + 界面" monorepo](#ch1)
2. [全景架构：五层栈 + 三条宿主 + 一条事件链](#ch2)
3. [启动流程：CLI / VS Code / hub daemon 三个入口](#ch3)
4. [输入捕获与分流：交互、headless、steering 打断、pending prompt](#ch4)
5. [上下文组装：MessageBuilder 的 API 安全整形](#ch5)
6. [Agent 主循环（心脏）：AgentRuntime 的无状态 while loop](#ch6)
7. [工具系统与审批：28 个工具 + 五套 preset + 桌面审批 IPC](#ch7)
8. [安全护栏：loop-detection、mistake-tracker、subprocess-sandbox](#ch8)
9. [会话、checkpoint 与版本化：git 快照回滚](#ch9)
10. [上下文压缩：basic 确定性折叠 vs agentic LLM 摘要](#ch10)
11. [Provider 层：Vercel AI SDK + 约 180 Provider ID + 4118 个模型](#ch11)
12. [生态：插件、MCP、hooks、多 agent 团队、cron、connectors、hub](#ch12)
13. [存储：JSON 文件 + SQLite 混合](#ch13)
14. [横向对比：与 Claude Code / opencode / CodePilot / pi / OpenWorker](#ch14)
15. [总结：三个最独特的设计与取舍](#ch15)

---

<h2 id="ch1">第 1 章 项目概览：从 VS Code 插件到"引擎 + 界面" monorepo</h2>

**Cline 是什么？** 用 README 第一句话说：*The open source coding agent in your IDE and terminal*。它在 VS Code 侧边栏里住着（曾经的定位），如今也能在终端跑（CLI），甚至能 headless 跑在 CI/CD 里。核心能力：

- **跨项目编辑**：读项目结构、理解文件关系、做协调一致的多文件修改，边做边盯 linter/编译器错误（`README.md`）。
- **Plan / Act 双模式**：Plan 模式只探索、只提问、出方案；Act 模式执行，每个文件编辑和终端命令默认要审批（可 auto-approve）。
- **28 个内置工具**（9 默认 + spawn_agent + 18 个 team_*），支持 MCP、插件、技能（skills）、`.clinerules` 规则。
- **约 180 个可注册 Provider ID / 4118 个模型**：Anthropic/OpenAI/Gemini/OpenRouter/Bedrock/Vertex/Ollama/LM Studio/任何 OpenAI 兼容端点（`ids.ts` 无 Azure 独立枚举项）。
- **多 agent 团队**：coordinator 拆任务 → 委派 specialist（`cline --team-name ...`）。
- **定时自动化**（`cline schedule create --cron ...`）、**IM 接入**（`cline connect telegram/slack/discord/...`）、**hub 本地协作中心**。

**它和 Claude Code 的关系**：Claude Code 是终端里的编程 Agent（Ink TUI），Cline 现在也做终端（OpenTUI），但根子仍在 IDE 插件。两个项目的架构哲学分叉得很清楚：Claude Code 是**单体**（一个包，工具前缀缓存排序、命令式 driver）；Cline 重构后是**分层可嵌入引擎**（agents 无状态循环 / core 有状态编排 / 界面层可插拔）。

**它和 open-design 的关系**：open-design 是"不写 Agent 主循环的宿主"；Cline 恰恰相反——**主循环本身（AgentRuntime）被提炼成库**，宿主（CLI/VS Code）都只是它的驱动者。

### 数字化的项目形状

| 维度 | 数字 | 说明 |
|---|---|---|
| 包 | 6 个 SDK 包 + 2 应用 | shared/llms/agents/core/sdk/ui + apps/cli + apps/vscode |
| 依赖方向 | 单向 | `shared ← llms ← agents ← core ← 应用`（`sdk/ARCHITECTURE.md`） |
| 主循环 | agent-runtime.ts 1969 行 | `AgentRuntime.execute()` 显式 while loop（L641） |
| 工具 | 28 个内置 | 9 默认 + 1 spawn_agent + 18 team_* |
| Provider | 约 179 唯一 ID | `BUILT_IN_PROVIDER` 枚举约 50 + models.dev 生成 163（重叠去重后约 179，不是 48+163=211） |
| 模型目录 | catalog.generated.ts 87274 行 | 4118 个模型，含 contextWindow/pricing |
| 存储 | JSON + SQLite 混合 | sessions.db / cron.db / connectors.db / secrets.json |
| 许可 | Apache-2.0 | 商业友好 |

---

<h2 id="ch2">第 2 章 全景架构：五层栈 + 三条宿主 + 一条事件链</h2>

官方 `sdk/ARCHITECTURE.md` 画的分层图（单向依赖，不允许反向）：

```mermaid
flowchart LR
    SH["@cline/shared<br/>低层契约：storage/llms/db/cron/hooks/tools"] --> LL["@cline/llms<br/>Provider 运行时：AI SDK 适配 + 模型目录"]
    LL --> AG["@cline/agents<br/>无状态主循环：AgentRuntime"]
    AG --> CO["@cline/core<br/>有状态编排：会话/存储/hub/插件/compaction"]
    CO --> APPS["宿主应用：CLI · VS Code 扩展 · hub"]
```

**五层栈**（自下而上）：

1. **shared**（20553 行）——纯契约层。路径解析（`~/.cline/data`）、`estimateRequestInputTokens`（3 chars/token 保守估算）、SQLite connector-store、事件枚举、工具类型、hook 事件。
2. **llms**（118772 行）——Provider 层。基于 **Vercel AI SDK（`ai@7` + `@ai-sdk/*`）** 的适配；`catalog.generated.ts`（87274 行）是 build:models 自动生成的模型目录；gateway 做统一 usage/流式归一化。
3. **agents**（4635 行）——**无状态** Agent 循环。`AgentRuntime`（`agent-runtime.ts:1969`）是唯一核心：`execute()` 显式 while loop。**禁止**持有持久化、宿主生命周期。
4. **core**（140027 行）——有状态编排。`SessionRuntime`（会话门面）、`LocalRuntimeHost`（宿主）、`MessageBuilder`（API 整形）、compaction、plugin、cron、connectors、hub。
5. **应用层**——CLI（OpenTUI + commander）、VS Code 扩展（单 WebView React）、hub daemon（WebSocket 协作中心）。

**三条宿主（RuntimeHost）**（`core/src/runtime/host/host.ts`）：`LocalRuntimeHost`（进程内）、`HubRuntimeHost`（连本地 hub 服务器，跨进程共享）、`RemoteRuntimeHost`（远程）。`createRuntimeHost()`（host.ts:137）在 auto 模式下自动发现 hub 并降级 local——**同一引擎可以三种方式被驱动**。

**贯穿全栈的一条事件链**：

```
AgentRuntime 的 while loop 每步发出 AgentRuntimeEvent
  → SessionRuntime.handleRuntimeEvent（core/src/runtime/orchestration/session-runtime-orchestrator.ts:1061）
  → RuntimeEventAdapter.translate（runtime-event-adapter.ts:183，14 种新事件（含 `run-failed`）→ 9 种 legacy AgentEvent）
  → AgentEventBridge → CoreSessionEvent
  → UI（CLI TUI / VS Code webview）消费
```

> 🧠 **一句话**：把"会转的循环"（agents，无状态）和"记得住状态的编排"（core，有状态）硬拆成两个包，是 Cline 重构后的根架构决策——这让同一个循环引擎能被 CLI、VS Code、hub 三种宿主反复驱动，而循环本身不知道宿主是谁。

---

<h2 id="ch3">第 3 章 启动流程：CLI / VS Code / hub daemon 三个入口</h2>

### 入口一：CLI（`apps/cli/src/index.ts`，94 行）

`#!/usr/bin/env bun`，package.json `bin: { cline: "src/index.ts" }`。index.ts 做进程分支决策（worker / hub daemon / connector 进程），转发 SIGINT 到 `active-runtime`，然后动态 `import("./main")` 的 `runCli()`（`src/main.ts`，1197 行）。框架是 **commander v14** + **@clack/prompts**（wizard 交互）+ **OpenTUI**（`@opentui/core` + `@opentui/react` + react-reconciler + react 19）。

命令全部注册在 `main.ts`：`auth`、`config`、`plugin`、`skill`、`connect`、`mcp`、`doctor`、`hook`、`schedule`、`hub`、`dashboard`、`history`、`team` + 默认 chat。共享根选项在 `commands/program.ts`（`--plan`、`--json`、`--auto-approve`、`-c --cwd`、`-P --provider`、`-k --key`、`-z --zen`、`--config`）。

**和 core 的集成**：`session/session.ts` 的 `createCliCore()` → `ClineCore.create()`（来自 `@cline/core`）。默认 `backendMode` 连 hub（传 `hub: {clientType: "cli"}`），`forceLocalBackend` 可进程内直跑。

### 入口二：VS Code 扩展（`apps/vscode/src/extension.ts`，753 行）

`activate`（L66）顺序：① `setupHostProvider`（必须最先）→ ② legacy 存储迁移 → ③ `exportVSCodeStorageToSharedFiles` 统一到 `~/.cline/data/`（与 CLI/JetBrains 共享）→ ④ `initialize` 创建 `VscodeWebviewProvider` → ⑤ 注册 commands。

**和 core 的连接是进程内直接 import**：`extension.ts` 与 `SdkController.ts`（2110 行）直接 `import @cline/core`，引擎跑在扩展宿主进程里。`hosts/vscode/hostbridge/`（gRPC）只是宿主能力桥（diff/terminal/workspace），**不承载 core**。整个 Cline UI 是**单个 WebView 内的 React 应用**（`claude-dev.SidebarProvider`，activitybar 容器）。

### 入口三：hub daemon（`apps/cli/src/commands/hub.ts` → `daemon/entry.ts`）

独立守护进程，本地 WebSocket 服务器（`core/src/hub/server/hub-websocket-server.ts`，ws 库，协议版本协商）。connectors、cron schedule、UI 都是 hub 客户端——实现**跨进程共享会话/审批/通知**。

### 鉴权与数据

登录走 **WorkOS Device Flow + OAuth**（`auth/cline.ts`，`api.workos.com/user_management/*`），本地 OAuth server 回调端口 48801-48811；Provider 密钥存 `~/.cline/data/secrets.json`（chmod 0o600）。

---

<h2 id="ch4">第 4 章 输入捕获与分流：交互、headless、steering 打断、pending prompt</h2>

Cline 的"输入"来源比终端 Agent 多：交互输入框、piped stdin（headless）、运行中 steering 打断、pending prompt 队列、IM 连接器（Slack/Telegram…）、cron 定时、团队委派。分流机制：

**① 交互模式**：`apps/cli/src/runtime/run-interactive.ts` 起 TUI，用户输入 → `session.send()` → host `runTurn()`。

**② headless 模式**（`main.ts` ~944 行判定）：`--json || (!stdin.isTTY && !interactive)`。`runtime/run-agent.ts`（425 行）是单发执行器；`--json` 输出 **NDJSON**（每行一个 JSON 事件：`run_start`/`run_abort_requested`/`message`/`error`…，由 `utils/output.ts` 的 `emitJsonLine` 逐行写 stdout）——CI 可逐行消费并以退出码收尾。`--zen` 更进一步：任务 fire-and-forget 给后台 hub daemon，CLI 立即退出。

**③ steering 打断（运行中插话）**（`core/src/runtime/turn-queue/pending-prompt-service.ts:372-379`）：`PendingPromptService`（L54）纯队列——enqueue 按 prompt 去重、**steer 插队到头部**；`PendingPromptsController`（L207）在 `agent.canStartRun()` 时 `scheduleDrain()`（L281）派发 `drain()`（L295）串行发 turn。steer 通道：`consumePendingUserMessage`（host L695）被 `AgentRuntime.generateAssistantMessage` 在 iteration>1 时消费（agent-runtime.ts:968-979）——**运行中打断注入**。

**对比**：OpenWorker 的收件箱是持久异步邮箱；CodePilot 的 turn-lock 直接拒绝并发。Cline 是**进程内会话队列 + 可 steering**——既允许排队，又允许实时打断，且不影响正在跑的循环（steering 在下一次迭代被消费）。

**④ IM 连接器**（`apps/cli/src/connectors/`）：slack / discord / telegram / gchat / whatsapp / linear 六平台，每平台独立 adapter 进程，注册到 hub，经 HubRuntimeHost 执行会话。

---

<h2 id="ch5">第 5 章 上下文组装：MessageBuilder 的 API 安全整形</h2>

`MessageBuilder`（`core/src/session/services/message-builder.ts`，1727 行，L108）是"会话消息 → provider API 请求"的整形器，入口 `buildForApi(messages)`（L166）。它做的事比想象的多：

**① 增量 reindex**（L278）：tail 引用比对，命中则只索引新增部分，否则全量重建。**② commitOutdatedRewrites**（L336）：读过的文件后来被改，把旧内容批量替换为 `[outdated - see the latest file content]`；超过 `minOutdatedRewriteBytes`（默认 64KB）才一次性提交——**避免频繁破坏 provider 前缀缓存**。**③ addMissingToolResults**（L502）：中断场景给孤儿 tool_call 补 `is_error: true` 的伪结果。**④ 逐 block 截断**：assistant 文本 12K（重复工具 markup）/200K（普通）、file 块 50K、tool_result 8K（保留首尾）、嵌套字符串深截断。**⑤ applyMediaBudget**（L1332）：图片按字节预算限流，超限替换 `IMAGE_OMITTED_PLACEHOLDER`。**⑥ truncateToTotalTextBudget**（L1162）：全局 6MB 字节兜底。

**系统提示**（不在 MessageBuilder 内）：由会话编排层 `session-runtime-orchestrator.ts` 的 `composeSystemPrompt()`（约 L679）= `config.systemPrompt`（`buildClineSystemPrompt` 拼 IDE/工作区元数据/rules/mode 等段）+ 插件规则 `mergeSystemPromptRules`（约 L102）。**工具定义由 orchestrator 单独传给 provider，不塞进消息数组**。

> 🧠 **一句话**：MessageBuilder 的所有设计都围绕一个目标——**保住 provider 前缀缓存**：增量索引、outdated 批量重写、截断顺序、6MB 兜底，全是"少动 transcript 中部"的工程化体现。这比 Claude Code 的"内置工具排连续前缀"更通用（Cline 面向约 180 个可注册 Provider ID / 4118 模型，不能赌每个 provider 都做前缀缓存）。

---

<h2 id="ch6">第 6 章 Agent 主循环（心脏）：AgentRuntime 的无状态 while loop</h2>

主循环在 `@cline/agents` 包的 `agent-runtime.ts`（1969 行），**不在** core。`AgentRuntime`/`Agent` 是同一类的两个名字（stateless loop）。核心 `execute()`（L641，循环体 L677-789）：

```mermaid
flowchart TD
    START["execute()<br/>emit run-started"] --> TURN["while 循环<br/>emit turn-started"]
    TURN --> GEN["generateAssistantMessageWithOverflowRecovery()<br/>（L876，for await 消费 model.stream 流式事件）"]
    GEN --> TOOL{"模型要工具?"}
    TOOL -->|否| STEER{"steering 打断?"}
    STEER -->|有| CONSUME["consumePendingUserMessage<br/>（iteration>1 时，agent-runtime.ts:968）"] --> TURN
    STEER -->|没有| DONE["finishRun(completed)"]
    TOOL -->|要| EXEC["executeToolCalls()<br/>（L1455，sequential/parallel）"]
    EXEC --> WRITE["写回 tool_result 消息"] --> TURN
    TOOL -->|terminal 完成工具<br/>（submit_and_exit）| FINISH["finishRun(completed)"]
```

**每个 turn** = 一次 `generateAssistantMessageWithOverflowRecovery()` + 若干 `executeToolCalls()`。无 tool-call 或命中 `submit_and_exit`（`lifecycle.completesRun: true`）即完成。

**与 Claude Code 的本质区别**：

1. **循环被封装为可复用类，会话层反复重入**。Claude Code 是一个长驻的 while-loop driver；Cline 每次 run 都 `new AgentRuntime()`，会话层把每条用户消息当一次独立 run，用**全量转录播种**（`initialMessages`）后 `runtime.run("")`——多轮 = 反复重入循环，而非单对象长驻。
2. **循环内部同步，外部全事件化**。所有进展经 `AgentRuntimeEvent` 订阅流出——这是"双层架构"的关键：引擎不知道谁在听。
3. **prepare-turn 投影 seam**：core 把 compaction 策略作为 prepareTurn 注入（agent-runtime 提供 seam，`@cline/agents` 保持无状态）。

**config**：判别联合（`WithModel`/`WithProvider`）；`createAgentRuntimeConfig`（core/src/runtime/config，纯函数）；`agent-message-codec` 做 AgentMessage↔Message 编解码。

---

<h2 id="ch7">第 7 章 工具系统与审批：28 个工具 + 五套 preset + 桌面审批 IPC</h2>

### 工具清单（28 个）

`extensions/tools/constants.ts` 的 `ALL_DEFAULT_TOOL_NAMES`（9 个）：`read_files`、`search_codebase`、`run_commands`、`fetch_web_content`、`apply_patch`、`editor`、`skills`、`ask_question`、`submit_and_exit`（工厂在 `definitions.ts` L247/343/457/518/611/660/723/780/801）。另有 `spawn_agent`（team/spawn-agent-tool.ts）和 18 个 `team_*` 工具（team-tools.ts:195）。

**对比 Claude Code 的 40 个**：**少了** WebSearch/Glob/TodoWrite/NotebookEdit/Task 等（web 搜索退化为仅 `fetch_web_content`，glob 靠 `search_codebase`+`run_commands`）；**多了** `ask_question`（交互提问）、`submit_and_exit`（无头结束运行）、`skills`（技能调用）、`spawn_agent` 与全套 `team_*` 多智能体工具。

### 编辑双雄：editor vs apply_patch

Cline 把编辑拆成两个互斥工具（definitions.ts:917 同一时刻只启用其一）：

- **editor**（最接近 Claude Code 的 Edit）：`old_text→new_text` 字面替换、`insert_line` 行插入或建文件，单文件精确编辑。
- **apply_patch**：aider 风格自由格式补丁（`*** Begin Patch / *** Update File / +- 上下文行 / Add/Delete/Move`），无行号、基于上下文匹配，**一次调用批量编辑多文件**（`executors/apply-patch.ts` + `apply-patch-parser.ts`）。

### 审批链路（tool-approval.ts，102 行）

流程：模型发出工具调用 → `SessionRuntime` 按 `toolPolicies` 合并全局 `*` 与工具级策略（session-runtime-orchestrator.ts:117-133）判 `enabled` → `beforeTool` 钩子（含循环检测）→ 若 `autoApprove !== true` 且宿主提供 `requestToolApproval` 能力 → 审批 → 执行 → `afterTool`。

**`requestDesktopToolApproval`**（tool-approval.ts:29）是桌面 IPC 实现：向 approvalDir 写 `<sessionId>.request.<id>.json`，**每 200ms 轮询 decision 文件，5 分钟超时**——一种"文件即 IPC"的朴素但可靠机制。`ToolPolicy = {enabled?, autoApprove?}`（`sdk/packages/shared/src/llms/tools.ts:7`），**默认 enabled + autoApprove**。

### 五套 preset（presets.ts）

`act` / `plan` / `search` / `minimal` / `yolo`。分级通过 `ToolPolicyPresetName = "default"|"yolo"`（presets.ts:137）实现——yolo 对 `*` 及全部默认工具 `autoApprove: true`。

### 工具注册：扁平声明式目录 vs 连续前缀

Claude Code 用 trie 做连续前缀匹配缓存。Cline 相反：`runtime.ts` 的 `BASE_TOOL_CATALOG`（9 条：工具 id/描述/headlessToolNames）→ 经 preset + `model-tool-routing`（按 provider/model 禁用工具的规则）+ `disabledToolIds` 解析出启用集合（`getCoreBuiltinToolCatalog`/`resolveCoreSelectedToolIds`，206-245 行）→ `createDefaultTools` 按"开关 flag && 有 executor"实例化 `AgentTool[]`（`createTool` 封装 name/description/inputSchema/execute/timeoutMs/retryable/maxRetries/lifecycle，`sdk/packages/shared/src/tools/create.ts:81`）。**模型请求端是普通 JSON Schema 数组，无前缀排序**——替代方案是 per-model 路由规则显式决定哪些工具可见。

---

<h2 id="ch8">第 8 章 安全护栏：loop-detection、mistake-tracker、subprocess-sandbox</h2>

### 死循环检测（runtime/safety/loop-detection.ts，162 行）

`toolCallSignature` 对 input 做排序键 JSON 序列化（L50）；`checkRepeatedToolCall` 统计连续相同"工具名+签名"次数，**soft=3 / hard=5**（L113）。`LoopDetectionTracker.inspect`（L136）返回 ok/soft/hard 三档；SessionRuntime 中 soft→往对话注入"换种方式"提示，hard→以 `forceAtLimit: true` 喂给 MistakeTracker 并中止运行（orchestrator:1244-1273）。

### MistakeTracker（runtime/safety/mistake-tracker.ts，229 行）

三种原因：`api_error / invalid_tool_call / tool_execution_failed`。`record()` 累加 `consecutiveMistakes`，达上限经 `onLimitReached` 回调决策（默认 stop）；continue 则清零并附加恢复指引；stop 则写停止信息并 `activeRuntime.abort()`。所有 record 经 `activeTrackerWork` Promise 链串行化保证顺序。

### SubprocessSandbox（runtime/tools/subprocess-sandbox.ts，346 行）

解决"插件/浏览器沙箱代码在主进程跑不安全、不可控"：spawn node/bun 子进程走 IPC，父进程发 `{type:"call"}`、子进程回 `{type:"response"|"event"}`；call 超时则 SIGTERM→SIGKILL 强杀（210-274 行）；`resolveSubprocessRuntimeExecutable`（L73）解析 node/bun 运行时。**崩溃隔离 + 超时强制 + 事件转发**。

### 规则系统（.clinerules，runtime/safety/rules.ts，49 行）

从 `UserInstructionConfigWatcher` 取快照，过滤 disabled、按名字排序，渲染为 `## 名称\n指令`，拼到 system prompt 的 `# Rules` 段。

---

<h2 id="ch9">第 9 章 会话、checkpoint 与版本化：git 快照回滚</h2>

### 会话数据模型（session/models + stores）

- **索引**：`sessions.index.json`（file-session-service.ts L50）——`{version:1, sessions: {sessionId: SessionRow}}` 单文件全量 JSON，atomicWriteJson 临时文件+rename 原子替换，`statusLock` 乐观并发（CAS）。
- **manifest**：`sessions/<id>/session.json`——会话元数据（Zod 校验）。
- **消息**：`sessions/<id>/<id>.json`——`{version:1, updated_at, agent, sessionId, messages[], system_prompt}`（session-data.ts L304）整体重写（非追加）。
- `SessionPersistenceAdapter` 抽象存储层，默认文件实现；hub/remote 可换。

### checkpoint（git 实现！）

**checkpoint-diff.ts**（150 行）：`compareCheckpointToWorkspace`（L142）→ `listChangedPaths`（L76）用 `git diff --name-only -z <ref>` + `git ls-files --others` 找变更文件，逐个对比产出 `CheckpointContentDiff[]`。有路径逃逸防护（L44）。

**checkpoint-restore.ts**（413 行）：
- `readSessionCheckpointHistory`（L156）：从 metadata 解析 `{ref, createdAt, runCount, kind}` 历史。
- `findCheckpointForRun`（L202）：runCount 之前最近一个 checkpoint。
- `trimMessagesToCheckpoint`（L245）：用 `getUserRunSpan` 定位第 runCount 次用户回合，截断消息。
- `beginWorktreeRestoreTransaction`（L50）：回滚前用 `git stash push --include-untracked` 快照当前工作区，对象转移到私有 ref `refs/cline/restore-transactions/<uuid>`——commit 时删 ref、rollback 时 `reset --hard` + `clean -fd` + `stash apply --index` 还原。
- `applyCheckpointToWorktree`（L357）：区分 stash 与普通 commit 的 reset 路径；仅当快照含第三个父提交（`<ref>^3`，捕获了 untracked）才 `clean -fd`，避免不可恢复删除。

**存什么**：工作区完整快照存成 git commit/stash（含 untracked 时三父提交），会话消息本身不存（靠截断保留）。**怎么回滚**：`SessionVersioningService.restoreCheckpoint`（session-versioning-service.ts:134）编排全流程：验证 → 恢复计划 → 事务快照 → apply → 以截断消息启动新会话 → commit 事务；失败则 rollback 工作区 + 清理新会话。

> 🧠 **一句话**：checkpoint 直接复用 git 对象库做"可回滚的工作区快照"，且把回滚本身做成**可回滚的事务**（先 stash 再动）——这是 Cline 最优雅的工程之一。

---

<h2 id="ch10">第 10 章 上下文压缩：basic 确定性折叠 vs agentic LLM 摘要</h2>

**触发**（extensions/context/compaction.ts，710 行）：`createContextCompactionPrepareTurn`（L256）每次模型请求前估算 `requestInputTokens`，`trigger = maxInputTokens * 0.9`（COMPACTION_TRIGGER_RATIO）——**90% 阈值**，比 Claude Code 的 microcompact 激进得多。三种 mode：`auto` / `manual`（用户 /compact）/ `overflow_recovery`（provider 拒绝后的强制恢复）。

**basic**（basic-compaction.ts，711 行，L452）：**不调 LLM**。typed 用户提示必保留；最新回合保留"最新消息 + 符合预算的后缀"（对齐 assistant 边界不断开工具对）；旧回合保留各自最终 assistant 答复（最近 3 条原文）；其余丢弃，折叠进相邻用户消息的 `<SYSTEM_NOTICE>` dropped-work 摘要；冻结上次压缩产物（`compaction: preserved`）不重复折叠。**确定性、零成本**，用于 overflow 恢复兜底。

**agentic**（agentic-compaction.ts，283 行，L97）：**调用 summarize 模型**（默认当前 provider）。`findCutIndex` 按 `preserveRecentTokens`（默认 20K）切分，旧段序列化发给 LLM 生成 "continuation note"，替换为一条 `metadata.kind=compaction_summary` 的用户消息，`userRunSpan=被折叠回合数`；已有 summary 则只折叠其后的新消息（增量）。失败自动回退 basic（L518）。

**状态持久化**（`createCompactionStateAwarePrepareTurn`，L643）：每次压缩后把 `{compacted messages, source_prefix_hash(sha256), source_message_count, system_prompt}` 存入侧车（`session-compaction.ts`），下一轮 `projectSessionCompactionState`（L161）校验前缀哈希匹配后 = 压缩产物 + 新消息尾部，**避免每轮全量重建**。

**与 Claude Code microcompact 对比**：Cline 触发阈值高（0.9× vs microcompact 约 0.5-0.6× 即时压缩）；agentic 每次一次完整 LLM 摘要（成本高但信息保留好），basic 零成本；Claude Code 的 microcompact 是轻量即时小压缩，Cline 更接近"检查点 + 全文摘要 + 可回滚"的宏观设计。

---

<h2 id="ch11">第 11 章 Provider 层：Vercel AI SDK + 约 180 Provider ID + 4118 个模型</h2>

`@cline/llms`（118772 行 / 66 文件）是 Provider 核心，**基于 Vercel AI SDK**（依赖 `ai@^7` + `@ai-sdk/anthropic/openai/google/google-vertex/amazon-bedrock/mistral/openai-compatible` + `ai-sdk-ollama` + `ai-sdk-provider-claude-code`）：

- **Provider 数量**：`ids.ts` 的 `BUILT_IN_PROVIDER` 枚举约 **50** 项 + models.dev **自动生成 163** 个 ID；去重并集约 **179** 个可注册 ID（不是 48+163=211，也难称「200+」）。`catalog.generated.ts` 约 87K 行 / **4118** 个模型。
- **双注册 Factory**：`factory-registry.ts`（`registerHandler`/`registerAsyncHandler`）+ `createHandler(config)`：先查注册表，否则落到 `gateway.ts` 的 `createGatewayApiHandler`；`GatewayRegistry` 持有 manifest/defaults/createProvider。
- **关键子目录**：`vendors/`（anthropic/bedrock/google/vertex/mistral/ollama/openai-compatible 的 AI SDK 适配）、`routing/`（anthropic-compatible prompt cache、GLM/MiniMax thinking、reasoning-options）、`middleware/`（retry-empty-response、split-tool-images）、`services/`（Langfuse OTel 遥测）。
- **流式与 token**：`ai-sdk.ts` 用 `streamText` + `formatMessagesForAiSdk`；usage 归一化为 `GatewayNormalizedUsage`（inputTokens/outputTokens/cacheReadTokens/cacheWriteTokens/reasoningTokenCount/totalCost）。
- **模型目录**：`catalog/catalog.generated.ts`（**87274 行**，163 provider / **4118 个模型**，含 contextWindow/pricing/capabilities），由 `scripts/generate-models.ts` 从 models.dev catalog-live 抓取生成（根脚本 `bun run build:models`）。

**token 估算**（shared/llms/tokens.ts）：3 chars/token 保守估算 `estimateRequestInputTokens`——compaction 触发靠它。

---

<h2 id="ch12">第 12 章 生态：插件、MCP、hooks、多 agent 团队、cron、connectors、hub</h2>

### 插件系统（extensions/plugin/）

插件通过 `SubprocessSandbox` 子进程加载，JSON IPC 通信（`initialize`/`executeTool`/`invokeHook`/`buildMessages`）。插件可贡献：**tools、commands、rules、messageBuilders、providers、automationEventTypes、mcpServers、shortcuts、flags**。安装来源 `npm / git / local / remote`（plugin-install.ts，1218 行），含官方 slug 校验。

### hooks（10 个生命周期事件）

外部 hook 事件（shared/hooks/events.ts）：`agent_start / agent_resume / agent_abort / agent_end / agent_error / tool_call / tool_result / prompt_submit / pre_compact / session_shutdown`。运行时钩子 `AgentHooks`：`beforeRun / afterRun / beforeModel / afterModel / beforeTool / afterTool / onEvent`。实现：`hook-file-hooks.ts`（1010 行，读 `.hooks/` 配置）+ `subprocess-runner.ts`（转发到 agent hook 子进程）。

### 多 agent 团队（extensions/tools/team/multi-agent.ts，1852 行）

`AgentTeamsRuntime`（协调器核心）：内存态含 **members / tasks / missionLog / mailbox / runs（队列+租约）/ outcomes / outcomeFragments**；lead 通过团队工具（team-tools.ts 916 行：create_team_task、spawn_teammate、route_to_teammate、team_outcome 等）拆任务委派给 specialist（spawn-agent-tool.ts）。任务状态机 `pending → in_progress → blocked（blockedBy）→ completed`；运行队列 `maxConcurrentRuns` 限流 + 心跳 + `buildRecoveredRunMessage` 中断自动恢复。持久化：`exportState()/hydrateState()` 全量快照 → `team-session-coordinator.ts`（240 行）转发 TeamEvent，落 `sqlite-team-store.ts`（537 行）/ `file-team-store.ts`。

### cron（31 个文件）

规范文件 `.md` 由 cron-watcher 监听、spec-parser 解析、reconciler 同步。`sqlite-cron-store.ts`（1719 行）：独立 `{data}/db/cron.db`，表 `cron_specs/cron_runs/cron_event_log`；**`claim_token`+`claim_until_at` 租约机制防多进程重复执行**。触发：`one_off / schedule（cron 表达式）/ event`；`schedule-service.ts`（443 行）轮询+并发限流。

### connectors（IM）

core 只管生命周期（active-connectors.ts）；实际 IM 实现在 `apps/cli/src/connectors/`：slack/discord/telegram/gchat/whatsapp/linear 六平台，每平台独立 adapter 进程注册到 hub。

### hub（46 个文件）——本地协作中心

本地 WebSocket 服务器，handlers 含 session/run/capability/approval/connector；`hub-runtime-host.ts`（2156 行）是 `RuntimeHost` 实现，hooks/tools/checkpoint/compaction 按 capability prefix 协商。

### auth / account

`auth/cline.ts`：WorkOS Device Flow + OAuth；`account/cline-account-service.ts`：用户信息 RPC、featurebase token。

---

<h2 id="ch13">第 13 章 存储：JSON 文件 + SQLite 混合</h2>

| 数据 | 位置 | 实现 |
|---|---|---|
| 全局设置 | `{data}/settings/global-settings.json` | JSON + Zod |
| Provider 设置 | `{data}/settings/providers.json` | JSON（含 apiKey） |
| 密钥 | `{data}/secrets.json` | JSON + chmod 0o600 |
| 会话索引/消息 | `{data}/sessions/` | JSON 文件（整体重写 + atomicWrite） |
| 会话 DB | `{data}/db/sessions.db` | SQLite（sqlite-session-store.ts 292 行） |
| cron | `{data}/db/cron.db` | SQLite + 租约 |
| 团队 | `{data}/teams/` | SQLite 或文件 |
| connectors | `{data}/db/connectors.db` | SQLite |

路径由 `@cline/shared/storage` 的 `resolveClineDataDir()` 决定，可用 `CLINE_DATA_DIR` 覆盖。设计原则：**会话消息要能整体读进内存重建（JSON 重写），但需要并发/租约/索引的用 SQLite**。

---

<h2 id="ch14">第 14 章 横向对比：与 Claude Code / opencode / CodePilot / pi / OpenWorker</h2>

Cline 重构后（CLI v3.0.49 / VS Code 4.1.3 / SDK 0.0.69）处于一个微妙的位置：它既是 **IDE 插件**（历史基因），又是 **CLI**（新形态），还是 **可嵌入引擎**（@cline/sdk）。以下逐维度对比。

### 14.1 引擎架构：单体 vs 分层可嵌入

| 维度 | Claude Code | opencode | Cline v3 | CodePilot | pi | OpenWorker |
|---|---|---|---|---|---|---|
| 架构形态 | 单体（一个 CLI 包） | 单体 TUI | **分层 monorepo + SDK** | Electron 桌面 + 3 Runtime | 9 包 monorepo | 本地 Python 服务 |
| 主循环归属 | 长驻 while-loop driver | 主循环 + doom_loop | **无状态 AgentRuntime（可反复重入）** | Native 循环 in-process | 双层 while loop | TurnEngine 异步循环 |
| 引擎可嵌入 | 否（CLI 为主） | 否 | **是（@cline/sdk）** | 半（Electron 内） | 是（npm 包） | 否（本地服务） |
| 语言/生态 | TS + Ink | TS + SolidJS | TS + bun | TS + Next.js | TS + bun | Python + Rust |

### 14.2 工具与权限

| 维度 | Claude Code | Cline v3 | OpenWorker |
|---|---|---|---|
| 工具数量 | 40（内置） | 28（9 默认 + spawn_agent + 18 team） | 40 个连接器描述符 + 家族工具 |
| 编辑工具 | Edit（单文件 old/new） | **editor + apply_patch 双雄**（后者批量多文件） | 窗口化 read_file / 自研 grep |
| 权限模型 | 命令式审批 + 工具三标记 | **preset 分级（default/yolo）+ per-tool policy** | 五档模式 + §25 精确 target |
| shell 防注入 | 前缀匹配白名单 | （经 run_commands 审批） | **shlex 精确 token + 操作符拦截** |
| 审批 UI | 终端弹窗 | **桌面 IPC 文件轮询（200ms）** | 内联卡 / 收件箱带外审批 |

### 14.3 上下文与缓存

| 维度 | Claude Code | Cline v3 |
|---|---|---|
| 缓存策略 | 内置工具排**连续前缀**（trie） | **MessageBuilder 增量 reindex + outdated 批量重写 + 6MB 兜底**（不赌 provider 缓存） |
| 压缩 | microcompact（0.5-0.6× 即时） | **90% 阈值 + basic 确定性 / agentic LLM 摘要 + 侧车前缀哈希** |
| 记忆 | 自动压缩为主 | 无显式记忆库，靠 checkpoint + 压缩 |

### 14.4 形态与目标

| 维度 | Claude Code | opencode | Cline | CodePilot | pi | OpenWorker |
|---|---|---|---|---|---|---|
| 主要界面 | 终端 TUI | 终端 TUI | **IDE 侧边栏 + CLI + headless** | 桌面 GUI | 终端 TUI | 桌面 + Slack + 无人值守 |
| 多模型 | 锁 Anthropic | 多 provider | **约 179 provider ID / 4118 模型** | 17+ provider | 38 provider | 十几家 + Ollama |
| 多 agent | 子 agent（Task） | 子 agent | **团队（coordinator + specialist）** | Sub-agent | 无 | persona + explorer + self-wake |
| 定时 | 无（计划中） | 无 | **cron（租约防重）** | cron | 无 | 调度器（catch-up + 重叠跳过） |
| 无人值守审批 | 无 | 无 | headless 直接拒绝/auto-approve | 无 | 无 | **收件箱幂等状态机** |
| 协作中心 | 无 | 无 | **hub（本地 WebSocket）** | Bridge（IM） | server/client 协议 | 无（本地优先） |

### 14.5 一句话各自的分工

- **Claude Code**：Claude 深度优化的终端单体——工具前缀缓存、microcompact、命令式 driver 都是为"单一模型极致体验"服务的。
- **opencode**：干净的多 provider 终端 TUI，工程模式（doom_loop、permission 三态）值得抄。
- **Cline**：**广度之王**——模型最多、形态最多（IDE/CLI/CI）、引擎可嵌入。缺点：工具少而精（web/glob 退化）、bun 工具链。
- **CodePilot**：桌面三 Runtime 客户端——同一个前端跑 Claude SDK/Native/Codex 三条引擎。
- **pi**：协议驱动可组合基础设施——无状态循环 + 二进制线协议 + 自扩展 Extensions，理念与 Cline 的"引擎 SDK 化"最接近，但 pi 把 Agent 拆得更碎、走协议。
- **OpenWorker**：交付成品的数字同事——重心在无人值守审批/连接器/定时/收件箱，不为写代码优化。

> 🧠 **一句话**：Cline 重构后的位置是"**Agent 引擎的中立供应商**"——不绑模型（约 180 Provider ID）、不绑界面（IDE/CLI/hub）、不绑语言（SDK 任意嵌入）。如果你要挑一个项目学"怎么把一个 Agent 做成能给别人用的引擎"，Cline 的 monorepo 分层（shared→llms→agents→core→apps）是最完整的教材。

---

<h2 id="ch15">第 15 章 总结：三个最独特的设计与取舍</h2>

### 三件事（如果只记三个设计）

**1. 无状态主循环引擎（@cline/agents）与有状态编排（@cline/core）的硬分离。**
`AgentRuntime` 不知道宿主是谁、不持有持久化；会话层反复 `new AgentRuntime()` 重入循环，用全量转录播种。这让**同一个引擎被 CLI、VS Code、hub 三种宿主驱动**成为可能——这是"引擎产品化"（@cline/sdk）的根。Claude Code 的单体架构做不出这个。

**2. 事件链的三段翻译（AgentRuntimeEvent → legacy AgentEvent → CoreSessionEvent）。**
引擎发出新事件，`RuntimeEventAdapter`（runtime-event-adapter.ts:183）做有状态翻译（usage 增量差值、tool durationMs），再经 AgentEventBridge 给 UI。重构期通过 adapter 保持对旧事件消费者的兼容——这是大型重构的教科书做法。

**3. checkpoint 的 git 事务回滚。**
工作区快照存成 git commit/stash（三父提交捕获 untracked），回滚本身先 stash 再动、可整体 rollback——"回滚回滚"的能力。比 Claude Code 的简单 diff 回滚强一个量级。

### 取舍与"适合谁"

| 维度 | Cline 的选择 | 代价 / 适合谁 |
|---|---|---|
| 形态 | IDE 插件 + CLI + headless 三栖 | 界面层最厚（12.8 万行 VS Code）；纯终端体验不如 Claude Code 顺滑 |
| 引擎 | 分层可嵌入 SDK（@cline/sdk） | 架构清晰，但多包调试成本高；bun 生态（非 node 官方工具链） |
| 模型 | 约 179 Provider ID / 4118 模型，Vercel AI SDK | 广度优先；不像 Claude Code 深度优化单一模型的前缀缓存 |
| 工具 | 9+1+18 声明式目录 + per-model 路由 | 工具少而精；web 搜索/glob 能力被合并退化 |
| 权限 | preset 分级 + 桌面审批 IPC（文件轮询） | 简单可靠；无 OpenWorker 那种精确 target 级 standing rule |
| 压缩 | 90% 阈值 + basic/agentic 双策略 + 侧车缓存 | agentic 成本高；basic 信息损失大 |

**一句话选型**：想要一个**住在 IDE 里、也能跑终端/CI、能嵌进自己产品的开源编程 Agent 引擎**——Cline（尤其重构后的 @cline/sdk）是当前最完整的选择。想要极致深度的 Claude 优化单体，回 Claude Code；想要协议驱动的可组合基础设施，看 pi；想要桌面多引擎客户端，看 CodePilot。

### 🔍 源码指路（回源码核对）

| 想看 | 去这里 |
|---|---|
| 主循环（无状态 while loop） | `sdk/packages/agents/src/agent-runtime.ts:641,677,876,1455,968` |
| 会话编排（跨轮状态） | `sdk/packages/core/src/runtime/orchestration/session-runtime-orchestrator.ts:278,737,1061` |
| 本地宿主（驱动会话） | `sdk/packages/core/src/runtime/host/local-runtime-host.ts:224,334,946,1551` |
| pending prompt / steering | `sdk/packages/core/src/runtime/turn-queue/pending-prompt-service.ts:54,207,281,295,372` |
| 消息整形（缓存友好） | `sdk/packages/core/src/session/services/message-builder.ts:108,166,278,336,1162` |
| 工具目录 + preset | `sdk/packages/core/src/extensions/tools/definitions.ts:247,343,660,917` · `runtime.ts:206-245` · `presets.ts:137` |
| 审批 IPC | `sdk/packages/core/src/runtime/tools/tool-approval.ts:29` |
| 循环检测 / 错误追踪 | `sdk/packages/core/src/runtime/safety/loop-detection.ts:50,113,136` · `mistake-tracker.ts` |
| checkpoint 事务回滚 | `sdk/packages/core/src/session/checkpoint-restore.ts:50,245,357` · `session-versioning-service.ts:134` |
| 压缩（basic/agentic） | `sdk/packages/core/src/extensions/context/compaction.ts:256` · `basic-compaction.ts:452` · `agentic-compaction.ts:97` |
| Provider/模型目录 | `sdk/packages/llms/src/`（vendors/ · catalog/catalog.generated.ts · factory-registry.ts） |
| CLI 入口/headless | `apps/cli/src/index.ts` · `apps/cli/src/main.ts:941-946`（isHeadless 判定）· `apps/cli/src/runtime/run-agent.ts` |
| VS Code 扩展 | `apps/vscode/src/extension.ts:66` · `sdk/SdkController.ts` |

---

*本分析基于 `cline/cline` main 分支 2026-08 实际检出源码撰写（CLI v3.0.49 / VS Code 4.1.3 / SDK 0.0.69），所有结论标注 `文件:行号` 可回源核对。与本系列其他分析同框架。*
