源码解析 · 第十八份 · CLI v3.0.49

从 IDE 插件
到可嵌入引擎

Cline 曾经是「VS Code 侧边栏里的编程 Agent」,重构后变成「引擎(SDK)与界面(CLI/VS Code/hub)分离的 monorepo」——无状态 AgentRuntime 主循环、28 个工具、179 个 Provider ID / 4118 个模型、git checkpoint 事务回滚、basic/agentic 双策略压缩、多 agent 团队。全文标注 文件:行号,可追溯到具体源码。

28
内置工具
179
Provider ID
4118
模型
5
层 monorepo

分析对象:cline(github.com/cline/cline),Apache-2.0,本分析基于 main 分支 2026-08 检出。仓库无统一版本号:apps/cliv3.0.49(下文提到的 v3.0.49 均指 CLI),apps/vscode(包名 claude-dev)为 4.1.3sdk/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 的"连续前缀缓存排序"。 读者对象:已经读过本系列至少一份分析的读者。本文沿用统一框架,标注 文件:行号,可回源码核对。


Part 2

第 1 章 项目概览:从 VS Code 插件到"引擎 + 界面" monorepo

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 商业友好

Part 3

第 2 章 全景架构:五层栈 + 三条宿主 + 一条事件链

官方 sdk/ARCHITECTURE.md 画的分层图(单向依赖,不允许反向):

flowchart LR
    SH["@cline/shared
低层契约:storage/llms/db/cron/hooks/tools"] --> LL["@cline/llms
Provider 运行时:AI SDK 适配 + 模型目录"] LL --> AG["@cline/agents
无状态主循环:AgentRuntime"] AG --> CO["@cline/core
有状态编排:会话/存储/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 循环。AgentRuntimeagent-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 三种宿主反复驱动,而循环本身不知道宿主是谁。


Part 4

第 3 章 启动流程:CLI / VS Code / hub daemon 三个入口

入口一: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.tsauthconfigpluginskillconnectmcpdoctorhookschedulehubdashboardhistoryteam + 默认 chat。共享根选项在 commands/program.ts--plan--json--auto-approve-c --cwd-P --provider-k --key-z --zen--config)。

和 core 的集成session/session.tscreateCliCore()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 的连接是进程内直接 importextension.tsSdkController.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.tsdaemon/entry.ts

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

鉴权与数据

登录走 WorkOS Device Flow + OAuthauth/cline.tsapi.workos.com/user_management/*),本地 OAuth server 回调端口 48801-48811;Provider 密钥存 ~/.cline/data/secrets.json(chmod 0o600)。


Part 5

第 4 章 输入捕获与分流:交互、headless、steering 打断、pending prompt

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.tsemitJsonLine 逐行写 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 执行会话。


Part 6

第 5 章 上下文组装:MessageBuilder 的 API 安全整形

MessageBuildercore/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.tscomposeSystemPrompt()(约 L679)= config.systemPromptbuildClineSystemPrompt 拼 IDE/工作区元数据/rules/mode 等段)+ 插件规则 mergeSystemPromptRules(约 L102)。工具定义由 orchestrator 单独传给 provider,不塞进消息数组

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


Part 7

第 6 章 Agent 主循环(心脏):AgentRuntime 的无状态 while loop

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

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

每个 turn = 一次 generateAssistantMessageWithOverflowRecovery() + 若干 executeToolCalls()。无 tool-call 或命中 submit_and_exitlifecycle.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 编解码。


Part 8

第 7 章 工具系统与审批:28 个工具 + 五套 preset + 桌面审批 IPC

工具清单(28 个)

extensions/tools/constants.tsALL_DEFAULT_TOOL_NAMES(9 个):read_filessearch_codebaserun_commandsfetch_web_contentapply_patcheditorskillsask_questionsubmit_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 行)

流程:模型发出工具调用 → SessionRuntimetoolPolicies 合并全局 * 与工具级策略(session-runtime-orchestrator.ts:117-133)判 enabledbeforeTool 钩子(含循环检测)→ 若 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.tsBASE_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 路由规则显式决定哪些工具可见。


Part 9

第 8 章 安全护栏:loop-detection、mistake-tracker、subprocess-sandbox

死循环检测(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_failedrecord() 累加 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 段。


Part 10

第 9 章 会话、checkpoint 与版本化:git 快照回滚

会话数据模型(session/models + stores)

  • 索引sessions.index.json(file-session-service.ts L50)——{version:1, sessions: {sessionId: SessionRow}} 单文件全量 JSON,atomicWriteJson 临时文件+rename 原子替换,statusLock 乐观并发(CAS)。
  • manifestsessions/<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 最优雅的工程之一。


Part 11

第 10 章 上下文压缩:basic 确定性折叠 vs agentic LLM 摘要

触发(extensions/context/compaction.ts,710 行):createContextCompactionPrepareTurn(L256)每次模型请求前估算 requestInputTokenstrigger = 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)。findCutIndexpreserveRecentTokens(默认 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 更接近"检查点 + 全文摘要 + 可回滚"的宏观设计。


Part 12

第 11 章 Provider 层:Vercel AI SDK + 约 180 Provider ID + 4118 个模型

@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.tsBUILT_IN_PROVIDER 枚举约 50 项 + models.dev 自动生成 163 个 ID;去重并集约 179 个可注册 ID(不是 48+163=211,也难称「200+」)。catalog.generated.ts 约 87K 行 / 4118 个模型。
  • 双注册 Factoryfactory-registry.tsregisterHandler/registerAsyncHandler)+ createHandler(config):先查注册表,否则落到 gateway.tscreateGatewayApiHandlerGatewayRegistry 持有 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 遥测)。
  • 流式与 tokenai-sdk.tsstreamText + formatMessagesForAiSdk;usage 归一化为 GatewayNormalizedUsage(inputTokens/outputTokens/cacheReadTokens/cacheWriteTokens/reasoningTokenCount/totalCost)。
  • 模型目录catalog/catalog.generated.ts87274 行,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 触发靠它。


Part 13

第 12 章 生态:插件、MCP、hooks、多 agent 团队、cron、connectors、hub

插件系统(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。运行时钩子 AgentHooksbeforeRun / 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_logclaim_token+claim_until_at 租约机制防多进程重复执行。触发:one_off / schedule(cron 表达式)/ eventschedule-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。


Part 14

第 13 章 存储:JSON 文件 + SQLite 混合

数据 位置 实现
全局设置 {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/storageresolveClineDataDir() 决定,可用 CLINE_DATA_DIR 覆盖。设计原则:会话消息要能整体读进内存重建(JSON 重写),但需要并发/租约/索引的用 SQLite


Part 15

第 14 章 横向对比:与 Claude Code / opencode / CodePilot / pi / OpenWorker

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)是最完整的教材。


Part 16

第 15 章 总结:三个最独特的设计与取舍

三件事(如果只记三个设计)

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),所有结论标注 文件:行号 可回源核对。与本系列其他分析同框架。