Single Page / Embedded CSS / Embedded JS

一页读懂这套源码解读文档

claude-code 项目快速解读

这是一份针对 claude-code 源码的快速解读文档集。目标不是逐行翻译,而是帮你在最短时间内建立“这个项目是什么、怎么启动、核心链路怎么跑、各目录负责什么、应该从哪里继续深读”的整体认知。

先说结论

claude-code 是一个用 TypeScript 编写、以 Bun 为主要运行时、面向终端的 AI 编程助手 CLI。它的核心能力不是“单次问答”,而是把下面几类能力拼成了一个完整系统:

  • 终端交互式 UI:基于 React + 自定义 Ink 渲染体系,在终端里实现多面板、多状态、可交互的 REPL。
  • 大模型对话主循环:把用户输入、系统提示、项目上下文、历史消息、工具调用结果组织成连续多轮 agent loop。
  • 工具系统:模型可以调用 Shell、读写文件、网页抓取、网页搜索、任务清单、子代理、MCP 等工具。
  • 权限与沙箱:不是简单的“能不能执行命令”,而是包含规则、模式、自动审批、交互审批、沙箱隔离、工作目录限制等多层控制。
  • 可扩展性:支持 Slash Commands、Skills、Plugins、MCP Server、Hooks、子代理、Worktree 等扩展方式。
  • 会话与持久化:支持恢复、压缩、统计、成本追踪、memory 目录、CLAUDE.md 等长期上下文机制。
阅读方式 Shell 分区阅读

每个文档都被包进一个 shell 面板:有独立标题栏、折叠控制、编号、跳转入口,适合长时间扫读和来回对照源码。

推荐动作 先总览,再跳源码

先从总览与启动链路建立地图,再用关键函数速查定位具体实现,最后回到仓库里沿导入链继续深读。

00-项目总览
文档 01 00-项目总览.md

项目总览

1. 项目是什么

这是一个“逆向还原 Claude Code CLI”的大型工程化项目。它试图复现官方 Claude Code 的主要形态:

  • 在终端中提供交互式 AI 编程助手
  • 让模型具有工具调用能力
  • 让工具调用具备权限控制与沙箱隔离
  • 支持命令、技能、插件、MCP、子代理等扩展
  • 支持会话恢复、上下文拼装、memory、成本统计、配置管理

从架构上看,它不是简单的“模型 SDK + 命令行包装”,而是五层叠加:

  1. 启动与配置层
  2. 终端 UI 与 REPL 层
  3. 消息/会话/上下文层
  4. 工具编排与权限执行层
  5. 扩展生态层

2. 它能做什么

从源码结构看,这个项目至少具备以下能力:

  • 交互式聊天和代码协作
  • 执行 shell 命令
  • 读取、编辑、写入文件与 Notebook
  • 网页抓取与网页搜索
  • 生成和管理任务列表
  • 进入/退出 plan mode
  • 启动子代理和团队代理
  • 管理 MCP server,并把 MCP tool 暴露给模型
  • 加载 skills、plugins、slash commands
  • 维护 memory 目录与 CLAUDE.md
  • 恢复历史会话、导出会话、压缩上下文
  • 做 doctor/health check/config/plugin/mcp 等工程辅助工作

3. 它实际做了什么

如果把一次完整交互简化成一句话,可以描述为:

“把用户输入、项目上下文、系统提示、历史消息、可用工具、权限模式、扩展能力组装到一起,然后驱动模型在多轮循环中持续产出文本或调用工具,直到本轮任务完成。”

更具体一点:

  1. CLI 启动后先走极轻量入口,处理 --version 等快速路径。
  2. 进入主初始化,加载配置、环境变量、认证、遥测、插件、MCP、命令、技能、工具。
  3. 打开 REPL UI。
  4. 用户输入消息或命令。
  5. 系统拼出 system prompt、user context、system context、历史消息、工具描述。
  6. 调用模型开始流式响应。
  7. 如果模型发起 tool_use,就先走权限检查,再真正执行工具。
  8. 工具结果回写成 tool_result 消息,继续下一轮模型推理。
  9. 直到模型输出最终答复,或者触发压缩、恢复、终止、切换模式等行为。

4. 核心架构图

mermaid
flowchart TD A[CLI 入口 src/entrypoints/cli.tsx] --> B[src/main.tsx 主初始化] B --> C[命令/工具/插件/技能/MCP 加载] B --> D[REPL UI 启动] D --> E[用户输入] E --> F[上下文组装 context.ts + prompts] F --> G[query.ts 主循环] G --> H{模型是否调用工具} H -- 否 --> I[直接输出回复] H -- 是 --> J[权限检查 useCanUseTool + permissions] J --> K[工具执行 tools/*] K --> L[tool_result 回写] L --> G

5. 这份源码的工程特点

5.1 体量大,且功能不是单核

从目录看,这不是单一主流程项目,而是“主系统 + 多扩展子系统”的集合。主系统包含:

  • src/main.tsx
  • src/query.ts
  • src/screens/REPL.tsx
  • src/tools.ts
  • src/commands.ts
  • src/context.ts
  • src/QueryEngine.ts

5.2 有明显的条件编译/特性门控

项目大量使用:

  • feature('...')
  • process.env.USER_TYPE === 'ant'
  • 各类环境变量

这意味着很多功能不是永远开启,而是按构建目标、平台、内部标识、实验开关动态裁剪。

5.3 有“镜像目录”和历史拆层痕迹

例如:

  • src/services/...
  • src/src/services/...
  • src/cli/src/...
  • src/bootstrap/src/...

这通常说明作者一边还原源码,一边做模块拆分、兼容转移或避免循环依赖。读代码时应优先认主入口真实引用到的路径,不要被重复目录吓到。

5.4 文档化程度不错

docs/ 并不是摆设,而是比较系统地解释了:

  • 架构总览
  • 对话循环
  • 工具系统
  • 上下文构建
  • 扩展机制
  • 权限和沙箱

所以这个项目很适合“文档 + 源码对照阅读”。

6. 运行与构建方式

6.1 依赖环境

  • 运行时以 Bun 为主
  • 也兼顾 Node 运行产物
  • 使用 Bun workspaces 管理多个本地包

6.2 常用命令

bash
bun install bun run dev bun run build bun test

6.3 构建逻辑

根目录 build.ts 会:

  1. 删除 dist/
  2. Bun.buildsrc/entrypoints/cli.tsx 为入口打包
  3. 开启代码分割
  4. 对产物中的 import.meta.require 做兼容处理,让 Node 也能运行

所以它的构建思路不是传统 tsup/esbuild 薄封装,而是 Bun 原生打包后再补兼容层。

7. 最值得先记住的几个文件

  • src/entrypoints/cli.tsx:最早入口,处理快速分流
  • src/main.tsx:主启动文件,项目的“大脑启动器”
  • src/replLauncher.tsx:REPL 启动封装
  • src/screens/REPL.tsx:交互式终端主界面
  • src/query.ts:模型主循环
  • src/QueryEngine.ts:抽象出来的会话/查询引擎
  • src/context.ts:系统上下文与用户上下文构建
  • src/tools.ts:工具注册中心
  • src/commands.ts:slash 命令注册中心
  • src/utils/permissions/*:权限规则与审批核心
  • src/utils/sandbox/sandbox-adapter.ts:沙箱运行时适配器
  • src/services/mcp/*:MCP 配置、连接、工具接入
  • src/skills/loadSkillsDir.ts:Skills 加载器
  • src/utils/plugins/pluginLoader.ts:插件加载器
  • src/memdir/*:memory 目录体系
01-启动与运行链路
文档 02 01-启动与运行链路.md

启动与运行链路

1. 启动入口分层

这个项目的启动不是一个文件直接跑到底,而是分两层:

  • 第一层:src/entrypoints/cli.tsx
  • 第二层:src/main.tsx

这样的好处是:

  • 快速路径可以尽量少加载模块,提升启动速度
  • 某些子模式可以直接分流,不必把完整 REPL 和大模块都加载起来
  • 大量 feature gate 可以在更早阶段裁剪

2. src/entrypoints/cli.tsx 做了什么

这个文件是非常典型的“轻入口 + 动态导入”设计。

2.1 提前设置运行时常量

它会在顶层设置:

  • MACRO.VERSION
  • BUILD_TARGET
  • BUILD_ENV
  • INTERFACE_TYPE

这些值在真实构建中通常会被 Bun 打包阶段替换,但开发或外部运行时也会提供兜底值。

2.2 处理早期环境变量

它会做几件重要的小事:

  • 关闭 COREPACK_ENABLE_AUTO_PIN
  • 在远程环境下给 NODE_OPTIONS 增加堆内存限制
  • 在某些实验/ablation 模式下提前注入环境变量

注意这里强调“提前”,是因为某些工具会在模块加载时就读取环境变量,等后面初始化再设置就晚了。

2.3 做快速路径分流

它会优先处理一些不需要完整系统的路径,例如:

  • --version
  • --dump-system-prompt
  • --claude-in-chrome-mcp
  • --chrome-native-host
  • --computer-use-mcp
  • --daemon-worker
  • remote-control / bridge
  • daemon
  • 后台 session 管理相关命令

这说明作者很在意:

  • 启动性能
  • 模式隔离
  • 子功能独立运行

2.4 真正进入主程序

如果不是上面的快速路径,才会继续进入完整 CLI 主流程。

3. src/main.tsx 为什么是核心启动器

src/main.tsx 是真正的大启动器。它做的事情非常多,可以理解为“把整个应用从零拉起来”。

3.1 顶层先启动几个并行的副作用

在文件最顶部,就已经做了几件启动优化:

  • 启动 startupProfiler
  • 预读 MDM 设置
  • 预取 keychain 凭据

这些都属于“为了减少首屏等待,把慢 IO 提前并行启动”。

3.2 主初始化依赖极多

这个文件会导入并协调:

  • 配置系统
  • 认证系统
  • GrowthBook/analytics
  • policy limits
  • remote managed settings
  • MCP
  • 工具注册
  • 命令注册
  • 插件与技能
  • LSP
  • worktree
  • remote/direct-connect/SSH
  • REPL 渲染
  • session 恢复
  • model 选择
  • permission mode 初始化

也就是说,它不是“业务逻辑文件”,而是“应用组装器”。

4. 启动主线可以怎么理解

main.tsx 的主线压缩成一句话:

“读取 CLI 参数,初始化环境和状态,构建命令/工具/上下文/连接能力,跑完启动向导,然后进入 REPL 或其他工作模式。”

拆开看,大致是:

  1. 调用 init() 完成基础初始化。
  2. 解析命令行参数与启动模式。
  3. 确定模型、权限模式、工作目录、是否交互式。
  4. 加载插件、技能、MCP 配置。
  5. 生成工具集和命令集。
  6. 准备 REPL 所需的初始状态。
  7. 运行 setup screens,例如 onboarding、trust dialog、权限确认等。
  8. 调用 launchRepl() 启动交互界面。

5. src/entrypoints/init.ts 做了哪些基础初始化

这个文件像“应用预热器”。

5.1 配置与环境

它负责:

  • enableConfigs() 启用配置系统
  • applySafeConfigEnvironmentVariables() 先应用安全环境变量
  • 处理额外 CA 证书
  • 后续在信任建立后应用完整环境变量

这里体现出一个设计原则:

  • 启动早期只应用安全配置
  • 需要信任边界之后再应用更危险的配置

5.2 清理与生命周期管理

它会:

  • 安装优雅退出处理
  • 注册 cleanup 逻辑
  • 注册 LSP、团队、scratchpad 等清理钩子

5.3 网络与认证预热

它还会:

  • 初始化 1P event logging
  • 补充 OAuth 账户信息
  • 配置 mTLS 和代理
  • 预连接 Anthropic API
  • 在远程模式下初始化 upstream proxy

这说明项目对“首个 API 请求延迟”是有明确优化的。

6. interactiveHelpers.tsx 在启动链路中的位置

这个文件负责把“启动前的对话框/设置页”和“正式 REPL 运行”连接起来。

它提供几个关键能力:

  • showDialog():渲染一个对话框并等待完成
  • showSetupDialog():带上 AppStateProvider 和按键上下文的 setup 对话框
  • renderAndRun():真正渲染主 UI,并等待退出
  • showSetupScreens():启动前引导页总控

7. showSetupScreens() 具体做什么

这是启动时非常关键的一个“信任边界”函数。

它负责依次处理:

  • onboarding
  • TrustDialog
  • GrowthBook 重置与重新初始化
  • 预取 system context
  • MCP server 审批
  • CLAUDE.md external include 警告
  • 完整环境变量应用
  • telemetry 初始化
  • 自定义 API key 审批
  • bypassPermissions / auto mode 等模式确认

这意味着项目不是一启动就直接把模型跑起来,而是非常重视“环境是否可信、用户是否同意、配置是否合规”。

8. REPL 是怎么启动的

8.1 launchRepl() 很薄

src/replLauncher.tsx 非常薄,它只做一件事:

  • 动态导入 components/App
  • 动态导入 screens/REPL
  • renderAndRun()<App><REPL /></App> 渲染出来

8.2 App.tsx 的作用

src/components/App.tsx 不是 UI 页面,而是 Provider 容器,主要包三层:

  • AppStateProvider
  • StatsProvider
  • FpsMetricsProvider

意思是:REPL 内所有组件共享一份全局状态、统计信息和渲染性能数据。

9. 启动方式总结

开发运行

bash
bun run dev

直接运行 src/entrypoints/cli.tsx

构建运行

bash
bun run build node dist/cli.js # 或 bun dist/cli.js

启动链一句话总结

cli.tsx 负责轻分流,main.tsx 负责重初始化,init.ts 负责底层预热,interactiveHelpers.tsx 负责启动向导,replLauncher.tsx 负责挂起 REPL,REPL.tsx 才开始正式进入交互会话。

02-会话循环与核心执行流
文档 03 02-会话循环与核心执行流.md

会话循环与核心执行流

1. 真正的核心不是 UI,而是 query loop

这个项目表面上是一个终端 UI 程序,但核心价值其实在会话执行引擎,也就是:

  • src/query.ts
  • src/QueryEngine.ts
  • src/context.ts
  • src/screens/REPL.tsx

你可以把它理解为:

  • REPL.tsx 负责“交互壳子”
  • query.ts 负责“本轮 agent loop”
  • QueryEngine.ts 负责“跨轮会话状态管理”
  • context.ts 负责“提示词前置上下文构造”

2. src/context.ts:会话前置上下文从哪来

这个文件主要暴露两个 memoized 函数:

  • getSystemContext()
  • getUserContext()

2.1 getSystemContext()

主要负责系统级补充信息,例如:

  • Git 状态快照
  • 当前分支
  • 默认分支
  • 最近提交
  • 可选的 system prompt injection

关键点:

  • Git 状态是会话开始时的快照,不会自动持续刷新
  • 有长度截断保护
  • 是否包含 Git 指令受配置和环境控制

2.2 getUserContext()

主要负责用户侧补充信息,例如:

  • CLAUDE.md
  • memory files
  • 当前日期

关键点:

  • --bare 模式下会减少自动发现
  • 会缓存 claudeMd 内容给某些分类器使用
  • 这部分内容最终会并入系统提示或用户上下文

3. src/query.ts:单轮主循环的心脏

这个文件是整个项目最重要的文件之一。

3.1 它的职责

query() 不是一次简单 API 请求,而是一个异步生成器,负责:

  • 接收消息、系统提示、上下文、工具上下文
  • 调用模型进行流式输出
  • 识别 tool_use
  • 执行工具
  • 把 tool_result 回写
  • 在多轮之间继续迭代
  • 处理压缩、恢复、budget、hook、fallback 等复杂逻辑

3.2 它为什么用 AsyncGenerator

因为整个过程本质上是流:

  • 模型流式 token 输出
  • 中途可能插入工具调用
  • 工具执行后又会继续回到模型
  • UI 和 SDK 都希望边接收边消费

所以 query() 返回的不是最终值,而是一连串事件流。

3.3 它处理的关键事情

从源码能看出它至少做了这些事:

  • 标准化消息格式
  • 组装 API 请求
  • 控制 token budget
  • 处理 max_output_tokens 恢复
  • 处理自动 compact / reactive compact / microcompact
  • 处理 tool summary
  • 处理 stop hooks
  • 处理附件与 memory 预取
  • 调用 runTools() 编排工具执行
  • 记录与回放工具结果

3.4 它的本质

query.ts 的本质是“模型驱动的状态机”。

输入:

  • 当前消息列表
  • 工具集
  • 权限能力
  • 系统提示
  • 上下文

输出:

  • assistant message
  • tool use
  • tool result
  • compact boundary
  • system message
  • tombstone message
  • request start event

4. src/QueryEngine.ts:把单轮循环升级成会话引擎

4.1 为什么还要一个 QueryEngine

query.ts 负责单轮 agent loop,但一个完整对话会有很多轮。于是 QueryEngine 提供了更高一层抽象:

  • 持有 mutableMessages
  • 持有 readFileCache
  • 持有 permissionDenials
  • 持有累计 usage
  • 管理本轮与跨轮状态
  • 对 SDK / headless 场景提供统一接口

4.2 重要方法:submitMessage()

这个方法是 QueryEngine 的核心入口。它会:

  1. 设置当前 cwd
  2. 解析初始模型与 thinking 配置
  3. 拉取系统提示各部分
  4. 拼出 user/system context
  5. 在必要时载入 memory prompt
  6. 并行加载插件缓存等辅助能力
  7. 调用 query() 执行本轮
  8. 把输出转成 SDK 可消费的格式
  9. 更新内部会话状态

4.3 它和 query.ts 的关系

可以简单记为:

  • query.ts:一次 turn 的底层执行器
  • QueryEngine.ts:整场 conversation 的上层控制器

5. src/screens/REPL.tsx:交互外壳非常大

这个文件非常大,说明 REPL 不只是一个输入框。

5.1 它承担的角色

  • 输入处理
  • 消息列表渲染
  • 权限弹窗
  • Hook 弹窗
  • MCP elicitation dialog
  • 通知提示
  • 成本显示
  • 模式切换
  • 背景任务与 teammate 视图
  • IDE/SSH/Remote/DirectConnect 集成
  • 文件历史与会话恢复
  • 自动建议、任务列表、状态提示

5.2 它不是业务核心,但它是 orchestrator

真正的 query logic 不在这里,但这里负责把几乎所有 UI 交互状态和 query 引擎串起来。

6. 一次用户输入的实际执行链

可以按下面这条链理解:

  1. 用户在 REPL.tsx 输入文本。
  2. 输入先经过 prompt 处理、引用展开、命令判断、历史记录处理。
  3. 如果是 slash command,就走命令系统。
  4. 如果是普通消息,就构造消息对象。
  5. 获取 system prompt + system context + user context。
  6. 调用 query() 开始本轮流式执行。
  7. 模型输出文本或发起 tool_use。
  8. tool_use 先走权限判断。
  9. 权限通过后,工具执行。
  10. 工具结果回注到消息流中。
  11. query() 继续下一轮,直到结束。
  12. REPL 把流式消息实时显示给用户。

7. 与上下文压缩相关的逻辑

源码里明显能看到 compact 相关逻辑很多:

  • auto compact
  • reactive compact
  • microcompact
  • compact boundary
  • post compact cleanup

这意味着项目不是“上下文太长就报错”,而是做了一整套自动恢复和上下文维持策略。

8. 与成本/预算相关的逻辑

代码中有:

  • token budget
  • task budget
  • model usage
  • total cost
  • output token snapshot
  • continuation count

说明这是一个“面向长会话和高成本 agent 使用”的系统,不是单轮 chat demo。

9. 会话核心的一句话总结

这个项目的核心不是调用一次模型,而是维护一个长期可持续运行的 agent loop:

  • 有上下文
  • 有状态
  • 有工具
  • 有权限
  • 有恢复
  • 有压缩
  • 有成本控制
  • 有 UI 和 SDK 两套消费方式
03-工具系统与权限沙箱
文档 04 03-工具系统与权限沙箱.md

工具系统与权限沙箱

1. 工具系统是这个项目最关键的能力之一

src/tools.ts 可以看到,这个项目不是“模型输出文本”,而是“模型通过工具对环境产生作用”。

当前注册体系里能看到的工具类型包括:

  • AgentTool
  • BashTool
  • FileReadTool
  • FileEditTool
  • FileWriteTool
  • NotebookEditTool
  • WebFetchTool
  • WebSearchTool
  • Todo/Task 系列
  • AskUserQuestionTool
  • SkillTool
  • MCP 资源工具
  • LSPTool
  • Team/Worktree/Cron 等工具

2. src/Tool.ts 定义了什么

这个文件定义的是工具系统的公共协议。最重要的是几个概念:

  • ToolInputJSONSchema:工具参数 schema
  • ToolPermissionContext:当前会话的权限上下文
  • ToolUseContext:执行工具时可访问的完整运行上下文

2.1 ToolUseContext 很重要

工具并不是单纯接受一个 input 就运行,它还能访问:

  • 当前命令列表
  • 当前工具列表
  • 当前模型
  • 当前 MCP 客户端
  • 当前 agent 定义
  • 当前 app state
  • 文件状态缓存
  • 通知接口
  • UI 更新接口
  • nested memory 状态
  • 追加系统消息等能力

这说明“工具”在这里不是孤立函数,而是被嵌入整个应用运行时中的一等对象。

3. src/tools.ts:工具注册中心

3.1 这是所有工具的总入口

getAllBaseTools() 列出了当前环境下可能存在的所有工具来源。

这里有几个重要特征:

  • 有些工具永远存在
  • 有些工具依赖 feature gate
  • 有些工具依赖平台或环境变量
  • 有些工具是 ant-only stub
  • 有些工具会被权限上下文进一步过滤

3.2 为什么这里会有大量 lazy require

源码里有很多 require() 和条件导入,主要为了:

  • 避免循环依赖
  • 让 feature gate 在构建时做 dead code elimination
  • 控制启动体积
  • 某些工具只在特定模式下需要

3.3 工具是如何暴露给模型的

流程大致是:

  1. tools.ts 先生成可用工具列表
  2. 根据 permission context 过滤掉不可见或被拒绝的工具
  3. 再和 MCP 工具池合并
  4. 最终把工具 schema 交给模型
  5. 模型如果返回 tool_use,再按名字定位工具并执行

4. 权限系统不只是一个 yes/no

权限相关代码主要在:

  • src/hooks/useCanUseTool.tsx
  • src/utils/permissions/permissions.ts
  • src/utils/permissions/permissionSetup.ts
  • src/utils/permissions/filesystem.ts
  • src/utils/permissions/pathValidation.ts
  • src/utils/permissions/*classifier*

4.1 useCanUseTool.tsx

这是 REPL 中工具调用权限的前端协调器。它会:

  • 调用 hasPermissionsToUseTool() 判断是否允许
  • 如果是 allow,直接通过
  • 如果是 deny,生成拒绝状态和通知
  • 如果是 ask,走交互审批、协调器审批、swarm worker 审批等流程
  • 在某些情况下还能消费 speculative classifier 的结果,自动批准命令

所以它是“权限决策结果接入 UI”的桥梁。

4.2 permissions.ts

这是权限判断核心。它处理:

  • allow / deny / ask 规则
  • 规则来源合并
  • tool 级匹配
  • MCP server 级匹配
  • decisionReason 生成
  • hooks 影响
  • auto mode / classifier 影响
  • sandbox override
  • 最终权限结果构造

换句话说,是否允许一个工具调用,不是单点判断,而是一个决策流水线。

4.3 permissionSetup.ts

这个文件偏“启动时的权限模式准备”。它负责:

  • 从 settings 与 CLI 构造初始 permission mode
  • 识别危险规则
  • auto mode 下剥离危险权限
  • 处理 plan mode / auto mode 切换逻辑
  • 生成默认工具集权限基线

它更像“权限上下文初始化器”,而不是“每次工具调用时的执行器”。

5. 沙箱:sandbox-adapter.ts

5.1 它不是自己实现沙箱内核

这个文件的定位很清楚:

  • @anthropic-ai/sandbox-runtime
  • 在 Claude CLI 这一层做适配和转换

所以它是“Claude Code 专用沙箱适配器”。

5.2 它做了什么适配

它会把项目里的设置转成沙箱运行时可理解的配置,例如:

  • 网络允许/拒绝域名
  • 文件读写允许/拒绝路径
  • settings 文件保护
  • .claude/skills 等敏感目录保护
  • 当前工作目录和 temp 目录允许写入
  • WebFetch 域名规则映射到网络规则

5.3 它的意义

权限系统决定“逻辑上允不允许”,沙箱系统负责“OS 层怎么限制”。

也就是说,这里至少有两层防线:

  1. 逻辑审批层
  2. 运行时隔离层

6. 文件与路径权限非常细

filesystem.tspathValidation.ts 可以看到,项目对路径控制非常细:

  • working directory 范围判断
  • glob pattern 校验
  • tilde 展开
  • sandbox allowlist 判断
  • 危险删除路径识别
  • internal path 可读可写校验
  • 自动编辑建议与路径归一化

这意味着文件工具不是“给路径就写”,而是被一整套安全规则包住。

7. 权限模式可以怎么理解

虽然具体模式细节散落在多个文件中,但整体可以概括成:

  • 默认模式:敏感操作倾向询问
  • Auto mode:尽量自动化,但会去掉危险规则并依赖分类器
  • Plan mode:偏规划阶段,权限策略会不同
  • Bypass / dangerous 模式:能力更强,但启动时会额外确认

8. 工具执行的真实链路

text
模型输出 tool_use -> 根据工具名找到 Tool 定义 -> 走 hasPermissionsToUseTool() -> 若需要,弹审批 UI / hook / classifier / sandbox override -> 获得 allow/deny/ask 最终决策 -> 允许后执行工具 -> 输出 tool_result -> 回到 query loop

9. 这一套设计说明了什么

说明这个项目把工具调用当成核心能力,而不是附属功能。

它并不是“给模型加几个 function calling”,而是做成了:

  • 有统一 schema
  • 有执行上下文
  • 有审批机制
  • 有沙箱
  • 有多模式策略
  • 有 UI 协同
  • 有自动化和远程场景兼容

这已经是一个完整的 agent 工具平台了。

04-扩展系统:命令、Skills、Plugins、MCP
文档 05 04-扩展系统:命令、Skills、Plugins、MCP.md

扩展系统:命令、Skills、Plugins、MCP

1. 这个项目的扩展能力非常完整

如果说工具系统解决的是“模型能做什么”,那扩展系统解决的是“平台怎么被继续长大”。

主要扩展入口有四类:

  • Slash Commands
  • Skills
  • Plugins
  • MCP Servers

它们分别解决不同问题。

2. Slash Commands:命令层扩展

主要文件:src/commands.ts

2.1 命令系统是什么

Slash command 是用户显式输入的命令,例如:

  • /help
  • /doctor
  • /review
  • /mcp
  • /plugin
  • /memory

它更像“CLI 内置功能入口”,而不是模型自动调用的工具。

2.2 commands.ts 做了什么

它负责:

  • 汇总所有内置命令
  • 处理 feature-gated 命令
  • 合并 skills 派生命令
  • 合并 plugin 命令
  • 做命令缓存
  • 根据运行条件动态过滤命令

2.3 命令与工具的区别

  • 命令:用户主动输入,偏产品功能入口
  • 工具:模型主动调用,偏 agent 能力接口

这两个体系会协作,但不是一回事。

3. Skills:提示能力模块化

主要文件:src/skills/loadSkillsDir.ts

3.1 Skills 是什么

Skill 本质上是一种基于 Markdown + frontmatter 的能力封装。它可以描述:

  • 叫什么
  • 做什么
  • 何时使用
  • 允许哪些工具
  • 参数如何替换
  • 是否允许用户直接调用
  • 是否指定模型和 effort
  • 是否绑定 hooks
  • 是否需要 fork 执行上下文

3.2 loadSkillsDir.ts 做了什么

它负责:

  • 从多个来源发现 skill 文件
  • 解析 frontmatter
  • 提取 description / when_to_use / allowed-tools / arguments
  • 校验 hooks
  • 处理 gitignore、路径限制、去重、动态激活
  • 生成可供命令或模型使用的 command/skill 对象

3.3 它的意义

Skill 是一种比硬编码命令更轻的扩展方式。它让新能力可以通过 Markdown 文件快速接入,而不用每次都改 TypeScript 主程序。

4. Plugins:插件系统

主要文件:src/utils/plugins/pluginLoader.ts

4.1 插件是什么

插件是比 Skill 更重的一层。它通常是一个目录,可能包含:

  • plugin.json
  • commands/
  • agents/
  • hooks/

4.2 pluginLoader.ts 做了什么

这个文件的职责很完整:

  • 插件发现
  • manifest 校验
  • hooks 加载
  • 名称冲突检测
  • 缓存路径管理
  • 版本目录管理
  • marketplace 与 git 来源处理
  • seed cache 与 zip cache 处理
  • 启用/禁用状态管理
  • 错误收集

4.3 插件系统说明了什么

说明这个项目不满足于“本地脚本式扩展”,而是试图构建一个可安装、可缓存、可版本化、可市场化分发的插件生态。

5. MCP:外部能力接入总线

主要文件:

  • src/services/mcp/config.ts
  • src/services/mcp/client.ts
  • src/services/mcp/MCPConnectionManager.tsx

5.1 MCP 在这里的角色

MCP 是把外部服务、IDE、浏览器、远程资源、第三方工具接进 Claude Code 的总线。

在这个项目里,MCP 不只是“列一下 server”,而是完整生命周期:

  • 配置读取
  • 连接建立
  • 认证
  • 工具拉取
  • 资源拉取
  • 命令拉取
  • 调用结果转换
  • URL elicitation 重试
  • UI 状态管理

5.2 config.ts 做了什么

MCP 配置层负责:

  • 读取多作用域配置
  • 处理 .mcp.json
  • 合并 Claude AI 提供的配置
  • 合并插件带来的 MCP 配置
  • 去重
  • 策略过滤
  • 启用/禁用管理
  • 解析 stdio/http/sse/ws 等不同 transport

5.3 client.ts 做了什么

这是 MCP 运行时核心,负责:

  • 建立客户端连接
  • 管理 transport
  • OAuth/认证处理
  • 连接缓存
  • 拉取工具/资源/命令
  • 把 MCP tool 包装成平台内 Tool
  • 调用 MCP tool
  • 处理返回内容、持久化与截断
  • 对 URL elicitation 等特殊错误做重试

5.4 为什么它重要

因为 MCP 让 Claude Code 从“自带工具集”升级为“可以连接外部能力宇宙的 agent 平台”。

6. Memory:长期上下文扩展

主要文件:src/memdir/memdir.ts 以及 src/memdir/*

6.1 memory 系统是什么

这是一个文件化、长期持久化的记忆系统,核心入口文件名是 MEMORY.md

6.2 memdir.ts 做了什么

它负责:

  • 规定 memory 目录结构和使用规范
  • 约束 MEMORY.md 的大小与行数
  • 构建 memory prompt
  • 确保 memory 目录存在
  • 记录 memory 目录加载情况
  • 定义什么该记、什么不该记

6.3 这不是普通缓存

它试图让模型在未来会话中仍然能记住:

  • 用户偏好
  • 协作方式
  • 项目约束
  • 历史反馈

所以 memory 属于“跨会话持久上下文”层。

7. 这些扩展机制如何协作

可以这样理解:

  • 命令:用户显式功能入口
  • Skill:轻量提示能力包
  • Plugin:重型功能包
  • MCP:外部服务连接总线
  • Memory:长期上下文扩展

它们合在一起,让这个项目从一个 CLI 变成“可扩展的 agent 平台”。

8. 扩展系统的阅读优先级

如果你要继续深入,建议顺序:

  1. src/commands.ts
  2. src/skills/loadSkillsDir.ts
  3. src/utils/plugins/pluginLoader.ts
  4. src/services/mcp/config.ts
  5. src/services/mcp/client.ts
  6. src/memdir/*
05-目录结构与重点文件地图
文档 06 05-目录结构与重点文件地图.md

目录结构与重点文件地图

1. 根目录级别

package.json

作用:

  • 定义项目名、脚本、工作区、本地包依赖
  • 暴露 CLI 二进制 claude-js
  • 指定 Bun 作为主要运行时

关注点:

  • scripts.build = bun run build.ts
  • scripts.dev = bun run src/entrypoints/cli.tsx
  • bin.claude-js = dist/cli.js
  • workspaces = packages/*, packages/@ant/*

build.ts

作用:

  • 构建脚本
  • 使用 Bun 打包入口
  • 开启 splitting
  • 对产物做 Node 兼容补丁

README.md

作用:

  • 项目定位说明
  • 开发/构建说明
  • 当前能力列表
  • 部分目录结构说明

docs/

作用:

  • 白皮书式说明文档
  • 对很多核心概念都有独立页面说明

2. src/ 目录主地图

src/entrypoints/

作用:

  • 各类运行入口
  • 主要 CLI 入口在 src/entrypoints/cli.tsx
  • 初始化入口在 src/entrypoints/init.ts

src/main.tsx

作用:

  • 主程序装配器
  • 解析参数、组装命令/工具/插件/MCP/模型/权限/状态
  • 决定最终进入哪种运行模式

src/screens/

作用:

  • 终端界面层
  • REPL.tsx 是交互主屏

src/components/

作用:

  • 各类 UI 组件
  • 权限弹窗、消息渲染、设置界面、MCP 交互、任务列表等

src/ink/

作用:

  • 自定义终端渲染基础设施
  • 不只是简单依赖第三方 Ink,而是做了大量底层扩展

说明:

这部分很值得重视,因为它决定了终端 UI 的能力上限。

src/query.ts

作用:

  • 单轮 agent loop 核心

src/QueryEngine.ts

作用:

  • 跨轮会话引擎
  • SDK/headless 入口的重要抽象

src/context.ts

作用:

  • 构建 system context 和 user context

src/tools/

作用:

  • 全部工具实现
  • 当前目录下有 55 个一级工具目录

重点子目录:

  • BashTool
  • FileReadTool
  • FileEditTool
  • FileWriteTool
  • AgentTool
  • WebFetchTool
  • WebSearchTool
  • SkillTool
  • Task*Tool
  • MCPTool

src/commands/

作用:

  • slash commands 实现
  • 当前目录下有 93 个命令目录

重点方向:

  • 用户功能类:helpdoctorstatusconfig
  • 协作类:reviewmemoryplantasks
  • 扩展类:mcppluginskills
  • 运行管理类:resumesessionexport

src/services/

作用:

  • 偏服务层能力
  • 包括 analytics、api、mcp、compact、plugins、lsp 等

重点子目录:

  • services/api
  • services/mcp
  • services/compact
  • services/plugins
  • services/analytics

src/utils/

作用:

  • 通用基础设施集合
  • 是项目里体量最大、最分散、也最关键的底座之一

重点方向:

  • utils/permissions
  • utils/sandbox
  • utils/model
  • utils/settings
  • utils/plugins
  • utils/git
  • utils/hooks
  • utils/sessionStorage

src/memdir/

作用:

  • 记忆系统
  • memory 目录解析与 prompt 生成

src/plugins/

作用:

  • 内置插件注册

src/skills/

作用:

  • 内置 skill 与 skill 加载逻辑

src/remote/ / src/server/ / src/ssh/

作用:

  • 远程会话、服务端连接、SSH 会话等能力
  • 说明此项目并不局限于本地单终端模式

3. packages/ 目录

这里是本地 workspace 包,主要包含一些独立原生能力或专用组件,例如:

  • audio-capture-napi
  • image-processor-napi
  • color-diff-napi
  • url-handler-napi
  • @ant/computer-use-*
  • @ant/claude-for-chrome-mcp

说明:

主项目不是所有能力都纯 TS 实现,部分能力通过 workspace 包承载,尤其是原生能力与平台集成能力。

4. 目录中的“异味”和阅读建议

4.1 为什么会看到 src/src/...

这是当前仓库一个明显特征。它更像还原过程中的镜像目录、分包迁移痕迹或兼容层,而不是标准手工整理后的一致结构。

阅读建议:

  • 先看真实入口引用到的路径
  • main.tsxtools.tscommands.tsquery.ts 的 import 为准
  • 不要先从重复目录开始看

4.2 为什么大量 require() 混用 import

原因通常有三类:

  • 避免循环依赖
  • 配合 feature gate 做 dead code elimination
  • 降低启动时不必要模块加载

所以这不是随意写法,而是为了大型 CLI 的工程现实。

5. 主阅读路径

如果你要顺着源码继续读,推荐顺序:

  1. src/entrypoints/cli.tsx
  2. src/main.tsx
  3. src/entrypoints/init.ts
  4. src/interactiveHelpers.tsx
  5. src/replLauncher.tsx
  6. src/screens/REPL.tsx
  7. src/context.ts
  8. src/tools.ts
  9. src/Tool.ts
  10. src/query.ts
  11. src/QueryEngine.ts
  12. src/utils/permissions/*
  13. src/utils/sandbox/sandbox-adapter.ts
  14. src/commands.ts
  15. src/skills/loadSkillsDir.ts
  16. src/utils/plugins/pluginLoader.ts
  17. src/services/mcp/config.ts
  18. src/services/mcp/client.ts
  19. src/memdir/*

6. 一句话速记表

  • 想看怎么启动:看 entrypoints/cli.tsx + main.tsx
  • 想看怎么显示 UI:看 screens/REPL.tsx + components/ + ink/
  • 想看怎么跑一轮问答:看 query.ts
  • 想看怎么管理整场会话:看 QueryEngine.ts
  • 想看模型为什么能调工具:看 tools.ts + Tool.ts
  • 想看为什么有的工具能直接执行、有的会弹确认:看 permissions.ts + useCanUseTool.tsx
  • 想看怎么隔离环境:看 sandbox-adapter.ts
  • 想看怎么扩展:看 commands.tsloadSkillsDir.tspluginLoader.tsservices/mcp/*
  • 想看怎么长期记忆用户与项目:看 memdir/* + context.ts
06-关键函数与类速查
文档 07 06-关键函数与类速查.md

关键函数与类速查

这份附录专门回答两个问题:

  • 关键逻辑到底落在哪些函数/类上
  • 读源码时先搜什么名字最有效

1. 启动相关

src/entrypoints/cli.tsx

  • main()
  • 作用:CLI 早期入口总控
  • 做什么:处理 --version、MCP 子模式、daemon/bridge 等快速路径,然后再进入完整主程序
  • 什么时候看:你想知道“程序为什么会走到某个模式”时先看它

src/entrypoints/init.ts

  • init()
  • 作用:底层初始化总入口
  • 做什么:启用配置、应用安全环境变量、注册 cleanup、初始化网络代理与认证预热、准备 scratchpad 等
  • 什么时候看:你想知道“主程序正式运行前做了哪些准备”时看它

src/replLauncher.tsx

  • launchRepl()
  • 作用:REPL 挂载器
  • 做什么:动态导入 AppREPL,然后调用 renderAndRun()
  • 什么时候看:你想知道 REPL 是如何被真正渲染出来时看它

src/interactiveHelpers.tsx

  • renderAndRun()
  • 作用:主界面渲染并等待退出
  • showSetupScreens()
  • 作用:启动前引导与信任确认总控
  • showDialog() / showSetupDialog()
  • 作用:统一的对话框渲染辅助

2. 上下文相关

src/context.ts

  • getGitStatus()
  • 作用:收集会话开始时的 Git 状态快照
  • getSystemContext()
  • 作用:生成系统级上下文
  • getUserContext()
  • 作用:生成用户级上下文,如 CLAUDE.md 与日期信息
  • setSystemPromptInjection()
  • 作用:设置额外系统提示注入,并清理上下文缓存

3. 会话与查询相关

src/query.ts

  • query(params)
  • 作用:单轮 agent loop 主入口
  • 做什么:流式请求模型、处理工具调用、回写工具结果、执行 compact/恢复/预算逻辑
  • 什么时候看:你想知道“模型和工具是怎样交替运行”的时候
  • queryLoop(...)
  • 作用:query() 内部的真实状态机主体
  • 做什么:承接每轮继续/终止逻辑

src/QueryEngine.ts

  • class QueryEngine
  • 作用:整场会话的上层执行引擎
  • 适用场景:SDK、headless、可复用的会话控制
  • submitMessage(prompt, options)
  • 作用:提交一条消息并推进一整轮会话
  • 做什么:准备上下文、加载 memory、调用 query()、归并消息与 usage

4. 工具系统相关

src/tools.ts

  • getAllBaseTools()
  • 作用:生成当前环境下可存在的所有基础工具
  • getToolsForDefaultPreset()
  • 作用:获取默认 preset 下的工具名列表
  • getTools(...)
  • 作用:结合权限上下文得到当前实际可用工具集
  • assembleToolPool(...)
  • 作用:把内置工具、MCP 工具等组装成最终工具池

src/Tool.ts

  • getEmptyToolPermissionContext()
  • 作用:生成空权限上下文
  • ToolUseContext
  • 作用:定义工具运行期上下文结构
  • ToolPermissionContext
  • 作用:定义权限规则的承载结构

5. 权限与沙箱相关

src/hooks/useCanUseTool.tsx

  • useCanUseTool(...)
  • 作用:REPL 场景的权限检查钩子
  • 做什么:调用底层权限判断,并在需要时接管交互审批、通知、分类器结果消费

src/utils/permissions/permissions.ts

  • hasPermissionsToUseTool(...)
  • 作用:工具权限判断核心入口
  • getAllowRules() / getDenyRules() / getAskRules()
  • 作用:从上下文提取不同类型规则
  • createPermissionRequestMessage()
  • 作用:生成用户可读的审批提示文案
  • checkRuleBasedPermissions(...)
  • 作用:规则匹配层的重要逻辑

src/utils/permissions/permissionSetup.ts

  • isDangerousBashPermission(...)
  • 作用:识别 auto mode 下危险 Bash 放行规则
  • isDangerousPowerShellPermission(...)
  • 作用:识别危险 PowerShell 放行规则
  • 其余逻辑重点:构造初始 permission mode、剥离危险规则、处理 plan/auto 切换

src/utils/sandbox/sandbox-adapter.ts

  • resolvePathPatternForSandbox(...)
  • 作用:把 Claude Code 风格路径规则转换成沙箱可识别形式
  • resolveSandboxFilesystemPath(...)
  • 作用:处理 sandbox 文件系统配置路径
  • convertToSandboxRuntimeConfig(...)
  • 作用:把项目 settings 转换成 sandbox-runtime 的配置对象
  • SandboxManager
  • 作用:Claude Code 对 sandbox-runtime 的统一适配入口

6. 命令、技能、插件、MCP

src/commands.ts

  • getCommands(cwd)
  • 作用:生成当前目录下可用的命令列表
  • getSkillToolCommands(...)
  • 作用:生成与 skill tool 相关的命令能力
  • findCommand(...) / getCommand(...)
  • 作用:查找命令定义
  • filterCommandsForRemoteMode(...)
  • 作用:远程模式命令过滤

src/skills/loadSkillsDir.ts

  • getSkillsPath(...)
  • 作用:计算不同来源的技能目录
  • parseSkillFrontmatterFields(...)
  • 作用:解析 skill frontmatter 的核心函数
  • getSkillDirCommands(...)
  • 作用:从 skills 目录加载并生成命令对象
  • discoverSkillDirsForPaths(...)
  • 作用:根据路径发现可激活的技能目录
  • addSkillDirectories(...)
  • 作用:动态添加 skill 目录

src/utils/plugins/pluginLoader.ts

  • getPluginCachePath()
  • 作用:插件缓存根目录
  • getVersionedCachePath(...)
  • 作用:插件版本缓存目录计算
  • probeSeedCache(...)
  • 作用:从 seed cache 中探测插件缓存
  • loadAllPluginsCacheOnly()
  • 作用:加载插件缓存,是主启动和 QueryEngine 中都会触达的重要入口

src/services/mcp/config.ts

  • getEnterpriseMcpFilePath()
  • 作用:企业托管 MCP 配置文件路径
  • getMcpServerSignature(...)
  • 作用:计算 MCP server 签名,用于去重
  • dedupPluginMcpServers(...)
  • 作用:去重插件提供的 MCP server
  • getClaudeCodeMcpConfigs(...)
  • 作用:获取 Claude Code 层面最终合并后的 MCP 配置
  • parseMcpConfig(...)
  • 作用:解析配置项到规范结构

src/services/mcp/client.ts

  • connectToServer(...)
  • 作用:建立 MCP 连接,是最关键的连接入口之一
  • ensureConnectedClient(...)
  • 作用:确保某个 server 已连接可用
  • fetchToolsForClient(...)
  • 作用:从 MCP server 拉取工具定义
  • fetchResourcesForClient(...)
  • 作用:从 MCP server 拉取资源列表
  • fetchCommandsForClient(...)
  • 作用:从 MCP server 拉取命令
  • getMcpToolsCommandsAndResources(...)
  • 作用:批量拉取并汇总 MCP 能力
  • callMCPToolWithUrlElicitationRetry(...)
  • 作用:调用 MCP tool,并在 URL elicitation 场景重试
  • processMCPResult(...)
  • 作用:处理 MCP 调用结果

7. memory 相关

src/memdir/memdir.ts

  • truncateEntrypointContent(...)
  • 作用:截断过大的 MEMORY.md
  • ensureMemoryDirExists(...)
  • 作用:确保 memory 目录存在
  • buildMemoryLines(...)
  • 作用:构建 memory 指令文本
  • loadMemoryPrompt()
  • 作用:加载 memory prompt,是 QueryEngine 会调用的重要入口

8. 搜索建议

如果你后面继续读源码,建议优先全局搜索这些名字:

  • main(
  • init(
  • launchRepl(
  • showSetupScreens(
  • getSystemContext(
  • getUserContext(
  • query(
  • submitMessage(
  • getTools(
  • getCommands(
  • hasPermissionsToUseTool(
  • convertToSandboxRuntimeConfig(
  • getSkillDirCommands(
  • loadAllPluginsCacheOnly(
  • getClaudeCodeMcpConfigs(
  • getMcpToolsCommandsAndResources(
  • loadMemoryPrompt(

9. 最短记忆版

  • 启动看 cli.tsx -> main.tsx -> init.ts
  • REPL 看 replLauncher.tsx -> REPL.tsx
  • 上下文看 context.ts
  • 会话引擎看 query.ts + QueryEngine.ts
  • 工具注册看 tools.ts + Tool.ts
  • 权限审批看 useCanUseTool.tsx + permissions.ts
  • 沙箱隔离看 sandbox-adapter.ts
  • 命令/技能/插件/MCP 分别看 commands.tsloadSkillsDir.tspluginLoader.tsservices/mcp/*
没有匹配到相关内容,可以换一个关键词试试。