拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Gemini CLI DevTools:终端 Agent 的本地 Network 与 Console 检查器实现解析

Gemini CLI DevTools终端 Agent 的本地 Network 与 Console 检查器实现解析【免费下载链接】gemini-cliAn open-source AI agent that brings the power of Gemini directly into your terminal.项目地址: https://gitcode.com/GitHub_Trending/gemi/gemini-cli当在 Gemini CLI 中启用general.devtools设置后CLI 会自动探测或启动一个监听在 25417 端口的本地 DevTools 服务实时捕获 Agent 会话发出的所有网络请求含流式响应分块与耗时和控制台日志log/warn/error/debug/info并通过一个类似 Chrome DevTools 的网页界面进行检视。本文以 packages/devtools/GEMINI.md 为主线结合 devtools 服务端实现、CLI 侧编排逻辑 与日志捕获层 的源码完整讲解其功能全景、端口竞争协调机制、WebSocket/SSE 数据协议、日志脱敏策略以及构建开发流程。功能全景一个“Chrome DevTools 式”的终端检视器DevTools 包提供四个核心能力与 GEMINI.md 的 Features 一节一一对应Network Inspector网络检查器实时记录请求/响应支持流式响应分块streaming chunks的逐块可视化与整体耗时duration追踪。对于大模型流式 API 这类“响应体分多次到达”的场景可以逐块观察 SSE 数据块何时到达。Console Inspector控制台检查器实时查看五种级别的控制台日志log/warn/error/debug/info。Session Management会话管理支持多个并发的 CLI 会话接入同一 DevTools 实例并显示实时连接状态UI 中可按会话过滤日志。Import/Export导入/导出可导入 JSONL 格式的日志文件即 CLI 文件日志模式的产物也可将当前会话日志导出为文件离线分析。如何启用与触发DevTools 由配置项general.devtools控制。从 settingsSchema.ts 可以看到其定义布尔类型、默认false、requiresRestart: false描述为 “Enable DevTools inspector on launch.”。启动链路分两条日志捕获初始化gemini.tsx 在交互式模式下检测到settings.merged.general.devtools为真时动态导入utils/devtoolsService.js并调用setupInitialActivityLogger(config)——注意这一步只是开始缓冲日志并不启动服务器。F12 触发检查器AppContainer.tsx 中Command.SHOW_ERROR_DETAILS键F12绑定到toggleDevToolsPanel它负责真正启动 DevTools 服务并尝试打开浏览器。文档中所述gemini.tsx / nonInteractiveCli.ts经由 dynamic import 接入devtoolsService的架构即来源于此。toggleDevToolsPanel的行为策略值得注意见 devtoolsService.tsexport async function toggleDevToolsPanel( config: Config, isOpen: boolean, toggle: () void, setOpen: () void, ): Promisevoid { if (isOpen) { toggle(); // 面板已打开 → 直接关闭 return; } try { const { openBrowserSecurely, shouldLaunchBrowser } await import( google/gemini-cli-core ); const url await startDevToolsServer(config); if (shouldLaunchBrowser()) { try { await openBrowserSecurely(url); return; // 浏览器打开成功 → 不再弹出内嵌面板 } catch (e) { /* ... */ } } setOpen(); // 无法打开浏览器时 → 打开 TUI 内嵌面板 } catch (e) { setOpen(); } }即优先在外部浏览器中打开http://localhost:port在无图形环境或打开失败时回退到 TUI 内嵌抽屉。工作原理端口探测、竞争协调与“晋升”文档 “How It Works” 一节描述的机制在源码中对应startOrJoinDevTools与handlePromotion探测CLI 先对127.0.0.1:25417的/ws路径发起一次 WebSocket 握手500ms 内成功打开即认为已有 DevTools 实例存活probeDevTools见 devtoolsService.ts。复用探测到实例则直接作为 WebSocket 客户端接入不重复起服务。自启探测失败则动态import(google/gemini-cli-devtools)取DevTools.getInstance()单例并start()。竞争裁决若两个 CLI 进程同时抢端口输的一方会检测到自身实际绑定端口不等于 25417服务端在EADDRINUSE时自动递增端口重试最多 10随后探测胜者是否存活——存活则停止自己的服务、转为客户端连向胜者若“胜者”无响应则保留自己实际绑定的端口继续服务见 devtoolsService.ts 与 index.ts。if (actualPort defaultPort) { // We won the port — we are the server return { host: defaultHost, port: actualPort }; } // Lost the race — someone else has the default port. const winnerAlive await probeDevTools(defaultHost, defaultPort); if (winnerAlive) { await devtools.stop(); return { host: defaultHost, port: defaultPort }; } // Winner isnt responding — keep ours此外还有一条“晋升”路径会话启动时日志以buffering 模式拦截暂存内存F12 或general.devtools触发时才挂接网络传输若 WebSocket 断开且 2 次重连失败handlePromotion会尝试重新“start or join”一个服务并挂上新的网络传输最多尝试 3 次MAX_PROMOTION_ATTEMPTS 3。整个过程无需任何环境变量——文档中 “No environment variables needed for normal use” 即指此。架构五层数据流原文档给出的架构分层如下每一层都能在当前仓库中找到对应实现gemini.tsx / nonInteractiveCli.ts │ (dynamic import) ▼ devtoolsService.ts ← orchestration DevTools lifecycle │ (imports) ▼ activityLogger.ts ← pure logging (capture, file, WebSocket transport) │ (events) ▼ DevTools server (:25417) ← this package (HTTP WebSocket SSE) │ (SSE /events) ▼ DevTools UI (React) ← client/ compiled by esbuild入口层gemini.tsx交互式与nonInteractiveCli.tsheadless通过 dynamic import 延迟加载 DevTools避免未启用时的启动开销。编排层devtoolsService.ts 负责生命周期探测、竞争裁决、并发调用去重startDevToolsServer对 in-flight 调用返回同一个 Promise、晋升重试。捕获层activityLogger.ts 是“纯日志”层负责拦截、文件落盘、WebSocket 传输对外以事件network/console/network-logging-enabled驱动下游。服务端packages/devtools/src/index.ts 中的DevTools类同时承担 HTTP 静态资源、WebSocket 接入、SSE 推送三种职责。UI 层client/src/App.tsx 的 React 应用由 esbuild 编译后内嵌进服务端见下文构建部分。服务端实现HTTP、WebSocket 与 SSE 三合一DevTools类是单例getInstance()默认端口 25417只绑定127.0.0.1从源码结构看这是一个纯本地组件。它内置了若干工程细节同源防护。HTTP 处理器对带Origin头的请求只放行http://127.0.0.1:port源码注释说明原因日志可能包含 API 密钥与请求头不能允许任意网页跨域窃取index.ts。SSE 快照 增量推送。/events端点在连接建立时立即写出一条event: snapshot内容为{ networkLogs, consoleLogs, sessions }全量快照之后订阅三个内部事件做增量推送事件名触发内容snapshotSSE 连接建立时网络日志 控制台日志 会话列表全量networkupdate事件单条NetworkLog新建或按 id 合并后的更新consoleconsole-update事件单条InspectorConsoleLogsessionsession-update事件当前全部会话 id 数组UI 断线重连后无需轮询靠 snapshot 事件即可恢复完整状态。会话注册与心跳。WebSocket 挂在/ws路径第一条消息必须是register携带 CLI 的sessionId服务端回registered确认并广播session-update随后每 10 秒向各会话发ping超过 30 秒未回pong的会话被关闭并从会话表移除index.ts。内存上限。控制台日志在服务端保留上限为 5000 条超出后丢弃最旧index.ts。从源码结构看服务端内存中的网络日志列表同样做了最旧项驱逐以约束内存UI 端依赖增量network事件自行累积展示二者分工互补。类型契约。共享的数据结构定义在 types.tsexport interface NetworkLog { id: string; sessionId?: string; timestamp: number; method: string; url: string; headers: Recordstring, string | string[] | undefined; body?: string; pending?: boolean; chunks?: Array{ index: number; data: string; timestamp: number }; response?: { status: number; headers: Recordstring, string | string[] | undefined; body?: string; durationMs: number; }; error?: string; } export interface ConsoleLogPayload { type: log | warn | error | debug | info; content: string; }chunks字段对应文档所说的 streaming chunks响应体流式到达时每个块带index与timestamp单独上报pending: true流结束后合并出完整response含durationMs。服务端在收到完整response.body后会丢弃冗余的chunks源码注释指出这是为了避免快照序列化时超出 V8 字符串上限index.ts。API 端点一览继承原文档的端点表并补充源码中可验证的行为细节EndpointMethodDescription/wsWebSocketLog ingestion from CLI sessionsregister/network/console另有ping/pong心跳与trigger-debugger下行消息/eventsSSEPushes snapshot on connect, then incremental network/console/session events/api/trigger-debuggerPOSTTriggers the Node.js debugger for a specific CLI session via WebSocket/api/trigger-debugger的完整链路是HTTP 层校验{ sessionId: string }请求体非法返回 400会话不存在返回 404见 index.ts→ 向目标会话的 WebSocket 下发{ type: trigger-debugger }→ CLI 侧 activityLogger.ts 收到后调用node:inspector的inspector.open()在调试器附加时提示用户在 Chrome 中打开chrome://inspect。也就是说UI 端可以按会话“远程”挂上 Node.js 调试器。此外还有两个静态资源路由/或/index.html返回内嵌的INDEX_HTML/assets/main.js返回内嵌的CLIENT_JS其余路径 404。CLI 侧捕获fetch 与 http/https 双重拦截ActivityLoggeractivityLogger.ts是单例enable()后通过 monkey-patch 两类出口global.fetch拦截为每个请求生成随机 id并注入x-activity-request-id请求头ACTIVITY_ID_HEADER常量先以pending: true上报请求信息再response.clone()后用 reader 逐块读取响应体每块触发一次带chunk的增量上报最后合并出完整响应与durationMs。http.request/https.request拦截用Object.defineProperty替换模块导出包装write/end收集请求体监听response的data/end事件收集响应流对content-encoding: gzip / deflate会用zlib.gunzip / inflate解压后再记录保证 UI 里看到的是可读明文。两条拦截路径共享三个重要策略本机流量豁免URL 包含127.0.0.1或localhost的请求直接放行不拦截——DevTools 自身通信与本地服务不进入检查器。敏感头脱敏sanitizeNetworkLog将请求头中的authorization、cookie、x-goog-api-key以及响应头中的set-cookie统一替换为[REDACTED]activityLogger.ts。这与服务端只绑回环地址、同源 CORS 两道防线叠加构成对凭据泄露的纵深防护。缓冲与背压网络事件按请求 id 分组缓冲bufferLimit 10组控制台日志缓冲 10 条WebSocket 未连接或网络日志未开启时消息进入传输缓冲上限 100 条注册成功后按时间戳排序一次性flushBuffer()补齐。三种传输模式与环境变量文档的 Environment Variables 一节列出了唯一的变量VariableDescriptionGEMINI_CLI_ACTIVITY_LOG_TARGETFile path for JSONL mode (optional, fallback)它对应setupInitialActivityLogger的模式选择逻辑devtoolsService.tsexport function setupInitialActivityLogger(config: Config) { const target process.env[GEMINI_CLI_ACTIVITY_LOG_TARGET]; if (target) { if (!config.storage) return; initActivityLogger(config, { mode: file, filePath: target }); } else { // Start in buffering mode — transport attached later on F12 initActivityLogger(config, { mode: buffer }); } }file 模式JSONL 落盘默认路径为项目临时日志目录下的session-sessionId.jsonl设置GEMINI_CLI_ACTIVITY_LOG_TARGET可覆盖路径。每行格式为{ type: console | network, payload, sessionId, timestamp }。buffer 模式默认路径只拦截 内存缓冲F12 触发时才挂网络传输并 flush 缓冲——这让未打开检查器的日常使用几乎零开销。控制台日志来源bridgeCoreEvents将 core 包的CoreEvent.ConsoleLog事件桥接进ActivityLogger.logConsole因此 UI 里看到的正是 CLI 内部各级别日志。客户端 UI 与构建管线client/src/App.tsx 是一个约 2000 行的单文件 React 应用另有 hooks.ts 提供 SSE 数据获取。从源码可见的功能包括Console / Network 两个标签页、会话过滤selectedSessionId、JSONL 导入按行解析{ type, payload }结构——与 file 模式产物完全兼容、以及持久化到localStorage的深浅色主题。数据获取依赖/events的 SSE 流snapshot 建立基线增量事件实时追加。构建管线的设计很有意味esbuild.client.jsawait esbuild.build({ entryPoints: [client/src/main.tsx], bundle: true, minify: true, format: esm, target: es2020, jsx: automatic, outfile: dist/client/main.js, define: { process.env.NODE_ENV: production }, }); // Embed client assets as string constants so the devtools server can be // bundled into the CLI without needing readFileSync __dirname at runtime. const indexHtml readFileSync(client/index.html, utf-8); const clientJs readFileSync(dist/client/main.js, utf-8); writeFileSync( src/_client-assets.ts, ... export const INDEX_HTML ${JSON.stringify(indexHtml)}; export const CLIENT_JS ${JSON.stringify(clientJs)};, );即构建时把index.html与压缩后的main.js作为字符串常量生成到src/_client-assets.ts服务端直接import { INDEX_HTML, CLIENT_JS }引用index.ts。这样 DevTools 服务端可以整体 bundle 进 CLI 发行包运行时不需要__dirname或文件读取天然适配 SEA/打包场景。package.json 中可确认的关键信息包名google/gemini-cli-devtools、入口dist/src/index.js、运行时依赖仅ws8.16.0React 19 仅为客户端构建期依赖、engines.node 20。开发构建与项目结构继承原文档 Development 一节的命令对应 package.json 的 scripts 字段build实际为build:client tsc -p tsconfig.build.json# Build everything (client server) npm run build # Rebuild client only after UI changes npm run build:client项目结构与 GEMINI.md 的 Project Structure 一节一致packages/devtools/ ├── src/ │ └── index.ts # DevTools server (HTTP, WebSocket, SSE) ├── client/ │ ├── index.html │ └── src/ │ ├── main.tsx # React entry │ ├── App.tsx # DevTools UI │ └── hooks.ts # Data fetching hooks ├── esbuild.client.js # Client build script └── dist/ # Build output ├── src/index.js # Compiled server └── client/ # Bundled client assets小结设计取舍回顾把文档与源码对照后可以提炼出 DevTools 包的几个核心设计决策“先探测、后竞争、再裁决”25417 默认端口 探测 端口递增重试最多 10 次 竞争败者转客户端保证多 CLI 会话共享同一个检查器且对“胜者假死”有兜底。零环境变量、渐进开销日常运行只有内存缓冲F12 才挂传输GEMINI_CLI_ACTIVITY_LOG_TARGET仅作 JSONL 文件模式的可选旁路。安全纵深仅绑定回环地址、同源 CORS、敏感头[REDACTED]、本机流量豁免四条防线共同约束可能含凭据的日志。资产内嵌客户端以字符串常量形式编译进服务端模块使整个 DevTools 可以无运行时文件依赖地随 CLI 分发。关键源码入口服务端 packages/devtools/src/index.ts、类型 packages/devtools/src/types.ts、CLI 编排 packages/cli/src/utils/devtoolsService.ts、捕获层 packages/cli/src/utils/activityLogger.ts、配置定义 packages/cli/src/config/settingsSchema.ts。【免费下载链接】gemini-cliAn open-source AI agent that brings the power of Gemini directly into your terminal.项目地址: https://gitcode.com/GitHub_Trending/gemi/gemini-cli创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门