Monorepo 架构与包设计
Gemini CLI — Monorepo 架构与包设计
学习目标
- 理解 Gemini CLI 的 npm workspaces monorepo 包组织
- 掌握包间依赖关系和导出控制策略
- 分析测试工具包的跨包复用模式
项目实践
包组织结构
gemini-cli/├── packages/│ ├── cli/ # @google/gemini-cli — CLI 入口和 TUI│ ├── core/ # @google/gemini-cli-core — 核心 Agent 逻辑│ ├── sdk/ # @google/gemini-cli-sdk — 编程 API│ ├── test-utils/ # 测试基础设施│ ├── a2a-server/ # A2A 协议服务器│ └── vscode-ide-companion/ # VS Code IDE 插件├── evals/ # 评估测试├── integration-tests/ # 集成测试夹具├── perf-tests/ # 性能测试├── docs/ # 文档└── scripts/ # 构建和发布脚本各包职责:
| 包 | NPM 名称 | 职责 | 使用者 |
|---|---|---|---|
cli | @google/gemini-cli | CLI 入口、React Ink TUI、命令解析 | 终端用户 |
core | @google/gemini-cli-core | Agent 循环、工具、调度、配置 | cli、sdk、a2a-server |
sdk | @google/gemini-cli-sdk | GeminiCliAgent / GeminiCliSession 封装 | 开发者 |
test-utils | 不发布 | 测试夹具、Mock 工具 | 其他包的测试 |
a2a-server | 不发布 | A2A 协议实现,将 CLI 暴露为远程 Agent | 远程调用者 |
vscode-ide-companion | 不发布 | VS Code 扩展,IDE 集成 | VS Code 用户 |
包间依赖关系
关键设计:core 是所有包的依赖中心,cli 和 sdk 不互相依赖,避免了循环依赖。
导出控制
每个包通过 index.ts 精确控制公开 API:
export { GeminiClient } from './src/core/client.js';export { Config } from './src/config/config.js';export { Scheduler } from './src/scheduler/scheduler.js';// ... 仅公开需要外部使用的类内部模块不通过 index.ts 导出,外部包无法访问。这使得 core 内部可以自由重构,只要公开 API 不变。
构建链
Vite + esbuild:
esbuild.config.js:使用 esbuild 进行快速捆绑- 各包有独立的
tsconfig.json vitest.config.ts:各包独立的测试配置
为什么选 esbuild:
- 极快的构建速度(Go 编写,非 TypeScript)
- 对 TypeScript 和 ESM 的良好支持
- 适合 CLI 工具的构建需求(不需要 tree-shaking 优化到极致)
测试基础设施共享
test-utils 包提供跨包复用的测试工具:
// test-utils 核心导出export { TestRig } from './src/test-rig.js'; // 集成测试夹具export { MemoryTestHarness } from './src/memory-test-harness.js'; // 内存基准测试export { PerfTestHarness } from './src/perf-test-harness.js'; // 性能基准测试export { createMockUtils } from './src/mock-utils.js'; // Mock 工具集export { setupTestEnv } from './src/env-setup.js'; // 环境初始化TestRig 示例:
const rig = await TestRig.create({ config: { model: 'gemini-2.5-flash' }, tools: [readFileTool, shellTool],});await rig.initialize();// 使用 rig.context 创建完整的 AgentLoopContext// 进行集成测试发布策略
哪些包发布到 npm:
@google/gemini-cli(CLI)@google/gemini-cli-core(core)@google/gemini-cli-sdk(SDK)
哪些包不发布:
test-utils:内部测试工具a2a-server:作为 CLI 的一部分分发vscode-ide-companion:通过 VS Code Marketplace 分发
发布流程:
- 每周发布稳定版(周二 UTC 20:00)
- 每周发布预览版(周二 UTC 23:59)
- 每夜发布 nightly(UTC 00:00)
陷阱与对策
包间版本同步
问题:cli 依赖特定版本的 core,版本不同步可能导致运行时错误。
对策:
- monorepo 内使用
workspace:*协议引用内部包 - 发布时统一版本号(通过 scripts 自动化)
- CI 中使用集成测试验证包间兼容性
循环依赖
问题:如果 core 依赖 cli,而 cli 依赖 core,形成循环。
对策:
core严格不依赖cli或sdkcore只定义接口,具体 UI/CLI 实现在cli中- 通过接口注入(如
EditorType由cli注入到core)实现反向依赖
设计取舍
Monorepo vs 多仓库
| 方案 | 优势 | 代价 |
|---|---|---|
| Monorepo | 统一版本、原子提交、跨包测试 | 仓库大、CI 构建慢、权限管理困难 |
| 多仓库 | 独立发布、权限隔离 | 版本同步困难、集成测试复杂 |
Gemini CLI 的选择:Monorepo。core/cli/sdk 需要紧密协作,统一版本简化用户理解和测试。
npm workspaces vs pnpm/turborepo
| 方案 | 优势 | 代价 |
|---|---|---|
| npm workspaces | Node.js 原生支持、无需.无需额外安装 | 缺少高级缓存和并行构建优化 |
| pnpm | 磁盘空间高效、严格依赖隔离 | 需要额外安装、兼容性偶尔问题 |
| turborepo | 远程缓存、增量构建 | 需要配置、增加构建基础设施依赖 |
Gemini CLI 的选择:npm workspaces。项目使用标准 npm 生态,npm workspaces 足够满足需求,减少构建链复杂度。