第二部分 · 源码解读

01 源码地图

从哪里开始读?按什么顺序读?每个模块和测试怎么对应?

🎯 本节目标
  • 知道第二部分每章对应哪些源码文件
  • 掌握推荐的阅读顺序(由简到难、由独立到耦合)
  • 了解测试文件如何作为「行为说明书」使用

1. 推荐的阅读顺序

第二部分按照「从简单独立 → 到核心耦合」的顺序编排:

章节源码文件难度为什么放这里
02 配置系统config/schema.ts、load-config.ts零依赖,先热身
03 通道层feishu/channel.ts、context.ts、webhook.ts只依赖 SDK 和 types,理解边界
04 路由与归一化bridge/conversation-router.ts、message-normalizer.ts⭐⭐纯函数逻辑,测试驱动理解
05 会话管理bridge/session-host-manager.ts⭐⭐⭐第一个「有状态」核心模块
06 运行时封装bridge/runtime-host.ts⭐⭐⭐⭐最复杂:对接 Pi SDK 全家桶
07 流式渲染bridge/stream-renderer.ts⭐⭐⭐流式状态机的经典范式
08 UI 桥接bridge/ui-context.ts⭐⭐⭐Promise 挂起 + 远程回调
09 卡片系统cards/*.ts、bridge/card-actions.ts⭐⭐把交互串起来
10 附件处理attachments/*.ts⭐⭐输入预处理决策树
11 文件回传工具tools/send-file-to-chat.ts⭐⭐AsyncLocalStorage 的实际应用
12 存储store/store.ts、json-store.ts⭐⭐接口抽象 + 并发写
13 入口与扩展bin/pi-remote-feishu.ts、extensions/index.ts⭐⭐最后看,因为它是组合根
14 测试与二次开发test/*.ts、package.json收尾 + 实践指南

2. 测试作为「行为说明书」

这个项目的测试写得非常干净,先读测试,再读实现是最高效的方式——测试告诉你「函数应该怎样表现」,实现告诉你「它是怎么做到的」。

测试文件验证的行为
prompt-queue.test.ts同队列串行 / 跨队列独立
conversation-router.test.ts私聊/群聊/群按用户/未 @ 拒绝
message-normalizer.test.ts命令识别、去 @、prompt 拼装
card-actions.test.ts卡片动作分发、身份恢复
attachments.test.ts附件分类决策树(mock channel)
send-file-to-chat.test.ts文件校验、发送(mock channel)
json-store.test.tsCRUD、过滤、损坏降级、并发写
config.test.ts配置解析合并默认值
💡 为什么绝大多数测试不依赖飞书?

因为 FeishuChannel接口。mock 一个接口比 mock 整个 SDK 容易得多。 这就是「依赖抽象而非实现」的直接回报——也是你写项目时应该学的。

3. 阅读工具建议

  • VS Code:打开项目后按 Ctrl+P 输入文件名快速跳转
  • F12 / Cmd+点击:跳转到类型定义,追接口实现
  • 跑测试:改代码后 npm test 快速验证你的理解

4. 每个源码模块的「一句话职责」

文件一句话职责
types.ts全项目类型契约,是「地基中的地基」
prompt-queue.ts26 行实现串行队列(Promise 链)
feishu/context.ts13 行实现 AsyncLocalStorage 上下文
cards/common.ts卡片基础组件(文本/按钮/下拉)
attachments/mime.tsMIME 推断 + 文本判断(19 行)
feishu/webhook.ts4 行的语义化占位
store/store.ts存储工厂(12 行)
✅ 本节小结

第二部分一共 14 章,按「简单 → 复杂 → 组合」编排。 每章建议配合 npm test 里的对应测试一起读。

✍️ 练习
  1. 先读 test/conversation-router.test.ts,预测 routeConversation 的行为,再去读实现验证。
  2. 打开 src/types.ts,把所有 interface 列出来,猜猜哪个是「被引用最多」的?