# 构建系统与功能标记架构 ## 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( 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 ```