Skip to content

4.3 monorepo 与 package 地图

本页分析版本earendil-works/pi@c13ffe12026-07-30

本章解决什么问题:Pi 仓库里有哪些 package、各自负责什么、谁依赖谁——给你一张读源码前必备的地图。 前置知识1.3 npm、package.json 与项目结构(monorepo 与 workspaces 的概念在那里首次讲解)。 学习目标:① 说出 7 个 package 的职责;② 画出它们的依赖方向;③ 知道每个 package 大致的体量与阅读优先级。

workspaces:一个仓库,多个包

Pi 根目录的 package.json 用 npm workspaces 声明了这是一个 monorepo(源码事实):

package.json · workspaces
earendil-works/pi@c13ffe1第 5–13 行在 GitHub 查看 ↗
根 package.json 的 workspaces 字段:packages/* 加上 storage 子目录与若干示例扩展目录。

npm install 在根目录执行一次,就会为所有子包统一安装依赖;子包之间通过包名互相引用(例如 coding-agent 依赖 @earendil-works/pi-agent-core),npm 会把它们链接到本地目录而不是从 registry 下载。

七个 package 一览

以下体量为锁定版本下 src/ 目录去除测试后的实际统计(源码事实,用 wc -l 统计):

packagenpm 包名职责体量(行)本书章节
packages/ai@earendil-works/pi-ai统一多 Provider 的 LLM API:消息类型、流式事件、20+ 家 Provider 适配、OAuth 登录≈21,0006.1 / 6.2
packages/agent@earendil-works/pi-agent-coreAgent 运行时:Agent Loop、工具执行、Harness、Session 抽象、Compaction 通用实现≈10,0006.3–6.6
packages/coding-agent@earendil-works/pi-coding-agent产品层:pi 命令本体。CLI、TUI 交互模式、RPC/JSON 模式、SDK、扩展/技能/主题系统、内置工具≈55,600第五、六、七部分
packages/tui@earendil-works/pi-tui终端 UI 库:组件模型与差分渲染(differential rendering)≈12,8006.9
packages/server@earendil-works/pi-server实验性本机守护进程:管理多个 RPC 子进程(官方说明其定位为 experimental)≈2,0006.10 附带
packages/storage/sqlite-node@earendil-works/pi-storage-sqlite-nodeSQLite 会话存储后端≈1,6006.5 附带
packages/evals@earendil-works/pi-evals评测脚本集≈1,300不深入
🌱 初学者提示为什么要分包
分包的边界就是职责的边界:ai 不知道什么是工具执行,agent 不知道什么是终端渲染,tui 甚至完全不知道 LLM 的存在。这让每一层都能被单独理解、单独测试、单独替换——第三方 Web UI 能存在,正是因为「界面层」与「Harness 层」被协议隔开。这也是你读源码时的导航原则:想找什么概念,先想它属于哪一层

依赖方向图

依赖关系全部来自各包 package.jsondependencies 字段(源码事实):

图加载中…

图 4.3-1 package 依赖方向
箭头 A → B 表示「A 依赖 B」。越靠下的包越基础:pi-ai 与 pi-tui 不依赖任何本仓库的包;pi-coding-agent 是汇聚点;pi-server 在其之上。虚线为 devDependencies。

读图要点:

  1. 依赖只朝一个方向流动,没有环。ai 永远不会 import agentagent 永远不会 import coding-agent。你在下层包里看到的任何符号,都可以放心地在不了解上层的情况下理解。
  2. tuiai 互不相识——终端渲染和模型调用是两个完全独立的世界,在 coding-agent 里才被组装到一起。
  3. bin 字段揭示了命令入口(源码事实):pi 命令来自 coding-agent 的 dist/cli.js
earendil-works/pi@c13ffe1第 9–11 行在 GitHub 查看 ↗
pi 命令的 bin 声明:全局安装后,敲 pi 实际执行的是这个包的 dist/cli.js。

每个包里有什么

按第五部分将要走的请求路径,预览各包内部的关键目录:

text
packages/
├── ai/src/
│   ├── types.ts            ← 统一消息与事件类型(全书引用最多的文件)
│   ├── models.ts           ← Models 集合:stream/complete 等对外 API
│   ├── api/                ← 各协议实现(anthropic-messages、openai-*、…)
│   ├── providers/          ← 20+ 家 Provider 注册与模型清单
│   ├── auth/               ← API Key / OAuth 凭据
│   └── utils/event-stream.ts ← 流式事件的缓冲与分发
├── agent/src/
│   ├── agent-loop.ts       ← Agent Loop 本体(6.3 的主角)
│   ├── agent.ts            ← 有状态的 Agent 类
│   └── harness/            ← AgentHarness、session/、tools/、compaction/
├── coding-agent/src/
│   ├── cli.ts → main.ts    ← 启动入口(5.1 的主角)
│   ├── core/               ← AgentSession、工具、扩展、技能、设置、compaction
│   ├── modes/interactive/  ← TUI 交互模式
│   ├── modes/rpc/          ← RPC/JSON 模式
│   └── extensions/         ← 内置扩展
├── tui/src/                ← Component 模型、差分渲染、编辑器组件
├── server/src/             ← supervisor + ipc(Unix socket 管理 RPC 子进程)
├── storage/sqlite-node/    ← SessionStorage 的 SQLite 实现
└── evals/                  ← 评测

不要现在就试图记住所有文件——这张目录树是后续章节的路标,每次深入一个模块时回来对一下位置即可。

哪些先读、哪些跳过

按学习价值排序(分析解释,依据是依赖层级与第五部分的主链路):

  1. 必读主线ai/src/types.tsagent/src/agent-loop.tscoding-agent/src/main.ts + core/agent-session.ts。第五部分沿这条线走。
  2. 按需深入ai/src/api/anthropic-messages.ts(看一个 Provider 如何实现协议)、coding-agent/src/core/tools/core/extensions/
  3. 暂时不读ai/src/providers/ 下几十个 Provider 文件(结构高度重复,看懂一个即可)、*.generated.ts(脚本生成的模型数据,不是手写代码)、evals/tui/ 的细节(除非你对终端渲染感兴趣)。

实践任务

🛠 实践任务亲手验证依赖图

目标:不相信书,自己从 package.json 里把依赖图挖出来。

步骤:在 Pi 仓库根目录运行:

for p in ai agent coding-agent tui server; do
  echo "== $p =="
  node -e "const d=require('./packages/$p/package.json'); console.log(Object.keys(d.dependencies||{}).filter(x=>x.startsWith('@earendil')))"
done

预期现象:输出与图 4.3-1 的箭头一一对应(ai 与 tui 为空数组;agent 只依赖 pi-ai;coding-agent 依赖三个;server 依赖 coding-agent)。

如何判断成功:你能解释为什么 storage 包依赖 agent 而不是反过来。

常见错误:忘了 storage 的路径多一层(packages/storage/sqlite-node)。

本章小结

  • Pi 是 npm workspaces monorepo:7 个 package,依赖单向流动、无环。
  • 三个核心层:pi-ai(模型接口)→ pi-agent-core(Agent 运行时)→ pi-coding-agent(产品);pi-tui 独立负责渲染。
  • coding-agent 体量最大(≈5.6 万行),但主链路入口清晰:cli.ts → main.ts
  • Provider 文件与 generated 文件可以跳过不读。
  • 关键术语:workspaces依赖方向bin 入口
  • 自测问题:① pi-tui 为什么不依赖 pi-ai?② pi 命令对应哪个文件?③ 想看 Agent Loop 应该去哪个包?
  • 下一章:4.4 从哪里开始读源码

本书分析的 Pi 版本:earendil-works/pi@c13ffe1(2026-07-30)