Cline Desktop Sidecar 架构解析:一个 Bun 进程如何把桌面 UI 适配到共享 Cline Hub Cline Desktop Sidecar 架构解析一个 Bun 进程如何把桌面 UI 适配到共享 Cline Hub【免费下载链接】clineAutonomous coding agent as an SDK, IDE extension, or CLI assistant.项目地址: https://gitcode.com/GitHub_Trending/cl/clineCline 桌面应用cline/code的核心枢纽是sidecar/目录下的 sidecar 进程它作为一个独立的 Bun 进程负责把桌面 Webview UI 和操作系统级原生操作适配到 Cline 的共享 HubCline Hub之上。读完本文你会理解 sidecar 的目录组织、HTTP WebSocket 传输协议、ClineCore的 Hub 客户端接入方式、工具审批tool approval的客户端 Promise 决议机制、完整的命令映射表以及如何在本地启动 sidecar 进行开发调试。一、Sidecar 的定位与总体设计sidecar 是一个Bun 进程它的职责可以概括为三件事导入cline/core发现或启动规范化的共享 Hubcanonical shared Hub作为 Hub 客户端client注册到该 Hub通过 HTTP WebSocket 向前端Next.js Webview提供服务。一个关键的设计约束是sidecar 不拥有私有的 agent 运行时 Hub。它复用由 CLI 发现的同一个兼容 Hub如果桌面端是第一个客户端则由 Core 启动规范化的 detached Hub。这保证了同一个工作区内的多个 Cline 客户端CLI、桌面端等收敛到同一个 Hub 进程上。sidecar 的入口文件是 index.ts从源码可以看到启动流程的几个关键节点runEntrypoint()先检查--telemetry-selfcheck参数用于 CI 校验构建期内联的遥测配置再检查claimHubDaemonProcess()如果本进程被选为 Hub daemon 宿主则直接转入cline/core/hub/daemon-entry让 sidecar 二进制承担共享 Hub 守护进程的启动职责否则进入main()解析工作区根目录、设置 home 目录、启动可观测性、创建SidecarContext、预热工作区元数据、initializeSessionManager()接入 Hub最后调用startServer()启动 HTTP WS 服务就绪后向 stdout 输出一行 JSONtype: ready携带endpoint、wsEndpoint含approval_token查询参数、pid、mode宿主应用据此把前端指向 sidecar进程通过SIGINT/SIGTERM/beforeExit统一走shutdown()并带 5 秒超时保护watchManagedHubBuildMismatch()会在其他 Cline 安装如更新后的 CLI替换共享 Hub 时向前端广播hub_build_mismatch事件提示用户更新重启。二、目录结构与职责划分ARCHITECTURE.md 中给出的核心目录结构如下sidecar/ ├── index.ts # Entry point: starts HTTPWS server ├── server.ts # Bun HTTP server WebSocket handlers ├── context.ts # SidecarContext type and factory ├── commands.ts # Command router ├── chat-session.ts # Shared-Hub chat session adapter ├── session-data/ # Shared discovery, messages, artifacts, search helpers ├── paths.ts # Path resolution ├── types.ts # Shared types └── ARCHITECTURE.md # This file结合当前仓库的实际目录sidecar/围绕上述核心还扩展了attachments.ts附件物化、mcp.ts/mcp-oauth.tsMCP 配置与 OAuth、marketplace.ts插件市场目录、observability.ts日志与遥测、shell-path.ts登录 shell PATH 修复、telemetry-selfcheck.ts等模块每个模块都配有同名.test.ts测试文件。几个核心文件的实际职责以源码为准types.ts定义SidecarContext含liveSessions、pendingApprovals、pendingQuestions、wsClients、sessionManager、hubClient等字段并导出环境配置常量SIDECAR_PORT Number(process.env.CLINE_SIDECAR_PORT) || 3126SIDECAR_HOST process.env.CLINE_SIDECAR_HOST?.trim() || 127.0.0.1默认仅监听回环地址注释说明可通过CLINE_SIDECAR_HOST0.0.0.0开放给容器端口映射等场景。context.tsSidecarContext工厂与ClineCore初始化、Hub 客户端管理、事件路由的所在地。commands.ts命令路由器handleCommand(ctx, command, args, options)按命令名分发到各子模块。paths.ts路径解析。resolveWorkspaceRoot()用git rev-parse --show-toplevel定位工作区根sharedSessionDataDir()优先读CLINE_SESSION_DATA_DIR否则回退到resolveSessionDataDir()MCP 设置路径默认为~/.cline/data/settings/cline_mcp_settings.json可被CLINE_MCP_SETTINGS_PATH覆盖会话日志写到~/.cline/apps/kanban/sessions/sessionId.jsonl可被CLINE_KANBAN_DATA_DIR覆盖。三、传输协议Request / Response / Event 三件套前端与 sidecar 之间走 WebSocket消息格式固定为三种文档原文协议保持不变Request: { type: command, id: string, command: string, args?: object } Response: { type: response, id: string, ok: boolean, result?: unknown, error?: string } Event: { type: event, event: { name: string, payload: unknown } }在 server.ts 中可以确认这条协议的落地细节createWebSocketHandler()的message()对每条入站消息做JSON.parse成功后调用handleCommand(ctx, request.command, request.args, { connection: ws })用jsonResponse(id, true, result)或jsonResponse(id, false, undefined, message)回包事件编码统一由encodeSidecarEvent(name, payload)位于 context.ts完成即{type:event,event:{name:...,payload:...}}。除/transportWebSocket 端点外HTTP fetch 处理器还暴露了若干端点端点作用GET /health返回{ ok: true, mode: sidecar, pid }用于存活探测POST /shutdown仅信任 origin 可调用异步触发onShutdown后process.exit(0)GET /api/marketplace/catalog返回插件市场目录失败时返回带error字段的空目录POST /telemetry/error接收 Webview 的前端错误上报字段截断后写入 SDK 遥测安全边界Origin 校验与 approval token/transport的 WebSocket 升级有两层门禁Origin 白名单TRUSTED_BROWSER_ORIGINS默认包含tauri://localhost、http://tauri.localhost、https://tauri.localhost、http://localhost:3125、http://127.0.0.1:3125可通过CLINE_SIDECAR_TRUSTED_ORIGINS逗号分隔追加approval tokenstartServer()生成或读取CLINE_SIDECAR_APPROVAL_TOKEN一个 token升级请求必须携带?approval_token...且通过timingSafeEqual恒定时间比较才会给该连接标记canApproveTools: true。源码注释明确说明无 origin 的本地客户端仍然可以连接但只有携带了有效 token 的浏览器托管桌面 UI 才能接收和决议审批。审批类命令poll_tool_approvals、hub_upgrade等在 commands.ts 中都会检查options.connection.data.canApproveTools不满足则直接抛错。另外startServer()采用“首选端口 OS 分配端口0”双候选策略若3126被占用则自动回退避免端口冲突直接启动失败。四、核心设计决策1. 聊天会话 —— 共享 Hub 客户端sidecar 通过ClineCore以 Hub 模式接入且不指定显式 endpoint。ClineCore因此复用 CLI 发现的同一个兼容 Hub当桌面端是第一个客户端时则启动规范化的 detached Hub。context.ts 中initializeSessionManager()的实际实现与文档示例一致并额外注入了能力、日志、遥测与特性开关const sessionManager await ClineCore.create({ clientName: cline-code, backendMode: hub, capabilities: createSidecarRuntimeCapabilities(ctx), logger: ctx.logger, telemetry: ctx.telemetry, featureFlags: getDesktopFeatureFlagsService({ ... }), hub: { strategy: require-hub, workspaceRoot: ctx.workspaceRoot, cwd: ctx.workspaceRoot, clientType: code-sidecar, displayName: Cline Desktop sidecar, }, });随后sessionManager.subscribe((event) handleCoreSessionEvent(ctx, event))订阅全部会话事件并转发给 WS 客户端ensureSharedHubClient(ctx, sessionManager.runtimeAddress)再创建第二个NodeHubClientclientType: code-sidecar-observer用ensureCompatibleLocalHubUrl({ strategy: require-hub, ... })解析 Hub URL 后connect()并subscribe(handleHubLiveEvent)。这个观察客户端用于接收 Hub 级事件如 Agenda 任务审批、task.*生命周期事件、经 Hub 附加的会话流。启动发现与加锁机制确保并发客户端收敛到同一个 Hub编译后的 sidecar 还识别 Core 的 Hub daemon 启动模式即上文claimHubDaemonProcess()分支让桌面端在尚无 CLI 进程时也能拉起同一个 detached Hub。会话事件如何变成前端 chunkhandleAgentEvent()将AgentEvent映射为chat_text、chat_reasoning、chat_tool_call_start/update/end、chat_media、chat_core_log、chat_usage、chat_done等流统一经emitChunk()广播并同步追加到会话日志文件每 session 串行化写入避免同步写阻塞事件循环。handleHubLiveEvent()则处理观察客户端路径把assistant.delta、reasoning.delta、tool.started/updated/finished、run.started/completed/failed/aborted等 Hub 事件翻译为同样的chat_*chunk供经 Hub 附加的会话attachedViaHub使用。chat_session_command支持的动作集合在 types.ts 的ChatSessionCommandRequest中定义start、attach、send、stop、abort、fork、reset、restore_checkpoint、pending_prompts、steer_prompt、update_pending_prompt、remove_pending_prompt。2. 工具审批 —— 客户端持有 Promise 决议共享 Hub 把审批请求路由回创建该会话的客户端。桌面端在 Webview 在线期间用内存 Promise Map 处理审批context.ts 中的实现requestSidecarToolApproval要点从ctx.wsClients中找到第一个canApproveTools true的连接作为 owner若没有直接拒绝并附原因No trusted desktop approval surface is connected将{ item, owner, resolve }存入ctx.pendingApprovals再向 owner 推送tool_approval_state事件携带该会话全部待审批项前端响应respond_tool_approval命令时 resolve 对应 Promiseowner 断连时cancelSidecarToolApprovalsForOwner()会把它名下的所有 pending 以{ approved: false, reason: Desktop approval surface disconnected }决议防止审批永远挂起连接集合变化开关 WS时syncSidecarApprovalReadiness()会向 Hub 更新客户端能力只要有能审批的 webview 在线就声明HUB_CLIENT_TOOL_APPROVAL_CAPABILITYCline Code has a live user surface for tool review.对于经 Hub 触发的任务审批approval.requested事件handleHubApprovalRequest()先走同一套桌面审批 Promise再把结果通过hubClient.command(approval.respond, { approvalId, approved, reason }, sessionId)回传 Hub。与审批同构的还有ask_question机制requestSidecarAskQuestion()把问题推送给前端并挂起 Promise带ASK_QUESTION_TIMEOUT_MS 5 分钟超时超时以ask_question_cancelled事件通知前端并 reject。3. 供应商管理 —— 直接使用 ProviderSettingsManagerimport { ProviderSettingsManager, listLocalProviders, ... } from cline/core; const manager new ProviderSettingsManager();供应商相关命令list_provider_catalog、list_provider_models、save_provider_settings、add_provider、run_provider_oauth_login都直接调用cline/core的本地供应商 API不经过 Hub。4. 会话存储 —— 直接使用 SqliteSessionStoreimport { SqliteSessionStore, resolveSessionBackend } from cline/core; const store new SqliteSessionStore();list_chat_sessions组合SqliteSessionStore与文件发现update_chat_session_title走resolveSessionBackend().updateSessiondelete_chat_session执行SqliteSessionStore.delete并清理文件产物。5. 例行计划Routine Schedules—— 直连 Hub 命令例行操作复用与聊天会话观察相同的已连接 Hub 客户端绝不启动第二个进程内 Hubawait ctx.hubClient.command(schedule.list, { limit: 200 });6. 原生命令pick_workspace_directory—— macOS 用osascript、Linux 用zenity弹出目录选择器open_mcp_settings_file—— 用open/xdg-open打开文件。7. 前端连接前端 desktop-client.ts 直接连接 sidecar 的 WebSocket优先从window.__SIDECAR_WS_ENDPOINT__发现端点由 sidecar 的 HTML scaffold 注入未注入时回退到默认值ws://127.0.0.1:3126/transport与 types.ts 中的默认端口一致不依赖 Tauri保持相同的invoke()/subscribe()API。五、命令映射表Command Map以下命令映射表完整继承自 ARCHITECTURE.md并可与 commands.ts 中的handleCommand实现一一对应Command实现chat_session_command经ClineCore走共享 Hublist_provider_catalogProviderSettingsManagerlistLocalProviderslist_provider_modelsgetLocalProviderModelssave_voice_input_settings校验并持久化所选转写供应商/模型create_streaming_transcription_session签发短时效、绑定转写用途的浏览器 token不暴露供应商凭据transcribe_audio已配置的语音输入选择 供应商凭据save_provider_settingssaveLocalProviderSettingsadd_provideraddLocalProviderrun_provider_oauth_loginloginLocalProviderlist_chat_sessionsSqliteSessionStore 文件发现list_discovered_sessions合并发现merged discoveryread_session_messages会话数据读取器commands.ts中默认maxMessages: 800read_session_hooks会话数据读取器默认limit: 300delete_chat_sessionSqliteSessionStore.delete 文件清理update_chat_session_titleresolveSessionBackend().updateSessionlist_mcp_servers直接文件 I/Oauthorize_mcp_server_oauth显式 Connect 动作 → 可取消的authorizeMcpServerOAuth 系统浏览器cancel_mcp_server_oauth取消挂起的 MCP OAuth 回调等待upsert_mcp_server直接文件 I/Odelete_mcp_server直接文件 I/Oget_git_branch异步execFile(git, ...)list_git_branches异步execFile(git, ...)checkout_git_branch异步execFile(git, ...)search_workspace_filesgetFileIndexget_process_context内存上下文返回 workspaceRoot、平台、app 版本、运行中会话数、Hub 连接状态等poll_tool_approvals内存 pending map需可信连接respond_tool_approval内存 Promise 决议poll_ask_questions内存 pending maprespond_ask_question内存 Promise 决议list_routine_schedules共享 Hub schedule 命令list_user_instruction_configs直接 core APIpick_workspace_directoryOS 原生对话框open_mcp_settings_fileOSopen命令从源码结构看handleCommand还包含文档表格未逐一列出的命令例如proceed_while_running转发run.proceed_while_runningHub 命令、list_session_agents、hub_upgrade强制升级托管 Hub同样要求可信桌面连接等阅读 commands.ts 可获得完整清单。六、开发工作流文档给出的开发命令可在 package.json 中核对对应脚本bun run dev:headless # Start sidecar and Next.js with a fresh shared approval credential bun run dev:sidecar # Start only the sidecar (no browser approval surface) bun run dev:web # Start only Next.js (no authenticated approval connection) bun run dev # Both concurrently脚本实际定义dev:sidecar执行bun run sidecar/index.tsdev:web执行next dev webview -p 3125 --turboNext.js 跑在 3125 端口正好命中 sidecar 的默认信任 origin 列表dev:headless走scripts/dev-headless.ts以全新共享审批凭据同时拉起 sidecar 与 Next.jsdev则是tauri dev完整桌面壳。七、关键环境变量速查综合 types.ts、server.ts 与 paths.ts 的解析逻辑环境变量默认值作用CLINE_SIDECAR_PORT3126sidecar 首选监听端口被占用时自动回退到 OS 分配端口CLINE_SIDECAR_HOST127.0.0.1监听地址设为0.0.0.0可接受外部连接如 Docker 端口发布但对外通告的 dial 地址仍为回环CLINE_SIDECAR_TRUSTED_ORIGINS空逗号分隔的额外信任 origin容器内非标准端口的 dev server 等场景CLINE_SIDECAR_APPROVAL_TOKEN运行时随机 UUID审批 token前端 WS 连接需携带才能标记canApproveToolsCLINE_HUB_PORT空显式钉住 Hub 端点设置后跳过启动期的 build mismatch 检测该宿主仅保持协议兼容CLINE_SESSION_DATA_DIRresolveSessionDataDir()共享会话数据目录CLINE_MCP_SETTINGS_PATH~/.cline/data/settings/cline_mcp_settings.jsonMCP 设置文件路径CLINE_TOOL_APPROVAL_DIR会话数据目录/tool-approvals工具审批目录保留用于文件清理兼容CLINE_KANBAN_DATA_DIR~/.cline/apps/kanban会话日志.jsonl根目录八、小结sidecar 的设计可以浓缩为三条主线传输层保持极简的三消息协议command/response/event并叠加 origin 白名单 approval token 双门禁运行时层坚持“共享 Hub、不私起 Hub”通过ClineCorerequire-hub策略与NodeHubClient观察客户端两条通道接入让桌面端与 CLI 等客户端共享同一 Hub 实例交互层把审批、提问等跨端等待统一实现为“推送事件 内存 Promise 决议 断连自动取消/拒绝”的模式保证了 UI 离线时 agent 流程不会被永久阻塞。理解了 ARCHITECTURE.md 描述的协议骨架再对照 index.ts、server.ts、context.ts 与 commands.ts 的实现即可完整掌握 Cline Desktop sidecar 从进程启动到事件回传的全链路。【免费下载链接】clineAutonomous coding agent as an SDK, IDE extension, or CLI assistant.项目地址: https://gitcode.com/GitHub_Trending/cl/cline创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考