codev / docs /cli /build-system.md
chenbhao's picture
chore: rename VersperClaw to Codev, update org to chenbhao
96f34e3
|
Raw
History Blame Contribute Delete
28.2 kB
# 构建系统与功能标记架构
## 1. 构建管道
构建入口位于 `scripts/build.ts`,基于 Bun 的原生打包工具 `bun build`。整个构建流程由 `package.json` 中的 npm scripts 驱动。
### 1.1 构建模式
| 命令 | 对应脚本参数 | 输出格式 | 说明 |
| --- | --- | --- | --- |
| `bun run build` | 无 | 源码产物 (`./cli`) | 默认构建,不编译为二进制 |
| `bun run build:dev` | `--dev` | 源码产物 (`./Codev`) | 开发版本,自动附加 git SHA 和构建时间作为开发版本号 |
| `bun run build:dev:full` | `--dev --feature-set=dev-full` | 源码产物 (`./Codev`) | 开发版本,启用全部实验性功能标记 |
| `bun run compile` | `--compile` | 二进制可执行文件 (`./dist/cli`) | 生产构建,编译为 Bun 原生二进制 |
| `bun run dev` | — | 直接运行 | 通过 `bun run ./src/entrypoints/cli.tsx` 直接执行,跳过构建步骤 |
### 1.2 构建流程步骤
1. **Friend 前端构建检查**:检查 `src/components/friend/frontend/dist/index.html` 是否存在,若不存在则调用 `npm run build` 构建 VRM 头像前端(该前端基于 Vite + React + Three.js,位于 `src/components/friend/frontend/`)。
2. **版本号计算**
- 开发模式(`--dev`):使用 `git rev-parse --short=8 HEAD` 获取当前 commit SHA,生成格式为 `{baseVersion}-dev.{YYYYMMDD}.t{HHmmss}.sha{commit}` 的版本号。
- 生产模式:直接使用 `package.json` 中的版本字段 `2.1.0`
- 同时获取最近的 20 条 git log 作为 changelog(仅开发模式)。
3. **编译时宏定义注入**:通过 `--define` 注入 `MACRO.*` 常量(见下文 2.1 节)。
4. **Bun 打包**:调用 `bun build`,以 `./src/entrypoints/cli.tsx` 为入口,使用以下关键参数:
- `--compile`:仅在 `compile` 模式下启用
- `--target bun`:目标运行时为 Bun
- `--format esm`:输出 ESM 格式
- `--minify`:启用代码压缩
- `--bytecode`:启用字节码缓存
- `--packages bundle`:将所有依赖打包进产物
- `--conditions bun`:使用 Bun 条件导出
5. **vendors 复制**:非编译模式下,将 `vendor/` 目录(包含 `audio-capture``opus-encdec` 等原生二进制库)复制到输出目录的 `vendor/` 子目录下。
6. **权限设置**:产物文件设置 `0o755` 可执行权限。
### 1.3 Friend VRM 前端构建集成
Friend 是桌面宠物 VRM 伴侣功能,其前端是一个独立的 Vite + React + Three.js 应用,位于 `src/components/friend/frontend/`。构建系统在主构建前检查其 `dist/` 目录是否已存在:
- 若已存在(如之前构建过),跳过前端构建步骤。
- 若不存在,自动执行 `npm run build`(调用 Vite 进行生产构建)。
- 构建产出包含 VRM 模型文件(`.vrm`)、FBX 动画文件、WASM 运行时(onnxruntime-web)、VAD 模型(silero_vad)和音效文件等静态资源。
此步骤是构建流程的**前置必要条件**——若 Friend 前端构建失败,整个构建过程退出并返回错误码 1。
### 1.4 外部依赖排除
以下 native 模块在构建时被声明为 `--external`,不会打包进最终产物,需在运行时由 Bun 动态解析:
- `@ant/*`(Anthropic 内部包)
- `audio-capture-napi`
- `image-processor-napi`
- `modifiers-napi`
- `url-handler-napi`
这些模块通过 workspace 管理或直接从 vendor 目录加载。
---
## 2. Feature Flag 系统
### 2.1 `bun:bundle` 编译时 Feature 标记
系统使用 Bun 内置的 `import { feature } from 'bun:bundle'` 实现编译时条件编译。`feature('NAME')` 是一个**编译时布尔常量**,在 `bun build` 阶段根据 `--feature=NAME` 参数确定值:
- 如果 `NAME` 在传递给 `bun build` 的 feature 集合中,`feature('NAME')` 求值为 `true`
- 否则求值为 `false`
- Bun 的打包器会对 `feature('NAME')` 条件分支进行**死代码消除**(Dead Code Elimination, DCE)
代码中典型的使用模式:
```typescript
import { feature } from 'bun:bundle'
// 编译时条件导入——false 分支在产物中完全不存在
const bridge = feature('BRIDGE_MODE')
? require('./commands/bridge/index.js').default
: null
// 编译时条件执行
if (feature('VOICE_MODE')) {
// 启用语音模式的代码
}
```
### 2.2 Feature 传递机制
Feature 标记通过三种方式传递给构建系统:
1. **编译参数**:`bun run ./scripts/build.ts --feature=NAME`
2. **批量设置**:`--feature-set=dev-full` 启用 `fullExperimentalFeatures` 数组中的所有标记
3. **默认集合**:`defaultFeatures = ['VOICE_MODE']` 始终包含在构建中
构建脚本中的优先级逻辑:
```typescript
const defaultFeatures = ['VOICE_MODE']
const featureSet = new Set(defaultFeatures)
// 解析 --feature-set=dev-full
// 解析 --feature NAME
// 解析 --feature=NAME
```
最终所有选中的 feature 通过 `--feature=${feature}` 逐条传递给 `bun build` 命令。
### 2.3 编译时宏注入
`feature()` 系统外,构建脚本还通过 `--define` 注入一系列编译时常量(`MACRO.*`)。这些常量在 TypeScript 环境中通过 `env.d.ts` 声明类型:
| 宏 | 含义 | 值来源 |
| --- | --- | --- |
| `MACRO.VERSION` | 当前版本号 | `package.json` version 或开发版 git 版本 |
| `MACRO.BUILD_TIME` | 构建时间 | `new Date().toISOString()` |
| `MACRO.PACKAGE_URL` | 包 URL | `package.json` name |
| `MACRO.NATIVE_PACKAGE_URL` | 原生包 URL | 始终为 `undefined`(外部构建) |
| `MACRO.FEEDBACK_CHANNEL` | 反馈渠道 | 固定为 `'github'` |
| `MACRO.ISSUES_EXPLAINER` | Issue 说明文本 | 固定字符串 |
| `MACRO.VERSION_CHANGELOG` | 版本变更日志 | 开发模式取 git log;生产模式固定 URL |
`MACRO.*` 外,以下 `process.env` 变量也在构建时注入:
| 变量 | 值 | 说明 |
| --- | --- | --- |
| `process.env.USER_TYPE` | `'external'` | 标记为外部构建(非 Anthropic 内部) |
| `process.env.CLAUDE_CODE_FORCE_FULL_LOGO` | `'true'` | 强制显示完整 logo |
| `process.env.NODE_ENV` | `'development'`(仅 dev 模式) | 运行时环境标识 |
| `process.env.CLAUDE_CODE_EXPERIMENTAL_BUILD` | `'true'`(仅 dev 模式) | 标记为实验性构建 |
| `process.env.CLAUDE_CODE_VERIFY_PLAN` | `'false'` | 禁用计划验证 |
| `process.env.CCR_FORCE_BUNDLE` | `'true'` | 强制打包 CCR 相关代码 |
### 2.4 运行时环境变量动态配置
开发环境中,`preload.ts` 在运行时会覆盖 `MACRO` 的值,使用环境变量进行本地开发配置:
```typescript
const version = process.env.CLAUDE_CODE_LOCAL_VERSION ?? '999.0.0-local'
// ...
Object.assign(globalThis, {
MACRO: {
VERSION: version,
PACKAGE_URL: packageUrl,
NATIVE_PACKAGE_URL: packageUrl,
BUILD_TIME: buildTime,
FEEDBACK_CHANNEL: 'local',
// ...
},
})
```
### 2.5 Feature 死代码消除机制详解
`feature()` 的死代码消除分为两种形态:
**形态 A — 条件导入(模块级 DCE)**
```typescript
const remoteControlServerCommand =
feature('DAEMON') && feature('BRIDGE_MODE')
? require('./commands/remoteControlServer/index.js').default
: null
```
`DAEMON``BRIDGE_MODE` 未启用时,`require()` 调用和整个依赖图(包括被导入模块的所有递归依赖)均被消除。这是最有效的 DCE 形式,可大幅减小产物体积。
**形态 B — 条件执行(语句级 DCE)**
```typescript
if (feature('VOICE_MODE')) {
// 语音相关逻辑
}
```
`VOICE_MODE` 未启用时,整个 `if` 块被消除。但被调用的模块如果已在前面的代码中被无条件导入,则仍会保留在产物中。
### 2.6 完整 Feature Flag 列表
以下是从代码库中提取的所有 `feature('NAME')` 调用,按类别分组:
#### 语音与输入
| Feature | 用途 | 涉及文件数 |
| --- | --- | --- |
| `VOICE_MODE` | 语音模式:语音录制、流式 STT(语音转文字)、语音状态指示器、VAD(语音活动检测);默认启用 | ~60+ 处调用 |
| `NATIVE_CLIPBOARD_IMAGE` | 原生剪贴板图片支持 | 1 |
#### 助手/Kairos 会话模式
| Feature | 用途 | 涉及文件数 |
| --- | --- | --- |
| `KAIROS` | Kairos 助手模式:会话管理、--session-id、--continue 参数、assistant 命令/模块、团队上下文、消息队列管理、daily-log 提示词 | ~100+ 处调用(最广泛) |
| `KAIROS_BRIEF` | Brief 摘要模式:简化版助手界面、brief 命令、SendUserMessage 替代 | ~25 处调用 |
| `KAIROS_CHANNELS` | Kairos 频道/通道系统:消息通道路由 | ~8 处调用 |
| `KAIROS_PUSH_NOTIFICATION` | 推送通知功能 | ~4 处调用 |
| `KAIROS_GITHUB_WEBHOOKS` | GitHub Webhook 订阅功能(subscribe-pr 命令) | ~3 处调用 |
| `KAIROS_BRIEF` | 同上(独立用途) | — |
#### 桥接/远程控制
| Feature | 用途 | 涉及文件数 |
| --- | --- | --- |
| `BRIDGE_MODE` | 桥接模式:CLI 与 mobile/web 客户端通信、remote-control 子命令 | ~30 处调用 |
| `CCR_AUTO_CONNECT` | CCR(Claude Code Remote)自动连接 | 2 |
| `CCR_MIRROR` | CCR 镜像模式 | ~5 处调用 |
| `CCR_REMOTE_SETUP` | 远程设置向导(web 命令) | 2 |
| `DAEMON` | 守护进程模式:daemon worker、后台长期运行 | 4 |
| `DIRECT_CONNECT` | 直接连接模式(URL/二维码直接连接) | ~8 处调用 |
| `SSH_REMOTE` | SSH 远程模式:通过 SSH 连接远程会话 | ~6 处调用 |
| `UDS_INBOX` | Unix Domain Socket 收件箱:对等节点发现、跨进程消息传递 | ~30 处调用 |
#### 协作与团队
| Feature | 用途 | 涉及文件数 |
| --- | --- | --- |
| `COORDINATOR_MODE` | 协调者模式:多 agent 协作、任务分配、worker 管理 | ~20 处调用 |
| `TEAMMEM` | 团队记忆系统:共享记忆文件、团队上下文读取/搜索/写入 | ~25 处调用 |
| `BUDDY` | 桌面宠物伴侣:CompanionSprite 渲染、提示词注入、通知 | ~15 处调用 |
| `FORK_SUBAGENT` | 子 agent 分支:fork 命令、agent 分支执行 | ~3 处调用 |
| `AGENT_TRIGGERS` | Agent 触发器:cron 定时任务(Create/Delete/List) | ~8 处调用 |
| `AGENT_TRIGGERS_REMOTE` | 远程触发器 | ~3 处调用 |
| `AGENT_MEMORY_SNAPSHOT` | Agent 记忆快照:自定义 agent 记忆持久化 | 2 |
| `COWORKER_TYPE_TELEMETRY` | 同事类型遥测 | 1 |
#### 权限与安全
| Feature | 用途 | 涉及文件数 |
| --- | --- | --- |
| `TRANSCRIPT_CLASSIFIER` | 转录分类器:自动模式(auto mode)、权限模式扩展、YOLO 分类器 | ~60 处调用 |
| `BASH_CLASSIFIER` | Bash 命令分类器:对 bash 命令进行安全分类、自动批准 | ~20 处调用 |
| `POWERSHELL_AUTO_MODE` | PowerShell 自动模式 | ~3 处调用 |
| `PROACTIVE` | 主动模式:模型主动发起交互、背景任务提示 | ~25 处调用 |
| `BYOC_ENVIRONMENT_RUNNER` | BYOC 环境运行器 | 1 |
| `SELF_HOSTED_RUNNER` | 自托管运行器 | 1 |
#### 上下文管理
| Feature | 用途 | 涉及文件数 |
| --- | --- | --- |
| `CONTEXT_COLLAPSE` | 上下文折叠:长上下文管理、413 错误处理 | ~15 处调用 |
| `CACHED_MICROCOMPACT` | 缓存微压缩:在对话流中增量压缩上下文 | ~15 处调用 |
| `COMPACTION_REMINDERS` | 压缩提醒 | 1 |
| `HISTORY_SNIP` | 历史摘要截取:SnipTool、会话上下文裁剪 | ~10 处调用 |
| `HISTORY_PICKER` | 历史选择器:对话历史浏览 | ~5 处调用 |
| `REACTIVE_COMPACT` | 响应式压缩 | 3 |
| `PROMPT_CACHE_BREAK_DETECTION` | 提示缓存断裂检测 | 3 |
| `BREAK_CACHE_COMMAND` | 缓存断裂命令 | 2 |
| `EXTRACT_MEMORIES` | 记忆提取:会话结束时的自动记忆提取 | ~10 处调用 |
| `MEMORY_SHAPE_TELEMETRY` | 记忆形状遥测 | 4 |
#### 工具
| Feature | 用途 | 涉及文件数 |
| --- | --- | --- |
| `WORKFLOW_SCRIPTS` | 工作流脚本:WorkflowTool、workflows 命令、后台工作流任务 | ~15 处调用 |
| `MONITOR_TOOL` | 监控工具:MonitorMcpTask、后台监控 | ~8 处调用 |
| `WEB_BROWSER_TOOL` | Web 浏览器工具:基于 Bun WebView 的浏览器 | ~4 处调用 |
| `OVERFLOW_TEST_TOOL` | 溢出测试工具 | 3 |
| `TERMINAL_PANEL` | 终端面板工具 | 2 |
| `TORCH` | Torch 命令 | 2 |
| `ULTRAPLAN` | 超计划模式:增强规划能力 | ~10 处调用 |
| `ULTRATHINK` | 超思考模式 | 1 |
| `VERIFICATION_AGENT` | 验证 agent | 2 |
| `EXPERIMENTAL_SKILL_SEARCH` | 实验性技能搜索 | ~10 处调用 |
| `SKILL_IMPROVEMENT` | 技能改进反馈 | 1 |
| `TEMPLATES` | 模板系统:new/list/reply 命令 | ~6 处调用 |
#### 构建与发布
| Feature | 用途 | 涉及文件数 |
| --- | --- | --- |
| `ABLATION_BASELINE` | 消融实验基线:设置多个环境变量 | 1 |
| `ALLOW_TEST_VERSIONS` | 允许测试版本(99.99.x) | 2 |
| `DUMP_SYSTEM_PROMPT` | 导出系统提示词(`--dump-system-prompt`) | 1 |
| `NEW_INIT` | 新的初始化流程 | 2 |
#### 用户界面
| Feature | 用途 | 涉及文件数 |
| --- | --- | --- |
| `MESSAGE_ACTIONS` | 消息操作:消息级交互操作 | ~4 处调用 |
| `QUICK_SEARCH` | 快速搜索:PromptInput 内联搜索 | ~5 处调用 |
| `MCP_RICH_OUTPUT` | MCP 富文本输出 | 3 |
| `AUTO_THEME` | 自动主题:跟随终端主题变化 | 1 |
| `BUDDY` | 同上(见协作与团队分组) | — |
#### 内部与实验性
| Feature | 用途 | 涉及文件数 |
| --- | --- | --- |
| `ANTI_DISTILLATION_CC` | 反蒸馏保护 | 1 |
| `BG_SESSIONS` | 后台会话:ps/logs/attach/kill 命令 | ~8 处调用 |
| `BUILDING_CLAUDE_APPS` | 构建 Claude Apps 技能 | 1 |
| `BUILTIN_EXPLORE_PLAN_AGENTS` | 内置探索/计划 agent | 1 |
| `CHICAGO_MCP` | Chicago MCP 协议:MCP 配置、computer-use-mcp 入口 | ~10 处调用 |
| `COMMIT_ATTRIBUTION` | 提交归属追踪 | ~4 处调用 |
| `CONNECTOR_TEXT` | Connector 文本块处理 | ~6 处调用 |
| `DOWNLOAD_USER_SETTINGS` | 下载用户设置 | 1 |
| `FILE_PERSISTENCE` | 文件持久化(public API / sessions) | 1 |
| `HARD_FAIL` | 硬失败模式 | 1 |
| `HOOK_PROMPTS` | Hook 提示词注入 | 1 |
| `IS_LIBC_GLIBC` | 检测是否使用 glibc | 1 |
| `IS_LIBC_MUSL` | 检测是否使用 musl libc | 1 |
| `LODESTONE` | LODESTONE 协议注册 | ~6 处调用 |
| `MCP_SKILLS` | MCP 技能 | 2 |
| `NATIVE_CLIENT_ATTESTATION` | 原生客户端认证 | 1 |
| `PERFETTO_TRACING` | Perfetto 性能追踪 | 1 |
| `REVIEW_ARTIFACT` | 审查构件技能 | 1 |
| `RUN_SKILL_GENERATOR` | 运行技能生成器 | 1 |
| `SHOT_STATS` | 射击统计(对话轮次分布) | 3 |
| `SLOW_OPERATION_LOGGING` | 慢操作日志 | 1 |
| `TOKEN_BUDGET` | Token 预算跟踪 | ~10 处调用 |
| `TREE_SITTER_BASH` | Tree-sitter Bash 解析器 | 1 |
| `TREE_SITTER_BASH_SHADOW` | Tree-sitter Bash 影子解析 | 1 |
| `UNATTENDED_RETRY` | 无人值守重试 | 1 |
| `UPLOAD_USER_SETTINGS` | 上传用户设置 | 1 |
### 2.7 实验性功能全集(`fullExperimentalFeatures`)
`scripts/build.ts` 中定义了一个`fullExperimentalFeatures` 常量数组,通过 `--feature-set=dev-full` 批量启用。完整列表:
```
AGENT_MEMORY_SNAPSHOT, AGENT_TRIGGERS, AGENT_TRIGGERS_REMOTE,
AWAY_SUMMARY, BASH_CLASSIFIER, BUDDY, BRIDGE_MODE,
BUILTIN_EXPLORE_PLAN_AGENTS, CACHED_MICROCOMPACT,
CCR_AUTO_CONNECT, CCR_MIRROR, CCR_REMOTE_SETUP,
COMPACTION_REMINDERS, CONNECTOR_TEXT, EXTRACT_MEMORIES,
HISTORY_PICKER, HOOK_PROMPTS, KAIROS_BRIEF, KAIROS_CHANNELS,
LODESTONE, MCP_RICH_OUTPUT, MESSAGE_ACTIONS, NATIVE_CLIPBOARD_IMAGE,
NEW_INIT, POWERSHELL_AUTO_MODE, PROMPT_CACHE_BREAK_DETECTION,
QUICK_SEARCH, SHOT_STATS, TEAMMEM, TOKEN_BUDGET, TREE_SITTER_BASH,
TREE_SITTER_BASH_SHADOW, TRANSCRIPT_CLASSIFIER, ULTRAPLAN, ULTRATHINK,
UNATTENDED_RETRY, VERIFICATION_AGENT, VOICE_MODE
```
注意:`VOICE_MODE` 同时出现在默认集合 `defaultFeatures` 和实验性集合中,此重复不会造成问题(Set 去重)。
---
## 3. 命令可用性门控
### 3.1 `availability` 声明
每个命令可以通过 `availability` 字段声明其适用的认证/供应商环境。`src/types/command.ts` 中定义了 `CommandAvailability` 类型:
```typescript
export type CommandAvailability =
| 'claude-ai' // claude.ai OAuth 订阅用户(Pro/Max/Team/Enterprise)
| 'console' // Console API key 用户(直接使用 api.anthropic.com)
```
可用性声明的命令示例:
```typescript
// src/commands/usage/index.ts
{ name: 'usage', availability: ['claude-ai'], ... }
// src/commands/fast/index.ts
{ name: 'fast', availability: ['claude-ai', 'console'], ... }
```
`availability``isEnabled()` 的职责分离:
- **`availability`** = 谁能使用(基于认证/供应商的静态检查)
- **`isEnabled()`** = 当前是否开启(基于 feature flags、GrowthBook、环境变量等动态条件)
不存在 `availability` 字段的命令被视为通用命令,在所有环境中可用。
### 3.2 `meetsAvailabilityRequirement()` 检查链
`src/commands.ts` 中实现了 `meetsAvailabilityRequirement()` 函数,负责检查命令是否满足可用性要求:
```typescript
export function meetsAvailabilityRequirement(cmd: Command): boolean {
if (!cmd.availability) return true // 无限制
for (const a of cmd.availability) {
switch (a) {
case 'claude-ai':
if (isClaudeAISubscriber()) return true
break
case 'console':
if (!isClaudeAISubscriber() && !isUsing3PServices() && isFirstPartyAnthropicBaseUrl())
return true
break
}
}
return false
}
```
检查逻辑:
- **`claude-ai`**:用户通过 claude.ai OAuth 认证且为订阅用户(Pro/Max/Team/Enterprise)
- **`console`**:用户非 claude.ai 订阅用户、不使用第三方服务(Bedrock/Vertex/Foundry)、且使用官方 Anthropic API base URL
该检查在命令列表构建时执行,且**不缓存**——因为认证状态可在会话中变化(例如通过 `/login` 命令)。
### 3.3 `getCommands()` 中的过滤链
命令的最终可用性由 `getCommands()` 函数(`src/commands.ts`)计算,过滤链如下:
```typescript
const allCommands = await loadAllCommands(cwd)
const baseCommands = allCommands.filter(
_ => meetsAvailabilityRequirement(_) && isCommandEnabled(_),
)
```
每个命令需**同时满足**
1. `meetsAvailabilityRequirement()` — 认证/供应商匹配
2. `isCommandEnabled()` — 命令级启用检查(可关连 feature flag 或动态条件)
### 3.4 命令级 `isEnabled()` / `isHidden()` 控制
除了全局的 feature flag 和 availability 机制,每个命令还可以单独定义 `isEnabled()``isHidden`
**`isEnabled()` 使用示例**
```typescript
// src/commands/voice/index.ts
{ isEnabled: () => isVoiceGrowthBookEnabled() }
// src/commands/review.ts
{ isEnabled: () => isUltrareviewEnabled() }
// src/commands/session/index.ts
{ isEnabled: () => getIsRemoteMode() }
// src/commands/extra-usage/index.ts
{ isEnabled: () => isExtraUsageAllowed() && !getIsNonInteractiveSession() }
```
**`isHidden` 使用模式**
```typescript
// 内部命令(外部构建中完全隐藏——这些命令的 stub 文件导出此配置)
// src/commands/share/index.js
export default { isEnabled: () => false, isHidden: true, name: 'stub' }
// 条件隐藏
// src/commands/cost/index.ts
{ get isHidden() { /* 动态条件 */ } }
// 始终隐藏
// src/commands/heapdump/index.ts
{ isHidden: true }
```
`isCommandEnabled()` 的默认值为 `true`(未定义时),`isHidden` 默认值为 `false`
### 3.5 `USER_TYPE` 环境变量
构建时通过 `process.env.USER_TYPE` 控制内部/外部构建的差异:
- 外部构建:`USER_TYPE = 'external'`(当前版本如此设置)
- 内部构建:`USER_TYPE = 'ant'`(Anthropic 内部)
`USER_TYPE` 控制以下差异:
1. **内部命令注册**`INTERNAL_ONLY_COMMANDS` 数组(包含 `backfillSessions``breakCache``bughunter``initVerifiers` 等 ~30 个内部命令)仅在 `USER_TYPE === 'ant'` 时注册。
2. **工具可用性**`ConfigTool``TungstenTool``REPLTool` 仅在内部构建中可用。
3. **YOLO 分类器**:内部构建使用更详细的权限分类模板。
---
## 4. 工具过滤
### 4.1 `filterToolsByDenyRules()`
`src/tools.ts` 中的 `filterToolsByDenyRules()` 函数根据权限上下文中的拒绝规则过滤工具:
```typescript
export function filterToolsByDenyRules<T extends { name: string; mcpInfo?: ... }>(
tools: readonly T[],
permissionContext: ToolPermissionContext,
): T[] {
return tools.filter(tool => !getDenyRuleForTool(permissionContext, tool))
}
```
此过滤在工具列表最终组装前执行,确保被拒绝的工具(包括按 MCP 服务器前缀拒绝的)在模型看到之前就已移除。
### 4.2 完整工具组装流程
`getTools()` 函数(`src/tools.ts`)的组装流程:
1. **Simple 模式**`CLAUDE_CODE_SIMPLE=1`):仅返回 `BashTool``FileReadTool``FileEditTool`(或 REPL 模式下的 `REPLTool`),加上协调者模式所需的 `AgentTool` + `TaskStopTool`
2. **完整模式**:通过 `getAllBaseTools()` 获取所有工具,移除特殊工具(`ListMcpResourcesTool``ReadMcpResourceTool``SYNTHETIC_OUTPUT_TOOL_NAME`)。
3. **应用拒绝规则**`filterToolsByDenyRules()`
4. **REPL 模式屏蔽**:当 REPL 启用时,隐藏 `REPL_ONLY_TOOLS` 集合中的原始工具。
5. **应用 `isEnabled()`**:每个工具自身的 `isEnabled()` 检查。
### 4.3 条件工具(`feature()` 门控导入)
`src/tools.ts` 中使用 `feature()` 进行条件导入的工具清单:
| Feature | 工具类 | 说明 |
| --- | --- | --- |
| `PROACTIVE` / `KAIROS` | `SleepTool` | 计划休眠工具 |
| `AGENT_TRIGGERS` | `CronCreateTool`, `CronDeleteTool`, `CronListTool` | 定时任务管理 |
| `AGENT_TRIGGERS_REMOTE` | `RemoteTriggerTool` | 远程触发器 |
| `MONITOR_TOOL` | `MonitorTool` | 监控工具 |
| `KAIROS` | `SendUserFileTool` | 发送用户文件 |
| `KAIROS` / `KAIROS_PUSH_NOTIFICATION` | `PushNotificationTool` | 推送通知 |
| `KAIROS_GITHUB_WEBHOOKS` | `SubscribePRTool` | PR 订阅 |
| `OVERFLOW_TEST_TOOL` | `OverflowTestTool` | 溢出测试 |
| `CONTEXT_COLLAPSE` | `CtxInspectTool` | 上下文检查 |
| `TERMINAL_PANEL` | `TerminalCaptureTool` | 终端捕获 |
| `WEB_BROWSER_TOOL` | `WebBrowserTool` | 浏览器工具 |
| `HISTORY_SNIP` | `SnipTool` | 历史摘要 |
| `UDS_INBOX` | `ListPeersTool` | 对等节点列表 |
| `WORKFLOW_SCRIPTS` | `WorkflowTool` | 工作流执行 |
内部构建特有的工具(不受 `feature()` 控制,受 `USER_TYPE === 'ant'` 控制):
- `REPLTool`:REPL 交互式开发环境
- `SuggestBackgroundPRTool`:PR 建议工具
- `ConfigTool``TungstenTool`:内部配置工具
### 4.4 MCP 工具合并
`assembleToolPool()` 函数(`src/tools.ts`)合并内置工具和 MCP 工具:
1. 通过 `getTools()` 获取内置工具
2. 通过 `filterToolsByDenyRules()` 过滤 MCP 工具
3. 使用 `uniqBy()` 按名称去重(内置工具优先)
4. 按名称排序以保证提示缓存稳定性
---
## 5. 构建产物
### 5.1 输出目录结构
构建产物的 `dist/` 目录结构:
```
dist/
├── cli # 生产二进制(`--compile` 模式,~192MB)
├── cli.js # 生产源码产物(非编译模式,~20MB)
├── Codev # 开发二进制(`--dev --compile` 模式,~202MB)
└── vendor/ # 原生二进制库(仅非编译模式)
├── audio-capture/ # 音频捕获原生模块
├── audio-capture-src/ # 音频捕获源码
└── opus-encdec/ # Opus 编码/解码
```
### 5.2 各模式产物对比
| 构建模式 | 入口文件 | 产物路径 | 大小 | 类型 |
| --- | --- | --- | --- | --- |
| `build`(默认) | `scripts/build.ts` | `./cli` | ~0(源码引用) | 源码(Bun bundle) |
| `build:dev` | `scripts/build.ts --dev` | `./Codev` | ~0(源码引用) | 源码 |
| `compile` | `scripts/build.ts --compile` | `./dist/cli` | ~192MB | Bun 编译二进制 |
| `compile + dev` | `scripts/build.ts --compile --dev` | `./dist/Codev` | ~202MB | Bun 编译二进制(调试) |
### 5.3 预加载脚本
`preload.ts` 是开发模式下的运行时预加载脚本,在执行入口文件前:
- 设置 `MACRO` 全局变量
- 设置 `CLAUDE_CODE_LOCAL_SKIP_REMOTE_PREFETCH=1` 跳过远程预取
- 切换到调用目录(`process.chdir(CALLER_DIR)`
### 5.4 Friend 前端静态资源
Friend VRM 前端构建产出包含大量静态资源(位于 `src/components/friend/frontend/dist/`):
- **VRM 模型**:5 个 `.vrm` 文件(11MB-48MB 不等)
- **FBX 动画**:约 10 个动画文件(`angry.fbx``happy.fbx``greeting.fbx` 等)
- **VMD/VRMA 动作**`jile.vmd``idle_loop.vrma``playFingers.vrma`
- **WASM 文件**:onnxruntime-web 运行时的多个 WASM 二进制(`ort-wasm-simd-threaded.wasm` 等,合计约 80MB)
- **VAD 模型**`silero_vad_legacy.onnx`(1.8MB)、`silero_vad_v5.onnx`(2.3MB)
- **音效**`jile.mp3`(4.2MB)、`love.mp3`(11MB)
- **音频工作集**`vad.worklet.bundle.min.js`(2.5KB)
- **HTML 入口**`index.html`
### 5.5 WASM 与原生库
项目依赖多个 WASM 和原生库:
- **onnxruntime-web**:用于语音活动检测(VAD)的推理引擎
- **audio-capture-napi**(workspace):原生音频捕获库,通过 workspace `packages/audio-capture-napi` 管理
- **doubaoime-asr**:字节跳动豆包语音识别引擎(workspace symlink)
---
## 6. 开发工作流
### 6.1 开发模式启动
```bash
# 直接运行(无需构建,适合快速迭代)
bun run dev
# 等价于:bun run ./src/entrypoints/cli.tsx
# 开发构建 + 运行
bun run build:dev
./Codev
# 开发构建(全部实验特性)+ 运行
bun run build:dev:full
./Codev
```
### 6.2 生产构建
```bash
# 生产编译
bun run compile
# 输出:./dist/cli(~192MB 二进制)
# 测试构建
bun run build:dev:compile # 注意:此命令需要额外添加 --compile 参数
```
### 6.3 包管理
项目使用 **Bun workspaces** 管理 monorepo:
```json
{
"workspaces": ["packages/*"],
"packageManager": "bun@1.3.11",
"engines": { "bun": ">=1.3.11" }
}
```
workspace 包:
- `packages/audio-capture-napi/`:音频捕获原生 N-API 模块
- `packages/doubaoime-asr/`:豆包语音识别(symlink 到 .bun 缓存)
TypeScript 配置(`tsconfig.json`):
```json
{
"compilerOptions": {
"lib": ["ESNext"],
"target": "ESNext",
"module": "Preserve",
"jsx": "react-jsx",
"types": ["bun"],
"moduleResolution": "bundler",
"noEmit": true,
"strict": false,
"skipLibCheck": true
},
"include": ["src", "scripts", "env.d.ts"]
}
```
### 6.4 依赖特性说明
- **运行时 UI**:基于 Ink(React for CLI)和 JSX 构建交互式终端界面
- **语音处理**:使用 `@ericedouard/vad-node-realtime`(VAD)、`node-edge-tts`(TTS)
- **AI 服务**:多供应商支持(Anthropic SDK、AWS Bedrock、Azure、Google Vertex、Groq)
- **MCP 协议**`@modelcontextprotocol/sdk``@anthropic-ai/mcpb`
- **功能标记运行时**`@growthbook/growthbook` 用于运行时功能开关(与编译时 `feature()` 互补)
- **WebView**:通过 Bun 内置的 `WebView` 支持 Web 浏览器工具
- **Feishu/Lark**`@larksuiteoapi/node-sdk` 集成飞书机器人
- **Telegram**:telegram 命令集成
### 6.5 构建脚本快速参考
| 命令 | 完整脚本 |
| --- | --- |
| `bun run dev` | `bun run ./src/entrypoints/cli.tsx` |
| `bun run build` | `bun run ./scripts/build.ts` |
| `bun run build:dev` | `bun run ./scripts/build.ts --dev` |
| `bun run build:dev:full` | `bun run ./scripts/build.ts --dev --feature-set=dev-full` |
| `bun run compile` | `bun run ./scripts/build.ts --compile` |
自定义构建示例:
```bash
# 带自定义 feature 的开发构建
bun run ./scripts/build.ts --dev --feature=KAIROS --feature=BUDDY
# 编译 + 特定 feature
bun run ./scripts/build.ts --compile --feature=TRANSCRIPT_CLASSIFIER
```