Compare commits

...

182 Commits

Author SHA1 Message Date
claude-code-best
d03af7bd4e chore: 1.10.0 2026-04-25 14:48:15 +08:00
claude-code-best
e8ef955ff9 docs: 添加 /login 说明 2026-04-25 14:47:43 +08:00
claude-code-best
a8ed0cdce5 fix: 修复构建后 vendor 二进制路径解析错误(ripgrep/audio-capture)
构建后 chunk 文件位于 dist/chunks/(Vite)或 dist/(Bun),vendor 二进制在
dist/vendor/,但 ripgrep 和 audio-capture 的路径解析未考虑 chunks/ 层级,
导致 ENOENT。改用 import.meta.url 路径中 lastIndexOf('dist') 定位 dist 根,
并同步在 build.ts 和 post-build.ts 中添加 ripgrep vendor 文件复制。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 14:46:02 +08:00
claude-code-best
1c3b280c6a fix: 尝试修复多轮对话缓存失效 skill 提升的问题 2026-04-25 14:31:32 +08:00
claude-code-best
7a3cc24a00 fix: 尝试修复 nodejs windows 环境的问题 2026-04-25 14:07:45 +08:00
claude-code-best
2e7fc428cd feat: 集成豆包 ASR 语音识别后端,支持 /voice doubao 切换 (#357)
* feat: 集成豆包 ASR 语音识别后端,支持 /voice doubao 切换

- 新增 src/services/doubaoSTT.ts 适配模块,将 doubaoime-asr 的
  AsyncGenerator 协议适配为现有 VoiceStreamConnection 接口
- /voice doubao 启用豆包后端,/voice 使用默认 Anthropic 后端
- 后端选择持久化到 settings.json 的 voiceProvider 字段
- 豆包后端跳过 Anthropic OAuth 认证、语言限制和 Focus Mode
- 豆包后端松手即出结果,跳过 processing 状态
- 凭证文件存放在 ~/.claude/tts/doubao/credentials.json
- doubaoime-asr 作为 optionalDependencies 安装
- 移除 /voice 命令的 claude-ai 可用性限制,所有用户可用

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: 更新 Voice Mode 文档,添加豆包 ASR 后端说明和致谢

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 13:57:30 +08:00
claude-code-best
ad09f38fd1 fix: 修复在已有文本前输入斜杠命令无法触发自动补全,以及 Tab 补全覆盖后续文本的问题
当用户在已输入文本前插入 /command 时,光标后的文本包含空格,导致补全逻辑误判命令已有参数而跳过建议。
修复方式:只取光标前的文本(commandInput)进行命令解析和补全生成。

同时修复 Tab 补全斜杠命令时覆盖光标后文本的问题,改为在光标位置拼接补全结果。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 09:27:14 +08:00
claude-code-best
b0a3ef90dc chore: 1.9.5 2026-04-25 08:56:31 +08:00
claude-code-best
c07ad4c738 chore: 清理仓库审计问题——修正 CLAUDE.md、删除冗余 yoga-layout、清除 621 个未使用的类型 stub (#354)
- 修正 CLAUDE.md/AGENTS.md 六处过时陈述:modifiers-napi、url-handler-napi 已非 stub,
  Magic Docs/LSP Server/Plugins/Marketplace 已恢复
- 删除未使用的 src/native-ts/yoga-layout/ 冗余副本(2715 行),权威版本保留在 packages/@ant/ink
- 删除 src/ 下 621 个 Auto-generated type stub 文件(全部 export type X = any,无活跃引用)

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 08:54:18 +08:00
claude-code-best
e38d45460e fix: 修复 Windows Node.js 构建产物因 stdin.ref() 泄漏导致进程挂起 (#353)
startCapturingEarlyInput() 调用 stdin.ref() 后,如果 Ink 未能接管
(如 raw mode 不支持或 setup 阶段异常),unref() 永远不会被调用,
导致 Node.js 事件循环无法退出。修复包括:
- stopCapturingEarlyInput() 中补充 stdin.unref() 调用
- 新增 10s 安全阀定时器自动清理 leaked ref()
- Ink App.componentWillUnmount 兜底 unref() 非 TTY stdin

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 21:16:15 +08:00
claude-code-best
e0c8e9dafc chore: 添加学习文件夹 2026-04-24 20:33:43 +08:00
claude-code-best
047c85fcbf fix: 修复 DeepSeek V4 reasoning_content 回传导致的 400 错误
- 扩大模型名称检测范围,匹配所有 deepseek 模型(V4、R1 等)
- 始终保留 thinking blocks 为 reasoning_content 回传给 API
- 移除有 bug 的 turn boundary 剥离逻辑

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 20:33:43 +08:00
claude-code-best
da6d06365d fix: 修复 anthropic 煞笔的四个 bug (#352)
* fix: 移除文件编辑前必须先读取的限制

移除 FileEditTool 和 FileWriteTool 中的 "read before edit" 校验,
允许直接编辑未读取过的文件。保留文件修改过期检测。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: 更新 teach-me 自动写 note 笔记的功能

* fix: 修复 DeepSeek V4 reasoning_content 回传导致的 400 错误

- 扩大模型名称检测范围,匹配所有 deepseek 模型(V4、R1 等)
- 始终保留 thinking blocks 为 reasoning_content 回传给 API
- 移除有 bug 的 turn boundary 剥离逻辑

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: Opus 4.6/4.7 默认推理 effort 从 medium 改为 high

Pro 和 Max/Team 订阅者的 Opus 默认 effort 之前被降级为 medium,
导致用户感知模型「变笨」。恢复为 high。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: 移除 thinkingClearLatched sticky-on 机制

空闲超过 1 小时后 thinkingClearLatched 会被触发且永不重置,
导致每轮 API 调用都清除 thinking 历史。完整移除该 latch 机制,
clearAllThinking 硬编码为 false。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: 移除 numeric_length_anchors 系统指令

删除「工具调用间文字 ≤25 词、最终回复 ≤100 词」的硬性限制。
ablation 测试显示该约束使整体智能下降 3%。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: 修复测试中 reasoning_content 类型断言

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 20:07:18 +08:00
claude-code-best
8613d558a8 Merge pull request #350 from YuanyuanMa03/fix-bun-install-readme
docs: clarify Bun setup without duplicate steps
2026-04-24 19:47:35 +08:00
YuanyuanMa03
017c251f78 docs: clarify bun setup without duplicate steps 2026-04-24 18:03:21 +08:00
YYMa
d4223abc34 Merge pull request #1 from YuanyuanMa03/fix-bun-install-readme
docs: correct Bun post-install instructions
2026-04-24 17:40:00 +08:00
YYMa
5125a159d2 docs: correct Bun post-install instructions 2026-04-24 17:36:57 +08:00
claude-code-best
d09f363414 Merge pull request #347 from amDosion/feat/ssh-remote-v2
feat: 启用 SKILL_LEARNING 编译开关
2026-04-24 16:07:10 +08:00
unraid
9d35f98ec7 feat: 启用 SKILL_LEARNING 编译开关
将 SKILL_LEARNING 加入 DEFAULT_BUILD_FEATURES,
构建产物中默认启用技能学习系统。
2026-04-24 15:18:26 +08:00
claude-code-best
eb833da33b fix: 创建 agent 后刷新 loadMarkdownFilesForSubdir 缓存
新建 agent 后 clearAgentDefinitionsCache 漏清底层
loadMarkdownFilesForSubdir 的 memoize 缓存,导致新
agent 不会立即出现在列表中,需要重启才能生效。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 15:05:05 +08:00
claude-code-best
eadd32ae47 docs: 同步 AGENTS.md 与 CLAUDE.md 2026-04-24 15:05:05 +08:00
claude-code-best
3c55a8c83f Merge pull request #344 from amDosion/feat/ssh-remote-v2
feat: SSH Remote — 本地 REPL + 远端工具执行
2026-04-24 14:36:11 +08:00
claude-code-best
5582bb47ef docs: 五一 lint 提示 2026-04-24 14:35:39 +08:00
claude-code-best
95bb191977 Merge pull request #341 from YuanyuanMa03/docs/bun-installation-guide
docs: 添加 Bun 安装详细说明
2026-04-24 14:29:39 +08:00
unraid
03811f973b feat: 实现 SSH Remote — 本地 REPL + 远端工具执行
SSH Remote 允许在本地运行交互式 REPL,同时将工具调用(Bash、文件读写等)
通过 SSH 隧道转发到远程主机执行。

核心模块:
- SSHSessionManager: NDJSON 双向通信、权限转发、指数退避重连
- SSHAuthProxy: 本地认证代理 + SSH -R 反向端口转发,nonce 验证
- SSHProbe: 远端主机平台/架构/已有二进制探测
- SSHDeploy: 远端二进制部署(scp)
- createSSHSession: 会话编排(probe → deploy → spawn → attach)

新增选项:
- --remote-bin: 跳过 probe/deploy,使用自定义远端二进制
- ANTHROPIC_AUTH_NONCE: API 请求认证 nonce header

包含 17 个单元测试和完整文档。
2026-04-24 14:25:56 +08:00
YuanyuanMa03
02ab1a0307 docs: 添加 Bun 安装详细说明
- 添加 Linux/macOS/Windows 各平台的安装命令
- 添加安装后的操作步骤(重启终端、验证安装、更新版本)
- 同步更新中英文 README
2026-04-24 12:07:18 +08:00
claude-code-best
2a5b263641 chore: 1.9.4 2026-04-24 10:50:53 +08:00
claude-code-best
f2dd5142b3 refactor: 解耦 BRIDGE_MODE 与 DAEMON,禁用 DAEMON 降低内存占用
- 从 DEFAULT_BUILD_FEATURES 注释掉 DAEMON(内存占用过高)
- remoteControlServer 命令门控从 feature('DAEMON') && feature('BRIDGE_MODE')
  改为仅 feature('BRIDGE_MODE'),bridge 不再依赖 daemon
- --daemon-worker 快速路径改为运行时检测,未启用时输出明确错误提示

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 10:01:05 +08:00
claude-code-best
4dcbaf1e66 fix: 修复 ACP 模式下 messageSelector require 失败导致 submitMessage 崩溃
ACP 模式不加载完整的 React/Ink UI 组件,导致 require('src/components/MessageSelector.js')
返回 undefined。添加 try-catch 和 optional chaining fallback。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 09:59:23 +08:00
claude-code-best
0b304730d8 docs: 为 DEFAULT_BUILD_FEATURES 每个 feature flag 添加功能注释
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 09:26:59 +08:00
claude-code-best
7a0dd3057e chore: 1.9.3 2026-04-23 23:21:43 +08:00
claude-code-best
ca1c87f460 fix: 修复 usePipeIpc 中 require 返回 undefined 导致启动崩溃
将 lazy require() 调用全部替换为静态 import,解决构建产物中
模块加载时序问题导致的 'undefined is not an object' 错误。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 23:21:38 +08:00
claude-code-best
fc7a85f5c7 chore: 1.9.2 2026-04-23 23:04:18 +08:00
claude-code-best
5bc12b00b2 chore: 更新版本流水线 2026-04-23 22:55:27 +08:00
claude-code-best
792777d68c chore: 1.9.1 2026-04-23 22:46:51 +08:00
claude-code-best
047634afe6 ci: 删除冗余 release 工作流 2026-04-23 22:45:53 +08:00
claude-code-best
a92af99448 ci: 添加 GitHub Release 和自动生成 changelog 到发布流程 2026-04-23 22:44:02 +08:00
claude-code-best
cfe1552ec9 ci: 统一 typecheck 命令并添加 npm 发布工作流 2026-04-23 22:42:33 +08:00
claude-code-best
9624f880e0 fix: 修复第三方 Anthropic base URL 应使用 ExaSearchAdapter 而非 BingSearchAdapter
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 21:52:16 +08:00
claude-code-best
85e5a8cffb chore: 贡献者更新工作流改为每周定时触发
移除 push 触发,仅保留每周一 schedule 触发。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 20:17:46 +08:00
claude-code-best
299953b0ee fix: 修复 cliHighlight 类型不兼容问题
loadedGetLanguage 返回类型中 name 字段改为可选,匹配 highlight.js
Language 类型中 name 为 string | undefined 的定义。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 20:12:47 +08:00
claude-code-best
7a3fdf6e67 chore: 1.9.0 2026-04-23 20:10:29 +08:00
claude-code-best
b642977afe Merge pull request #335 from realorange1994/feature/cli-highlight
fix: 将 highlight.js 改为静态导入以兼容 Bun --compile 模式
2026-04-23 20:07:27 +08:00
claude-code-best
781188862e Merge pull request #333 from realorange1994/feature/exa-search
feat: 添加 Exa AI 搜索适配器
2026-04-23 20:06:53 +08:00
claude-code-best
b966eef5a9 Merge branch 'main' into feature/exa-search 2026-04-23 20:04:13 +08:00
claude-code-best
c3d63c8fe2 chore: 添加 release 脚本 2026-04-23 19:58:55 +08:00
Bot
7d4c4278c0 fix: 将 highlight.js 改为静态导入以兼容 Bun --compile 模式
- cliHighlight.ts: 使用静态 import 替换 dynamic import('highlight.js'),
  因为编译模式下模块解析指向内部 bunfs 路径导致无法找到
- color-diff-napi/src/index.ts: 同样改为静态导入,移除 createRequire 延迟加载
2026-04-23 18:47:31 +08:00
Bot
93bfdabff1 feat: 添加 Exa AI 搜索适配器
- 新增 ExaSearchAdapter,基于 MCP 协议调用 Exa 搜索 API
- WebSearchTool 支持 num_results、livecrawl、search_type、context_max_characters 等高级选项
- 非 Anthropic 官方 base URL 时默认使用 Exa 适配器
2026-04-23 18:43:41 +08:00
claude-code-best
1173a62301 refactor: 统一 log.ts/debug.ts 的测试 mock 为共享定义
- 新增 tests/mocks/log.ts 和 tests/mocks/debug.ts,覆盖源文件全部实际导出
- 移除旧 mock 中不存在的导出(logToFile、logEvent、getLogFilePath)
- 13 个测试文件改为使用共享 mock,避免定义分散和不一致

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 11:39:53 +08:00
claude-code-best
7ea69ca279 fix: 修复 build 过程中的问题 2026-04-23 11:39:46 +08:00
claude-code-best
4e82fb5974 Merge pull request #330 from claude-code-best/feature/improve-v2-final
feat: 整合功能恢复与技能学习闭环 v2 (重构版)
2026-04-22 22:55:20 +08:00
claude-code-best
f43350e600 fix: 修复 4 个测试失败(路径规范化、SDK 签名变更、空消息防护)
- projectContext.test.ts: 使用 realpathSync 处理 macOS /var→/private/var 符号链接
- bedrockClient.test.ts: 适配 Bedrock SDK v0.80 Bearer 认证(原 AWS4-HMAC-SHA256)
- bridge.ts: forwardSessionUpdates 添加 null guard 防止空消息导致 TypeError

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 22:52:37 +08:00
unraid
23fcbf9004 feat: 添加 UI 组件增强与测试覆盖
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:10 +08:00
unraid
23bb09d240 feat: 添加 model/provider 层改进
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:10 +08:00
unraid
d208855f07 feat: 添加 builtin-tools 增强与测试覆盖
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:10 +08:00
unraid
7881cc617c feat: 增强 ACP 桥接与权限处理
- 增强 ACP agent 测试覆盖
- 扩展 ACP bridge 测试用例
- 改进 ACP utils 权限管道

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:10 +08:00
unraid
c7e1c50b86 feat: 添加服务层增强与零散改进
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:10 +08:00
unraid
2247026bd5 chore: 添加脚本与构建配置更新
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:10 +08:00
unraid
eec961352b feat: 添加 napi 包测试覆盖与 stub 改进
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:10 +08:00
unraid
fb41513b32 feat: 添加工具类增强与状态管理改进
- 新增 workflowRuns、remoteTriggerAudit、pipeStatus 等工具
- 增强 permissionSetup: auto mode 和 bypass permissions 始终可用
- 新增多组测试覆盖 (modifiers, teamDiscovery, deepLink 等)
- 修复 parseInt 缺少 radix 参数
- 移除多余 biome-ignore 注释

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:10 +08:00
unraid
94c4b37eed feat: 添加 summary 命令 TypeScript 重写与其他命令增强
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:09 +08:00
unraid
6c5df395c3 feat: 添加 compact 缓存与上下文压缩增强
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:09 +08:00
unraid
be97a0b010 feat: 添加 Bedrock API 客户端及 API 层增强
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:09 +08:00
unraid
59f8675fa3 feat: 添加 Windows Terminal swarm 后端及 swarm 增强
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:09 +08:00
unraid
c4775fff58 feat: 添加 autonomy 自主模式命令系统
- 新增 autonomy CLI handler 和交互式面板
- 新增 autonomyCommandSpec 命令规范定义
- 新增 autonomyAuthority 权限控制
- 新增 autonomyStatus 状态管理
- 注册 CLI 子命令 (claude autonomy status/runs/flows/flow)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:09 +08:00
unraid
31b2fdd97a feat: 添加 provider usage 统计与余额查询
- 新增 providerUsage 服务(anthropic/bedrock/openai 适配器)
- 新增余额查询(deepseek/generic poller)
- StatusLine 保留原有 rateLimits 接口不变

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:09 +08:00
unraid
1837df5f88 feat: 添加 skill learning 技能学习闭环系统
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:09 +08:00
unraid
04c7ed4250 chore: 删除废弃文档和残留文件
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 22:38:08 +08:00
claude-code-best
711927f01b chore: 更新 lock 文件 2026-04-21 08:20:40 +00:00
claude-code-best
956e98a445 fix: 修复重复依赖声明 2026-04-21 16:16:38 +08:00
claude-code-best
cee62bc654 fix: 修复 model alias 导致无限递归栈溢出
当用户 settings 中配置 model = "opus[1m]" 等 alias 值时,
getDefaultOpusModel() → parseUserSpecifiedModel() → getDefaultOpusModel()
形成无限递归,导致启动时 RangeError: Maximum call stack size exceeded。

在 getDefaultOpusModel/Sonnet/Haiku 的 fallback 路径中增加
isAliasOrAliasWithSuffix 守卫,跳过 alias 值直接使用硬编码默认值。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 16:10:16 +08:00
claude-code-best
5fc7c8e13d chore: 添加 highlight.js 包 2026-04-21 12:42:10 +08:00
claude-code-best
300faa18d0 Merge branch 'feature/unknown-llm-feature-test' 2026-04-21 12:06:19 +08:00
claude-code-best
96ec96c720 feat: 添加 ccb update 命令,支持 npm/bun 自动更新
从 package.json 读取当前版本,查询 npm registry 最新版本,
自动检测安装方式(bun 或 npm)执行全局更新。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 22:35:57 +08:00
claude-code-best
13a0bfc479 fix: 修复构建产物 import 失效问题 2026-04-20 22:29:44 +08:00
claude-code-best
84f0271813 chore: 1.7.1 2026-04-20 22:13:31 +08:00
claude-code-best
ed4bdb9338 feat: 增强 auto mode 的易用性 (#312)
* feat: poor 模式降级 yolo 审阅模型

* feat: 为多模块添加 Langfuse tracing 支持

在 web search、agent creation、away summary、token estimation、
skill improvement 等模块中集成 Langfuse trace,并透传至
compact/apiQueryHook/execPromptHook 等调用链。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 让 auto mode 记录回主 trace

* fix: reopen auto mode prompt when classifier is unavailable

* fix: 修复 auto mode 情况下, llm 报错导致弹窗也不打开的问题

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 21:13:09 +08:00
claude-code-best
e4ce08fe39 Fixture/langfuse record auto mode data error (#308)
* fix: 修复状态栏 context 计数器在 loading 时闪现为 0 的问题

第三方 API(如智谱)在 message_start 中可能不返回完整 usage 数据,
导致 getCurrentUsage 返回全零 usage 对象,使 ctx 显示为 0%。

双重保护:
- getCurrentUsage: 跳过全零 usage,继续往前找有真实数据的 message
- calculateContextPercentages: totalInputTokens 为 0 时返回 null

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 外部化 ESM 包使用 createRequire 替代裸 require

color-diff-napi、image-processor-napi、audio-capture-napi 声明
"type": "module" 但使用裸 require(),Node.js ESM 中 require
不可用。改用 createRequire(import.meta.url) 或顶层 import。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: getDefaultSonnetModel 优先使用用户配置的模型,修复第三方 provider 模型不存在错误

当用户通过 ANTHROPIC_MODEL 或 settings 配置了自定义 provider 支持的模型时,
getDefaultSonnetModel/Haiku/Opus 现在会优先使用该配置,而非硬编码 Anthropic 官方模型 ID。
同时改进 Langfuse 可观测性:sideQuery 失败时记录错误信息到 span,
optional 模式下标记 WARNING 而非 ERROR。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 将 auto_mode classifier 的 side-query span 绑定到父 trace

classifyYoloAction 及 classifyYoloActionXml 接收 parentSpan 参数,
透传给 sideQuery 调用,使 auto_mode 的 side-query span 嵌套在主 agent trace 下。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 穷鬼模式下跳过 memdir_relevance side-query

Poor mode 启用时不执行 findRelevantMemories 的预取调用,
避免额外的 API token 消耗。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: 添加 test:all 脚本用于完成任务后的全量检查

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Vite 构建补齐缺失的 feature flags,修复 auto mode 不可见

Vite 构建插件的 DEFAULT_BUILD_FEATURES 缺少 BUDDY、TRANSCRIPT_CLASSIFIER、
BRIDGE_MODE、ACP、BG_SESSIONS、TEMPLATES,导致 feature('TRANSCRIPT_CLASSIFIER')
被替换为 false,auto mode 从 Shift+Tab 循环中消失。与 build.ts 对齐。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 统一 feature flags 到 defines.ts,修复 Vite 构建缺失 auto mode

将 DEFAULT_BUILD_FEATURES 列表从 build.ts、dev.ts、vite-plugin-feature-flags.ts
三处内联定义统一到 scripts/defines.ts 单一导出。之前的 Vite 插件缺少
TRANSCRIPT_CLASSIFIER 等 feature flag,导致 auto mode 在 Vite 构建中不可见。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 13:30:05 +08:00
claude-code-best
92f8a92fbb feat: 正式启用 auto mode (#307)
* fix: 修复settings.json内存状态溢出的问题

* fix: 修复auto mode gate check未处理的promise rejection

在 bypassPermissionsKillswitch.ts 的 useKickOffCheckAndDisableAutoModeIfNeeded
中,void fire-and-forget 调用缺少 .catch() 处理,导致 verifyAutoModeGateAccess
失败时产生 unhandled promise rejection。同时移除 permissionSetup.ts 中冗余的
null check。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: 开放 auto mode 和 bypass mode 给所有用户

通过 Shift+Tab 统一循环:default → acceptEdits → plan → auto → bypassPermissions → default

- 移除 USER_TYPE 分支判断,所有用户使用同一循环路径
- isBypassPermissionsModeAvailable 始终为 true
- isAutoModeAvailable 初始化直接为 true
- 移除 AutoModeOptInDialog 确认流程
- 简化 isAutoModeGateEnabled 仅保留快模式熔断器
- 简化 verifyAutoModeGateAccess 仅检查快模式
- 移除 GrowthBook/Statsig 远程门控
- bypass permissions killswitch 改为 no-op
- 新增 24 个测试覆盖循环逻辑和门控不变量

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: 为sideQuery添加Langfuse追踪

sideQuery 绕过了 claude.ts 的主 API 路径,导致所有走 sideQuery 的调用
(auto mode classifier、permission explainer、session search 等)都没有
Langfuse 记录。现在为每次 sideQuery 调用创建独立 trace 并记录 LLM observation,
未配置 Langfuse 时全部 no-op。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: ACP availableModes 补齐 bypassPermissions 并修正测试 import 路径

- ACP agent availableModes 按条件包含 bypassPermissions(非 root/sandbox)
- 顺序对齐 REPL 循环:default → acceptEdits → plan → auto → bypassPermissions
- 新增 2 个测试验证 availableModes 包含 bypassPermissions 及模式切换
- 修正 getNextPermissionMode.test.ts 和 permissionSetup.test.ts 的 import 路径

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 10:20:27 +08:00
claude-code-best
a67e2d0e97 docs: 更新 npm 安装 2026-04-19 22:00:48 +08:00
claude-code-best
8c629858ab chore: 1.6.0 2026-04-19 21:37:35 +08:00
claude-code-best
494eab7204 feat: 接入内建 weixin channel(同 #301 重构版本) (#303)
* feat: 接入 weixin 服务层与命令入口

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* feat: 注册内建 weixin channel 插件

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: 修正 channel permission relay 路由与能力判定

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: 修复 builtin channel 的 ChannelsNotice 误报

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* docs: 补充内建 weixin channel 使用说明

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* docs: 更新微信 channel 接入计划状态

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: 延迟加载 weixin 登录二维码依赖

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: 改用 qrcode 生成 weixin 登录二维码

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: 修正 vite 构建的 Windows 路径解析

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* chore: 删除临时规划文档 wx_channel.md 并还原 package.json 排序

wx_channel.md 内容已整合到 docs/features/channels.md,不再需要。
package.json 中 @ant/model-provider 位置从原始位置被无意移动,还原。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 将 weixin 模块从 src/ 迁移至 packages/weixin 工作区包

将 src/services/weixin/ 中的纯业务逻辑迁入 @claude-code-best/weixin
workspace 包,降低 src/ 耦合度。仅保留 server.ts 作为薄适配层。

- 迁移 7 个无修改的纯模块 (types/api/accounts/login/pairing/media/send)
- monitor.ts 内联 PERMISSION_REPLY_RE 正则,解除对 src/ 的依赖
- permissions.ts 本地定义 ChannelPermissionRequestParams 接口
- cli.ts 拆分:serve 子命令通过回调注入,login/access 保留在包内
- server.ts 重写为从 @claude-code-best/weixin 导入
- 新增 cli-serve.ts 作为 serve 入口薄壳

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 修正 weixin barrel export 中 interface 的导出方式

ChannelPermissionRequestParams 是纯类型,必须用 export type 导出,
否则 Bun 运行时会报 "export not found" 错误。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 将 server.ts 迁入 packages/weixin,彻底移除 src/services/weixin/

通过依赖注入(WeixinServerDeps)解耦 src/ 依赖(analytics、config、
MCP channel schema),server.ts 完全移入包内。cli.tsx 入口处一次性
注入所有依赖。

src/services/weixin/ 目录已完全删除。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 修复 markdownToPlainText 中代码块正则的 ReDoS 风险

用非正则的线性扫描替代 \`\`\`[\s\S]*?\n([\s\S]*?)\`\`\` 匹配,
避免在含有大量重复 \`\`\` 序列的输入上触发多项式回溯。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: 1111 <11111@asd.c>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 21:33:27 +08:00
claude-code-best
b83c3008d0 docs: 更新 discord 地址 2026-04-19 21:21:04 +08:00
claude-code-best
66d2671c98 feat: acp manager (#304)
* feat: acp 控制器第一版

* feat: acp-link 命令二合一
2026-04-19 21:18:18 +08:00
claude-code-best
c7bc8c8636 feat: remote control 支持 auto bind 功能 (#300)
* feat: acp-link 支持 --group 参数指定 channel group

- 添加 --group CLI flag,校验格式 [a-zA-Z0-9_-]+
- 支持 ACP_RCS_GROUP 环境变量 fallback
- 传递 channelGroupId 到 RcsUpstreamClient
- 更新 README 文档说明 --group 和相关环境变量

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: RCS 后端 session 复用与 group 绑定

- storeFindEnvironmentByMachineName 匹配 offline 状态,防止重连创建重复 session
- registerEnvironment 复用已有 session 而非每次新建
- EnvironmentResponse 返回 channel_group_id 字段
- 注册时将 session 绑定到 group ID,支持 web UI 按 group 查询
- apiKeyAuth 不再设置 uuid,由 uuidAuth 统一处理

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: Web UI Token Manager — 多 token 切换与 session 隔离

- 新增 useTokens hook 管理 localStorage token CRUD
- 新增 TokenManagerDialog 弹窗组件(添加/编辑/删除/切换 token)
- api client 支持Bearer token 认证,UUID 跟随 token 变化
- Navbar 添加 token 切换按钮
- 切换 token 时自动 reload,实现 session 数据隔离

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 修复 useTokens useState 初始化函数签名错误

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 13:04:09 +08:00
claude-code-best
673ccd1800 chore: 1.5.0 2026-04-19 12:34:51 +08:00
claude-code-best
d1ab38c089 chore: 移除 pre-commit git hook
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 12:31:31 +08:00
claude-code-best
f9d011164a fix: 替换 web 端 crypto.randomUUID 为 uuid 库以支持 HTTP 环境
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 10:33:15 +08:00
claude-code-best
481e2a58a9 feat: 恢复 --channels 能力 (#297)
* feat: 恢复  --channels 能力

* docs: 添加 channels 注释
2026-04-19 10:24:34 +08:00
claude-code-best
c5edee431f docs: 文档检查/check 20260419 (#296)
* docs: 修复文档巡检发现的 4 处错误

- daemon.md: 反映实际实现状态(supervisor/worker 已实现而非 stub)
- bridge-mode.md: API 操作数量从 7 修正为 9
- web-search-tool.md: 文件路径从 src/tools/ 修正为 packages/builtin-tools/src/tools/
- remote-control-self-hosting.md: 补充缺失的 RCS_WS_IDLE_TIMEOUT 和 RCS_WS_KEEPALIVE_INTERVAL 配置项

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 Safety 和 Context 文档中的代码引用和类型错误

- permission-model: 修正规则来源从"五层"到八层,优先级顺序对齐代码
- permission-model: PermissionUpdate 类型改为实际的 addRules/replaceRules 等
- permission-model: 补充 acceptEdits 和 dontAsk 两种权限模式
- permission-model: DENIAL_LIMITS 字段名对齐实际代码
- plan-mode: 工具路径从 src/tools/ 改为 packages/builtin-tools/src/tools/
- compaction: 修正 COMPACTABLE_TOOLS 和 POST_COMPACT_* 的行号
- project-memory: 修正 ENTRYPOINT_NAME 常量的行号
- system-prompt: 修正 SystemPrompt 类型定义文件路径和多个行号引用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修复 introduction 文档中的错误路径和行号引用

- why-this-whitepaper.mdx: BashTool 路径从 src/tools/ 修正为 packages/builtin-tools/src/tools/
- what-is-claude-code.mdx: 移除不存在的 Azure provider,改为实际的 7 种 provider
- architecture-overview.mdx: State 类型行号从 204 修正为 207

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修复 conversation/features 文档中的错误

- streaming.mdx: queryStreamRaw → queryModelWithStreaming 函数名修正
- streaming.mdx: Azure 提供商不存在,替换为实际 7 个提供商
- debug-mode.mdx: --inspect-wait 描述错误,实际使用 BUN_INSPECT 环境变量
- buddy.mdx: 补充缺失的 companionReact.ts、CompanionCard.tsx、index.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修复文档巡检中的源码引用错误

- feature-flags.mdx: 修正 feature() 兜底描述,实际从 bun:bundle 导入而非 cli.tsx:3 内联
- feature-flags.mdx: 修正工具 require 路径为 @claude-code-best/builtin-tools 包路径
- ant-only-world.mdx: 修正 tools.ts 中 require 路径为包路径
- ant-only-world.mdx: 修正 INTERNAL_ONLY_COMMANDS 行号 (267-295) 和数量 (24+)
- skills.mdx: 修正 COMMANDS memoize 行号 258 → 299
- mcp-protocol.mdx: 修正 fetchToolsForClient LRU 缓存上限 20 → 100
- streaming.mdx: 修正流式事件引用
- file-operations.mdx: 修正工具路径引用
- search-and-navigation.mdx: 修正搜索工具引用
- shell-execution.mdx: 修正 shell 工具引用
- buddy.mdx: 补充缺失的 frontmatter 字段
- debug-mode.mdx: 修正调试模式描述

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 tools/agent 文档中的文件路径和行号引用

- 修正 TodoWriteTool、AgentTool、ToolSearchTool 等工具路径
  src/tools/ → packages/builtin-tools/src/tools/
- 更新 Tool.ts、tools.ts、BashTool.tsx 中过时的行号引用
- 修正 WebSearchTool/WebFetchTool/EnterWorktreeTool/ExitWorktreeTool 路径
- 修正 AgentTool.tsx 中多行行号引用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 feature 文档中的文件路径和行号引用

- ultraplan.md: 更新文件行数(525/349/127)
- fork-subagent.md: 路径迁移 src/tools/ → packages/builtin-tools/
- mcp-skills.md: 修正 getMcpSkillCommands 行号 547→604,client.ts 行号 117→129
- kairos.md: 修正 getBriefSection/getProactiveSection 行号
- proactive.md: 修正 getProactiveSection 行号 860→864

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正顶层文档中的路径迁移和行号引用

- auto-updater.md: config.ts 行号 1735→1737,标注未接入启动流程的函数
- external-dependencies.md: WebSearchTool/WebFetchTool 路径迁移到 builtin-tools 包,Vertex 行号修正
- lsp-integration.md: LSPTool 路径从 src/tools/ 迁移到 packages/builtin-tools/
- stub-recovery-design-1-4.md: 修正 Windows 绝对路径链接为标准代码引用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 task 文档中的文件扩展名和路径引用

- task-004: AssistantSessionChooser.ts → .tsx, assistant.ts → .tsx
- task-003: cli.tsx 行号 249→272, markdownConfigLoader.ts 行号 29→35
- lan-pipes: SendMessageTool 路径迁移到 packages/builtin-tools/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 补充 computer-use-tools-reference 缺失的 Windows 工具

添加遗漏的 open_terminal 和 activate_window 两个 Windows 专属工具,
修正工具总数 37→39,Windows 工具数 10→12。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 audit/bash-classifier/token-budget/tree-sitter 文档

- feature-flags-audit: ScheduleCronTool 路径迁移、DAEMON 状态更新为 COMPLETE、assistant 文件标记已补全、UDS 标记已实现
- bash-classifier: BashPermissionRequest 文件路径修正、withRetry 行号移除
- token-budget: attachments.ts 行号范围修正
- tree-sitter-bash: bashPermissions.ts 路径迁移到 packages/builtin-tools

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 langfuse-monitoring AgentTool 路径迁移

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 bridgeApi 行号和 Tool.ts 行号引用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 Safety/Extensibility 文档中的工具路径迁移和行号引用

- sandbox.mdx: shouldUseSandbox.ts 和 bashPermissions.ts 路径迁移至 packages/builtin-tools
- why-safety-matters.mdx: bashPermissions.ts 路径迁移(3 处)
- plan-mode.mdx: EnterPlanModeTool/prompt.ts 路径迁移
- auto-mode.mdx: Auto mode 指令行号 3464→3481
- hooks.mdx: AgentTool/runAgent.ts 路径迁移
- skills.mdx: SkillTool.ts 路径迁移
- custom-agents.mdx: Agent built-in 目录和 exploreAgent.ts 路径迁移

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 internals 文档引用计数和路径

- ant-only-world: USER_TYPE 引用计数 465→410+,工具路径迁移到 builtin-tools
- growthbook-ab-testing: growthbook.ts 行数 1156→1258
- hidden-features: 语音模式状态更新(audio-napi 已恢复)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正工具文档中的行号引用

- sub-agents: AgentTool.call 入口行号 340→387
- shell-execution: ShellCommand onTimeout 行号 129→144

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 feature 文档中的状态、路径和计数

- all-features-guide: 修正 feature flag 启用范围(dev only vs dev+build)
- tier3-stubs: 大量状态修正(stub→已实现),缩减过时条目
- workflow-scripts: 路径迁移到 builtin-tools,状态更新
- web-browser-tool: 工具状态缺失→已实现,路径迁移
- context-collapse: CtxInspectTool 状态缺失→已实现
- computer-use: 行号引用更新,平台分发描述修正
- computer-use-tools-reference: 工具数 39→38
- voice-mode: voiceModeEnabled 行数 55→54

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 更新 the-loop 查询循环行号引用

query.ts 代码变更后终止原因行号整体偏移约 40 行

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 补充 feature-flags-audit 完整 build 默认 feature 列表

添加 ULTRATHINK/LODESTONE/ACP/DAEMON 等 19 个缺失的 build 默认 feature,
修正 dev-only 特征标注(UDS_INBOX/LAN_PIPES/BG_SESSIONS/TEMPLATES)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 feature-flags-audit ConfigTool 路径迁移

ConfigTool 路径从 src/tools/ 迁移到 packages/builtin-tools/src/tools/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 feature-flags-audit BashTool 路径迁移

BashTool 路径从 src/tools/ 迁移到 packages/builtin-tools/src/tools/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 修正 feature-flags-audit SkillTool 路径迁移

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 更新 feature-flags-audit WorkflowTool 状态为已实现

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 09:30:00 +08:00
claude-code-best
a57ca08566 fix: 修复 node 的 es 版本太高不兼容的构建问题 2026-04-19 09:28:57 +08:00
claude-code-best
6536757428 feat: 对其他 provider 提供 langfuse 监控 2026-04-19 09:09:27 +08:00
claude-code-best
a0dc4540ca fix: 修复服务器两个 / 的问题 2026-04-19 08:55:55 +08:00
claude-code-best
7e4df5c3e9 build: 更改构建逻辑 2026-04-19 08:45:06 +08:00
claude-code-best
4d939e5722 chore: 更新构建 feature 的问题 2026-04-19 08:27:25 +08:00
claude-code-best
2e9aaf4993 feat: ACP 协议版本 remote control (#293)
* fix: 添加 usage 字段缺失时的防御性防护

第三方 API(如智谱 GLM)在某些流式响应中不返回 usage 字段,
导致 usage.input_tokens 访问 undefined 崩溃并连锁影响后续所有请求。

- claude.ts: content_block_stop 创建消息时 fallback 到 EMPTY_USAGE
- LocalAgentTask.tsx: usage 为 undefined 时提前返回
- tokens.ts: getTokenCountFromUsage 加 null guard 和 ?? 0
- cost-tracker.ts: input_tokens/output_tokens 加 ?? 0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: ACP Plan 展示 — 支持 session/update plan 类型的可视化

补全 PlanUpdate 类型定义(PlanEntry/Priority/Status),新建 PlanView 组件
渲染进度条、状态图标和优先级标签,在 ChatInterface 中处理 plan 更新逻辑。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: 穷鬼模式下跳过 verification agent 以节省 token

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: 补充 RCS 后端 + 前端测试覆盖 (+116 tests)

后端新增 3 个测试文件 (70 tests):
- automationState: normalize/snapshot/equals 纯函数
- client-payload: toClientPayload 协议转换
- transport-normalize: normalizePayload + extractContent

前端新增 2 个测试文件 (46 tests):
- utils: formatTime/statusClass/truncate/extractEventText 等
- api-client: getUuid/setUuid/api GET/POST 错误处理

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: RCS ACP 页面添加权限模式选择器 + 权限响应修复

- 新增权限模式选择器 UI(6种模式:默认/自动接受编辑/跳过权限/规划/不询问/自动判断)
- 权限模式通过 ACP _meta 从 web → acp-link → agent 全链路传递
- 修复 PermissionPanel 点击"允许"发送 cancelled 而非 selected 的 bug
- 权限模式和模型选择持久化到 localStorage
- acp-link 直接连接路径同步支持 permissionMode 透传

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: RCS Web UI 重构 + QR 修复 + ACP 扫描自动跳转

- RCS Web UI 组件全面重构: Dialog 迁移 Radix UI, lazy loading,
  主题系统改进, 组件样式优化
- IdentityPanel QR 码显示修复: requestAnimationFrame 延迟绘制
  解决 Radix Dialog Portal 挂载时序问题
- ACP QR 扫描自动跳转: IdentityPanel 扫描 ACP 格式 { url, token }
  后存储 sessionStorage 并跳转 /code/?acp=1
- 新增 ACPDirectView 组件: ACP 直连视图, 用 ACPClient 连接并
  渲染 ACPMain 聊天界面

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: ACP 权限管道改进 — 模式同步 + bypass 检测 + 统一权限流水线

- agent.ts: applySessionMode 同步 appState.toolPermissionContext.mode
- agent.ts: bypassPermissions 可用性检测 (非 root 或 sandbox 环境)
- permissions.ts: createAcpCanUseTool 接入 hasPermissionsToUseTool
  统一权限流水线, 替代原来分散的处理逻辑
- permissions.ts: 支持 onModeChange 回调, 模式变更时实时同步

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: acp-link 支持 permissionMode 默认值传递给 agent

客户端 (Zed/VS Code 等) 的 new_session 不一定携带 permissionMode,
导致 agent 收到 _meta: undefined, permission 回退到 default。

修复: handleNewSession 使用 fallback 链:
  客户端传值 > config.permissionMode > ACP_PERMISSION_MODE 环境变量

使用: ACP_PERMISSION_MODE=auto acp-link claude

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 更新文档及说明

* fix: 修复类型错误

* chore: 提交脚本

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-18 21:54:22 +08:00
claude-code-best
34154ee3f5 feat: 支持 acp-link 包进行 acp 通用的 remote-control (#292)
* fix: 修复超时问题

* feat: 添加 acp-link 代码

* refactor: 样式重构完成

* feat: RCS 添加 ACP 后端支持

- 新增 ACP WebSocket handler (agent 注册、EventBus 订阅)
- 新增 relay handler (前端 WS → acp-link 透传 + EventBus inbound 转发)
- 新增 SSE event stream 供外部消费者订阅 channel group 事件
- ACP REST 接口无鉴权 (agents、channel-groups)
- WebSocket 端点保留 token 鉴权
- SPA 路由 /acp/ 指向 acp.html

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: 添加 ACP 专属前端界面

- 新增 /acp/ SPA 页面 (agent 列表 + 实时交互)
- Agent 列表按 channel group 分组,显示在线状态
- 通过 RCS WebSocket relay 与 agent 通信
- Vite multi-page 构建 (index.html + acp.html)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: acp-link 支持 RCS relay 双向通信

- rcs-upstream 新增 messageHandler 转发非控制消息
- server.ts 新增虚拟 WS + relay client state 处理 relay ACP 消息
- newSession/loadSession 补充 mcpServers 参数
- 连接成功后显示 ACP Dashboard URL

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 移除 FileExplorer 及文件操作相关代码

- 删除 FileExplorer 组件
- ACPMain 移除 Files tab,仅保留 Chat 和 History
- client.ts 移除 listDir/readFile/onFileChanges 等方法
- types.ts 移除 FileItem/FileContent/FileChange 等类型

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 修复类型问题

* feat: RCS 后端统一 ACP/Bridge 注册逻辑

- store: EnvironmentRecord 增加 capabilities 字段、storeFindEnvironmentByMachineName 复用逻辑
- store: 新增 storeGetSessionOwners,支持未绑定 session 自动 claim
- environment: registerEnvironment 支持 ACP 复用已有记录,返回 session_id
- session: resolveOwnedWebSessionId 支持无 owner session 自动绑定
- acp-ws-handler: 新增 handleIdentify 支持 REST+WS 两步注册
- acp routes: /acp/relay 和 /acp/agents 支持 UUID 认证
- event-bus: 增加 error 类型 payload 日志

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: acp-link 改 REST 注册 + WS identify 两步流程

- rcs-upstream: 新增 registerViaRest() 通过 POST /v1/environments/bridge 注册
- rcs-upstream: WS 连接后发送 identify 替代 register,携带 agentId
- rcs-upstream: 入口链接改为 /code/?sid=${sessionId} 实现用户绑定
- server: 修复心跳跳过 relay 虚拟连接的 bug
- server: maxSessions 配置传入 RCS upstream

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: 前端统一 Chat 组件 + ACP 聊天界面重构

- 新增 chat/ 组件: ChatView, ChatInput, MessageBubble, ToolCallGroup, PermissionPanel, SessionSidebar, CommandMenu
- ACPMain: 重构支持完整 ACP 协议交互(session/prompt/permission)
- rcs-chat-adapter: 统一 bridge session SSE 适配器
- ACPClient: 增强 session 管理、permission 流程、streaming 支持
- index.css: 新增 chat 相关样式、动画、布局
- useCommands: 新增快捷命令 hook

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 删除 /acp/ 独立页面,ACP 聊天统一到 /code/:sessionId

- 删除 acp.html、acp-main.tsx 入口文件和 pages/acp/ 目录
- SessionDetail: ACP session 在同一页面渲染 ACPSessionDetail 组件
- App.tsx: ?sid= 参数自动调用 apiBind 绑定用户 UUID
- Dashboard: 统一 session 列表导航,ACP 显示紫色标签
- relay-client: 改用 UUID 认证替代 API token
- EnvironmentList: 显示 workerType 标签(ACP Agent / Claude Code)
- index.ts: 移除 /acp/ SPA 路由,vite.config 移除 acp 入口

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* build: 更新构建及测试修复

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-18 17:59:29 +08:00
claude-code-best
29cc74a170 docs: 更新 CLAUDE.md 2026-04-17 21:37:43 +08:00
claude-code-best
d2b66d9d2c docs: update contributors 2026-04-17 12:45:56 +00:00
claude-code-best
d70e7f7f05 feat: 支持 langfuse 工具调用映射 2026-04-17 20:45:14 +08:00
Cheng Zi Feng
72a2093cd6 feat(remote-control): 优化 Web 展示、状态同步与桥接控制流程 (#288)
Co-authored-by: chengzifeng <chengzifeng@meituan.com>
2026-04-17 16:21:27 +08:00
claude-code-best
b5c299f5d2 build: CI 添加通过过滤 2026-04-17 11:33:57 +08:00
claude-code-best
ac42ce2d67 fix: 解决 node 下 loading 按钮计算错误问题 2026-04-17 10:42:40 +08:00
claude-code-best
c659912517 docs: 更新说明 2026-04-17 10:22:56 +08:00
claude-code-best
a14b7f352b test: 修正 mock 的滥用情况 2026-04-17 10:13:09 +08:00
claude-code-best
c5ab83a3fc fix: 修复 linux 端的安装问题 2026-04-17 09:51:59 +08:00
claude-code-best
03b7f9b453 chore: 1.4.1 2026-04-17 09:45:36 +08:00
claude-code-best
bddd146f25 feat: 重构供应商层次 (#286)
* refactor: 创建 @anthropic-ai/model-provider 包骨架与类型定义

- 新建 workspace 包 packages/@anthropic-ai/model-provider
- 定义 ModelProviderHooks 接口(依赖注入:分析、成本、日志等)
- 定义 ClientFactories 接口(Anthropic/OpenAI/Gemini/Grok 客户端工厂)
- 搬入核心类型:Message 体系、NonNullableUsage、EMPTY_USAGE、SystemPrompt、错误常量
- 主项目 src/types/message.ts 等改为 re-export,保持向后兼容

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 提升 OpenAI 转换器和模型映射到 model-provider 包

- 搬入 OpenAI 消息转换(convertMessages)、工具转换(convertTools)、流适配(streamAdapter)
- 搬入 OpenAI 和 Grok 模型映射(resolveOpenAIModel、resolveGrokModel)
- 主项目文件改为 thin re-export proxy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 搬入 Gemini 兼容层到 model-provider 包

- 搬入 Gemini 类型定义、消息转换、工具转换、流适配、模型映射
- 主项目 gemini/ 目录下文件改为 thin re-export proxy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 搬入 errorUtils 并迁移消费者导入到 model-provider

- 搬入 formatAPIError、extractConnectionErrorDetails 等 errorUtils
- 迁移 10 个消费者文件直接从 @anthropic-ai/model-provider 导入
- 更新 emptyUsage、sdkUtilityTypes、systemPromptType 为 re-export proxy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: compact 模型降级为 -1 模式(Opus→Sonnet, Sonnet→Haiku)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 添加 agent-loop 绘图

* Revert "feat: compact 模型降级为 -1 模式(Opus→Sonnet, Sonnet→Haiku)"

This reverts commit e458d6391d.

* docs: 添加简化版 agent loop

* fix: 修复 n 快捷键导致关闭的问题

* fix: 修复 node 下 ws 没打包问题

* docs: 修复链接

* test: 添加测试支持

* fix: 修复类型问题(#267) (#271)

* fix: 修复 Bun 的 polyfill 问题

* fix: 类型修复完成

* feat: 统一所有包的类型文件

* fix: 修复构建问题

* test: 修复类型校验 (#279)

* fix: 修复 Bun 的 polyfill 问题

* fix: 类型修复完成

* feat: 统一所有包的类型文件

* fix: 修复构建问题

* fix(remote-control): harden self-hosted session flows (#278)

Co-authored-by: chengzifeng <chengzifeng@meituan.com>

* docs: update contributors

* build: 新增 vite 构建流程

* feat: 添加环境变量支持以覆盖 max_tokens 设置

* feat(langfuse): LLM generation 记录工具定义

将 Anthropic 格式的工具定义转换为 Langfuse 兼容的 OpenAI 格式,
并在 generation 的 input 中以 { messages, tools } 结构传入,
以便在 Langfuse UI 中查看完整的工具定义信息。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: 添加对 ACP 协议的支持 (#284)

* feat: 适配 zed acp 协议

* docs: 完善 acp 文档

* chore: 1.4.0

* conflict: 解决冲突

* feat: 添加测试覆盖率上报

* style: 改名加移动文件夹位置

* refactor: 移动测试用例及实现

* test: 修复测试用例完成

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Cheng Zi Feng <1154238323@qq.com>
Co-authored-by: chengzifeng <chengzifeng@meituan.com>
Co-authored-by: claude-code-best <272536312+claude-code-best@users.noreply.github.com>
2026-04-17 09:33:14 +08:00
claude-code-best
c8d08d235b Feat/integrate lint preview (#285)
* feat: 适配 zed acp 协议

* docs: 完善 acp 文档

* feat: integrate feature branches + daemon/job 命令层级化 + 跨平台后台引擎

Cherry-picked from origin/lint/preview (637c908), excluding lint-only changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: correct detectMimeFromBase64 to decode raw bytes from base64

Cherry-picked from origin/lint/preview (ee36954).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: daemon 子进程 spawn 跨平台修复 + CliLaunchSpec 集中化重构

Cherry-picked from origin/lint/preview (c5f52cd), excluding lint-only formatting changes.

- 新建 src/utils/cliLaunch.ts: 集中化 CLI 子进程启动层
- 修复 --daemon-worker=kind 等号格式解析
- 修复 daemon/bg fast path 缺少 setShellIfWindows()
- 修复 checkPathExists 用 existsSync 替代 execSync('dir')
- 7 个 spawn 站点迁移到 CliLaunchSpec

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: merge tsconfig.base.json into tsconfig.json with full compiler options

The cherry-pick from 637c908 dropped jsx/strict/etc settings when removing
tsconfig.base.json. This commit restores them in a single tsconfig.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: merge tsconfig.base.json into tsconfig.json with full compiler options

The cherry-pick from 637c908 dropped jsx/strict/etc settings when removing
tsconfig.base.json. This commit restores them in a single tsconfig.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 20:59:29 +08:00
claude-code-best
a02dc0bded chore: 1.4.0 2026-04-16 20:48:09 +08:00
claude-code-best
3cb1e50b25 feat: 添加对 ACP 协议的支持 (#284)
* feat: 适配 zed acp 协议

* docs: 完善 acp 文档
2026-04-16 20:31:50 +08:00
claude-code-best
cfab161e28 feat(langfuse): LLM generation 记录工具定义
将 Anthropic 格式的工具定义转换为 Langfuse 兼容的 OpenAI 格式,
并在 generation 的 input 中以 { messages, tools } 结构传入,
以便在 Langfuse UI 中查看完整的工具定义信息。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 15:31:18 +08:00
claude-code-best
90027279e6 feat: 添加环境变量支持以覆盖 max_tokens 设置 2026-04-16 13:01:07 +08:00
claude-code-best
3470783ced build: 新增 vite 构建流程 2026-04-16 12:39:19 +08:00
claude-code-best
8169b96250 docs: update contributors 2026-04-16 02:46:47 +00:00
Cheng Zi Feng
fe08cacf8d fix(remote-control): harden self-hosted session flows (#278)
Co-authored-by: chengzifeng <chengzifeng@meituan.com>
2026-04-16 10:46:31 +08:00
claude-code-best
5a4c820e1d test: 修复类型校验 (#279)
* fix: 修复 Bun 的 polyfill 问题

* fix: 类型修复完成

* feat: 统一所有包的类型文件

* fix: 修复构建问题
2026-04-16 10:28:47 +08:00
claude-code-best
1a4e9702c2 fix: 修复类型问题(#267) (#271)
* fix: 修复 Bun 的 polyfill 问题

* fix: 类型修复完成

* feat: 统一所有包的类型文件

* fix: 修复构建问题
2026-04-15 10:54:00 +08:00
claude-code-best
2273a0bcfe docs: 修复链接 2026-04-14 21:19:36 +08:00
claude-code-best
b80483c23e fix: 修复 node 下 ws 没打包问题 2026-04-14 21:19:25 +08:00
claude-code-best
8442aaadd2 fix: 修复 n 快捷键导致关闭的问题 2026-04-14 21:18:36 +08:00
claude-code-best
dad3ad2b8d docs: 添加浏览器说明支持 2026-04-13 21:22:41 +08:00
claude-code-best
b5b81dfe49 chore: 更改 chrome 的依赖 2026-04-13 20:55:04 +08:00
claude-code-best
ecbd5a93e4 fix: 修复 Bun.hash 不存在的问题 2026-04-13 20:21:14 +08:00
claude-code-best
be80da4ce0 fix: 修复缓存 2026-04-13 20:09:23 +08:00
claude-code-best
fce40fed1f feat: 加上 userId 的传递 2026-04-13 19:04:51 +08:00
claude-code-best
a7e03a5b30 fix: 修复 interrupt 日志不上传 2026-04-13 18:12:23 +08:00
claude-code-best
05cabbbd73 feat: langfuse 工具调用显示为嵌套结构 2026-04-13 18:09:12 +08:00
claude-code-best
d4b30d32c3 fix: 修复 chrome 链接版本 2026-04-13 17:30:47 +08:00
claude-code-best
e0484e2817 fix: 使用简化版本的 chrome 桥接器 2026-04-13 16:03:47 +08:00
claude-code-best
2fb1c9dcd8 feat: 工具层及 mcp 大重构 (#252)
* feat: 第一版大重构

* fix: 修复类型问题

* chore: 更新版本到 1.3.2

* Add brave as alternative WebSearchTool

* fix: 修正顺序

* fix: 修复对穷鬼模式的 auto dream 和 session memory 越过

* feat: 穷鬼模式去除 session-summary

* feat: 创建 builtin-tools 包,搬运所有工具实现

将 src/tools/ 下的全部 60 个工具目录迁移至 packages/builtin-tools/src/tools/,
内部导入路径已更新为 src/ alias 模式。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 更新 src/ 中所有工具引用至 builtin-tools 包,删除 src/tools/

- src/tools.ts 及 178 个 src/ 文件的 import 路径从 ./tools/ 改为 builtin-tools/tools/
- 删除 src/tools/ 整个目录(已迁移至 packages/builtin-tools/)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: 添加 builtin-tools 路径别名至 tsconfig,更新 bun.lock

- tsconfig.json 新增 builtin-tools/* 和 builtin-tools 路径映射
- 新增 packages/builtin-tools/src 至 include

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 为 builtin-tools、mcp-client、agent-tools 添加 @claude-code-best 作用域前缀

所有包名及 import 路径统一添加 @claude-code-best/ 前缀:
- builtin-tools → @claude-code-best/builtin-tools
- mcp-client → @claude-code-best/mcp-client
- agent-tools → @claude-code-best/agent-tools

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 修复 node 环境没有 bun 的问题

---------

Co-authored-by: Eric-Guo <eric.guocz@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 09:52:05 +08:00
claude-code-best
bbb8b613a9 docs: update contributors 2026-04-13 01:51:00 +00:00
claude-code-best
c63b875ae3 chore: 1.3.3 版本 2026-04-13 09:50:38 +08:00
claude-code-best
9b8503d13d fix: 修复 node 环境没有 bun 的问题 2026-04-13 09:47:33 +08:00
claude-code-best
3cf94fbda0 fix: 修复对穷鬼模式的 auto dream 和 session memory 越过 2026-04-12 23:24:12 +08:00
claude-code-best
9a3081dff6 Merge branch 'pr/Eric-Guo/245' 2026-04-12 23:12:23 +08:00
claude-code-best
bd6448ecda fix: 修正顺序 2026-04-12 23:12:09 +08:00
claude-code-best
1071270ce3 chore: 更新版本到 1.3.2 2026-04-12 22:47:03 +08:00
Eric-Guo
711440474c Add brave as alternative WebSearchTool 2026-04-12 22:23:11 +08:00
claude-code-best
8399d9ed20 fix: 修复类型问题 2026-04-12 22:19:54 +08:00
claude-code-best
513ccc3003 fix: 修复需要鉴权的问题 2026-04-12 21:45:22 +08:00
claude-code-best
e770f1ef9d feat: 完成第一个 mcp-chrome 接入版本 2026-04-12 21:32:09 +08:00
claude-code-best
227083d31f fix: 修复截图 MIME 类型硬编码导致 API 拒绝的问题
macOS screencapture 输出 PNG,但代码硬编码 mimeType 为 image/jpeg,
导致 API 报错 "specified using image/jpeg but appears to be image/png"。
改为通过 magic bytes 检测实际图片格式。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-12 17:32:28 +08:00
claude-code-best
14c46df881 docs: 清理垃圾文档 2026-04-12 17:32:28 +08:00
Dosion
e0e4ee41c2 docs: add complete features guide and rewrite LAN Pipes docs (#246)
- Add docs/features/all-features-guide.md — comprehensive guide covering
  all 18 features across 13 PRs (Buddy, Remote Control, Voice, Chrome,
  Computer Use, GrowthBook, Ultraplan, Daemon, Pipe IPC, LAN Pipes,
  Monitor, Workflow, Coordinator, Proactive, History/Snip, Fork, etc.)

- Rewrite docs/features/lan-pipes.md — user-facing guide with step-by-step
  quickstart, firewall config (Windows/macOS/Linux), command reference,
  keyboard shortcuts, routing modes, permission forwarding, FAQ

- Rewrite docs/features/lan-pipes-implementation.md — developer reference
  with updated architecture (hook extraction, ndjsonFramer, module singletons),
  corrected code references, NDJSON protocol spec, attach flow sequence

Co-authored-by: unraid <local@unraid.local>
2026-04-12 11:37:51 +08:00
claude-code-best
e9861415c0 fix: 修复穷鬼模式的写入问题 2026-04-12 09:15:12 +08:00
claude-code-best
423f114db6 docs: 更新 langfuse 文档 2026-04-11 23:53:21 +08:00
claude-code-best
c8a502f81f chore: 删除重复 feature 定义 2026-04-11 23:27:28 +08:00
claude-code-best
09fc515edb feat: 远程群控 (#243)
* feat: restore pipe IPC, LAN pipes, monitor tool, and PR-package features

Core IPC system (UDS_INBOX):
- PipeServer/PipeClient with UDS + TCP dual transport, NDJSON protocol
- PipeRegistry: machineId-based role assignment, file locking
- Master/slave attach, prompt relay, permission forwarding
- Heartbeat lifecycle with parallel isPipeAlive probes
- Commands: /pipes, /attach, /detach, /send, /claim-main, /pipe-status

LAN Pipes (LAN_PIPES):
- UDP multicast beacon (224.0.71.67:7101) for zero-config LAN discovery
- PipeServer TCP listener, PipeClient TCP connect mode
- Heartbeat auto-attaches LAN peers via TCP
- Cross-machine attach allowed regardless of role
- /pipes shows [LAN] peers with role + hostname/IP
- SendMessageTool supports tcp: scheme with user consent

Architecture — extracted hooks from REPL.tsx (~830 lines → ~20 lines):
- usePipeIpc: lifecycle (bootstrap, handlers, heartbeat, cleanup)
- usePipeRelay: slave→master message relay via module singleton
- usePipePermissionForward: permission request/cancel forwarding
- usePipeRouter: selected pipe input routing with role+IP labels
- Shared ndjsonFramer.ts replaces 3 duplicate NDJSON parsers

Key fixes applied during development:
- Multicast binds to correct LAN interface (not WSL/Docker)
- Beacon ref stored as module singleton (not Zustand state mutation)
- Heartbeat preserves LAN peers in discoveredPipes and selectedPipes
- Disconnect handler calls removeSlaveClient (fixes listener leak)
- cleanupStaleEntries probes without lock, writes briefly under lock
- getMachineId uses async execFile (not blocking execSync)
- globalThis.__pipeSendToMaster replaced with setPipeRelay singleton
- M key only toggles route mode when selector panel is expanded
- User prompt displayed in message list on pipe broadcast
- Broadcast notifications show [role] + hostname/IP for LAN peers

Other restored features:
- Monitor tool: /monitor command, MonitorTool, MonitorMcpTask lifecycle
- Daemon supervisor and remoteControlServer command
- Tools: SnipTool, SleepTool, ListPeersTool, SendUserFileTool,
  WebBrowserTool, WorkflowTool, and 10+ stub→implementation rewrites
- Feature flags: UDS_INBOX, LAN_PIPES, MONITOR_TOOL, FORK_SUBAGENT,
  KAIROS, COORDINATOR_MODE, WORKFLOW_SCRIPTS, HISTORY_SNIP

Tests: 2190 pass / 0 fail (15 new: lanBeacon 7, peerAddress 8)

* fix: resolve merge conflicts and fix all tsc/test errors after main merge

- Export ToolResultBlockParam from Tool.ts (14 tool files fixed)
- Migrate ink imports from ../../ink.js to @anthropic/ink (7 files)
- Fix toolUseID → toolUseId typo in monitor.ts and MonitorTool.tsx
- Add fallback values for string|undefined type errors (8 locations)
- Fix AppState type in assistant.ts, add NewInstallWizard stubs
- Fix ParsedRepository.repo → .name in subscribe-pr.ts
- Fix AgentId/string type mismatch in BackgroundTasksDialog.tsx
- Fix PipeRelayFn return type in pipePermissionRelay.ts
- Use PipeMessage type in usePipeRelay.ts
- Fix lanBeacon.test.ts mock type assertions
- Create missing MouseActionEvent class for ink package
- Use ansi: color format instead of bare "green"/"red"
- Resolve theme.permission access via getTheme()

Result: 0 tsc errors, 2496 tests pass, 0 fail

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 恢复 /poor 的说明

---------

Co-authored-by: unraid <local@unraid.local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 23:22:55 +08:00
claude-code-best
2fea429dc6 feat: 添加对 langfuse 监控的支持 (#242)
* docs: 更新类型检查的 CLAUDE.md

* feat: 添加模型 1M 上下文切换

* chore: remove prefetchOfficialMcpUrls call on startup

* docs: 添加 git commit 规范

* feat: 第一次接入 langfuse

* fix: 修复 generation 的计时的错误

* feat: 添加多 agent 的监控

* feat: 添加 /poor 省流模式,toggle 关闭 extract_memories 和 prompt_suggestion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: 修复 lock 文件

* chore: 更新类型依赖

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 22:07:38 +08:00
claude-code-best
6a9da9d546 docs: 添加 git commit 规范 2026-04-11 15:13:41 +08:00
claude-code-best
d27c6cbc64 chore: remove prefetchOfficialMcpUrls call on startup 2026-04-11 15:13:41 +08:00
claude-code-best
ffd1c366eb feat: 添加模型 1M 上下文切换 2026-04-11 15:13:41 +08:00
claude-code-best
5beeebad59 docs: 更新类型检查的 CLAUDE.md 2026-04-11 15:13:41 +08:00
claude-code-best
c676ac4693 docs: update contributors 2026-04-11 05:19:38 +00:00
claude-code-best
eeb0f2776e docs: update contributors 2026-04-11 02:24:22 +00:00
claude-code-best
6a70056910 feat: 全部类型问题解决 2026-04-11 10:24:00 +08:00
claude-code-best
7088fe3c8b Merge remote-tracking branch 'guunergooner/fix/openai-stop-reason-usage' 2026-04-10 22:27:16 +08:00
claude-code-best
b060eabda9 chore: 添加类型测试 2026-04-10 22:24:17 +08:00
sobird
9da7345f8e Add Ultraplan Feature for Advanced Multi-Agent Planning (#232)
* feat: add ultraplan feature for advanced multi-agent planning

Implement ultraplan command with web-based planning interface,
supporting multiple prompt modes and interactive plan approval.

* chore: add semi

* chore: add semi
2026-04-10 22:17:00 +08:00
claude-code-best
8137b66a46 fix: 修复初次登陆的校验问题 2026-04-10 22:06:02 +08:00
claude-code-best
b681139b63 docs: update contributors 2026-04-10 10:14:34 +00:00
claude-code-best
0b1e678fb7 fix: 修复 mintlify ignore, 修复侧边栏 2026-04-10 18:14:07 +08:00
CyberScrubber
81073135e2 docs: 审校 Agent 文档术语与架构描述准确性(docs/agent) (#231)
基于源码验证和官方文档对照,修正三份 Agent 文档的内容准确性:

coordinator-and-swarm.mdx:
- 对齐官方术语:Leader→Team Lead, teammate→Teammate, 引入 Mailbox 消息系统
- 修正 Swarm 门控为 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1(原文"默认启用"不准确)
- 拓扑描述改为"星型+P2P混合"(官方有 Team Lead 角色,非纯网状)
- 新增架构组件表、Mailbox 消息系统、Hook 事件(TeammateIdle/TaskCreated/TaskCompleted)、限制说明
- 新增持久化存储路径(~/.claude/teams/, ~/.claude/tasks/)
- 移除虚构的"高水位标记"(claimTask 仅使用文件锁)
- 修正 Scratchpad 描述(Workers 获得,非 Coordinator 拥有)
- 修复引号不匹配

sub-agents.mdx:
- 修正为三路径路由(命名 Agent / Fork / GP 回退),原文仅两种
- 补充 isForkSubagentEnabled() 三前提(feature flag + 非Coordinator + 非非交互式)
- 新增模型解析优先级(4级链 + inherit 运行时解析)
- 新增内置 Agent 表(Explore/Plan/GP/statusline-setup/claude-code-guide)
- 新增 Hook 事件表(frontmatter + settings.json 双级别)
- 补充异步生命周期完整链路(finalizeAgentTool → getWorktreeResult)
- 补充 transcript 存储路径和结果格式细节

worktree-isolation.mdx:
- 区分 createWorktreeForSession vs createAgentWorktree 两种函数
- 修正清理机制为 cleanupWorktreeIfNeeded(非 ExitWorktreeTool 手动操作)
- 补充 usedSparsePaths 字段
2026-04-10 18:00:42 +08:00
claude-code-best
ff03fe7fcb fix: 修复类型问题 2026-04-10 17:34:01 +08:00
guunergooner
c82f59943c fix(openai): fix stop_reason null, zero usage fields and max_tokens forwarding
- Fix stop_reason always null in assembled AssistantMessage by applying
  the value captured from message_delta event
- Reset partialMessage to null after message_stop to prevent duplicate
  AssistantMessage emission causing doubled content in next API request
- Forward computed maxTokens into buildOpenAIRequestBody as max_tokens
  so OpenAI-compatible endpoints receive the intended output cap
- Extract assembleFinalAssistantOutputs helper to deduplicate message
  assembly logic between message_stop handler and post-loop fallback
- Fix test helper to use events parameter instead of hidden global
- Add regression test for max_tokens request forwarding

Signed-off-by: guunergooner <tongchao0923@gmail.com>
2026-04-10 12:17:52 +08:00
claude-code-best
e70319e8f5 docs: 更新远程控制及 rg 下载 2026-04-10 12:11:04 +08:00
claude-code-best
609e91143f docs: 尝试 docs 文档更新 2026-04-10 10:15:19 +08:00
claude-code-best
637531f81f fix(types): simplify bridge transport message type
Replace StdoutMessageWithSession conditional type with simpler
TransportMessage intersection type. The conditional type was
over-engineered for what is just StdoutMessage & { session_id? }.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 23:55:54 +08:00
claude-code-best
875510e1eb docs: update CLAUDE.md with architecture details and type safety guidelines
- Update build/dev mode descriptions to reflect current feature flags
- Add workspace packages table and multi-API compatibility layer docs
- Add Type Safety Guidelines section: prohibit `as any` in non-test code,
  document proper alternatives (Record<string, unknown>, dual assertion,
  type guards, specific SDK types)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 23:55:05 +08:00
claude-code-best
34bbc1d403 fix(types): replace all as any with proper type assertions
Eliminate unsafe `as any` casts across 21 non-test source files,
replacing them with specific type annotations:

- Bridge transport: use StdoutMessage type for write/writeBatch calls
- print.ts: type msg.request as Record<string, unknown> for unknown
  SDK control subtypes; use StdoutMessage for output.enqueue()
- API providers (openai/grok/gemini): import ChatCompletion types,
  type streams as AsyncIterable<ChatCompletionChunk>, type request
  bodies as ChatCompletionCreateParamsStreaming
- Computer use executor: use Partial<ResolvePrepareCaptureResult>
  for cross-platform screenshot result
- Components: replace Ink color string casts with proper typing
- Win32 bridge: type stdin as Writable after null check

All 2453 tests pass with 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 23:51:33 +08:00
claude-code-best
a14d3dc8f0 fix(types): clean type fixes across 92 files
Apply proper TypeScript type corrections without any unsafe casts:
- Fix unknown/never/{} types from decompilation
- Correct function signatures and parameter types
- Add missing type declarations and interfaces
- Fix Ink component prop types
- Update API client/provider type annotations

Test files with mock data casts are included as-is (acceptable pattern).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 23:45:56 +08:00
claude-code-best
ab3d8ef87e docs: update contributors 2026-04-09 14:04:36 +00:00
claude-code-best
dfce6d02f9 docs: 更新私有部署文档 2026-04-09 22:03:54 +08:00
claude-code-best
01cf45f4ac fix: 修复 permission 面板 2026-04-09 22:03:54 +08:00
HitMargin
e6affc7053 1. 修复 src/commands/fork/index.ts — 将空 stub 改为有效的 Command 定义 2. 新增 src/commands/fork/fork.tsx — 完整实现 /fork 命令,复用了 AgentTool 的 fork 子 agent 逻辑 (#221)
* 1. 修复 src/commands/fork/index.ts — 将空 stub 改为有效的 Command 定义
  2. 新增 src/commands/fork/fork.tsx — 完整实现 /fork 命令,复用了 AgentTool 的 fork 子 agent 逻辑

* Update src/commands/fork/fork.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix

---------

Co-authored-by: HitMargin <hitmargin@qq.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-04-09 21:53:07 +08:00
Alan
bb07836231 fix: support CRLF SSE frame parsing (#223) 2026-04-09 21:52:28 +08:00
claude-code-best
87230cf3bf docs: update contributors 2026-04-09 12:47:35 +00:00
claude-code-best
8c619a215c build: 修复构建报错 2026-04-09 20:47:13 +08:00
claude-code-best
2b0d31aaca feat: 对齐构建时的目标 2026-04-09 20:30:53 +08:00
bonerush
562e9daadd fix: Handle undefined command names in getCommandName function (#217)
* fix: reorder tool and user messages for OpenAI API compatibility (#168)
Fixes #168
OpenAI requires that an assistant message with tool_calls be immediately
followed by tool messages. Previously, convertInternalUserMessage
output user content before tool results, causing 400 errors.
Now tool messages are pushed first.

* fix: 修复OpenAI兼容层中deferred tools处理问题

  提交描述:
  修复了在使用OpenAI兼容API时TaskCreate工具调用失败的问题。

  问题:
  - 当使用OpenAI兼容API模型时,调用TaskCreate工具出现"InputValidationError: The required
  parameter `subject` is missing"错误
  - OpenAI兼容层没有正确处理deferred tools的过滤逻辑,导致工具schema没有被正确发送给模型

  修复:
  1. 在OpenAI兼容层中添加了与Anthropic API路径一致的deferred tools处理逻辑
  2. 导入必要的工具搜索相关函数: isToolSearchEnabled, extractDiscoveredToolNames,
  isDeferredTool等
  3. 实现工具过滤逻辑:
     - 检查工具搜索是否启用
     - 构建deferred tools集合
     - 过滤工具列表: 只包含非deferred工具或已发现的deferred工具
     - 为deferred tools设置deferLoading标志
  4. 修正了extractDiscoveredToolNames函数的导入路径错误

  影响:
  - 解决了TaskCreate工具调用时的参数验证错误
  - 确保OpenAI兼容层与Anthropic API路径在处理deferred tools时行为一致
  - 支持工具搜索功能在OpenAI兼容模式下正常工作

  修改的文件:
  - src/services/api/openai/index.ts - 主要修复文件

  测试建议:
  1. 使用OpenAI兼容API模型时,TaskCreate工具应该可以正常调用
  2. 如果工具搜索功能启用,可能需要先使用ToolSearchTool来发现TaskCreate工具
  3. 验证工具调用时不再出现"InputValidationError"错误

  这个修复确保了当使用OpenAI兼容API(如Ollama、DeepSeek、vLLM等)时,deferred
  tools(如TaskCreate)能够被正确处理,解决了工具调用失败的问题。

* fix: 更新未发送工具架构提示,提供OpenAI兼容模型的使用步骤

* fix: Handle undefined command names in getCommandName function

- Modified getCommandName in src/types/command.ts to return empty string instead of undefined when cmd.name is undefined
- Added null checks in src/hooks/useTypeahead.tsx to safely handle command names
- Prevents "undefined is not an object" error when FEATURE_BUDDY=1 and FEATURE_FORK_SUBAGENT=1 are enabled

The error occurred because getCommandName(cmd) could return undefined when cmd.name was undefined, causing .length access to fail.
2026-04-09 17:53:43 +08:00
CyberScrubber
8b2532a9c1 docs: fix documentation deviations from source code (#220)
* docs: 修正 docs/conversation 文档与源码的偏差(multi-turn/streaming/the-loop)

- multi-turn: TranscriptWriter→Project 私有类, 会话路径改用 sanitized-cwd,
  补充 StoredCostState.lastDuration 字段, 模型切换改为 setModel(),
  QueryEngine 状态补全 loadedNestedMemoryPaths/hasHandledOrphanedPermission,
  行号改为符号引用
- streaming: STALL_THRESHOLD_MS 10s→30s, 新增 90s 主动空闲看门狗描述,
  非流式降级补充 didFallBackToNonStreaming/executeNonStreamingRequest,
  行号改为符号引用
- the-loop: 终止条件 7→11, 继续条件重整为 5 组层级结构,
  max_output_tokens 拆分 escalate/recovery 子阶段,
  prompt-too-long 拆分 collapse_drain/reactive_compact 子策略,
  State 类型修正 autoCompactTracking 为可选, 行号改为符号引用
- 全部: 添加 sourceRef 版本锚定(3ec5675)

* docs: 修正 docs/extensibility 文档与源码的偏差(custom-agents/hooks/skills)

- custom-agents: Verification 模型修正为 inherit, 补充 Plugin Agent 字段限制
  (permissionMode/hooks/mcpServers 被安全忽略, isolation 仅 worktree),
  加载流程修正为 6 层优先级, 补充 memory snapshot 门控条件
- hooks: 事件数 22→27(补充 Notification), Hook 类型定义位置修正为 3 个文件,
  行号改为符号引用, Zod schema 范围修正, 去重键修正为四部分复合键,
  registerFrontmatterHooks/clearSessionHooks 区分定义位置和调用位置
- skills: 字段数 17→16, 权限层级 4→5(补充 remote canonical auto-allow),
  SAFE_SKILL_PROPERTIES 28→30, skillUsageTracking 路径修正,
  行号改为符号引用
- mcp-protocol: 全部验证通过, 无需修改
- 全部: 添加 sourceRef 版本锚定(3ec5675)

* Revert "docs: 修正 docs/extensibility 文档与源码的偏差(custom-agents/hooks/skills)"

* docs: 修正 docs/extensibility 文档与源码的偏差(hooks/skills/mcp-protocol)

hooks:
- 事件数 22→27(补充 Notification 事件)
- Hook 类型定义位置修正为 3 个文件分布
  (schemas/hooks.ts / types/hooks.ts / utils/hooks/sessionHooks.ts)
- Zod schema 引用从硬编码行号改为符号引用
- hookSpecificOutput 表从 6 扩展至 15 个事件
  (补全 permissionDecisionReason / PostToolUseFailure / SubagentStart 等)
- 去重键从 pluginRoot\0command 修正为四部分复合键
  (pluginRoot\0shell\0command\0ifCondition)
- 全部硬编码行号改为符号引用以避免版本漂移

skills:
- parseSkillFrontmatterFields 字段数 17→16
- SAFE_SKILL_PROPERTIES 属性数 28→30
- checkPermissions 层级 4→5
- 第 2 层描述从"官方市场"修正为"远程 canonical"

mcp-protocol:
- 配置层级从"三级"修正为
  "enterprise 独占或合并 user/project/local + plugin + claude.ai"

* docs: 修正 system-prompt.mdx 中 Boundary 章节的层级与可读性

- Boundary 插入条件从 ### 降为 blockquote,不再打断三种分块模式的并列结构
- 表格中 Boundary 缓存策略列补充说明其分割作用
- 新增 Boundary 概念释义(blockquote),解释其分割静态区/动态区以实现全局缓存的设计意图
2026-04-09 17:53:11 +08:00
2209 changed files with 102420 additions and 31474 deletions

View File

@@ -41,7 +41,8 @@ All teach-me data is stored under `.claude/skills/teach-me/records/`:
.claude/skills/teach-me/records/
├── learner-profile.md # Cross-topic notes (created on first session)
└── {topic-slug}/
── session.md # Learning state: concepts, status, notes
── session.md # Learning state: concepts, status, notes
└── {topic-slug}-notes.md # Learner-facing summary notes (generated at session end)
```
**Slug**: Topic in kebab-case, 2-5 words. Example: "Python decorators" → `python-decorators`
@@ -275,7 +276,8 @@ Update `session.md` after each round:
When all concepts mastered or user ends session:
1. Update `session.md` with final state.
2. Update `.claude/skills/teach-me/records/learner-profile.md` (keep under 30 lines):
2. **Generate learner-facing notes** — write `{topic-slug}-notes.md` in the topic directory. This is a standalone reference document the learner can review later. See "Notes Generation" below for format.
3. Update `.claude/skills/teach-me/records/learner-profile.md` (keep under 30 lines):
```markdown
# Learner Profile
@@ -293,7 +295,48 @@ Updated: {timestamp}
- Python decorators (8/10 concepts, 2025-01-15)
```
3. Give a brief text summary of what was covered, key insights, and areas for further study.
4. Give a brief text summary of what was covered, key insights, and areas for further study.
## Notes Generation
At session end, generate a learner-facing notes file at `{topic-slug}/{topic-slug}-notes.md`. This file is **written for the learner to review later**, not for the tutor. It should be self-contained and organized as a quick-reference.
### Notes Structure
```markdown
# {Topic} 核心笔记
## 1. {Section Name}
{Key concept, mechanism, or principle}
* **One-line summary**: {what it does / why it matters}
* **Detail**: {brief explanation, 2-4 sentences max}
* **Example** (if applicable): {code snippet, command, or concrete scenario}
---
## 2. {Section Name}
...
---
## n. 实战参数 / Cheat Sheet (if applicable)
{Practical commands, config, or quick-reference table}
| Parameter / Concept | What it does | Tuning tip |
|---------------------|-------------|------------|
| ... | ... | ... |
```
### Notes Writing Rules
1. **Start with "what & why"** before "how". Each section should answer: what is this, why does it exist, what problem does it solve.
2. **Use analogies sparingly but effectively**. Only include an analogy if it clarifies a non-obvious mechanism (e.g., "PagedAttention is like OS virtual memory paging").
3. **Include trade-offs**. Every optimization or design choice has a cost. Always state it (e.g., "TP improves throughput but increases communication latency").
4. **Code / command examples should be minimal**. Under 10 lines, self-contained, with comments explaining the key flags.
5. **Organize by concept dependency**, not by chronological teaching order. Foundation concepts first, advanced ones last.
6. **No quiz questions, no misconceptions, no tutor-side notes**. This is a clean reference document.
7. **Language matches the session**. If the session was in Chinese, notes are in Chinese (technical terms can stay in English).
8. **Keep it under 150 lines**. If it gets too long, the learner won't review it. Be ruthless about cutting fluff.
## Resuming Sessions

View File

@@ -1,22 +0,0 @@
#!/bin/sh
# pre-commit hook: 对暂存的文件运行 Biome 检查
# 仅检查 src/ 下的 .ts/.tsx/.js/.jsx 文件
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '^src/.*\.(ts|tsx|js|jsx)$')
if [ -z "$STAGED_FILES" ]; then
exit 0
fi
echo "Running Biome lint on staged files..."
# 使用 biome lint 对暂存文件进行检查(仅 lint不格式化不自动修复
echo "$STAGED_FILES" | xargs bunx biome lint --no-errors-on-unmatched
if [ $? -ne 0 ]; then
echo ""
echo "Biome lint failed. Fix errors or use --no-verify to bypass."
exit 1
fi
exit 0

View File

@@ -8,7 +8,7 @@ on:
jobs:
ci:
runs-on: macos-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -20,8 +20,19 @@ jobs:
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Test
run: bun test
- name: Type check
run: bun run typecheck
- name: Test with Coverage
run: |
set -o pipefail
bun test --coverage --coverage-reporter=lcov 2>&1 | grep -vE '^\s*(\(pass\)|\(skip\))' | sed '/^.*\/__tests__\/.*:$/d' | cat -s
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
file: ./coverage/lcov.info
token: ${{ secrets.CODECOV_TOKEN }}
- name: Build
run: bun run build
run: bun run build:vite

79
.github/workflows/publish-npm.yml vendored Normal file
View File

@@ -0,0 +1,79 @@
name: Publish to npm
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: '版本号 (例如: v1.9.0)'
required: true
type: string
permissions:
contents: write
packages: write
id-token: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.version || github.ref }}
- uses: actions/setup-node@v6
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Type check
run: bun run typecheck
- name: Run tests
run: bun test
- name: Publish to npm
run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Generate changelog
id: changelog
run: |
VERSION="${{ github.event.inputs.version || github.ref_name }}"
PREV_TAG=$(git tag --sort=-version:refname | grep -v "^${VERSION#v}$" | head -1)
if [ -n "$PREV_TAG" ]; then
COMMITS=$(git log "${PREV_TAG}..${VERSION}" --pretty=format:"- %s (%h)" --no-merges)
else
COMMITS=$(git log --pretty=format:"- %s (%h)" --no-merges -20)
fi
{
echo "commits<<EOF"
echo "$COMMITS"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
name: ${{ github.event.inputs.version || github.ref_name }}
body: |
## What's Changed
${{ steps.changelog.outputs.commits }}
**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ github.event.inputs.version || github.ref_name }}^...${{ github.event.inputs.version || github.ref_name }}
draft: false
prerelease: ${{ contains(github.event.inputs.version || github.ref_name, 'rc') || contains(github.event.inputs.version || github.ref_name, 'beta') || contains(github.event.inputs.version || github.ref_name, 'alpha') }}

View File

@@ -1,11 +1,8 @@
name: Update Contributors
on:
push:
branches:
- main
schedule:
- cron: '0 0 * * *' # 每更新一次
- cron: '0 0 * * 1' # 每周一更新一次
permissions:
contents: write

20
.gitignore vendored
View File

@@ -12,13 +12,18 @@ src/utils/vendor/
# AI tool runtime directories
.agents/
.codex/
.claude/
.omx/
.docs/task/
# Binary / screenshot files (root only)
/*.png
*.bmp
# Internal system prompt documents
Claude-Opus-*.txt
Claude-Sonnet-*.txt
Claude-Haiku-*.txt
# Agent / tool state dirs
.swarm/
.agents/__pycache__/
@@ -29,3 +34,14 @@ __pycache__/
logs
data
.omc
.codex/*
!.codex/agents/
!.codex/agents/**
!.codex/skills/
!.codex/skills/**
.codex/skills/.system/**
!.codex/prompts/
!.codex/prompts/**
teach-me
credentials.json

78
.impeccable.md Normal file
View File

@@ -0,0 +1,78 @@
# Impeccable Design Context
## Users
**Primary**: Technical teams and enterprises using AI-assisted coding in production workflows.
- DevOps engineers managing remote agents via RCS dashboard
- Development teams collaborating through shared sessions
- Individual developers using terminal CLI daily
**Context**: Used during focused work sessions — debugging, code review, agent orchestration. Users are in "get things done" mode, not browsing. They value efficiency but also appreciate warmth and personality.
**Job to be done**: Make advanced AI coding tools accessible and controllable, especially features that normally require enterprise accounts or Anthropic OAuth.
## Brand Personality
**3 words**: Warm, Considered, Human
**Voice**: Like a knowledgeable colleague who's genuinely enthusiastic about the craft — not a corporate product manager. Community-first, open, slightly playful. Chinese developer community culture (贴吧/discord 温暖氛围).
**Emotional goals**: Confidence (this tool is solid), Warmth (this community is welcoming), Delight (small moments of personality make the difference).
**References**:
- **Anthropic's own design language** — their clean, considered aesthetic with warm undertones. The terra cotta/burnt orange as a human accent. Lots of breathing room. Typography-forward.
- **NOT**: Generic AI product (no ChatGPT blue, no gradient text, no "AI slop"). NOT corporate SaaS (no Salesforce-blue dashboards, no enterprise sterility).
**Anti-references**: Corporate enterprise dashboards, generic AI product pages, anything that looks like it was "designed by committee."
## Aesthetic Direction
**Theme**: Light + Dark dual mode (user/system preference switch)
**Tone**: Anthropomorphic warmth meets terminal precision. The brand orange (Claude's terra cotta) is the thread that ties everything together — it's the human element in a technical world.
**Typography**: Clean, considered, with good hierarchy. Terminal-native for CLI; modern web fonts for Web UI (RCS dashboard, docs). Favor readability and personality.
**Color**:
- Primary: Claude orange family (`#D77757` / terra cotta)
- Accent: Warm neutrals tinted toward orange
- Semantic: Success/Error/Warning following Anthropic's established palette
- Dark mode: Warm dark surfaces (not cold blue-black)
**Differentiation**: The CCB brand sits at the intersection of "serious tool" and "community project." It should feel like Anthropic's design principles applied to an open-source context — less corporate polish, more human craft. The mascot "Clawd" and the playful "踩踩背" naming hint at personality that the design should honor.
**Scope**: All Web UI — RCS control panel, documentation site, landing pages.
## Design Principles
1. **Considered over clever** — Every design choice should feel intentional, not trendy. If it doesn't serve the user, it doesn't ship.
2. **Warmth through subtlety** — Orange tints on neutrals, breathing room in layouts, personality in copy. Not giant emoji or aggressive color.
3. **Density with clarity** — Technical users need information density, but not chaos. Every pixel earns its place.
4. **Community voice** — The design should feel like it was made by people who use it, not by a distant design team. Slightly rough edges are fine if they're honest.
5. **Anthropic's shadow** — When in doubt, follow Anthropic's design instincts — the clean layouts, the generous spacing, the warm color temperature. Then add the community touch.
## Existing Design Assets
### Brand Colors (from theme system)
- Claude Orange: `rgb(215,119,87)` / `#D77757`
- Claude Blue: `rgb(87,105,247)` / `#5769F7`
- Permission Blue: `rgb(87,105,247)`
- Auto Accept Violet: `rgb(135,0,255)`
- Plan Mode Teal: `rgb(0,102,102)`
- Success: `rgb(78,186,101)`
- Error: `rgb(255,107,128)`
- Warning: `rgb(255,193,7)`
### Logo
- CCB text + orange play button icon
- Dark/Light SVG variants in `docs/logo/`
- Favicon: Orange circle `#D97706` with white play triangle
### Mascot
- "Clawd" — terminal-art character with multiple poses
- Theme-aware coloring
### Theme System
- 7 variants: dark, light, dark-ansi, light-ansi, dark-daltonized, light-daltonized, auto
- 89+ semantic color tokens
- Full documentation in `packages/@ant/ink/docs/04-theme-system.md`

2
.mintignore Normal file
View File

@@ -0,0 +1,2 @@
src/
packages/

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
registry=https://registry.npmjs.org/

357
AGENTS.md Normal file
View File

@@ -0,0 +1,357 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) and other AI coding agents when working with code in this repository.
## Project Overview
This is a **reverse-engineered / decompiled** version of Anthropic's official Claude Code CLI tool. The goal is to restore core functionality while trimming secondary capabilities. Many modules are stubbed or feature-flagged off. TypeScript strict mode is enforced — **`bunx tsc --noEmit` must pass with zero errors**.
## Git Commit Message Convention
使用 **Conventional Commits** 规范:
```
<type>: <描述>
```
常见 type`feat``fix``docs``chore``refactor`
示例:
- `feat: 添加模型 1M 上下文切换`
- `fix: 修复初次登陆的校验问题`
- `chore: remove prefetchOfficialMcpUrls call on startup`
## Commands
```bash
# Install dependencies
bun install
# Dev mode (runs cli.tsx with MACRO defines injected via -d flags)
bun run dev
# Dev mode with debugger (set BUN_INSPECT=9229 to pick port)
bun run dev:inspect
# Pipe mode
echo "say hello" | bun run src/entrypoints/cli.tsx -p
# Build (code splitting, outputs dist/cli.js + chunk files)
bun run build
# Build with Vite (alternative build pipeline)
bun run build:vite
# Test
bun test # run all tests
bun test src/utils/__tests__/hash.test.ts # run single file
bun test --coverage # with coverage report
# Lint & Format (Biome)
bun run lint # check only
bun run lint:fix # auto-fix
bun run format # format all src/
# Health check
bun run health
# Check unused exports
bun run check:unused
# Full check (typecheck + lint + test) — run after completing any task
bun run test:all
bun run typecheck
# Remote Control Server
bun run rcs
# Docs dev server (Mintlify)
bun run docs:dev
```
详细的测试规范、覆盖状态和改进计划见 `docs/testing-spec.md`
## Architecture
### Runtime & Build
- **Runtime**: Bun (not Node.js). All imports, builds, and execution use Bun APIs.
- **Build**: `build.ts` 执行 `Bun.build()` with `splitting: true`,入口 `src/entrypoints/cli.tsx`,输出 `dist/cli.js` + chunk files。Build 默认启用 19 个 feature见下方 Feature Flag 段)。构建后自动替换 `import.meta.require` 为 Node.js 兼容版本(产物 bun/node 都可运行)。
- **Dev mode**: `scripts/dev.ts` 通过 Bun `-d` flag 注入 `MACRO.*` defines运行 `src/entrypoints/cli.tsx`。默认启用全部 feature。
- **Module system**: ESM (`"type": "module"`), TSX with `react-jsx` transform.
- **Monorepo**: Bun workspaces — 15 个 workspace packages + 若干辅助目录 in `packages/` resolved via `workspace:*`
- **Lint/Format**: Biome (`biome.json`)。`bun run lint` / `bun run lint:fix` / `bun run format`
- **Defines**: 集中管理在 `scripts/defines.ts`。当前版本 `2.1.888`
- **CI**: GitHub Actions — `ci.yml`(构建+测试)、`release-rcs.yml`RCS 发布)、`update-contributors.yml`(自动更新贡献者)。
### Entry & Bootstrap
1. **`src/entrypoints/cli.tsx`** — True entrypoint。`main()` 函数按优先级处理多条快速路径:
- `--version` / `-v` — 零模块加载
- `--dump-system-prompt` — feature-gated (DUMP_SYSTEM_PROMPT)
- `--claude-in-chrome-mcp` / `--chrome-native-host`
- `--computer-use-mcp` — 独立 MCP server 模式
- `--daemon-worker=<kind>` — feature-gated (DAEMON)
- `remote-control` / `rc` / `remote` / `sync` / `bridge` — feature-gated (BRIDGE_MODE)
- `daemon` [subcommand] — feature-gated (DAEMON)
- `ps` / `logs` / `attach` / `kill` / `--bg` — feature-gated (BG_SESSIONS)
- `new` / `list` / `reply` — Template job commands
- `environment-runner` / `self-hosted-runner` — BYOC runner
- `--tmux` + `--worktree` 组合
- 默认路径:加载 `main.tsx` 启动完整 CLI
2. **`src/main.tsx`** (~6981 行) — Commander.js CLI definition。注册大量 subcommands`mcp` (serve/add/remove/list...)、`server``ssh``open``auth``plugin``agents``auto-mode``doctor``update` 等。主 `.action()` 处理器负责权限、MCP、会话恢复、REPL/Headless 模式分发。
3. **`src/entrypoints/init.ts`** — One-time initialization (telemetry, config, trust dialog)。
### Core Loop
- **`src/query.ts`** — The main API query function. Sends messages to Claude API, handles streaming responses, processes tool calls, and manages the conversation turn loop.
- **`src/QueryEngine.ts`** — Higher-level orchestrator wrapping `query()`. Manages conversation state, compaction, file history snapshots, attribution, and turn-level bookkeeping. Used by the REPL screen.
- **`src/screens/REPL.tsx`** — The interactive REPL screen (React/Ink component). Handles user input, message display, tool permission prompts, and keyboard shortcuts.
### API Layer
- **`src/services/api/claude.ts`** — Core API client. Builds request params (system prompt, messages, tools, betas), calls the Anthropic SDK streaming endpoint, and processes `BetaRawMessageStreamEvent` events.
- **7 providers**: `firstParty` (Anthropic direct), `bedrock` (AWS), `vertex` (Google Cloud), `foundry`, `openai`, `gemini`, `grok` (xAI)。
- Provider selection in `src/utils/model/providers.ts`。优先级modelType 参数 > 环境变量 > 默认 firstParty。
### Tool System
- **`src/Tool.ts`** — Tool interface definition (`Tool` type) and utilities (`findToolByName`, `toolMatchesName`).
- **`src/tools.ts`** — Tool registry. Assembles the tool list; tools are imported from `@claude-code-best/builtin-tools` package. Some tools are conditionally loaded via `feature()` flags or `process.env.USER_TYPE`.
- **`packages/builtin-tools/src/tools/`** — 59 个子目录(含 shared/testing 等工具目录),通过 `@claude-code-best/builtin-tools` 包导出。主要分类:
- **文件操作**: FileEditTool, FileReadTool, FileWriteTool, GlobTool, GrepTool
- **Shell/执行**: BashTool, PowerShellTool, REPLTool
- **Agent 系统**: AgentTool, TaskCreateTool, TaskUpdateTool, TaskListTool, TaskGetTool
- **规划**: EnterPlanModeTool, ExitPlanModeV2Tool, VerifyPlanExecutionTool
- **Web/MCP**: WebFetchTool, WebSearchTool, MCPTool, McpAuthTool
- **调度**: CronCreateTool, CronDeleteTool, CronListTool
- **其他**: LSPTool, ConfigTool, SkillTool, EnterWorktreeTool, ExitWorktreeTool 等
- **`src/tools/shared/`** / **`packages/builtin-tools/src/tools/shared/`** — Tool 共享工具函数。
### UI Layer (Ink)
- **`src/ink.ts`** — Ink render wrapper with ThemeProvider injection.
- **`packages/@ant/ink/`** — Custom Ink frameworkforked/internal包含 components、core、hooks、keybindings、theme、utils。注意不是 `src/ink/`
- **`src/components/`** — 149 个组件目录/文件,渲染于终端 Ink 环境中。关键组件:
- `App.tsx` — Root provider (AppState, Stats, FpsMetrics)
- `Messages.tsx` / `MessageRow.tsx` — Conversation message rendering
- `PromptInput/` — User input handling
- `permissions/` — Tool permission approval UI
- `design-system/` — 复用 UI 组件Dialog, FuzzyPicker, ProgressBar, ThemeProvider 等)
- Components use React Compiler runtime (`react/compiler-runtime`) — decompiled output has `_c()` memoization calls throughout.
### State Management
- **`src/state/AppState.tsx`** — Central app state type and context provider. Contains messages, tools, permissions, MCP connections, etc.
- **`src/state/AppStateStore.ts`** — Default state and store factory.
- **`src/state/store.ts`** — Zustand-style store for AppState (`createStore`).
- **`src/state/selectors.ts`** — State selectors.
- **`src/bootstrap/state.ts`** — Module-level singletons for session-global state (session ID, CWD, project root, token counts, model overrides, client type, permission mode).
### Workspace Packages
| Package | 说明 |
|---------|------|
| `packages/@ant/ink/` | Forked Ink 框架components、hooks、keybindings、theme |
| `packages/@ant/computer-use-mcp/` | Computer Use MCP server截图/键鼠/剪贴板/应用管理) |
| `packages/@ant/computer-use-input/` | 键鼠模拟dispatcher + darwin/win32/linux backend |
| `packages/@ant/computer-use-swift/` | 截图 + 应用管理dispatcher + per-platform backend |
| `packages/@ant/claude-for-chrome-mcp/` | Chrome 浏览器控制(通过 `--chrome` 启用) |
| `packages/@ant/model-provider/` | Model provider 抽象层 |
| `packages/builtin-tools/` | 内置工具集60 个 tool 实现,通过 `@claude-code-best/builtin-tools` 导出) |
| `packages/agent-tools/` | Agent 工具集 |
| `packages/acp-link/` | ACP 代理服务器WebSocket → ACP agent 桥接) |
| `packages/cc-knowledge/` | Claude Code 知识库(非 workspace 包) |
| `packages/langfuse-dashboard/` | Langfuse 可观测性面板(非 workspace 包) |
| `packages/mcp-client/` | MCP 客户端库 |
| `packages/mcp-server/` | MCP 服务端库(非 workspace 包) |
| `packages/remote-control-server/` | 自托管 Remote Control ServerDocker 部署,含 Web UI— Web UI 已重构为 React + Vite + Radix UI支持 ACP agent 接入 |
| `packages/swarm/` | Swarm 解耦模块(非 workspace 包) |
| `packages/shell/` | Shell 抽象(非 workspace 包) |
| `packages/audio-capture-napi/` | 原生音频捕获(已恢复) |
| `packages/color-diff-napi/` | 颜色差异计算完整实现11 tests |
| `packages/image-processor-napi/` | 图像处理(已恢复) |
| `packages/modifiers-napi/` | 键盘修饰键检测macOS FFI 实现) |
| `packages/url-handler-napi/` | URL scheme 处理(环境变量 + CLI 参数读取) |
### Bridge / Remote Control
- **`src/bridge/`** — Remote Control / Bridge 模式。feature-gated by `BRIDGE_MODE`。包含 bridge API、会话管理、JWT 认证、消息传输、权限回调等。Entry: `bridgeMain.ts`
- **`packages/remote-control-server/`** — 自托管 RCS支持 Docker 部署,含 Web UI 控制面板React 19 + Vite + Radix UI。支持 ACP agent 通过 acp-link 接入ACP WebSocket handler、relay handler、SSE event stream。通过 `bun run rcs` 启动。
- CLI 快速路径: `claude remote-control` / `claude rc` / `claude bridge`
- 详见 `docs/features/remote-control-self-hosting.md`
### ACP Protocol (Agent Client Protocol)
- **`src/services/acp/`** — ACP agent 实现,包含 `agent.ts`AcpAgent 类)、`bridge.ts`Claude Code ↔ ACP 桥接)、`permissions.ts`(权限处理)、`entry.ts`(入口)。
- **`packages/acp-link/`** — ACP 代理服务器,将 WebSocket 客户端桥接到 ACP agent。提供 `acp-link` CLI 命令,支持自定义端口/HTTPS/认证/会话管理、RCS 集成REST 注册 + WS identify 两步流程、权限模式透传fallback: 客户端传值 > config > `ACP_PERMISSION_MODE` 环境变量)。
- ACP 权限管道改进:`createAcpCanUseTool` 统一权限流水线,`applySessionMode` 模式同步,`bypassPermissions` 可用性检测(非 root/sandbox 环境)。
- ACP Plan 可视化已支持 `session/update plan` 类型的消息展示PlanView 组件,含进度条/状态图标/优先级标签)。
### Daemon Mode
- **`src/daemon/`** — Daemon 模式(长驻 supervisor。feature-gated by `DAEMON`。包含 `main.ts`entry`workerRegistry.ts`worker 管理)。
### Context & System Prompt
- **`src/context.ts`** — Builds system/user context for the API call (git status, date, CLAUDE.md contents, memory files).
- **`src/utils/claudemd.ts`** — Discovers and loads CLAUDE.md files from project hierarchy.
### Feature Flag System
Feature flags control which functionality is enabled at runtime. 代码中统一通过 `import { feature } from 'bun:bundle'` 导入,调用 `feature('FLAG_NAME')` 返回 `boolean`
**启用方式**: 环境变量 `FEATURE_<FLAG_NAME>=1`。例如 `FEATURE_BUDDY=1 bun run dev`
**Build 默认 features**19 个,见 `build.ts`:
- 基础: `BUDDY`, `TRANSCRIPT_CLASSIFIER`, `BRIDGE_MODE`, `AGENT_TRIGGERS_REMOTE`, `CHICAGO_MCP`, `VOICE_MODE`
- 统计/缓存: `SHOT_STATS`, `PROMPT_CACHE_BREAK_DETECTION`, `TOKEN_BUDGET`
- P0 本地: `AGENT_TRIGGERS`, `ULTRATHINK`, `BUILTIN_EXPLORE_PLAN_AGENTS`, `LODESTONE`
- P1 API 依赖: `EXTRACT_MEMORIES`, `VERIFICATION_AGENT`, `KAIROS_BRIEF`, `AWAY_SUMMARY`, `ULTRAPLAN`
- P2: `DAEMON`
**Dev mode 默认**: 全部启用(见 `scripts/dev.ts`)。
**类型声明**: `src/types/internal-modules.d.ts` 中声明了 `bun:bundle` 模块的 `feature` 函数签名。
**新增功能的正确做法**: 保留 `import { feature } from 'bun:bundle'` + `feature('FLAG_NAME')` 的标准模式,在运行时通过环境变量或配置控制,不要绕过 feature flag 直接 import。
### Multi-API 兼容层
所有兼容层均采用流适配器模式:将第三方 API 格式转为 Anthropic 内部格式,下游代码完全不改。通过 `/login` 命令配置。
#### OpenAI 兼容层
通过 `CLAUDE_CODE_USE_OPENAI=1` 启用,支持 Ollama/DeepSeek/vLLM 等任意 OpenAI Chat Completions 协议端点。含 DeepSeek thinking mode 支持。
- **`src/services/api/openai/`** — client、消息/工具转换、流适配、模型映射
- 关键环境变量:`CLAUDE_CODE_USE_OPENAI``OPENAI_API_KEY``OPENAI_BASE_URL``OPENAI_MODEL`
#### Gemini 兼容层
通过 `CLAUDE_CODE_USE_GEMINI=1` 启用。独立环境变量体系。
- **`src/services/api/gemini/`** — client、模型映射、类型定义
- 关键环境变量:`GEMINI_API_KEY`(必填)、`GEMINI_MODEL`(直接指定)、`GEMINI_DEFAULT_SONNET_MODEL`/`GEMINI_DEFAULT_OPUS_MODEL`(按能力映射)
- 模型映射优先级:`GEMINI_MODEL` > `GEMINI_DEFAULT_*_MODEL` > `ANTHROPIC_DEFAULT_*_MODEL`(已废弃) > 原样返回
#### Grok 兼容层
通过 `CLAUDE_CODE_USE_GROK=1` 启用。自定义模型映射支持 xAI Grok API。
- **`src/services/api/grok/`** — client、模型映射
详见各兼容层的 docs 文档。
### 穷鬼模式Budget Mode
- 通过 `/poor` 命令切换,持久化到 `settings.json`
- 启用后跳过 `extract_memories``prompt_suggestion``verification_agent`,显著减少 token 消耗。
- 实现在 `src/commands/poor/poorMode.ts`
### Stubbed/Deleted Modules
| Module | Status |
|--------|--------|
| Computer Use (`@ant/*`) | Restored — macOS + Windows + Linux后端完整度不一 |
| `*-napi` packages | 全部已恢复/实现:`audio-capture-napi``image-processor-napi` 已恢复;`color-diff-napi` 完整;`modifiers-napi`macOS FFI`url-handler-napi`(环境变量+CLI |
| Voice Mode | Restored — Push-to-Talk 语音输入(需 Anthropic OAuth |
| OpenAI/Gemini/Grok 兼容层 | Restored |
| Remote Control Server | Restored — 自托管 RCS + Web UI |
| Analytics / GrowthBook / Sentry | Empty implementations |
| Magic Docs / LSP Server | Restored — Magic Docs 自动更新 + LSP 服务器管理器 |
| Plugins / Marketplace | Restored — 插件安装/卸载/启用/禁用 + Marketplace 浏览 |
| MCP OAuth | Simplified |
### Key Type Files
- **`src/types/global.d.ts`** — Declares `MACRO`, `BUILD_TARGET`, `BUILD_ENV` and internal Anthropic-only identifiers.
- **`src/types/internal-modules.d.ts`** — Type declarations for `bun:bundle`, `bun:ffi`, `@anthropic-ai/mcpb`.
- **`src/types/message.ts`** — Message type hierarchy (UserMessage, AssistantMessage, SystemMessage, etc.).
- **`src/types/permissions.ts`** — Permission mode and result types.
## Testing
- **框架**: `bun:test`(内置断言 + mock
- **单元测试**: 就近放置于 `src/**/__tests__/`,文件名 `<module>.test.ts`
- **集成测试**: `tests/integration/` — 4 个文件cli-arguments, context-build, message-pipeline, tool-chain
- **共享 mock/fixture**: `tests/mocks/`api-responses, file-system, fixtures/
- **命名**: `describe("functionName")` + `test("behavior description")`,英文
- **包测试**: `packages/` 下各包也有独立测试(如 `color-diff-napi` 11 tests
### Mock 使用规范
**只 mock 有副作用的依赖链,不 mock 纯函数/纯数据模块。**
被迫 mock 的根源:`log.ts` / `debug.ts``bootstrap/state.ts`(模块级 `realpathSync` / `randomUUID` 副作用)。必须 mock 的模块:`log.ts``debug.ts``bun:bundle``settings/settings.js``config.ts``auth.ts`、第三方网络库。
**`log.ts``debug.ts` 使用共享 mock**`tests/mocks/log.ts` / `tests/mocks/debug.ts`),不要在测试文件中内联 mock 定义。使用方式:
```ts
import { logMock } from "../../../tests/mocks/log";
mock.module("src/utils/log.ts", logMock);
import { debugMock } from "../../../../tests/mocks/debug";
mock.module("src/utils/debug.ts", debugMock);
```
源文件导出变更时只需更新 `tests/mocks/` 下的对应文件,不需要逐个修改测试。
不要 mock纯函数模块`errors.ts``stringUtils.js`、mock 值与真实实现相同的模块、mock 路径与实际 import 不匹配的模块。
路径规则:统一用 `.ts` 扩展名 + `src/*` 别名路径,禁止双重 mock 同一模块。
### 类型检查
项目使用 TypeScript strict 模式,**tsc 必须零错误**。每次修改后运行:
```bash
bun run typecheck
```
**类型规范**
- 生产代码禁止 `as any`;测试文件中 mock 数据可用 `as any`
- 类型不匹配优先用 `as unknown as SpecificType` 双重断言,或补充 interface
- 未知结构对象用 `Record<string, unknown>` 替代 `any`
- 联合类型用类型守卫type guard收窄不要强转
- `msg.request` 属性访问:`const req = msg.request as Record<string, unknown>`
- Ink `color` prop`as keyof Theme` 而非 `as any`
## Working with This Codebase
- **tsc must pass** — `bun run typecheck` 必须零错误,任何修改都不能引入新的类型错误。
- **Feature flags** — 默认全部关闭(`feature()` 返回 `false`。Dev/build 各有自己的默认启用列表。不要在 `cli.tsx` 中重定义 `feature` 函数。
- **React Compiler output** — Components have decompiled memoization boilerplate (`const $ = _c(N)`). This is normal.
- **`bun:bundle` import** — `import { feature } from 'bun:bundle'` 是 Bun 内置模块,由运行时/构建器解析。不要用自定义函数替代它。**`feature()` 只能直接用在 `if` 语句或三元表达式的条件位置**Bun 编译器限制),不能赋值给变量、不能放在箭头函数体里、不能作为 `&&` 链的一部分。正确:`if (feature('X')) {}``feature('X') ? a : b`
- **`src/` path alias** — tsconfig maps `src/*` to `./src/*`. Imports like `import { ... } from 'src/utils/...'` are valid.
- **MACRO defines** — 集中管理在 `scripts/defines.ts`。Dev mode 通过 `bun -d` 注入build 通过 `Bun.build({ define })` 注入。修改版本号等常量只改这个文件。
- **构建产物兼容 Node.js** — `build.ts` 会自动后处理 `import.meta.require`,产物可直接用 `node dist/cli.js` 运行。
- **Biome 配置** — 大量 lint 规则被关闭decompiled 代码不适合严格 lint`.tsx` 文件用 120 行宽 + 强制分号;其他文件 80 行宽 + 按需分号。
- **Ink 框架在 `packages/@ant/ink/`** — 不是 `src/ink/`该目录不存在。Ink 相关的组件、hooks、keybindings 都在 packages 中。
- **Provider 优先级** — `modelType` 参数 > 环境变量 > 默认 `firstParty`。新增 provider 需在 `src/utils/model/providers.ts` 注册。
## Design Context
Impeccable 设计上下文保存在 `.impeccable.md` 中。设计 Web UIRCS 控制面板、文档站、着陆页)时必须参考该文件。
### 核心设计原则
1. **Considered over clever** — 每个设计选择都应感觉有意为之,而非追逐潮流
2. **Warmth through subtlety** — 通过橙色色调的中性色、留白布局、有温度的文案来传达温暖
3. **Density with clarity** — 技术用户需要信息密度,但不能混乱
4. **Community voice** — 设计应感觉是由使用者创造的,而非遥远的设计团队
5. **Anthropic's shadow** — 遵循 Anthropic 的设计直觉:干净的布局、充足的间距、温暖的色温
### 品牌色
- 主色Claude Orange `#D77757`terra cotta
- 辅色Claude Blue `#5769F7`
- 暗色模式使用温暖的深色表面(非冷蓝黑色)
### 目标用户
技术团队/企业,在专业工作流中使用 AI 辅助编程。友好的开源社区氛围,非企业 SaaS 风格。
### 视觉参考
Anthropic 公司的设计风格 — 干净、考究、温暖的底色。大量留白,以排版为核心。避免 AI 产品常见的设计套路(渐变文字、玻璃态、霓虹色)。

311
CLAUDE.md
View File

@@ -1,10 +1,25 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This file provides guidance to Claude Code (claude.ai/code) and other AI coding agents when working with code in this repository.
## Project Overview
This is a **reverse-engineered / decompiled** version of Anthropic's official Claude Code CLI tool. The goal is to restore core functionality while trimming secondary capabilities. Many modules are stubbed or feature-flagged off. The codebase has ~1341 tsc errors from decompilation (mostly `unknown`/`never`/`{}` types) — these do **not** block Bun runtime execution.
This is a **reverse-engineered / decompiled** version of Anthropic's official Claude Code CLI tool. The goal is to restore core functionality while trimming secondary capabilities. Many modules are stubbed or feature-flagged off. TypeScript strict mode is enforced — **`bunx tsc --noEmit` must pass with zero errors**.
## Git Commit Message Convention
使用 **Conventional Commits** 规范:
```
<type>: <描述>
```
常见 type`feat``fix``docs``chore``refactor`
示例:
- `feat: 添加模型 1M 上下文切换`
- `fix: 修复初次登陆的校验问题`
- `chore: remove prefetchOfficialMcpUrls call on startup`
## Commands
@@ -21,13 +36,16 @@ bun run dev:inspect
# Pipe mode
echo "say hello" | bun run src/entrypoints/cli.tsx -p
# Build (code splitting, outputs dist/cli.js + ~450 chunk files)
# Build (code splitting, outputs dist/cli.js + chunk files)
bun run build
# Build with Vite (alternative build pipeline)
bun run build:vite
# Test
bun test # run all tests
bun test # run all tests
bun test src/utils/__tests__/hash.test.ts # run single file
bun test --coverage # with coverage report
bun test --coverage # with coverage report
# Lint & Format (Biome)
bun run lint # check only
@@ -40,6 +58,13 @@ bun run health
# Check unused exports
bun run check:unused
# Full check (typecheck + lint + test) — run after completing any task
bun run test:all
bun run typecheck
# Remote Control Server
bun run rcs
# Docs dev server (Mintlify)
bun run docs:dev
```
@@ -51,12 +76,15 @@ bun run docs:dev
### Runtime & Build
- **Runtime**: Bun (not Node.js). All imports, builds, and execution use Bun APIs.
- **Build**: `build.ts` 执行 `Bun.build()` with `splitting: true`,入口 `src/entrypoints/cli.tsx`,输出 `dist/cli.js` + chunk files。默认启用 `AGENT_TRIGGERS_REMOTE``CHICAGO_MCP``VOICE_MODE` feature。构建后自动替换 `import.meta.require` 为 Node.js 兼容版本(产物 bun/node 都可运行)
- **Dev mode**: `scripts/dev.ts` 通过 Bun `-d` flag 注入 `MACRO.*` defines运行 `src/entrypoints/cli.tsx`。默认启用 `BUDDY``TRANSCRIPT_CLASSIFIER``BRIDGE_MODE``AGENT_TRIGGERS_REMOTE``CHICAGO_MCP``VOICE_MODE` 六个 feature
- **Build**: `build.ts` 执行 `Bun.build()` with `splitting: true`,入口 `src/entrypoints/cli.tsx`,输出 `dist/cli.js` + chunk files。Build 默认启用 19 个 feature见下方 Feature Flag 段)。构建后自动替换 `import.meta.require` 为 Node.js 兼容版本(产物 bun/node 都可运行)。构建时会将 `vendor/audio-capture/``src/utils/vendor/ripgrep/` 复制到 `dist/vendor/`
- **Build (Vite)**: `vite.config.ts` + `scripts/post-build.ts`chunk 输出到 `dist/chunks/`。post-build 同样复制 vendor 文件到 `dist/vendor/`
- **Vendor 路径解析**: 构建后 chunk 文件位于 `dist/``dist/chunks/`vendor 二进制在 `dist/vendor/``src/utils/ripgrep.ts``packages/audio-capture-napi/src/index.ts` 均通过 `import.meta.url` 路径中 `lastIndexOf('dist')` 定位 dist 根目录,再拼接 `vendor/` 子路径,确保不同构建产物层级下路径一致。
- **Dev mode**: `scripts/dev.ts` 通过 Bun `-d` flag 注入 `MACRO.*` defines运行 `src/entrypoints/cli.tsx`。默认启用全部 feature。
- **Module system**: ESM (`"type": "module"`), TSX with `react-jsx` transform.
- **Monorepo**: Bun workspaces — internal packages live in `packages/` resolved via `workspace:*`.
- **Monorepo**: Bun workspaces — 15 个 workspace packages + 若干辅助目录 in `packages/` resolved via `workspace:*`
- **Lint/Format**: Biome (`biome.json`)。`bun run lint` / `bun run lint:fix` / `bun run format`
- **Defines**: 集中管理在 `scripts/defines.ts`。当前版本 `2.1.888`
- **CI**: GitHub Actions — `ci.yml`(构建+测试)、`release-rcs.yml`RCS 发布)、`update-contributors.yml`(自动更新贡献者)。
### Entry & Bootstrap
@@ -64,13 +92,16 @@ bun run docs:dev
- `--version` / `-v` — 零模块加载
- `--dump-system-prompt` — feature-gated (DUMP_SYSTEM_PROMPT)
- `--claude-in-chrome-mcp` / `--chrome-native-host`
- `--computer-use-mcp` — 独立 MCP server 模式
- `--daemon-worker=<kind>` — feature-gated (DAEMON)
- `remote-control` / `rc` / `bridge` — feature-gated (BRIDGE_MODE)
- `daemon` — feature-gated (DAEMON)
- `remote-control` / `rc` / `remote` / `sync` / `bridge` — feature-gated (BRIDGE_MODE)
- `daemon` [subcommand] — feature-gated (DAEMON)
- `ps` / `logs` / `attach` / `kill` / `--bg` — feature-gated (BG_SESSIONS)
- `new` / `list` / `reply` — Template job commands
- `environment-runner` / `self-hosted-runner` — BYOC runner
- `--tmux` + `--worktree` 组合
- 默认路径:加载 `main.tsx` 启动完整 CLI
2. **`src/main.tsx`** (~4680 行) — Commander.js CLI definition。注册大量 subcommands`mcp` (serve/add/remove/list...)、`server``ssh``open``auth``plugin``agents``auto-mode``doctor``update` 等。主 `.action()` 处理器负责权限、MCP、会话恢复、REPL/Headless 模式分发。
2. **`src/main.tsx`** (~6981 行) — Commander.js CLI definition。注册大量 subcommands`mcp` (serve/add/remove/list...)、`server``ssh``open``auth``plugin``agents``auto-mode``doctor``update` 等。主 `.action()` 处理器负责权限、MCP、会话恢复、REPL/Headless 模式分发。
3. **`src/entrypoints/init.ts`** — One-time initialization (telemetry, config, trust dialog)。
### Core Loop
@@ -82,21 +113,28 @@ bun run docs:dev
### API Layer
- **`src/services/api/claude.ts`** — Core API client. Builds request params (system prompt, messages, tools, betas), calls the Anthropic SDK streaming endpoint, and processes `BetaRawMessageStreamEvent` events.
- Supports multiple providers: Anthropic direct, AWS Bedrock, Google Vertex, Azure.
- Provider selection in `src/utils/model/providers.ts`.
- **7 providers**: `firstParty` (Anthropic direct), `bedrock` (AWS), `vertex` (Google Cloud), `foundry`, `openai`, `gemini`, `grok` (xAI)。
- Provider selection in `src/utils/model/providers.ts`。优先级modelType 参数 > 环境变量 > 默认 firstParty。
### Tool System
- **`src/Tool.ts`** — Tool interface definition (`Tool` type) and utilities (`findToolByName`, `toolMatchesName`).
- **`src/tools.ts`** — Tool registry. Assembles the tool list; some tools are conditionally loaded via `feature()` flags or `process.env.USER_TYPE`.
- **`src/tools/<ToolName>/`** — 61 个 tool 目录(如 BashTool, FileEditTool, GrepTool, AgentTool, WebFetchTool, LSPTool, MCPTool 等)。每个 tool 包含 `name``description``inputSchema``call()` 及可选的 React 渲染组件。
- **`src/tools/shared/`** — Tool 共享工具函数。
- **`src/tools.ts`** — Tool registry. Assembles the tool list; tools are imported from `@claude-code-best/builtin-tools` package. Some tools are conditionally loaded via `feature()` flags or `process.env.USER_TYPE`.
- **`packages/builtin-tools/src/tools/`** — 59 个子目录(含 shared/testing 等工具目录),通过 `@claude-code-best/builtin-tools` 包导出。主要分类:
- **文件操作**: FileEditTool, FileReadTool, FileWriteTool, GlobTool, GrepTool
- **Shell/执行**: BashTool, PowerShellTool, REPLTool
- **Agent 系统**: AgentTool, TaskCreateTool, TaskUpdateTool, TaskListTool, TaskGetTool
- **规划**: EnterPlanModeTool, ExitPlanModeV2Tool, VerifyPlanExecutionTool
- **Web/MCP**: WebFetchTool, WebSearchTool, MCPTool, McpAuthTool
- **调度**: CronCreateTool, CronDeleteTool, CronListTool
- **其他**: LSPTool, ConfigTool, SkillTool, EnterWorktreeTool, ExitWorktreeTool 等
- **`src/tools/shared/`** / **`packages/builtin-tools/src/tools/shared/`** — Tool 共享工具函数。
### UI Layer (Ink)
- **`src/ink.ts`** — Ink render wrapper with ThemeProvider injection.
- **`src/ink/`** — Custom Ink framework (forked/internal): custom reconciler, hooks (`useInput`, `useTerminalSize`, `useSearchHighlight`), virtual list rendering.
- **`src/components/`** — 大量 React 组件170+ 项),渲染于终端 Ink 环境中。关键组件:
- **`packages/@ant/ink/`** — Custom Ink frameworkforked/internal),包含 components、core、hooks、keybindings、theme、utils。注意不是 `src/ink/`
- **`src/components/`** — 149 个组件目录/文件,渲染于终端 Ink 环境中。关键组件:
- `App.tsx` — Root provider (AppState, Stats, FpsMetrics)
- `Messages.tsx` / `MessageRow.tsx` — Conversation message rendering
- `PromptInput/` — User input handling
@@ -112,10 +150,45 @@ bun run docs:dev
- **`src/state/selectors.ts`** — State selectors.
- **`src/bootstrap/state.ts`** — Module-level singletons for session-global state (session ID, CWD, project root, token counts, model overrides, client type, permission mode).
### Workspace Packages
| Package | 说明 |
|---------|------|
| `packages/@ant/ink/` | Forked Ink 框架components、hooks、keybindings、theme |
| `packages/@ant/computer-use-mcp/` | Computer Use MCP server截图/键鼠/剪贴板/应用管理) |
| `packages/@ant/computer-use-input/` | 键鼠模拟dispatcher + darwin/win32/linux backend |
| `packages/@ant/computer-use-swift/` | 截图 + 应用管理dispatcher + per-platform backend |
| `packages/@ant/claude-for-chrome-mcp/` | Chrome 浏览器控制(通过 `--chrome` 启用) |
| `packages/@ant/model-provider/` | Model provider 抽象层 |
| `packages/builtin-tools/` | 内置工具集60 个 tool 实现,通过 `@claude-code-best/builtin-tools` 导出) |
| `packages/agent-tools/` | Agent 工具集 |
| `packages/acp-link/` | ACP 代理服务器WebSocket → ACP agent 桥接) |
| `packages/cc-knowledge/` | Claude Code 知识库(非 workspace 包) |
| `packages/langfuse-dashboard/` | Langfuse 可观测性面板(非 workspace 包) |
| `packages/mcp-client/` | MCP 客户端库 |
| `packages/mcp-server/` | MCP 服务端库(非 workspace 包) |
| `packages/remote-control-server/` | 自托管 Remote Control ServerDocker 部署,含 Web UI— Web UI 已重构为 React + Vite + Radix UI支持 ACP agent 接入 |
| `packages/swarm/` | Swarm 解耦模块(非 workspace 包) |
| `packages/shell/` | Shell 抽象(非 workspace 包) |
| `packages/audio-capture-napi/` | 原生音频捕获(已恢复) |
| `packages/color-diff-napi/` | 颜色差异计算完整实现11 tests |
| `packages/image-processor-napi/` | 图像处理(已恢复) |
| `packages/modifiers-napi/` | 键盘修饰键检测macOS FFI 实现) |
| `packages/url-handler-napi/` | URL scheme 处理(环境变量 + CLI 参数读取) |
### Bridge / Remote Control
- **`src/bridge/`** (~35 files) — Remote Control / Bridge 模式。feature-gated by `BRIDGE_MODE`。包含 bridge API、会话管理、JWT 认证、消息传输、权限回调等。Entry: `bridgeMain.ts`
- **`src/bridge/`** — Remote Control / Bridge 模式。feature-gated by `BRIDGE_MODE`。包含 bridge API、会话管理、JWT 认证、消息传输、权限回调等。Entry: `bridgeMain.ts`
- **`packages/remote-control-server/`** — 自托管 RCS支持 Docker 部署,含 Web UI 控制面板React 19 + Vite + Radix UI。支持 ACP agent 通过 acp-link 接入ACP WebSocket handler、relay handler、SSE event stream。通过 `bun run rcs` 启动。
- CLI 快速路径: `claude remote-control` / `claude rc` / `claude bridge`
- 详见 `docs/features/remote-control-self-hosting.md`
### ACP Protocol (Agent Client Protocol)
- **`src/services/acp/`** — ACP agent 实现,包含 `agent.ts`AcpAgent 类)、`bridge.ts`Claude Code ↔ ACP 桥接)、`permissions.ts`(权限处理)、`entry.ts`(入口)。
- **`packages/acp-link/`** — ACP 代理服务器,将 WebSocket 客户端桥接到 ACP agent。提供 `acp-link` CLI 命令,支持自定义端口/HTTPS/认证/会话管理、RCS 集成REST 注册 + WS identify 两步流程、权限模式透传fallback: 客户端传值 > config > `ACP_PERMISSION_MODE` 环境变量)。
- ACP 权限管道改进:`createAcpCanUseTool` 统一权限流水线,`applySessionMode` 模式同步,`bypassPermissions` 可用性检测(非 root/sandbox 环境)。
- ACP Plan 可视化已支持 `session/update plan` 类型的消息展示PlanView 组件,含进度条/状态图标/优先级标签)。
### Daemon Mode
@@ -128,91 +201,70 @@ bun run docs:dev
### Feature Flag System
Feature flags control which functionality is enabled at runtime:
Feature flags control which functionality is enabled at runtime. 代码中统一通过 `import { feature } from 'bun:bundle'` 导入,调用 `feature('FLAG_NAME')` 返回 `boolean`
- **在代码中使用**: 统一通过 `import { feature } from 'bun:bundle'` 导入,调用 `feature('FLAG_NAME')` 返回 `boolean`。**不要**在 `cli.tsx` 或其他文件里自己定义 `feature` 函数或覆盖这个 import
- **启用方式**: 通过环境变量 `FEATURE_<FLAG_NAME>=1`。例如 `FEATURE_BUDDY=1 bun run dev` 启用 BUDDY 功能。
- **Dev 默认 features**: `BUDDY``TRANSCRIPT_CLASSIFIER``BRIDGE_MODE``AGENT_TRIGGERS_REMOTE``CHICAGO_MCP``VOICE_MODE`(见 `scripts/dev.ts`
- **Build 默认 features**: `AGENT_TRIGGERS_REMOTE``CHICAGO_MCP``VOICE_MODE`(见 `build.ts`)。
- **常见 flag**: `BUDDY`, `DAEMON`, `BRIDGE_MODE`, `BG_SESSIONS`, `PROACTIVE`, `KAIROS`, `VOICE_MODE`, `FORK_SUBAGENT`, `SSH_REMOTE`, `DIRECT_CONNECT`, `TEMPLATES`, `CHICAGO_MCP`, `BYOC_ENVIRONMENT_RUNNER`, `SELF_HOSTED_RUNNER`, `COORDINATOR_MODE`, `UDS_INBOX`, `LODESTONE`, `ABLATION_BASELINE` 等。
- **类型声明**: `src/types/internal-modules.d.ts` 中声明了 `bun:bundle` 模块的 `feature` 函数签名。
**启用方式**: 环境变量 `FEATURE_<FLAG_NAME>=1`。例如 `FEATURE_BUDDY=1 bun run dev`
**Build 默认 features**19 个,见 `build.ts`:
- 基础: `BUDDY`, `TRANSCRIPT_CLASSIFIER`, `BRIDGE_MODE`, `AGENT_TRIGGERS_REMOTE`, `CHICAGO_MCP`, `VOICE_MODE`
- 统计/缓存: `SHOT_STATS`, `PROMPT_CACHE_BREAK_DETECTION`, `TOKEN_BUDGET`
- P0 本地: `AGENT_TRIGGERS`, `ULTRATHINK`, `BUILTIN_EXPLORE_PLAN_AGENTS`, `LODESTONE`
- P1 API 依赖: `EXTRACT_MEMORIES`, `VERIFICATION_AGENT`, `KAIROS_BRIEF`, `AWAY_SUMMARY`, `ULTRAPLAN`
- P2: `DAEMON`
**Dev mode 默认**: 全部启用(见 `scripts/dev.ts`)。
**类型声明**: `src/types/internal-modules.d.ts` 中声明了 `bun:bundle` 模块的 `feature` 函数签名。
**新增功能的正确做法**: 保留 `import { feature } from 'bun:bundle'` + `feature('FLAG_NAME')` 的标准模式,在运行时通过环境变量或配置控制,不要绕过 feature flag 直接 import。
### Multi-API 兼容层
所有兼容层均采用流适配器模式:将第三方 API 格式转为 Anthropic 内部格式,下游代码完全不改。通过 `/login` 命令配置。
#### OpenAI 兼容层
通过 `CLAUDE_CODE_USE_OPENAI=1` 启用,支持 Ollama/DeepSeek/vLLM 等任意 OpenAI Chat Completions 协议端点。含 DeepSeek thinking mode 支持。
- **`src/services/api/openai/`** — client、消息/工具转换、流适配、模型映射
- 关键环境变量:`CLAUDE_CODE_USE_OPENAI``OPENAI_API_KEY``OPENAI_BASE_URL``OPENAI_MODEL`
#### Gemini 兼容层
通过 `CLAUDE_CODE_USE_GEMINI=1` 启用。独立环境变量体系。
- **`src/services/api/gemini/`** — client、模型映射、类型定义
- 关键环境变量:`GEMINI_API_KEY`(必填)、`GEMINI_MODEL`(直接指定)、`GEMINI_DEFAULT_SONNET_MODEL`/`GEMINI_DEFAULT_OPUS_MODEL`(按能力映射)
- 模型映射优先级:`GEMINI_MODEL` > `GEMINI_DEFAULT_*_MODEL` > `ANTHROPIC_DEFAULT_*_MODEL`(已废弃) > 原样返回
#### Grok 兼容层
通过 `CLAUDE_CODE_USE_GROK=1` 启用。自定义模型映射支持 xAI Grok API。
- **`src/services/api/grok/`** — client、模型映射
详见各兼容层的 docs 文档。
### 穷鬼模式Budget Mode
- 通过 `/poor` 命令切换,持久化到 `settings.json`
- 启用后跳过 `extract_memories``prompt_suggestion``verification_agent`,显著减少 token 消耗。
- 实现在 `src/commands/poor/poorMode.ts`
### Stubbed/Deleted Modules
| Module | Status |
|--------|--------|
| Computer Use (`@ant/*`) | Restored — `computer-use-swift`, `computer-use-input`, `computer-use-mcp`, `claude-for-chrome-mcp` 均有完整实现,macOS + Windows 可用,Linux 后端待完成 |
| `*-napi` packages | `audio-capture-napi``image-processor-napi` 已恢复实现`color-diff-napi` 完整实现`url-handler-napi``modifiers-napi` 仍为 stub |
| Voice Mode | Restored — `src/voice/``src/hooks/useVoiceIntegration.tsx``src/services/voiceStreamSTT.ts` 等,Push-to-Talk 语音输入(需 Anthropic OAuth |
| OpenAI 兼容层 | Restored`src/services/api/openai/`,支持 Ollama/DeepSeek/vLLM 等任意 OpenAI 协议端点,通过 `CLAUDE_CODE_USE_OPENAI=1` 启用 |
| Computer Use (`@ant/*`) | Restored — macOS + Windows + Linux后端完整度不一) |
| `*-napi` packages | 全部已恢复/实现:`audio-capture-napi``image-processor-napi` 已恢复;`color-diff-napi` 完整;`modifiers-napi`macOS FFI`url-handler-napi`(环境变量+CLI |
| Voice Mode | Restored — Push-to-Talk 语音输入(需 Anthropic OAuth |
| OpenAI/Gemini/Grok 兼容层 | Restored |
| Remote Control Server | Restored — 自托管 RCS + Web UI |
| Analytics / GrowthBook / Sentry | Empty implementations |
| Magic Docs / LSP Server | Removed |
| Plugins / Marketplace | Removed |
| Magic Docs / LSP Server | Restored — Magic Docs 自动更新 + LSP 服务器管理器 |
| Plugins / Marketplace | Restored — 插件安装/卸载/启用/禁用 + Marketplace 浏览 |
| MCP OAuth | Simplified |
### Computer Use
Feature flag `CHICAGO_MCP`dev/build 默认启用。实现跨平台屏幕操控macOS + Windows 可用Linux 待完成)。
- **`packages/@ant/computer-use-mcp/`** — MCP server注册截图/键鼠/剪贴板/应用管理工具
- **`packages/@ant/computer-use-input/`** — 键鼠模拟dispatcher + per-platform backend`backends/darwin.ts``win32.ts``linux.ts`
- **`packages/@ant/computer-use-swift/`** — 截图 + 应用管理,同样 dispatcher + per-platform backend
- **`packages/@ant/claude-for-chrome-mcp/`** — Chrome 浏览器控制(独立于 Computer Use通过 `--chrome` CLI 参数启用)
详见 `docs/features/computer-use.md`
### Voice Mode
Feature flag `VOICE_MODE`dev/build 默认启用。Push-to-Talk 语音输入,音频通过 WebSocket 流式传输到 Anthropic STTNova 3。需要 Anthropic OAuth非 API key
- **`src/voice/voiceModeEnabled.ts`** — 三层门控feature flag + GrowthBook + OAuth auth
- **`src/hooks/useVoice.ts`** — React hook 管理录音状态和 WebSocket 连接
- **`src/services/voiceStreamSTT.ts`** — STT WebSocket 流式传输
详见 `docs/features/voice-mode.md`
### OpenAI 兼容层
通过 `CLAUDE_CODE_USE_OPENAI=1` 环境变量启用,支持任意 OpenAI Chat Completions 协议端点Ollama、DeepSeek、vLLM 等)。流适配器模式:在 `queryModel()` 中将 Anthropic 格式请求转为 OpenAI 格式,再将 SSE 流转换回 `BetaRawMessageStreamEvent`,下游代码完全不改。
- **`src/services/api/openai/`** — client、消息/工具转换、流适配、模型映射
- **`src/utils/model/providers.ts`** — 添加 `'openai'` provider 类型(最高优先级)
关键环境变量:`CLAUDE_CODE_USE_OPENAI``OPENAI_API_KEY``OPENAI_BASE_URL``OPENAI_MODEL``OPENAI_DEFAULT_OPUS_MODEL``OPENAI_DEFAULT_SONNET_MODEL``OPENAI_DEFAULT_HAIKU_MODEL`。详见 `docs/plans/openai-compatibility.md`
### Gemini 兼容层
通过 `CLAUDE_CODE_USE_GEMINI=1` 环境变量或 `modelType: "gemini"` 设置启用,支持 Google Gemini API。独立的环境变量体系不与 OpenAI 或 Anthropic 配置混杂。
- **`src/services/api/gemini/`** — client、模型映射、类型定义
- **`src/utils/model/providers.ts`** — 添加 `'gemini'` provider 类型
- **`src/utils/managedEnvConstants.ts`** — Gemini 专用的 managed env vars
关键环境变量:
- `CLAUDE_CODE_USE_GEMINI` - 启用 Gemini provider
- `GEMINI_API_KEY` - API 密钥(必填)
- `GEMINI_BASE_URL` - API 端点(可选,默认 `https://generativelanguage.googleapis.com/v1beta`
- `GEMINI_MODEL` - 直接指定模型(最高优先级)
- `GEMINI_DEFAULT_HAIKU_MODEL` / `GEMINI_DEFAULT_SONNET_MODEL` / `GEMINI_DEFAULT_OPUS_MODEL` - 按能力级别映射
- `GEMINI_DEFAULT_HAIKU_MODEL_NAME` / `DESCRIPTION` / `SUPPORTED_CAPABILITIES` - 显示名称和描述
- `GEMINI_SMALL_FAST_MODEL` - 快速任务使用的模型(可选)
模型映射优先级(`src/services/api/gemini/modelMapping.ts`
1. `GEMINI_MODEL` - 直接覆盖
2. `GEMINI_DEFAULT_*_MODEL` - 独立配置(推荐)
3. `ANTHROPIC_DEFAULT_*_MODEL` - 向后兼容 fallback已废弃
4. 原样返回 Anthropic 模型名
使用示例:
```bash
export CLAUDE_CODE_USE_GEMINI=1
export GEMINI_API_KEY="your-api-key"
export GEMINI_DEFAULT_SONNET_MODEL="gemini-2.5-flash"
export GEMINI_DEFAULT_OPUS_MODEL="gemini-2.5-pro"
```
### Key Type Files
- **`src/types/global.d.ts`** — Declares `MACRO`, `BUILD_TARGET`, `BUILD_ENV` and internal Anthropic-only identifiers.
@@ -227,16 +279,81 @@ export GEMINI_DEFAULT_OPUS_MODEL="gemini-2.5-pro"
- **集成测试**: `tests/integration/` — 4 个文件cli-arguments, context-build, message-pipeline, tool-chain
- **共享 mock/fixture**: `tests/mocks/`api-responses, file-system, fixtures/
- **命名**: `describe("functionName")` + `test("behavior description")`,英文
- **Mock 模式**: 对重依赖模块使用 `mock.module()` + `await import()` 解锁(必须内联在测试文件中,不能从共享 helper 导入
- **当前状态**: ~1623 tests / 114 files (110 unit + 4 integration) / 0 fail详见 `docs/testing-spec.md`
- **包测试**: `packages/` 下各包也有独立测试(如 `color-diff-napi` 11 tests
### Mock 使用规范
**只 mock 有副作用的依赖链,不 mock 纯函数/纯数据模块。**
被迫 mock 的根源:`log.ts` / `debug.ts``bootstrap/state.ts`(模块级 `realpathSync` / `randomUUID` 副作用)。必须 mock 的模块:`log.ts``debug.ts``bun:bundle``settings/settings.js``config.ts``auth.ts`、第三方网络库。
**`log.ts``debug.ts` 使用共享 mock**`tests/mocks/log.ts` / `tests/mocks/debug.ts`),不要在测试文件中内联 mock 定义。使用方式:
```ts
import { logMock } from "../../../tests/mocks/log";
mock.module("src/utils/log.ts", logMock);
import { debugMock } from "../../../../tests/mocks/debug";
mock.module("src/utils/debug.ts", debugMock);
```
源文件导出变更时只需更新 `tests/mocks/` 下的对应文件,不需要逐个修改测试。
不要 mock纯函数模块`errors.ts``stringUtils.js`、mock 值与真实实现相同的模块、mock 路径与实际 import 不匹配的模块。
路径规则:统一用 `.ts` 扩展名 + `src/*` 别名路径,禁止双重 mock 同一模块。
### 类型检查
项目使用 TypeScript strict 模式,**tsc 必须零错误**。每次修改后运行:
```bash
bun run typecheck
```
**类型规范**
- 生产代码禁止 `as any`;测试文件中 mock 数据可用 `as any`
- 类型不匹配优先用 `as unknown as SpecificType` 双重断言,或补充 interface
- 未知结构对象用 `Record<string, unknown>` 替代 `any`
- 联合类型用类型守卫type guard收窄不要强转
- `msg.request` 属性访问:`const req = msg.request as Record<string, unknown>`
- Ink `color` prop`as keyof Theme` 而非 `as any`
## Working with This Codebase
- **Don't try to fix all tsc errors** — they're from decompilation and don't affect runtime.
- **tsc must pass** — `bun run typecheck` 必须零错误,任何修改都不能引入新的类型错误。
- **Feature flags** — 默认全部关闭(`feature()` 返回 `false`。Dev/build 各有自己的默认启用列表。不要在 `cli.tsx` 中重定义 `feature` 函数。
- **React Compiler output** — Components have decompiled memoization boilerplate (`const $ = _c(N)`). This is normal.
- **`bun:bundle` import** — `import { feature } from 'bun:bundle'` 是 Bun 内置模块,由运行时/构建器解析。不要用自定义函数替代它。
- **`bun:bundle` import** — `import { feature } from 'bun:bundle'` 是 Bun 内置模块,由运行时/构建器解析。不要用自定义函数替代它。**`feature()` 只能直接用在 `if` 语句或三元表达式的条件位置**Bun 编译器限制),不能赋值给变量、不能放在箭头函数体里、不能作为 `&&` 链的一部分。正确:`if (feature('X')) {}``feature('X') ? a : b`
- **`src/` path alias** — tsconfig maps `src/*` to `./src/*`. Imports like `import { ... } from 'src/utils/...'` are valid.
- **MACRO defines** — 集中管理在 `scripts/defines.ts`。Dev mode 通过 `bun -d` 注入build 通过 `Bun.build({ define })` 注入。修改版本号等常量只改这个文件。
- **构建产物兼容 Node.js** — `build.ts` 会自动后处理 `import.meta.require`,产物可直接用 `node dist/cli.js` 运行。
- **Biome 配置** — 大量 lint 规则被关闭decompiled 代码不适合严格 lint`.tsx` 文件用 120 行宽 + 强制分号;其他文件 80 行宽 + 按需分号。
- **Ink 框架在 `packages/@ant/ink/`** — 不是 `src/ink/`该目录不存在。Ink 相关的组件、hooks、keybindings 都在 packages 中。
- **Provider 优先级** — `modelType` 参数 > 环境变量 > 默认 `firstParty`。新增 provider 需在 `src/utils/model/providers.ts` 注册。
## Design Context
Impeccable 设计上下文保存在 `.impeccable.md` 中。设计 Web UIRCS 控制面板、文档站、着陆页)时必须参考该文件。
### 核心设计原则
1. **Considered over clever** — 每个设计选择都应感觉有意为之,而非追逐潮流
2. **Warmth through subtlety** — 通过橙色色调的中性色、留白布局、有温度的文案来传达温暖
3. **Density with clarity** — 技术用户需要信息密度,但不能混乱
4. **Community voice** — 设计应感觉是由使用者创造的,而非遥远的设计团队
5. **Anthropic's shadow** — 遵循 Anthropic 的设计直觉:干净的布局、充足的间距、温暖的色温
### 品牌色
- 主色Claude Orange `#D77757`terra cotta
- 辅色Claude Blue `#5769F7`
- 暗色模式使用温暖的深色表面(非冷蓝黑色)
### 目标用户
技术团队/企业,在专业工作流中使用 AI 辅助编程。友好的开源社区氛围,非企业 SaaS 风格。
### 视觉参考
Anthropic 公司的设计风格 — 干净、考究、温暖的底色。大量留白,以排版为核心。避免 AI 产品常见的设计套路(渐变文字、玻璃态、霓虹色)。

View File

@@ -1,5 +1,194 @@
# DEV-LOG
## /poor 省流模式 (2026-04-11)
新增 `/poor` 命令toggle 关闭 `extract_memories``prompt_suggestion`,省 token。
- 新增 `POOR` feature flagbuild.ts + dev.ts
- `src/commands/poor/` — 命令定义 + toggle 实现 + 状态管理
- `src/query/stopHooks.ts` — POOR 模式激活时跳过 extract_memories 和 prompt_suggestion
---
## Pipe IPC + LAN Pipes + Monitor Tool + 工具恢复 (2026-04-08 ~ 2026-04-11)
**分支**: `feat/pr-package-adapt`
### 背景
从 decompiled 代码恢复大量 stub 为完整实现,同时新增 LAN 跨机器通讯能力。本次 PR 覆盖Pipe IPC 系统、LAN Pipes、Monitor Tool、20+ 工具/组件<E7BB84><E4BBB6><EFBFBD>复、REPL hook 架构重构。
### 实现
#### 1. PipeServer TCP 双模式(`src/utils/pipeTransport.ts`
从原始的纯 UDS 服务器扩展为 UDS + TCP 双模式:
- 提取 `setupSocket()` 共享方法UDS 和 TCP 的 socket 处理逻辑完全一致
- `start(options?: PipeServerOptions)` 新增可选参数 `{ enableTcp, tcpPort }`
- 内部维护两个 `net.Server`UDS + TCP共享同一组 `clients: Set<Socket>``handlers`
- TCP server 绑定 `0.0.0.0` + 动态端口port=0 由 OS 分配)
- `tcpAddress` getter 暴露 TCP 端口信息
- `close()` 同时关闭两个 server
- 新增类型:`PipeTransportMode``TcpEndpoint``PipeServerOptions`
PipeClient 对应扩展:
- 构造函数新增可选 `TcpEndpoint` 参数
- `connect()` 根据是否有 TCP endpoint 分派到 `connectTcp()``connectUds()`
- TCP 连接不需要文件存在轮询,直接建立连接
#### 2. LAN Beacon — UDP Multicast 发现(`src/utils/lanBeacon.ts`,新文件)
零配置局域网 peer 发现:
- **协议**UDP multicast 组 `224.0.71.67`"CC" ASCII端口 `7101`TTL=1
- **Announce 包**JSON `{ proto, pipeName, machineId, hostname, ip, tcpPort, role, ts }`
- **广播间隔**3 秒,首次在 socket bind 完成后立即发送
- **Peer 超时**15 秒无 announce 视为 lost
- **事件**`peer-discovered``peer-lost`
- **存储**module-level singleton `getLanBeacon()`/`setLanBeacon()`,不挂在 Zustand state 上
关键修复:
- `addMembership(group, localIp)` + `setMulticastInterface(localIp)` 指定 LAN 网卡,解决 Windows 上 WSL/Docker 虚拟网卡劫持 multicast 的问题
- announce/cleanup 定时器移入 `bind()` 回调内,修复 socket 未就绪时发送的竞态
#### 3. Registry 扩展(`src/utils/pipeRegistry.ts`
- `PipeRegistryEntry` 新增 `tcpPort?``lanVisible?` 字段
- `mergeWithLanPeers(registry, lanPeers)` 合并本地 registry 和 LAN beacon peers本地优先
#### 4. Peer Address 扩展(`src/utils/peerAddress.ts`
- `parseAddress()` 新增 `tcp` scheme`tcp:192.168.1.20:7100`
- 新增 `parseTcpTarget()` 解析 `host:port` 字符串
#### 5. REPL 集成(`src/screens/REPL.tsx`
三个阶段的改动:
**Bootstrap**`createPipeServer()` 时根据 `feature('LAN_PIPES')` 传入 TCP 选项 → 启动 `LanBeacon` → 注册 entry 携带 tcpPort
**Heartbeat**(每 5 秒):
- `refreshDiscoveredPipes()` 同时包含本地 subs 和 LAN beacon peers防止 LAN peer 状态被覆盖
- auto-attach 循环统一遍历本地 subs + LAN peersLAN peers 通过 TCP endpoint 连接
- cleanup 检查 LAN beacon peers 列表,避免误删存活的 LAN 连接
- attach 请求携带 `machineId`,接收方区分 LAN peer不要求 sub 角色)
**Cleanup**:通过 `getLanBeacon()` 获取并 `stop()``setLanBeacon(null)` 清除
#### 6. 命令更新
- `/pipes``src/commands/pipes/pipes.ts`):显示 `[LAN]` 标记的远端实例
- `/attach``src/commands/attach/attach.ts`):自动查找 LAN beacon 获取 TCP endpoint
- `SendMessageTool``src/tools/SendMessageTool/SendMessageTool.ts`):支持 `tcp:` scheme权限检查要求用户确认
#### 7. Feature Flag
`LAN_PIPES` — 在 `scripts/dev.ts``build.ts` 的默认 features 列表中启用。所有 LAN 代码路径均通过 `feature('LAN_PIPES')` 门控。
#### 8. Pipe IPC 基础系统(`UDS_INBOX` feature
- `PipeServer`/`PipeClient`UDS 传输NDJSON 协议(共享 `ndjsonFramer.ts`
- `PipeRegistry`machineId 绑定的角色分配main/sub文件锁并行探测
- Master/slave attach 流程、prompt 转发、permission 转发
- Heartbeat 生命周期5s 间隔stale entry 清理busy flag 防重叠)
- 命令:`/pipes``/attach``/detach``/send``/claim-main``/pipe-status`
#### 9. Monitor Tool`MONITOR_TOOL` feature
- `MonitorTool`AI 可调用的后台 shell 监控工具
- `/monitor` 命令用户快捷入口Windows 兼容watch → PowerShell 循环)
- `MonitorMcpTask`:从 stub 恢复完整生命周期register/complete/fail/kill
- `MonitorPermissionRequest`React 权限确认 UI
- `MonitorMcpDetailDialog`Shift+Down 详情面板
#### 10. 工具恢复stub → 实现)
- SnipTool、SleepTool、ListPeersTool、SendUserFileTool
- WebBrowserTool、SubscribePRTool、PushNotificationTool
- CtxInspectTool、TerminalCaptureTool、WorkflowTool
- REPLTool (.js → .ts)、VerifyPlanExecutionTool (.js → .ts)、SuggestBackgroundPRTool (.js → .ts)
- 组件 .ts → .tsx 重写MonitorPermissionRequest、ReviewArtifactPermissionRequest、MonitorMcpDetailDialog、WorkflowDetailDialog、WorkflowPermissionRequest
#### 11. REPL Hook 架构重构
从 REPL.tsx 提取 ~830 行 Pipe IPC 内联代码为 4 个独立 hook
| Hook | 行数 | 职责 |
|------|------|------|
| `usePipeIpc` | 623 | 生命周期bootstrap、handlers、heartbeat、cleanup |
| `usePipeRelay` | 38 | slave→master 消息回传(通过 `setPipeRelay` singleton |
| `usePipePermissionForward` | 159 | 权限请求转发 + 流式通知显示 |
| `usePipeRouter` | 130 | selected pipe 输入路由 + role/IP 标签显示 |
共享工具:`ndjsonFramer.ts` 替换 3 份重复的 NDJSON 解析。
#### 12. Feature Flags 新增启用
UDS_INBOX、LAN_PIPES、MONITOR_TOOL、FORK_SUBAGENT、KAIROS、COORDINATOR_MODE、WORKFLOW_SCRIPTS、HISTORY_SNIP、CONTEXT_COLLAPSE
### 踩坑记录
1. **Multicast 绑错网卡**Windows 上 `addMembership(group)` 不指定本地接口时,默认绑到 WSL/Docker 虚拟网卡(`172.19.112.1`LAN 上的真实机器收不到。必须 `addMembership(group, localIp)` + `setMulticastInterface(localIp)`
2. **Beacon ref 丢失**:最初用 `(store.getState() as any)._lanBeacon` 挂载 beacon 引用,但 Zustand `setState` 展开 `prev` 时不包含 `_lanBeacon` 属性,下次读取就是 `undefined`。改为 module-level singleton 解决。
3. **Heartbeat 清洗 LAN 连接**`refreshDiscoveredPipes()` 每 5 秒用仅含本地 registry subs 的列表完全覆盖 `discoveredPipes` + `selectedPipes`LAN peer 的发现和选择状态被持续清空。必须在 refresh 中同时包含 beacon peers。
4. **Heartbeat cleanup 误删**`!aliveSubNames.has(slaveName)` 导致 LAN peer不在本地 registry被判定为死连接每 5 秒清除一次。需要同时检查 beacon peers 列表。
5. **跨机器 attach 被拒**:两台机器各自为 `main`attach handler 硬编码 `role !== 'sub'` 拒绝。通过 attach_request 携带 `machineId`,接收方对不同 machineId 的请求放行。
6. **`feature()` 使用约束**Bun 的 `feature()` 是编译时常量,只能在 `if` 语句或三元条件中直接使用,不能赋值给变量(如 `const x = feature('...')`),否则构建报错。
### 已知限制
- TCP 无认证:同 LAN 内任何设备知道端口号即可连接
- JSON.parse 无 schema 验证code review 建议增加 Zod 校验
- Beacon 明文广播 IP/hostname/machineId建议后续 hash 处理
- `getLocalIp()` 可能返回 VPN 地址:多网卡环境需更精确的接口选择
### 测试
- `src/utils/__tests__/lanBeacon.test.ts`7 个测试mock dgram
- `src/utils/__tests__/peerAddress.test.ts`8 个测试(纯函数)
- 全量2190 pass / 0 fail
### 防火墙配置
**Windows**(管理员 PowerShell
```powershell
New-NetFirewallRule -DisplayName "Claude Code LAN Beacon (UDP)" -Direction Inbound -Protocol UDP -LocalPort 7101 -Action Allow -Profile Private
New-NetFirewallRule -DisplayName "Claude Code LAN Pipes (TCP)" -Direction Inbound -Protocol TCP -LocalPort 1024-65535 -Program (Get-Command bun).Source -Action Allow -Profile Private
New-NetFirewallRule -DisplayName "Claude Code LAN Beacon Out (UDP)" -Direction Outbound -Protocol UDP -RemotePort 7101 -Action Allow -Profile Private
```
**macOS**(首次运行时系统会弹出"允许接受传入连接"对话框,点击允许即可。手动放行):
```bash
# 如果使用 pf <20><><EFBFBD>火墙添加规则
echo "pass in proto udp from any to any port 7101" | sudo pfctl -ef -
# 或<><E68896>接在 System Settings → Network → Firewall 中允许 bun 进程
```
**Linux**firewalld
```bash
sudo firewall-cmd --zone=trusted --add-port=7101/udp --permanent
sudo firewall-cmd --zone=trusted --add-port=1024-65535/tcp --permanent
sudo firewall-cmd --reload
```
**Linux**iptables
```bash
sudo iptables -A INPUT -p udp --dport 7101 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 1024:65535 -m owner --uid-owner $(id -u) -j ACCEPT
sudo iptables-save | sudo tee /etc/iptables/rules.v4
```
**通用验证**:确认网络为局域网(非公共 WiFi<EFBC8C><E8B7AF><EFBFBD>器未开启 AP 隔离。
---
## Daemon + Remote Control Server 还原 (2026-04-07)
**分支**: `feat/daemon-remote-control-server`

132
README.md
View File

@@ -6,37 +6,53 @@
[![GitHub License](https://img.shields.io/github/license/claude-code-best/claude-code?style=flat-square)](https://github.com/claude-code-best/claude-code/blob/main/LICENSE)
[![Last Commit](https://img.shields.io/github/last-commit/claude-code-best/claude-code?style=flat-square&color=blue)](https://github.com/claude-code-best/claude-code/commits/main)
[![Bun](https://img.shields.io/badge/runtime-Bun-black?style=flat-square&logo=bun)](https://bun.sh/)
[![Discord](https://img.shields.io/badge/Discord-Join-5865F2?style=flat-square&logo=discord)](https://discord.gg/qZU6zS7Q)
[![Discord](https://img.shields.io/badge/Discord-Join-5865F2?style=flat-square&logo=discord)](https://discord.gg/uApuzJWGKX)
> Which Claude do you like? The open source one is the best.
牢 A (Anthropic) 官方 [Claude Code](https://docs.anthropic.com/en/docs/claude-code) CLI 工具的源码反编译/逆向还原项目。目标是将 Claude Code 大部分功能及工程化能力复现 (问就是老佛爷已经付过钱了)。虽然很难绷, 但是它叫做 CCB(踩踩背)...
牢 A (Anthropic) 官方 [Claude Code](https://docs.anthropic.com/en/docs/claude-code) CLI 工具的源码反编译/逆向还原项目。目标是将 Claude Code 大部分功能及工程化能力复现 (问就是老佛爷已经付过钱了)。虽然很难绷, 但是它叫做 CCB(踩踩背)... 而且, 我们实现了企业版或者需要登陆 Claude 账号才能使用的特性, 实现技术普惠
[文档在这里, 支持投稿 PR](https://ccb.agent-aura.top/) | [留影文档在这里](./Friends.md) | [Discord 群组](https://discord.gg/qZU6zS7Q)
> 我们将会在五一期间进行整个代码仓库的 lint 规范化, 这个期间提交的 PR 可能会有非常多的冲突, 所以大的功能请尽量在这之前提交哈
- ✅ [x] V4 — 测试补全、[Buddy](https://ccb.agent-aura.top/docs/features/buddy)、[Auto Mode](https://ccb.agent-aura.top/docs/safety/auto-mode)、环境变量 Feature 开关
- ✅ [x] V5 — [Sentry](https://ccb.agent-aura.top/docs/internals/sentry-setup) / [GrowthBook](https://ccb.agent-aura.top/docs/internals/growthbook-adapter) 企业监控、[自定义 Login](https://ccb.agent-aura.top/docs/features/custom-platform-login)、[OpenAI 兼容](https://ccb.agent-aura.top/docs/plans/openai-compatibility)、[Web Search](https://ccb.agent-aura.top/docs/features/web-browser-tool)、[Computer Use](https://ccb.agent-aura.top/docs/features/computer-use) / [Chrome Use](https://ccb.agent-aura.top/docs/features/claude-in-chrome-mcp)、[Voice Mode](https://ccb.agent-aura.top/docs/features/voice-mode)、[Bridge Mode](https://ccb.agent-aura.top/docs/features/bridge-mode)、[/dream 记忆整理](https://ccb.agent-aura.top/docs/features/auto-dream)
- 🔮 [ ] V6 — 大规模重构石山代码全面模块分包全新分支main 封存为历史版本)
[文档在这里, 支持投稿 PR](https://ccb.agent-aura.top/) | [留影文档在这里](./Friends.md) | [Discord 群组](https://discord.gg/uApuzJWGKX)
| 特性 | 说明 | 文档 |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **Claude 群控技术** | Pipe IPC 多实例协作:同机 main/sub 自动编排 + LAN 跨机器零配置发现与通讯,`/pipes` 选择面板 + `Shift+↓` 交互 + 消息广播路由 | [Pipe IPC](https://ccb.agent-aura.top/docs/features/uds-inbox) / [LAN](https://ccb.agent-aura.top/docs/features/lan-pipes) |
| **ACP 协议一等一支持** | 支持接入 Zed、Cursor 等 IDE支持会话恢复、Skills、权限桥接 | [文档](https://ccb.agent-aura.top/docs/features/acp-zed) |
| **Remote Control 私有部署** | Docker 自托管远程界面, 可以手机上看 CC | [文档](https://ccb.agent-aura.top/docs/features/remote-control-self-hosting) |
| **Langfuse 监控** | 企业级 Agent 监控, 可以清晰看到每次 agent loop 细节, 可以一键转化为数据集 | [文档](https://ccb.agent-aura.top/docs/features/langfuse-monitoring) |
| **Web Search** | 内置网页搜索工具, 支持 bing 和 brave 搜索 | [文档](https://ccb.agent-aura.top/docs/features/web-browser-tool) |
| **Poor Mode** | 穷鬼模式,关闭记忆提取和键入建议,大幅度减少并发请求 | /poor 可以开关 |
| **Channels 频道通知** | MCP 服务器推送外部消息到会话(飞书/Slack/Discord/微信等),`--channels plugin:name@marketplace` 启用 | [文档](https://ccb.agent-aura.top/docs/features/channels) |
| **自定义模型供应商** | OpenAI/Anthropic/Gemini/Grok 兼容 (`/login`) | [文档](https://ccb.agent-aura.top/docs/features/all-features-guide) |
| Voice Mode | 语音输入,支持豆包语言输入(`/voice doubao` | [文档](https://ccb.agent-aura.top/docs/features/voice-mode) |
| Computer Use | 屏幕截图、键鼠控制 | [文档](https://ccb.agent-aura.top/docs/features/computer-use) |
| Chrome Use | 浏览器自动化、表单填写、数据抓取 | [自托管](https://ccb.agent-aura.top/docs/features/chrome-use-mcp) [原生版](https://ccb.agent-aura.top/docs/features/claude-in-chrome-mcp) |
| Sentry | 企业级错误追踪 | [文档](https://ccb.agent-aura.top/docs/internals/sentry-setup) |
| GrowthBook | 企业级特性开关 | [文档](https://ccb.agent-aura.top/docs/internals/growthbook-adapter) |
| /dream 记忆整理 | 自动整理和优化记忆文件 | [文档](https://ccb.agent-aura.top/docs/features/auto-dream) |
- 🚀 [想要启动项目](#快速开始源码版)
- 🐛 [想要调试项目](#vs-code-调试)
- 📖 [想要学习项目](#teach-me-学习项目)
## ⚡ 快速开始(安装版)
不用克隆仓库, 从 NPM 下载后, 直接使用
```sh
bun i -g claude-code-best
bun pm -g trust claude-code-best
ccb # 直接打开 claude code
```
npm i -g claude-code-best
⚠️ 国内对 github 网络较差的, 需要先设置这个环境变量
# bun 安装比较多问题, 推荐 npm 装
# bun i -g claude-code-best
# bun pm -g trust claude-code-best @claude-code-best/mcp-chrome-bridge
```bash
DEFAULT_RELEASE_BASE=https://ghproxy.net/https://github.com/microsoft/ripgrep-prebuilt/releases/download/v15.0.1
ccb # 以 nodejs 打开 claude code
ccb-bun # 以 bun 形态打开
ccb update # 更新到最新版本
CLAUDE_BRIDGE_BASE_URL=https://remote-control.claude-code-best.win/ CLAUDE_BRIDGE_OAUTH_TOKEN=test-my-key ccb --remote-control # 我们有自部署的远程控制
```
## ⚡ 快速开始(源码版)
@@ -46,20 +62,69 @@ DEFAULT_RELEASE_BASE=https://ghproxy.net/https://github.com/microsoft/ripgrep-pr
一定要最新版本的 bun 啊, 不然一堆奇奇怪怪的 BUG!!! bun upgrade!!!
- 📦 [Bun](https://bun.sh/) >= 1.3.11
**安装 Bun**
```bash
# Linux 和 macOS
curl -fsSL https://bun.sh/install | bash
# Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"
```
**安装后的操作:**
1. **让当前终端识别 `bun` 命令**
安装脚本会把 `~/.bun/bin` 写入对应的 shell 配置文件。macOS 默认 zsh 环境通常会看到:
```text
Added "~/.bun/bin" to $PATH in "~/.zshrc"
```
可以按安装脚本提示重启当前 shell
```bash
exec /bin/zsh
```
如果你使用 bash重新加载 bash 配置:
```bash
source ~/.bashrc
```
Windows PowerShell 用户关闭并重新打开 PowerShell 即可。
2. **验证 Bun 是否可用**
```bash
bun --help
bun --version
```
3. **如果已经安装过 Bun更新到最新版本**
```bash
bun upgrade
```
- ⚙️ 常规的配置 CC 的方式, 各大提供商都有自己的配置方式
### 📍 命令执行位置
- 安装或检查 Bun 的命令可以在任意目录执行:
`curl -fsSL https://bun.sh/install | bash`、`bun --help`、`bun --version`、`bun upgrade`
- 安装本项目依赖、启动开发模式、构建项目时,必须先进入本仓库根目录,也就是包含 `package.json` 的目录。
### 📥 安装
```bash
cd /path/to/claude-code
bun install
```
⚠️ 国内对 github 网络较差的,可以使用这个环境变量
```bash
DEFAULT_RELEASE_BASE=https://ghproxy.net/https://github.com/microsoft/ripgrep-prebuilt/releases/download/v15.0.1
```
### ▶️ 运行
```bash
@@ -83,17 +148,17 @@ bun run build
需要填写的字段:
| 📌 字段 | 📝 说明 | 💡 示例 |
|------|------|------|
| Base URL | API 服务地址 | `https://api.example.com/v1` |
| API Key | 认证密钥 | `sk-xxx` |
| Haiku Model | 快速模型 ID | `claude-haiku-4-5-20251001` |
| Sonnet Model | 均衡模型 ID | `claude-sonnet-4-6` |
| Opus Model | 高性能模型 ID | `claude-opus-4-6` |
| 📌 字段 | 📝 说明 | 💡 示例 |
| ------------ | ------------- | ---------------------------- |
| Base URL | API 服务地址 | `https://api.example.com/v1` |
| API Key | 认证密钥 | `sk-xxx` |
| Haiku Model | 快速模型 ID | `claude-haiku-4-5-20251001` |
| Sonnet Model | 均衡模型 ID | `claude-sonnet-4-6` |
| Opus Model | 高性能模型 ID | `claude-opus-4-6` |
- ⌨️ **Tab / Shift+Tab** 切换字段,**Enter** 确认并跳到下一个,最后一个字段按 Enter 保存
> 支持所有 Anthropic API 兼容服务(如 OpenRouter、AWS Bedrock 代理等),只要接口兼容 Messages API 即可。
## Feature Flags
@@ -113,16 +178,17 @@ TUI (REPL) 模式需要真实终端,无法直接通过 VS Code launch 启动
### 步骤
1. **终端启动 inspect 服务**
```bash
bun run dev:inspect
```
会输出类似 `ws://localhost:8888/xxxxxxxx` 的地址。
会输出类似 `ws://localhost:8888/xxxxxxxx` 的地址。
2. **VS Code 附着调试器**
- 在 `src/` 文件中打断点
- F5 → 选择 **"Attach to Bun (TUI debug)"**
## Teach Me 学习项目
我们新加了一个 teach-me skills, 通过问答式引导帮你理解这个项目的任何模块。(调整 [sigma skill 而来](https://github.com/sanyuan0704/sanyuan-skills))
@@ -149,7 +215,7 @@ TUI (REPL) 模式需要真实终端,无法直接通过 VS Code launch 启动
## 相关文档及网站
- **在线文档Mintlify**: [ccb.agent-aura.top](https://ccb.agent-aura.top/) — 文档源码位于 [`docs/`](docs/) 目录,欢迎投稿 PR
- **DeepWiki**: <https://deepwiki.com/claude-code-best/claude-code>
- **DeepWiki**: [https://deepwiki.com/claude-code-best/claude-code](https://deepwiki.com/claude-code-best/claude-code)
## Contributors
@@ -167,6 +233,10 @@ TUI (REPL) 模式需要真实终端,无法直接通过 VS Code launch 启动
</picture>
</a>
## 致谢
- [doubaoime-asr](https://github.com/starccy/doubaoime-asr) — 豆包 ASR 语音识别 SDK为 Voice Mode 提供无需 Anthropic OAuth 的语音输入方案
## 许可证
本项目仅供学习研究用途。Claude Code 的所有权利归 [Anthropic](https://www.anthropic.com/) 所有。

View File

@@ -48,11 +48,64 @@ Sponsor placeholder.
Make sure you're on the latest version of Bun, otherwise you'll run into all sorts of weird bugs. Run `bun upgrade`!
- [Bun](https://bun.sh/) >= 1.3.11
**Install Bun:**
```bash
# Linux and macOS
curl -fsSL https://bun.sh/install | bash
# Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"
```
**Post-installation steps:**
1. **Make `bun` available in the current terminal**
The installer adds `~/.bun/bin` to the matching shell configuration file. On macOS with the default zsh shell, you may see:
```text
Added "~/.bun/bin" to $PATH in "~/.zshrc"
```
Restart the current shell as the installer suggests:
```bash
exec /bin/zsh
```
If you use bash, reload the bash configuration:
```bash
source ~/.bashrc
```
Windows PowerShell users can close and reopen PowerShell.
2. **Verify that Bun is available:**
```bash
bun --help
bun --version
```
3. **Update to latest version (if already installed):**
```bash
bun upgrade
```
- Standard Claude Code configuration — each provider has its own setup method
### Command Execution Location
- Bun installation and checking commands can be run from any directory:
`curl -fsSL https://bun.sh/install | bash`, `bun --help`, `bun --version`, `bun upgrade`
- Project dependency installation, development mode, and builds must be run from this repository root, the directory containing `package.json`.
### Install
```bash
cd /path/to/claude-code
bun install
```

View File

@@ -1,6 +1,7 @@
import { readdir, readFile, writeFile, cp } from 'fs/promises'
import { join } from 'path'
import { getMacroDefines } from './scripts/defines.ts'
import { DEFAULT_BUILD_FEATURES } from './scripts/defines.ts'
const outdir = 'dist'
@@ -8,30 +9,6 @@ const outdir = 'dist'
const { rmSync } = await import('fs')
rmSync(outdir, { recursive: true, force: true })
// Default features that match the official CLI build.
// Additional features can be enabled via FEATURE_<NAME>=1 env vars.
const DEFAULT_BUILD_FEATURES = [
'AGENT_TRIGGERS_REMOTE',
'CHICAGO_MCP',
'VOICE_MODE',
'SHOT_STATS',
'PROMPT_CACHE_BREAK_DETECTION',
'TOKEN_BUDGET',
// P0: local features
'AGENT_TRIGGERS',
'ULTRATHINK',
'BUILTIN_EXPLORE_PLAN_AGENTS',
'LODESTONE',
// P1: API-dependent features
'EXTRACT_MEMORIES',
'VERIFICATION_AGENT',
'KAIROS_BRIEF',
'AWAY_SUMMARY',
'ULTRAPLAN',
// P2: daemon + remote control server
'DAEMON',
]
// Collect FEATURE_* env vars → Bun.build features
const envFeatures = Object.keys(process.env)
.filter(k => k.startsWith('FEATURE_'))
@@ -75,27 +52,49 @@ for (const file of files) {
}
}
// Also patch unguarded globalThis.Bun destructuring from third-party deps
// (e.g. @anthropic-ai/sandbox-runtime) so Node.js doesn't crash at import time.
let bunPatched = 0
const BUN_DESTRUCTURE = /var \{([^}]+)\} = globalThis\.Bun;?/g
const BUN_DESTRUCTURE_SAFE = 'var {$1} = typeof globalThis.Bun !== "undefined" ? globalThis.Bun : {};'
for (const file of files) {
if (!file.endsWith('.js')) continue
const filePath = join(outdir, file)
const content = await readFile(filePath, 'utf-8')
if (BUN_DESTRUCTURE.test(content)) {
await writeFile(
filePath,
content.replace(BUN_DESTRUCTURE, BUN_DESTRUCTURE_SAFE),
)
bunPatched++
}
}
BUN_DESTRUCTURE.lastIndex = 0
console.log(
`Bundled ${result.outputs.length} files to ${outdir}/ (patched ${patched} for Node.js compat)`,
`Bundled ${result.outputs.length} files to ${outdir}/ (patched ${patched} for import.meta.require, ${bunPatched} for Bun destructure)`,
)
// Step 4: Copy native .node addon files (audio-capture)
const vendorDir = join(outdir, 'vendor', 'audio-capture')
await cp('vendor/audio-capture', vendorDir, { recursive: true })
console.log(`Copied vendor/audio-capture/ → ${vendorDir}/`)
// Step 4: Copy native .node addon files (audio-capture) and vendored binaries (ripgrep)
const audioCaptureDir = join(outdir, 'vendor', 'audio-capture')
await cp('vendor/audio-capture', audioCaptureDir, { recursive: true })
console.log(`Copied vendor/audio-capture/ → ${audioCaptureDir}/`)
// Step 5: Bundle download-ripgrep script as standalone JS for postinstall
const rgScript = await Bun.build({
entrypoints: ['scripts/download-ripgrep.ts'],
outdir,
target: 'node',
})
if (!rgScript.success) {
console.error('Failed to bundle download-ripgrep script:')
for (const log of rgScript.logs) {
console.error(log)
}
// Non-fatal — postinstall fallback to bun run scripts/download-ripgrep.ts
} else {
console.log(`Bundled download-ripgrep script to ${outdir}/`)
}
const ripgrepDir = join(outdir, 'vendor', 'ripgrep')
await cp('src/utils/vendor/ripgrep', ripgrepDir, { recursive: true })
console.log(`Copied src/utils/vendor/ripgrep/ → ${ripgrepDir}/`)
// Step 5: Generate cli-bun and cli-node executable entry points
const cliBun = join(outdir, 'cli-bun.js')
const cliNode = join(outdir, 'cli-node.js')
await writeFile(cliBun, '#!/usr/bin/env bun\nimport "./cli.js"\n')
await writeFile(cliNode, '#!/usr/bin/env node\nimport "./cli.js"\n')
// Make both executable
const { chmodSync } = await import('fs')
chmodSync(cliBun, 0o755)
chmodSync(cliNode, 0o755)
console.log(`Generated ${cliBun} (shebang: bun) and ${cliNode} (shebang: node)`)

2488
bun.lock

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

188
docs.json Normal file
View File

@@ -0,0 +1,188 @@
{
"$schema": "https://mintlify.com/docs.json",
"theme": "mint",
"name": "Claude Code Architecture",
"colors": {
"primary": "#D97706",
"light": "#F59E0B",
"dark": "#B45309"
},
"favicon": "/docs/favicon.svg",
"navigation": {
"groups": [
{
"group": "开始",
"pages": [
{
"group": "介绍",
"pages": [
"docs/introduction/what-is-claude-code",
"docs/introduction/why-this-whitepaper",
"docs/introduction/architecture-overview"
]
}
]
},
{
"group": "对话是如何运转的",
"pages": [
"docs/conversation/the-loop",
"docs/conversation/streaming",
"docs/conversation/multi-turn"
]
},
{
"group": "工具AI 的双手",
"pages": [
"docs/tools/what-are-tools",
"docs/tools/file-operations",
"docs/tools/shell-execution",
"docs/tools/search-and-navigation",
"docs/tools/task-management"
]
},
{
"group": "上下文工程",
"pages": [
"docs/context/system-prompt",
"docs/context/project-memory",
"docs/context/compaction",
"docs/context/token-budget"
]
},
{
"group": "多 Agent 协作",
"pages": [
"docs/agent/sub-agents",
"docs/agent/worktree-isolation",
"docs/agent/coordinator-and-swarm"
]
},
{
"group": "可扩展性",
"pages": [
"docs/extensibility/mcp-protocol",
"docs/extensibility/hooks",
"docs/extensibility/skills",
"docs/extensibility/custom-agents"
]
},
{
"group": "安全与权限",
"pages": [
"docs/safety/why-safety-matters",
"docs/safety/permission-model",
"docs/safety/sandbox",
"docs/safety/plan-mode",
"docs/safety/auto-mode"
]
},
{
"group": "揭秘:隐藏功能与内部机制",
"pages": [
"docs/internals/three-tier-gating",
"docs/internals/feature-flags",
"docs/internals/growthbook-ab-testing",
"docs/internals/growthbook-adapter",
"docs/internals/sentry-setup",
"docs/internals/hidden-features",
"docs/internals/ant-only-world",
"docs/features/debug-mode",
"docs/features/buddy"
]
},
{
"group": "隐藏功能详解",
"pages": [
{
"group": "Agent 与协作",
"pages": [
"docs/features/coordinator-mode",
"docs/features/fork-subagent",
"docs/features/daemon",
"docs/features/teammem"
]
},
{
"group": "运行模式",
"pages": [
"docs/features/kairos",
"docs/features/voice-mode",
"docs/features/bridge-mode",
"docs/features/remote-control-self-hosting",
"docs/features/proactive",
"docs/features/ultraplan"
]
},
{
"group": "工具增强",
"pages": [
"docs/features/mcp-skills",
"docs/features/tree-sitter-bash",
"docs/features/bash-classifier",
"docs/features/web-browser-tool",
"docs/features/experimental-skill-search"
]
},
{
"group": "上下文与自动化",
"pages": [
"docs/features/token-budget",
"docs/features/context-collapse",
"docs/features/workflow-scripts",
"docs/features/auto-dream"
]
},
"docs/features/tier3-stubs"
]
},
{
"group": "基础设施与依赖",
"pages": [
"docs/auto-updater",
"docs/lsp-integration",
"docs/external-dependencies",
"docs/telemetry-remote-config-audit"
]
}
]
},
"logo": {
"light": "/docs/logo/light.svg",
"dark": "/docs/logo/dark.svg"
},
"background": {
"color": {
"light": "#FFFFFF",
"dark": "#0F172A"
}
},
"navbar": {
"primary": {
"type": "github",
"href": "https://github.com/claude-code-best/claude-code"
}
},
"search": {
"prompt": "搜索 Claude Code 架构文档..."
},
"seo": {
"metatags": {
"og:image": "https://ccb.agent-aura.top/docs/images/og-cover.png",
"twitter:image": "https://ccb.agent-aura.top/docs/images/og-cover.png",
"twitter:card": "summary_large_image"
},
"indexing": "navigable"
},
"footer": {
"socials": {
"github": "https://github.com/anthropics/claude-code"
}
},
"redirects": [
{
"source": "/docs/introduction",
"destination": "/docs/introduction/what-is-claude-code"
}
]
}

View File

@@ -1,128 +0,0 @@
# 文档修正计划
> 目标:补充源码级洞察,让每篇文档从"概念科普"升级为"逆向工程白皮书"水准。
---
## 第一梯队:空壳页,需要大幅重写
### 1. `safety/sandbox.mdx` — 沙箱机制 ✅ DONE
**现状**35 行,只列了"文件系统/网络/进程/时间"四个维度,没有任何实现细节。
**修正方向**
- 补充 macOS `sandbox-exec` 的实际调用方式,展示沙箱 profile 的关键片段
- 说明 `getSandboxConfig()` 的判定逻辑:哪些命令走沙箱、哪些跳过
- 补充 `dangerouslyDisableSandbox` 参数的设计权衡
- 加入 Linux 平台的沙箱差异对比seatbelt vs namespace
- 展示一次命令执行从权限检查→沙箱包裹→实际执行的完整链路
---
### 2. `introduction/what-is-claude-code.mdx` — 什么是 Claude Code ✅ DONE
**现状**39 行,纯营销文案,和"普通聊天 AI"的对比表太低级。
**修正方向**
- 砍掉"能做什么"的泛泛列表,改为一个具体的端到端示例(从用户输入→系统处理→最终输出)
- 用一张简化架构图替代文字描述,让读者 30 秒建立直觉
- 补充 Claude Code 的技术定位:不是 IDE 插件、不是 Web Chat而是 terminal-native agentic system
- 加入与 Cursor / Copilot / Aider 等工具的定位差异(架构层面而非功能清单)
---
### 3. `introduction/why-this-whitepaper.mdx` — 为什么写这份白皮书 ✅ DONE
**现状**40 行,全是空话,四张 Card 只是后续章节标题的预告。
**修正方向**
- 明确定位:这是对 Anthropic 官方 CLI 的逆向工程分析,不是官方文档
- 列出逆向过程中发现的 3-5 个最意外/最精妙的设计决策(吊住读者胃口)
- 说明白皮书的阅读路线图:推荐的阅读顺序和每个章节解决什么问题
- 补充"这份白皮书不是什么"——不是使用教程,不是 API 文档
---
### 4. `safety/why-safety-matters.mdx` — 为什么安全至关重要 ✅ DONE
**现状**40 行,只列了显而易见的风险,"安全 vs 效率的平衡"只有 3 个 bullet。
**修正方向**
- 从源码角度展示安全体系的全景图:权限规则 → 沙箱 → Plan Mode → 预算上限 → Hooks 的纵深防御链
- 补充 Claude 自身 System Prompt 中的安全指令("执行前确认"、"优先可逆操作"等),展示 AI 端的安全约束
- 用真实场景说明"安全 vs 效率"的工程权衡:比如 Read 工具为什么免审批、Bash 工具为什么要逐条确认
- 加入 Prompt Injection 防御的简要说明tool result 中的恶意内容如何被系统标记)
---
## 第二梯队:有骨架但太浅,需要补肉
### 5. `conversation/streaming.mdx` — 流式响应 ✅ DONE
**现状**43 行,只说了"流式好"和 3 行 provider 表。
**修正方向**
- 补充 `BetaRawMessageStreamEvent` 的核心事件类型及其含义
- 展示文本 chunk 和 tool_use block 交织的状态机流转
- 说明流式中的错误处理网络断开、API 限流、token 超限时的重试/降级策略
- 补充 `processStreamEvents()` 的核心逻辑如何从事件流中分离出文本、工具调用、usage 统计
---
### 6. `tools/search-and-navigation.mdx` — 搜索与导航 ✅ DONE
**现状**43 行,只说 Glob 和 Grep 存在。
**修正方向**
- 补充 ripgrep 二进制的内嵌方式vendor 目录、平台适配)
- 说明搜索结果的 head_limit 默认 250 的设计原因token 预算)
- 展示 ToolSearch 的实现:如何用语义匹配在 50+ 工具(含 MCP中找到最相关的
- 补充 Glob 按修改时间排序的意义:最近修改的文件最可能与当前任务相关
---
### 7. `tools/task-management.mdx` — 任务管理 ✅ DONE
**现状**50 行,只有流程 Steps 和状态展示的 4 个 bullet。
**修正方向**
- 补充任务的数据模型id / subject / description / status / blockedBy / blocks / owner
- 说明依赖管理的实现blockedBy 如何阻止任务被认领、完成一个任务后如何自动解锁下游
- 展示任务与 Agent 工具的联动:子 Agent 如何认领任务、报告进度
- 补充 activeForm 字段的 UX 设计:进行中任务的 spinner 动画文案
---
### 8. `context/token-budget.mdx` — Token 预算管理 ✅ DONE
**现状**55 行,预算控制只有 3 张 Card 各一句话。
**修正方向**
- 补充 `contextWindowTokens``maxOutputTokens` 的动态计算逻辑
- 说明缓存 breakpoint 的放置策略System Prompt 中不变内容在前、变化内容在后的原因
- 展示工具输出截断的具体机制:超长结果如何被 truncate、何时触发 micro-compact
- 补充 token 计数的实现:`countTokens` 的调用时机和近似 vs 精确计数的权衡
---
### 9. `agent/worktree-isolation.mdx` — Worktree 隔离 ✅ DONE
**现状**55 行,只描述了 git worktree 的概念。
**修正方向**
- 展示 `.claude/worktrees/` 的目录结构和分支命名规则
- 说明 worktree 的生命周期:创建时机(`isolation: "worktree"`)→ 子 Agent 执行 → 完成/放弃 → 自动清理
- 补充 worktree 与子 Agent 的绑定关系Agent 结束时如何判断 keep or remove
- 加入 EnterWorktree / ExitWorktree 工具的交互设计
---
### 10. `extensibility/custom-agents.mdx` — 自定义 Agent ✅ DONE
**现状**56 行,只有配置表和示例表。
**修正方向**
- 展示 agent markdown 文件的完整 frontmatter 格式name / description / model / allowedTools 等)
- 说明 agent 如何被加载和注入 System Prompt`loadAgentDefinitions()` 的发现和合并逻辑
- 展示工具限制的实现allowedTools 如何过滤工具列表
- 补充 agent 与 subagent_type 参数的关联Agent 工具如何指定使用自定义 Agent

View File

@@ -10,13 +10,13 @@ keywords: ["协调者模式", "蜂群模式", "Agent Swarm", "多 Agent 协作",
| 维度 | Coordinator Mode | Agent Swarms |
|------|-----------------|--------------|
| **门控** | `feature('COORDINATOR_MODE')` + `CLAUDE_CODE_COORDINATOR_MODE=1` | 任务系统 V2默认启用 |
| **拓扑** | 星型Coordinator 居中Worker 外围 | 网状:对等 Agent 共享任务列表 |
| **角色** | 明确分工Coordinator 编排、Worker 执行 | 模糊:每个 Agent 自主认领任务 |
| **通信** | `SendMessage` 定向通信 + `<task-notification>` | 任务文件系统 + 邮箱广播 |
| **适用** | 需要集中决策的复杂任务 | 并行度高的独立子任务 |
| **门控** | `feature('COORDINATOR_MODE')` + `CLAUDE_CODE_COORDINATOR_MODE=1` | `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` 环境变量 |
| **拓扑** | 星型Coordinator 居中Worker 外围 | 星型+P2P 混合Team Lead 协调Teammate 间可直接通信 |
| **角色** | 明确分工Coordinator 编排、Worker 执行 | Team Lead 协调 + Teammate 自主认领任务 |
| **通信** | `SendMessage` 定向通信 + `<task-notification>` | Mailbox 消息系统message / broadcast |
| **适用** | 需要集中决策的复杂任务 | 并行度高、需要 Teammate 间直接协作的任务 |
两者不是互斥的——Coordinator Mode 可以在 Swarm 架构之上运行,将 Coordinator 作为特殊的 Leader Agent
两者不是互斥的——理论上 Coordinator Mode 可以在 Agent Teams 架构之上运行(概念层叠加,非嵌套团队),将 Coordinator 作为特殊的 Team Lead但这部分集成`workerAgent.ts` 中的 `getCoordinatorAgents`)目前为 stub 实现,尚未完整落地
## Coordinator Mode星型编排架构
@@ -45,7 +45,7 @@ Coordinator 被剥夺了所有"动手"工具,只保留编排能力:
| **TaskStop** | 中途停止走错方向的 Worker |
| **subscribe_pr_activity** | 订阅 GitHub PR 事件review comments、CI 结果) |
Coordinator **不写代码、不读文件、不执行命令**——它只做三件事:理解需求、分配任务、综合结果。
Coordinator **不写代码、不读文件、不执行命令**——它的核心职责是:理解需求、分配任务、综合结果,以及在无需工具时直接回答用户问题
### Worker 的工具权限
@@ -53,7 +53,7 @@ Worker 的可用工具由 `getCoordinatorUserContext()``coordinatorMode.ts:80
```typescript
// 简化模式下:只有 Bash + Read + Edit
const workerTools = isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE')
const workerTools = isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE)
? [BASH_TOOL_NAME, FILE_READ_TOOL_NAME, FILE_EDIT_TOOL_NAME]
: Array.from(ASYNC_AGENT_ALLOWED_TOOLS)
.filter(name => !INTERNAL_WORKER_TOOLS.has(name))
@@ -63,7 +63,7 @@ const workerTools = isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE')
### Scratchpad跨 Worker 的共享知识库
当 `tengu_scratch` feature flag 启用时Coordinator 拥有一个 Scratchpad 目录
当 `isScratchpadGateEnabled()`(内部检查 `tengu_scratch` feature gate启用时Workers 获得一个 Scratchpad 目录Coordinator 通过其系统上下文知晓该目录的存在
```
Scratchpad 目录:
@@ -113,32 +113,84 @@ Coordinator System Prompt`coordinatorMode.ts:111-369`,约 260 行)明确
这是 Coordinator Mode 最核心的设计约束Coordinator 必须先理解,再分配。
## Agent Swarms:蜂群式协作
## Agent Teams (Swarm):蜂群式协作
Swarm 模式基于任务系统 V2详见[任务管理](../tools/task-management.mdx)),核心机制是**共享任务列表 + 竞争认领**
Swarm 模式基于任务系统 V2详见[任务管理](../tools/task-management.mdx)),核心机制是**共享任务列表 + 竞争认领 + Mailbox 消息系统**
### 团队初始化
```
Leader 创建团队TeamCreateTool
Team Lead 创建团队TeamCreateTool
设置 teamName → setLeaderTeamName()
所有 teammate 自动获得相同的 taskListId
所有 Teammate 自动获得相同的 taskListId
teammate 启动时:
Teammate 启动时:
1. CLAUDE_CODE_TASK_LIST_ID 环境变量(显式覆盖)
2. teammate 上下文的 teamName共享 leader 的任务列表)
2. Teammate 上下文的 teamName共享 Lead 的任务列表)
3. CLAUDE_CODE_TEAM_NAME 环境变量
4. leader 设置的 teamName
4. Lead 设置的 teamName
5. getSessionId()(兜底)
```
多级优先级确保了 Leader 和所有 Teammate 指向同一个任务列表,无需额外协调。
多级优先级确保了 Team Lead 和所有 Teammate 指向同一个任务列表,无需额外协调。
### 架构组件
官方 Agent Teams 架构定义了四个核心组件:
| 组件 | 角色 |
|------|------|
| **Team Lead** | 创建团队、分配任务、综合结果的主 Claude Code 会话 |
| **Teammate** | 独立的 Claude Code 实例,各自拥有独立的上下文窗口 |
| **Task List** | 共享的任务列表Teammate 竞争认领和完成 |
| **Mailbox** | 消息系统,支持 Teammate 间直接通信 |
### Mailbox 消息系统
官方架构中的 Mailbox 是 Teammate 间通信的核心原语,支持两种消息模式(`broadcast` 模式来自源码推断,官方文档未明确细分):
| 模式 | 作用 | 场景 |
|------|------|------|
| **message** | 定向发送给指定 Teammate | 传递具体指令、请求协作 |
| **broadcast** | 广播给所有 Teammate | 全局通知、状态同步 |
Mailbox 的关键特性:
- **自动投递**:消息自动送达目标 Teammate 的对话上下文
- **空闲通知**TeammateIdleTeammate 完成当前任务进入空闲时,自动通过 Mailbox 通知 Team Lead
- **直接通信**:与 Coordinator Mode 不同Teammate 之间可以直接通信,无需经过 Lead 中转
### Hook 事件
Agent Teams 提供三个关键 Hook 事件,用于在团队生命周期中注入自定义逻辑:
| Hook | 触发时机 | 典型用途 |
|------|---------|---------|
| **TaskCreated** | 新任务添加到任务列表时 | 自动分配、优先级排序 |
| **TaskCompleted** | 任务标记为完成时 | 结果通知、依赖解锁 |
| **TeammateIdle** | Teammate 完成所有任务进入空闲时 | Lead 重新分配、动态扩缩容 |
### 限制
当前 Agent Teams 实现的限制:
- **不支持嵌套团队**Teammate 不能再创建子团队
- **每 session 一个团队**:一个会话只能属于一个团队
- **Lead 固定**Team Lead 创建后不可更换
- **不支持 in-process Teammate 的会话恢复**:进程重启后 in-process 类型 Teammate 的状态丢失
### 持久化存储
团队状态通过文件系统持久化,确保进程重启后可恢复:
```
~/.claude/teams/{team-name}/config.json ← 团队配置
~/.claude/tasks/{team-name}/ ← 共享任务列表(文件锁保护)
```
### 任务认领与竞争
`claimTask()` 是 Swarm 的核心并发原语:
`claimTask()` 是 Agent Teams 的核心并发原语:
```
Teammate A 调用 TaskList → 发现 task #3 是 pending
@@ -146,7 +198,7 @@ Teammate B 同时发现 task #3 是 pending
两者同时尝试 TaskUpdate(task #3, {status: "in_progress"})
文件锁 + 高水位标记保证原子性:
文件锁保证原子性:
- 第一个写入者获得 owner 锁定
- 第二个写入者收到 already_claimed 错误
@@ -166,8 +218,11 @@ unassignTeammateTasks()
→ 扫描任务列表,找到 owner === teammateName 的未完成任务
→ 重置为 pending + owner=undefined
Leader 通过 mailbox 收到通知
→ 重新分配或创建新 Teammate
Team Lead 感知途径:
1. 任务状态变化pending 重置)—— 通过共享任务列表
2. Mailbox 空闲通知TeammateIdle hook—— Teammate 停止时自动通知 Lead
Team Lead 重新分配任务或创建新 Teammate
```
## 任务类型全景
@@ -186,11 +241,11 @@ Leader 通过 mailbox 收到通知
`InProcessTeammateTask` 与 `LocalAgentTask` 的关键差异:前者共享进程的内存空间和基础设施状态(如 MCP 连接池),但有独立的对话上下文和工具权限;后者是完全隔离的子进程,启动开销更大但更安全。
## Coordinator vs Swarm 的选择
## Coordinator vs Agent Teams 的选择
| 场景 | 推荐模式 | 原因 |
|------|---------|------|
| "重构认证系统,需要多模块协调" | Coordinator | 需要集中决策Worker 间有依赖 |
| "修复 10 个独立的 lint 警告" | Swarm | 任务独立,可完全并行 |
| "修复 10 个独立的 lint 警告" | Agent Teams | 任务独立Teammate 可完全并行 |
| "研究方案 A 和方案 B然后选一个实现" | Coordinator | 先并行研究,再集中决策 |
| "在大仓库中搜索所有 TODO 并分类" | Swarm | 无依赖,各自领任务即可 |
| "在大仓库中搜索所有 TODO 并分类" | Agent Teams | 无依赖,各自领任务即可 |

View File

@@ -13,44 +13,48 @@ keywords: ["子 Agent", "AgentTool", "任务委派", "forkSubagent", "子进程
```
AI 生成 tool_use: { prompt: "修复 bug", subagent_type: "Explore" }
AgentTool.call() ← 入口AgentTool.tsx:239
├── 解析 effectiveTypefork vs 命名 agent
├── filterDeniedAgents() ← 权限过滤
AgentTool.call() ← 入口AgentTool.tsx:387
├── 解析 effectiveTypefork vs 命名 agent vs GP 回退
├── filterDeniedAgents() ← 仅命名 Agent 路径执行:权限过滤
├── 检查 requiredMcpServers ← MCP 依赖验证(最长等 30s
├── assembleToolPool(workerPermissionContext) ← 独立组装工具池
├── createAgentWorktree() ← 可选 worktree 隔离
runAgent() ← 核心执行runAgent.ts:248
runAgent() ← 核心执行runAgent.ts
├── getAgentSystemPrompt() ← 构建 agent 专属 system prompt
├── initializeAgentMcpServers() ← agent 级 MCP 服务器
├── executeSubagentStartHooks() ← Hook 注入
├── query() ← 进入标准 agentic loop
│ ├── 消息流逐条 yield
│ └── recordSidechainTranscript() ← JSONL 持久化
│ └── recordSidechainTranscript() ← JSONL 持久化~/.claude/projects/{project}/{session}/subagents/
finalizeAgentTool() ← 结果汇总
├── 提取文本内容 + usage 统计
└── mapToolResultToToolResultBlockParam() ← 格式化为 tool_result
```
## 两种子 Agent 路径:命名 Agent vs Fork
## 子 Agent 的三种路径
`AgentTool.call()` 根据是否提供 `subagent_type` 走两条完全不同的路径(`AgentTool.tsx:322-356`
`AgentTool.call()` 根据 `subagent_type` 参数和 Fork 实验开关,走三条不同的路径
| 维度 | 命名 Agent`subagent_type` 指定) | Fork 子进程(`subagent_type` 省略) |
|------|-------------------------------------|--------------------------------------|
| **触发条件** | `subagent_type` 有值 | `isForkSubagentEnabled()` && 未指定类型 |
| **System Prompt** | Agent 自身的 `getSystemPrompt()` | 继承父 Agent 的完整 System Prompt |
| **工具池** | `assembleToolPool()` 独立组装 | 父 Agent 的原始工具池(`useExactTools: true` |
| **上下文** | 仅任务描述 | 父 Agent 的完整对话历史(`forkContextMessages` |
| **模型** | 可独立指定 | 继承父模型(`model: 'inherit'` |
| **权限模式** | Agent 定义的 `permissionMode` | `'bubble'`(上浮到父终端) |
| **目的** | 专业任务委派 | Prompt Cache 命中率优化 |
| 维度 | 命名 Agent`subagent_type` 指定) | Fork 子进程(Fork 启用 + 类型省略) | General-purpose 回退Fork 关闭 + 类型省略) |
|------|-------------------------------------|--------------------------------------|---------------------------------------------|
| **触发条件** | `subagent_type` 有值 | `isForkSubagentEnabled() === true` 且未指定类型 | `isForkSubagentEnabled() === false` 且未指定类型 |
| **System Prompt** | Agent 自身的 `getSystemPrompt()` | 继承父 Agent 的完整 System Prompt | General-purpose Agent 的 `getSystemPrompt()` |
| **工具池** | `assembleToolPool()` 独立组装 | 父 Agent 的原始工具池(`useExactTools: true` | `assembleToolPool()` 独立组装 |
| **上下文** | 仅任务描述 | 父 Agent 的完整对话历史(`forkContextMessages` | 仅任务描述 |
| **模型** | 可独立指定 | 继承父模型(`model: 'inherit'` | 可独立指定 |
| **权限模式** | Agent 定义的 `permissionMode` | `'bubble'`(上浮到父终端) | Agent 定义的 `permissionMode` |
| **目的** | 专业任务委派 | Prompt Cache 命中率优化 | 通用任务处理 |
<Note>
Fork 实验的门控函数 `isForkSubagentEnabled()` 需要同时满足三个前提:`FORK_SUBAGENT` feature flag 已启用、当前不在 Coordinator 模式中、且不是非交互式会话。任一条件不满足时,省略 `subagent_type` 会静默降级为 General-purpose Agent而非触发 Fork。
</Note>
Fork 路径的设计核心是 **Prompt Cache 共享**:所有 fork 子进程共享父 Agent 的完整 `assistant` 消息(所有 `tool_use` 块),用相同的占位符 `tool_result` 填充,只有最后一个 `text` 块包含各自的指令。这使得 API 请求前缀字节完全一致,最大化缓存命中。
```typescript
// forkSubagent.ts:142 — 所有 fork 子进程的占位结果
// forkSubagent.ts:93 — 所有 fork 子进程的占位结果
const FORK_PLACEHOLDER_RESULT = 'Fork started — processing in background'
// buildForkedMessages() 构建:
@@ -59,14 +63,46 @@ const FORK_PLACEHOLDER_RESULT = 'Fork started — processing in background'
### Fork 递归防护
Fork 子进程保留 Agent 工具(为了 cache-identical tool defs但通过两道防线防止递归 fork`AgentTool.tsx:332`
Fork 子进程保留 Agent 工具(为了 cache-identical tool defs但通过两道防线防止递归 fork
1. **`querySource` 检查**(压缩安全):`context.options.querySource === 'agent:builtin:fork'`
2. **消息扫描**(降级兜底):检测 `<fork-boilerplate>` 标签
## 工具池的独立组装
### 模型解析优先级
子 Agent 不继承父 Agent 的工具限制——它的工具池完全独立组装(`AgentTool.tsx:573-577`
子 Agent 的模型选择遵循严格的优先级链(`src/utils/model/agent.ts`
```
1. CLAUDE_CODE_SUBAGENT_MODEL 环境变量 ← 全局覆盖
↓(未设置时)
2. 每次调用的 model 参数 ← AgentTool 入参
↓(未指定时)
3. Agent 定义的 model frontmatter ← 如 "sonnet", "haiku", "inherit"
↓(未定义时)
4. 继承父对话模型conversation model ← getDefaultSubagentModel() 返回 "inherit"
```
其中 `inherit` 不是简单的模型传递——它经过 `getRuntimeMainLoopModel()` 解析,确保 plan mode 下的 `opusplan→Opus` 等运行时映射正确生效。当 Agent 指定的模型族(如 `haiku`)与父模型同族时,直接复用父模型的精确 ID避免跨 provider 降级。
## 命名 Agent 的工具池独立组装
### 内置 Agent
系统预定义了几个内置 Agent`packages/builtin-tools/src/tools/AgentTool/builtInAgents.ts`),各有明确的职责和模型配置:
| Agent | 模型 | 权限 | 用途 |
|-------|------|------|------|
| **Explore** | Haiku轻量快速 | 只读Read/Grep/Glob | 代码库搜索与探索 |
| **Plan** | 继承父模型 | 只读 | 为 Plan Mode 收集研究信息 |
| **General-purpose** | 继承父模型 | 全部工具 | 复杂的通用任务处理 |
| **statusline-setup** | 继承父模型 | 受限 | 配置状态栏设置 |
| **claude-code-guide** | 继承父模型 | 受限 | 解答 Claude Code 使用问题 |
用户还可通过 `.claude/agents/` 目录或 settings 定义自定义 Agent作用域优先级为managed settings > CLI `--agents` > 项目级 `.claude/agents/` > 用户级 `~/.claude/agents/` > plugin。
命名 Agent包括 General-purpose 回退)不继承父 Agent 的工具限制——它的工具池完全独立组装。Fork 子进程则通过 `useExactTools: true` 直接继承父 Agent 的原始工具池,以保持 Prompt Cache 中工具定义的字节一致性。
命名 Agent 的工具池组装逻辑:
```typescript
const workerPermissionContext = {
@@ -83,7 +119,7 @@ const workerTools = assembleToolPool(workerPermissionContext, appState.mcp.tools
### 工具过滤的 resolveAgentTools
`runAgent.ts:500-502` 在工具组装后进一步过滤:
`runAgent.ts:508` 在工具组装后进一步过滤:
```typescript
const resolvedTools = useExactTools
@@ -93,9 +129,20 @@ const resolvedTools = useExactTools
`resolveAgentTools()` 会根据 Agent 定义中的 `tools` 字段过滤可用工具,将 `['*']` 映射为全量工具。
### Hook 事件
子 Agent 支持 Agent 定义 frontmatter 和全局 settings.json 两种级别的 Hook
| 来源 | 事件 | 说明 |
|------|------|------|
| Agent frontmatter `hooks` | `PreToolUse` / `PostToolUse` | 工具调用前后拦截 |
| Agent frontmatter `hooks` | `Stop` | 自动转换为 `SubagentStop``registerFrontmatterHooks` 传入 `isAgent=true` |
| settings.json | `SubagentStart` | 子 Agent 启动时触发(`executeSubagentStartHooks()` |
| settings.json | `SubagentStop` | 子 Agent 停止时触发 |
## Worktree 隔离机制
`isolation: "worktree"` 参数让子 Agent 在独立的 git worktree 中工作(`AgentTool.tsx:590-593`
`isolation: "worktree"` 参数让子 Agent 在独立的 git worktree 中工作(`AgentTool.tsx:863`
```typescript
const slug = `agent-${earlyAgentId.slice(0, 8)}`
@@ -115,24 +162,28 @@ Worktree 生命周期:
### 异步 Agent后台运行
当 `run_in_background=true``selectedAgent.background=true` Agent 立即返回 `async_launched` 状态`AgentTool.tsx:686-764`
当 `run_in_background=true``selectedAgent.background=true`、或系统判定应强制异步(如 `assistantForceAsync`、`proactiveModule` 激活)Agent 立即返回 `async_launched` 状态:
```
registerAsyncAgent(agentId, ...) ← 注册到 AppState.tasks
↓ (void — 火后不管)
runAsyncAgentLifecycle() ← 后台执行
runAsyncAgentLifecycle() ← 后台执行agentToolUtils.ts
├── runAgent().onCacheSafeParams ← 进度摘要初始化
├── 消息流迭代
├── completeAsyncAgent() ← 标记完成
├── classifyHandoffIfNeeded() ← 安全检查
├── finalizeAgentTool() 结果汇总(提取文本 + usage 统计)
├── completeAsyncAgent() ← 标记完成(先于通知,确保 TaskOutput 尽快解除阻塞)
├── classifyHandoffIfNeeded() ← 安全分类(需 TRANSCRIPT_CLASSIFIER feature
├── getWorktreeResult() ← Worktree 清理(如有隔离)
└── enqueueAgentNotification() ← 通知主 Agent
```
如果异步 Agent 提供了 `name` 参数,还会注册到 `agentNameRegistry`,支撑 `SendMessage` 工具通过名称路由到该 Agent。
异步 Agent 获得独立的 `AbortController`,不与父 Agent 共享——用户按 ESC 取消主线程不会杀掉后台 Agent。
### 同步 Agent前台运行
同步 Agent 的关键特性是 **可后台化**`AgentTool.tsx:818-833`
同步 Agent 的关键特性是 **可后台化**`AgentTool.tsx:1107`
```typescript
const registration = registerAgentForeground({
@@ -154,27 +205,27 @@ const raceResult = await Promise.race([
## 结果回传格式
`mapToolResultToToolResultBlockParam()` 根据状态返回不同格式`AgentTool.tsx:1298-1375`
`mapToolResultToToolResultBlockParam()` 根据状态返回不同格式:
| 状态 | 返回内容 |
|------|---------|
| `completed` | 内容 + `<usage>` 块token/tool_calls/duration |
| `async_launched` | agentId + outputFile 路径 + 操作指引 |
| `completed` | 内容 + `<usage>` 块token/tool_calls/duration;无内容时插入占位文本 `"(Subagent completed but returned no output.)"` 防止模型误判为空 |
| `async_launched` | agentId + outputFile 路径 + 操作指引(指引内容取决于 `canReadOutputFile`:有读取权限时提示通过 Read/Bash 查看进度,否则仅告知已启动) |
| `teammate_spawned` | agent_id + name + team_name |
| `remote_launched` | taskId + sessionUrl + outputFile |
对于一次性内置 AgentExplore、Plan`<usage>` 块被省略——每周节省约 1-2 Gtok 的上下文窗口
对于一次性内置 AgentExplore、Plan当**不存在** worktree 隔离时,`<usage>` 块和 agentId 尾部被省略——每周节省约 1-2 Gtok 的上下文窗口。存在 worktree 时仍需返回 `worktreePath` 和 `worktreeBranch` 信息
## MCP 依赖的等待机制
如果 Agent 声明了 `requiredMcpServers``call()` 会等待这些服务器连接完成(`AgentTool.tsx:371-410`
如果 Agent 声明了 `requiredMcpServers``call()` 会等待这些服务器连接完成(`AgentTool.tsx:576`
```typescript
const MAX_WAIT_MS = 30_000 // 最长等 30 秒
const POLL_INTERVAL_MS = 500 // 每 500ms 轮询
```
早期退出条件:任何必需服务器进入 `failed` 状态时立即停止等待。工具可用性通过 `mcp__` 前缀工具名解析(`mcp__serverName__toolName`)判断。
早期退出条件:任何必需服务器进入 `failed` 状态时立即停止等待。工具可用性通过 `mcp__` 前缀工具名解析(`mcp__serverName__toolName`)判断。等待结束后如果仍有必需服务器未就绪,`call()` 会抛出错误并明确列出缺失的服务器名称。
## 适用场景

View File

@@ -37,7 +37,7 @@ Worktree 文件统一存放在仓库根目录下的 `.claude/worktrees/`
## 创建流程EnterWorktreeTool
`EnterWorktreeTool``src/tools/EnterWorktreeTool/EnterWorktreeTool.ts`)的执行链路:
`EnterWorktreeTool``packages/builtin-tools/src/tools/EnterWorktreeTool/EnterWorktreeTool.ts`)的执行链路:
```
EnterWorktreeTool.call({ name? })
@@ -83,7 +83,7 @@ EnterWorktreeTool.call({ name? })
## 退出流程ExitWorktreeTool
`ExitWorktreeTool``src/tools/ExitWorktreeTool/ExitWorktreeTool.ts`)支持两种退出策略:
`ExitWorktreeTool``packages/builtin-tools/src/tools/ExitWorktreeTool/ExitWorktreeTool.ts`)支持两种退出策略:
### keep保留 worktree
@@ -143,14 +143,18 @@ call() — 实际执行
## 与 Agent 工具的联动
Agent 工具(`AgentTool`)的 `isolation` 参数决定子 Agent 是否在 worktree 中运行:
Agent 工具(`AgentTool`)的 `isolation` 参数决定子 Agent 是否在 worktree 中运行。注意 Agent 工具使用**专用的** `createAgentWorktree()``src/utils/worktree.ts`),而非用户会话用的 `createWorktreeForSession()`,两者有关键差异
- `isolation: "worktree"` → 调用 `createWorktreeForSession()`,子 Agent 在独立 worktree 中执行
- 无 isolation → 子 Agent 共享主工作目录
| 维度 | `createWorktreeForSession`(用户会话) | `createAgentWorktree`(子 Agent |
|------|---------------------------------------|----------------------------------|
| 调用者 | EnterWorktreeTool | AgentTool |
| Session 管理 | 设置 `currentWorktreeSession` | **不设置** `currentWorktreeSession` |
| 恢复已有 worktree | 直接复用 | 复用并 bump mtime防止被周期性清理误删 |
子 Agent 结束时的处理:
- **成功**:主 Agent 通过 `ExitWorktreeTool(action: "keep")` 保留 worktree然后手动合并
- **失败/放弃**:主 Agent 通过 `ExitWorktreeTool(action: "remove", discard_changes: true)` 清理
子 Agent 结束时的处理由 `cleanupWorktreeIfNeeded()` 自动完成——它不走 `ExitWorktreeTool`(因为 Agent worktree 没有会话状态,`ExitWorktreeTool` 的 `validateInput` 会拒绝)
- **有变更** → 保留 worktree返回 `worktreePath` 供主 Agent 后续合并
- **无变更** → 自动删除
- **Hook-based** → 始终保留
## Session 状态持久化
@@ -168,6 +172,7 @@ Agent 工具(`AgentTool`)的 `isolation` 参数决定子 Agent 是否在 wor
tmuxSessionName?: string, // 关联的 tmux session
hookBased?: boolean, // 是否由 hook 创建
creationDurationMs?: number, // 创建耗时(分析用)
usedSparsePaths?: boolean, // 是否使用了 sparse checkout
}
```

View File

@@ -42,7 +42,7 @@ useInterval(checkForUpdates, 30 * 60 * 1000); // 每 30 分钟
任何更新尝试之前,系统会依次检查:
1. **自动更新是否被禁用?**`getAutoUpdaterDisabledReason()``src/utils/config.ts:1735`
1. **自动更新是否被禁用?**`getAutoUpdaterDisabledReason()``src/utils/config.ts:1737`
- `NODE_ENV === 'development'`
- 设置了 `DISABLE_AUTOUPDATER` 环境变量
- 仅限必要流量模式
@@ -81,7 +81,7 @@ useInterval(checkForUpdates, 30 * 60 * 1000); // 每 30 分钟
`src/utils/autoUpdater.ts:70``assertMinVersion()`
`src/main.tsx:1775` 在启动时调用
定义于 `src/utils/autoUpdater.ts:70`,设计上在启动时调用(当前未接入启动流程)
```typescript
void assertMinVersion();
@@ -200,7 +200,7 @@ Windows 系统使用文件复制而非符号链接。
**文件**: `src/migrations/migrateAutoUpdatesToSettings.ts`
一次性将旧版 `globalConfig.autoUpdates = false` 迁移为 settings 中的 `DISABLE_AUTOUPDATER=1` 环境变量。 `src/main.tsx:325` 在启动时调用
一次性将旧版 `globalConfig.autoUpdates = false` 迁移为 settings 中的 `DISABLE_AUTOUPDATER=1` 环境变量。定义于 `src/migrations/migrateAutoUpdatesToSettings.ts`(当前未接入启动流程)
---
@@ -270,7 +270,7 @@ React hook `useUpdateNotification(updatedVersion)` — 确保每次 semver 变
| `src/utils/releaseNotes.ts` | Changelog 获取、缓存与展示 |
| `src/utils/semver.ts` | Semver 版本比较Bun 原生 + npm 回退) |
| `src/utils/doctorDiagnostic.ts` | 安装类型检测与健康诊断 |
| `src/utils/config.ts:1735` | `getAutoUpdaterDisabledReason()` — 禁用检查逻辑 |
| `src/utils/config.ts:1737` | `getAutoUpdaterDisabledReason()` — 禁用检查逻辑 |
| `src/migrations/migrateAutoUpdatesToSettings.ts` | 旧版配置迁移 |
| `src/screens/Doctor.tsx` | Doctor 命令 UI展示自动更新状态 |

View File

@@ -48,7 +48,7 @@ const messagesForCompact = microcompactResult.messages
MicroCompact 不压缩整个对话,而是**清除旧工具输出的内容**。它维护一个白名单:
```typescript
// src/services/compact/microCompact.ts:41-48
// src/services/compact/microCompact.ts:41-50
const COMPACTABLE_TOOLS = new Set([
FILE_READ_TOOL_NAME, // 'Read' - 文件读取
...SHELL_TOOL_NAMES, // 'Bash' - 命令输出
@@ -143,7 +143,7 @@ const stripped2 = stripReinjectedAttachments(stripped) // 移除会被重新注
压缩后,系统会从摘要中**重新注入关键上下文**
```typescript
// compact.ts:124-132
// compact.ts:126-134
export const POST_COMPACT_TOKEN_BUDGET = 50_000 // 总预算
export const POST_COMPACT_MAX_FILES_TO_RESTORE = 5 // 最多恢复 5 个文件
export const POST_COMPACT_MAX_TOKENS_PER_FILE = 5_000 // 每文件 5K token

View File

@@ -39,7 +39,7 @@ Claude Code 的记忆系统是**纯文件**的——没有数据库、没有向
`MEMORY.md` 是记忆的入口索引,每次对话都完整加载到上下文中:
```typescript
// memdir.ts:35-38
// memdir.ts:34-38
export const ENTRYPOINT_NAME = 'MEMORY.md'
export const MAX_ENTRYPOINT_LINES = 200
export const MAX_ENTRYPOINT_BYTES = 25_000

View File

@@ -20,12 +20,12 @@ buildSystemPromptBlocks() → TextBlockParam[] (分块 + cache_control 标
1. **`getSystemPrompt()`**`src/constants/prompts.ts:444`)—— 收集静态段 + 动态段,插入 `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 分界标记
2. **`buildEffectiveSystemPrompt()`**`src/utils/systemPrompt.ts:41`)—— 按 Override > Coordinator > Agent > Custom > Default 优先级选择
3. **`buildSystemPromptBlocks()`**`src/services/api/claude.ts:3214`)—— 调用 `splitSysPromptPrefix()` 分块,为每个块附加 `cache_control`
3. **`buildSystemPromptBlocks()`**`src/services/api/claude.ts:3279`)—— 调用 `splitSysPromptPrefix()` 分块,为每个块附加 `cache_control`
## SystemPrompt 品牌类型
```typescript
// src/utils/systemPromptType.ts:8
// packages/@ant/model-provider/src/types/systemPrompt.ts:4
export type SystemPrompt = readonly string[] & {
readonly __brand: 'SystemPrompt'
}
@@ -43,9 +43,11 @@ export function asSystemPrompt(value: readonly string[]): SystemPrompt {
| 阶段 | 内容 | 缓存策略 |
|------|------|----------|
| **静态区** | Intro Section、System Rules、Doing Tasks、Actions、Using Tools、Tone & Style、Output Efficiency | 可跨组织缓存(`scope: 'global'` |
| **BOUNDARY** | `SYSTEM_PROMPT_DYNAMIC_BOUNDARY = '__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__'` | 分界标记(不发送给 API |
| **BOUNDARY** | `SYSTEM_PROMPT_DYNAMIC_BOUNDARY = '__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__'` | 分界标记(不发送给 API,仅用于分割静态区与动态区以实现全局缓存 |
| **动态区** | Session Guidance、Memory、Model Override、Env Info、Language、Output Style、MCP Instructions、Scratchpad、FRC、Summarize Tool Results、Token Budget、Brief | 每次会话不同(`scope: 'org'` 或无缓存) |
> **Boundary 是什么**:它把 System Prompt 分成"不变的静态区"和"因用户/会话而异的动态区"。静态区对所有用户相同,可获得 `scope: 'global'` 跨组织缓存;动态区每次不同,只能 `scope: 'org'` 或不缓存。它本身是一个特殊字符串,在发送给 API 前被移除AI 永远看不到。
### 动态区的 Section 注册表
动态区通过 `systemPromptSection()` / `DANGEROUS_uncachedSystemPromptSection()` 注册,这两个工厂函数定义于 `src/constants/systemPromptSections.ts`
@@ -151,9 +153,7 @@ MCP 工具列表在会话中可能变化(连接/断开),破坏了跨组织
这是缓存效率最高的模式。`SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 之前的静态内容Intro、Rules、Tone & Style 等)对所有用户相同,可跨组织缓存。
### Boundary 插入条件
`SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 标记**仅在特定条件**下插入:
> **Boundary 插入条件**`SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 标记**仅在特定条件**下插入:
```typescript
// src/utils/betas.ts:226-229
@@ -185,7 +185,7 @@ export function shouldUseGlobalCacheScope(): boolean {
### `getCacheControl()`TTL 决策
`src/services/api/claude.ts:359` 生成的 `cache_control` 对象:
`src/services/api/claude.ts:348` 生成的 `cache_control` 对象:
```typescript
{
@@ -195,14 +195,14 @@ export function shouldUseGlobalCacheScope(): boolean {
}
```
1 小时 TTL 的判定逻辑(`should1hCacheTTL()`,第 394 行):
1 小时 TTL 的判定逻辑(`should1hCacheTTL()`,第 383 行):
- **Bedrock 用户**:通过环境变量 `ENABLE_PROMPT_CACHING_1H_BEDROCK` 启用
- **1P 用户**:通过 GrowthBook 配置的 `allowlist` 数组匹配 `querySource`,支持前缀通配符(如 `"repl_main_thread*"`
- **会话级锁定**:资格判定结果在 bootstrap state 中缓存,防止 GrowthBook 配置中途变化导致同一会话内 TTL 不一致
### 缓存破坏Session-Specific Guidance 的放置
`getSessionSpecificGuidanceSection()``src/constants/prompts.ts:352`)的内容必须放在 `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` **之后**。因为它包含:
`getSessionSpecificGuidanceSection()``src/constants/prompts.ts:354`)的内容必须放在 `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` **之后**。因为它包含:
- 当前会话的 enabledTools 集合
- `isForkSubagentEnabled()` 的运行时判定
- `getIsNonInteractiveSession()` 的结果

View File

@@ -2,6 +2,7 @@
title: "多轮对话管理 - QueryEngine 会话编排与持久化"
description: "从源码角度解析 Claude Code 多轮对话管理QueryEngine 的会话状态机、JSONL transcript 持久化、成本追踪模型和模型热切换机制。"
keywords: ["多轮对话", "会话管理", "QueryEngine", "transcript", "成本追踪"]
sourceRef: "3ec5675 (2026-04-08)"
---
{/* 本章目标:从源码角度揭示会话编排、持久化存储、成本追踪和模型切换的完整链路 */}
@@ -11,15 +12,17 @@ keywords: ["多轮对话", "会话管理", "QueryEngine", "transcript", "成本
- **单轮**(一次 Agentic Loop`query()` 函数的一次完整执行——组装上下文 → 调 API → 处理工具调用 → 循环直到结束
- **多轮**(一个 Session`QueryEngine` 类管理的一次会话——跨越数十轮 `submitMessage()` 调用,持续数小时
`QueryEngine``src/QueryEngine.ts:186`)是单轮 Agentic Loop 之上的**会话编排器**,它管理的状态远不止消息列表:
`QueryEngine``src/QueryEngine.ts`,类定义)是单轮 Agentic Loop 之上的**会话编排器**,它管理的状态远不止消息列表:
```
QueryEngine 内部状态
QueryEngine 内部状态src/QueryEngine.ts 构造函数)
├── mutableMessages: Message[] ← 完整对话历史,跨 turn 累积
├── readFileState: FileStateCache ← 已读文件内容缓存,避免重复读取
├── totalUsage: NonNullableUsage ← 累计 token 消耗input/output/cache
├── permissionDenials: SDKPermissionDenial[] ← 权限拒绝记录
├── discoveredSkillNames: Set<string> ← 当前 turn 已发现的 skill
├── loadedNestedMemoryPaths: Set<string> ← 已加载的嵌套 memory 路径(防重复)
├── hasHandledOrphanedPermission: boolean ← 是否已处理孤立权限请求
└── abortController: AbortController ← 会话级中断控制
```
@@ -28,29 +31,37 @@ QueryEngine 内部状态
每次用户输入一条消息REPL 或 SDK 调用 `submitMessage()`,它会执行完整的 turn 初始化链路:
```typescript
// src/QueryEngine.ts:211 — 简化的 submitMessage 流程
async *submitMessage(prompt, options?): AsyncGenerator<SDKMessage> {
// src/QueryEngine.ts — QueryEngine.submitMessage() 简化流程
async *submitMessage(
prompt: string | ContentBlockParam[],
options?: { uuid?: string; isMeta?: boolean },
): AsyncGenerator<SDKMessage> {
// 1. 清除 turn 级追踪状态
this.discoveredSkillNames.clear()
// 2. 解析模型(用户可能中途切换了模型)
const mainLoopModel = userSpecifiedModel
? parseUserSpecifiedModel(userSpecifiedModel)
// 2. 解析模型(用户可能中途通过 setModel() 切换了模型)
const mainLoopModel = this.config.userSpecifiedModel
? parseUserSpecifiedModel(this.config.userSpecifiedModel)
: getMainLoopModel()
// 3. 动态组装 System Prompt每次 turn 都重新构建)
const { defaultSystemPrompt, userContext, systemContext } =
await fetchSystemPromptParts({ tools, mainLoopModel, mcpClients })
// 4. 包装权限检查(追踪每次拒绝)
const wrappedCanUseTool = async (tool, input, ...) => {
const result = await canUseTool(tool, input, ...)
if (result.behavior !== 'allow') {
this.permissionDenials.push({ tool_name: tool.name, ... })
this.permissionDenials.push({
type: 'permission_denial',
tool_name: sdkCompatToolName(tool.name),
tool_use_id: toolUseID,
tool_input: input,
})
}
return result
}
// 5. 调用核心 query() 函数执行 agentic loop
yield* query({
systemPrompt, messages: this.mutableMessages,
@@ -68,36 +79,43 @@ async *submitMessage(prompt, options?): AsyncGenerator<SDKMessage> {
### 存储路径
```
~/.claude/projects/<project-hash>/<session-id>.jsonl
~/.claude/projects/<sanitized-cwd>/<session-uuid>.jsonl
```
- `project-hash` 由 `getProjectDir(originalCwd)` 生成,同一项目目录的会话归入同一子目录
- 路径由 `getProjectDir(originalCwd)` 生成,使用 `sanitizePath()` 将项目目录路径转换为安全的目录名(非 hash同一项目目录的会话归入同一子目录
- 每条记录是一行 JSONJSONL 格式),支持追加写入而不需要读取-修改-写入整个文件
- 读取上限为 50MB`MAX_TRANSCRIPT_READ_BYTES`),防止超大会话导致 OOM
- 读取上限为 50MB`MAX_TRANSCRIPT_READ_BYTES` 常量,`src/utils/sessionStorage.ts`),防止超大会话导致 OOM
### Transcript 写入器
`TranscriptWriter``src/utils/sessionStorage.ts:1200+`)是一个写队列,确保并发消息追加不会互相覆盖:
`Project` 类`src/utils/sessionStorage.ts`,私有类)管理 transcript 的写入。它通过 `writeQueues`(按文件分组的写队列)和 `drainWriteQueue()`(定时批量刷写)确保并发消息追加不会互相覆盖:
```
写入流程:
appendEntryToFile(sessionId, entry)
写入流程(异步排队路径)
recordTranscript(sessionId, entry)
ensureCurrentSessionFile() ← 懒初始化:首次写入时才创建文件
project.enqueueWrite(filePath, entry) 入列到 writeQueues
序列化为 JSON + 换行符
scheduleDrain() ← 设置定时器FLUSH_INTERVAL_MS
appendFile(path, line) ← 原子追加
drainWriteQueue() ← 按 MAX_CHUNK_BYTES 分批
↓ 写入每批
appendToFile(path, batchContent) ← 批量追加
如果配置了远程持久化:
persistToRemote(sessionId, entry)
├── CCR v2: internalEventWriter('transcript', entry)
└── v1 Ingress: sessionIngress.appendSessionLog(...)
同步直写路径(用于元数据重写等场景):
appendEntryToFile(fullPath, entry) ← 同步 appendFileSync
失败时 mkdir + 重试
```
### 会话恢复链路
`--resume` 参数触发的恢复流程(`src/main.tsx:3620+`
`--resume` 参数触发的恢复流程(`src/main.tsx` 中 `--resume` 分支
```
1. 解析 resume 参数:
@@ -130,7 +148,7 @@ async *submitMessage(prompt, options?): AsyncGenerator<SDKMessage> {
### 累计层cost-tracker.ts
```typescript
// src/cost-tracker.ts — StoredCostState 数据模型
// src/cost-tracker.ts — StoredCostState 类型定义
type StoredCostState = {
totalCostUSD: number // 累计美元花费
totalAPIDuration: number // API 调用总时长(含重试)
@@ -138,7 +156,8 @@ type StoredCostState = {
totalToolDuration: number // 工具执行总时长
totalLinesAdded: number // 代码增加行数
totalLinesRemoved: number // 代码删除行数
modelUsage: { [modelName: string]: ModelUsage } // 按模型分拆的用量
lastDuration: number | undefined // 最近一次会话时长
modelUsage: { [modelName: string]: ModelUsage } | undefined // 按模型分拆的用量
}
```
@@ -156,18 +175,18 @@ saveCurrentSessionCosts(sessionId)
### 预算熔断
`QueryEngineConfig.maxBudgetUsd` 提供了会话级的硬性预算上限。在 REPL 中,当累计费用超过 $5 时(`src/screens/REPL.tsx:2208`),弹出费用提醒对话框——这不是硬性阻断,而是"软提醒"。
`QueryEngineConfig.maxBudgetUsd` 提供了会话级的硬性预算上限。在 REPL 中,当累计费用超过 $5 时(`src/screens/REPL.tsx` 中费用阈值 `useEffect`),弹出费用提醒对话框——这不是硬性阻断,而是"软提醒",且仅在 `hasConsoleBillingAccess()` 为 true 时显示
## 模型热切换
在一个会话中切换模型不会丢失对话历史——因为 `mutableMessages` 与模型选择是解耦的:
```
/model sonnet → setMainLoopModelOverride('claude-sonnet-4-20250514')
/model sonnet → QueryEngine.setModel('claude-sonnet-4-20250514')
实际操作this.config.userSpecifiedModel = modelQueryEngine.setModel() 方法)
下一次 submitMessage() 开始时:
parseUserSpecifiedModel(userSpecifiedModel)
parseUserSpecifiedModel(this.config.userSpecifiedModel)
→ 返回新的模型配置
fetchSystemPromptParts({ mainLoopModel: newModel })

View File

@@ -2,6 +2,7 @@
title: "流式响应机制 - Claude Code 打字机效果原理"
description: "解析 Claude Code 流式响应实现:如何通过 SSE 逐 token 接收 AI 输出,实现实时打字机效果,提升用户等待体验。"
keywords: ["流式响应", "SSE", "streaming", "实时输出", "API streaming"]
sourceRef: "3ec5675 (2026-04-08)"
---
## 为什么需要流式
@@ -31,7 +32,7 @@ message_stop ← 消息结束
### 事件处理状态机
`src/services/api/claude.ts:1980-2298` 实现了一个基于 `switch(part.type)` 的状态机:
`src/services/api/claude.ts` 中 `queryModelWithStreaming()` 函数的事件处理循环实现了一个基于 `switch(part.type)` 的状态机:
| 事件类型 | 处理逻辑 | 状态变更 |
|----------|----------|----------|
@@ -76,7 +77,7 @@ content_block_stop (index=2)
`stop_reason` 要等到 `message_delta` 才确定(可能是 `end_turn`、`tool_use`、`max_tokens` 等),所以最后一条消息的 `stop_reason` 是**回写**的:
```typescript
// claude.ts:2246 — 直接属性修改,不用对象替换
// claude.ts — stop_reason 回写逻辑(直接属性修改,不用对象替换
// 因为 transcript 写队列持有 message.message 的引用
const lastMsg = newMessages.at(-1)
if (lastMsg) {
@@ -89,16 +90,21 @@ if (lastMsg) {
### 网络断开
流式连接依赖 SSEServer-Sent Events。当连接中断时
流式连接依赖 SSEServer-Sent Events。当连接中断时,系统有两层检测机制
1. **Stream idle watchdog**:定时检测事件间隔超过阈值(stall触发告警和重试
2. **Stream abort**:如果 watchdog 检测到长时间无事件,抛出错误进入重试流程
3. **非流式降级**:作为最后手段,回退到非流式请求(一次性获取完整响应)
1. **被动停滞检测**`src/services/api/claude.ts` 中 stall 检测逻辑):当下一个事件到达时,计算与上一个事件的时间间隔超过阈值(30 秒,`STALL_THRESHOLD_MS = 30_000`)记录为一次 stall累积计数并写入遥测日志。这是被动检测——仅在下一个 chunk 到达时才触发,不会主动中断流。
2. **主动空闲超时看门狗**`src/services/api/claude.ts` 中 `STREAM_IDLE_TIMEOUT_MS` 看门狗逻辑):使用 `setTimeout` 设置 90 秒(可通过 `CLAUDE_STREAM_IDLE_TIMEOUT_MS` 环境变量覆盖)的硬性超时。如果在此期间没有收到任何事件,主动终止流并抛出错误进入重试流程
3. **非流式降级**:作为最后手段,设置 `didFallBackToNonStreaming` 标志,通过 `executeNonStreamingRequest()` 回退到非流式请求(一次性获取完整响应)
```typescript
// claude.ts:2338-2355 — 检测空流
// 1. 完全没有事件 → 代理返回了非 SSE 响应
// 2. 有 message_start 但没有 content_block_stop → 流被截断
// claude.ts — 被动停滞检测
const STALL_THRESHOLD_MS = 30_000 // 30 秒无事件视为停滞
let totalStallTime = 0
let stallCount = 0
// claude.ts — 主动空闲超时
const STREAM_IDLE_TIMEOUT_MS =
parseInt(process.env.CLAUDE_STREAM_IDLE_TIMEOUT_MS || '', 10) || 90_000
```
### API 限流
@@ -118,7 +124,7 @@ if (lastMsg) {
| **上下文窗口超限** | `model_context_window_exceeded` | 触发 compaction 压缩对话历史后重试 |
```typescript
// claude.ts:2267-2293
// claude.ts — stop_reason 处理
if (stopReason === 'max_tokens') {
yield createAssistantAPIErrorMessage({ error: 'max_output_tokens', ... })
}
@@ -133,8 +139,8 @@ if (stopReason === 'model_context_window_exceeded') {
系统持续监控事件到达间隔,检测"停滞"stall
```typescript
// claude.ts:1940-1966
const STALL_THRESHOLD_MS = 10_000 // 10 秒无事件视为停滞
// claude.ts — stall 检测逻辑
const STALL_THRESHOLD_MS = 30_000 // 30 秒无事件视为停滞
if (timeSinceLastEvent > STALL_THRESHOLD_MS) {
stallCount++
totalStallTime += timeSinceLastEvent
@@ -142,7 +148,7 @@ if (timeSinceLastEvent > STALL_THRESHOLD_MS) {
}
```
多个 stall 累积后watchdog 可能决定中断流并触发重试
这是**被动检测**——仅在下一个 chunk 到达时才触发比较。与之互补的是 90 秒主动空闲超时看门狗(`STREAM_IDLE_TIMEOUT_MS`),会直接中断长时间无响应的流
## 工具执行的流式反馈
@@ -161,10 +167,13 @@ UI 层通过 `useToolCallProgress` hook 实时展示命令输出,而不是等
| Provider | 流式协议 | 特殊处理 |
|----------|----------|----------|
| **Anthropic Direct** | 原生 SSE | 延迟最低TTFT 最快 |
| **firstParty** (Anthropic Direct) | 原生 SSE | 延迟最低TTFT 最快 |
| **AWS Bedrock** | AWS SDK 流式接口 | 需要额外的 beta header 和认证 |
| **Google Vertex** | gRPC → 事件流 | 通过 `getMergedBetas()` 适配 |
| **Azure** | Anthropic 兼容 API | 自定义 base URL |
| **foundry** | Anthropic 兼容 API | 内部部署 |
| **openai** | OpenAI 流式适配器 | 转换为 Anthropic 内部格式 |
| **gemini** | Gemini 流式适配器 | 转换为 Anthropic 内部格式 |
| **grok** (xAI) | Grok 流式适配器 | 转换为 Anthropic 内部格式 |
所有 Provider 通过统一的 `Stream<BetaRawMessageStreamEvent>` 抽象层屏蔽差异。上层代码QueryEngine、REPL不需要关心底层用的是哪个 Provider。

View File

@@ -2,6 +2,7 @@
title: "Agentic LoopAI 自主循环的核心机制"
description: "深入解析 Claude Code 的 query() 异步生成器循环——从流式 API 调用、工具并行执行、上下文压缩、错误恢复到终止条件的完整状态机,基于 src/query.ts 的源码级分析。"
keywords: ["Agentic Loop", "query loop", "tool_use", "状态机", "auto-compact", "streaming", "recovery"]
sourceRef: "3ec5675 (2026-04-08)"
---
{/* 本章目标:基于 src/query.ts 揭示 Agentic Loop 的完整状态机 */}
@@ -11,7 +12,7 @@ keywords: ["Agentic Loop", "query loop", "tool_use", "状态机", "auto-compact"
传统聊天机器人:你问一句,它答一句。
Claude Code 不一样:你说一个需求,它可能连续执行十几步操作才给你最终结果。
这背后的机制叫做 **Agentic Loop**(智能体循环),核心实现在 `src/query.ts` 的 `queryLoop()` 异步生成器函数(第 241 行)。它是一个 `while(true)` 无限循环,每次迭代代表一次"思考→行动→观察"周期。
这背后的机制叫做 **Agentic Loop**(智能体循环),核心实现在 `src/query.ts` 的 `queryLoop()` 异步生成器函数。它是一个 `while(true)` 无限循环,每次迭代代表一次"思考→行动→观察"周期。
<Frame caption="Agentic Loop 循环示意">
<img src="/docs/images/agentic-loop.png" alt="Agentic Loop 循环图" />
@@ -19,7 +20,7 @@ Claude Code 不一样:你说一个需求,它可能连续执行十几步操
## 循环的完整结构
`queryLoop()` 的每次迭代(`src/query.ts:307` `while(true)`)包含以下阶段:
`queryLoop()` 的每次迭代(`src/query.ts` 中 `while(true)` 主循环)包含以下阶段:
### 阶段 1上下文预处理Pre-Processing Pipeline
@@ -39,7 +40,7 @@ messagesForQuery处理后的消息→ 发往 API
### 阶段 2流式 API 调用Streaming Loop
`deps.callModel()` 发起流式请求(第 659 行),返回一个 AsyncGenerator。在流式过程中
`deps.callModel()` 发起流式请求(`src/query.ts` 中 `attemptWithFallback` 循环内),返回一个 AsyncGenerator。在流式过程中
- **AssistantMessage** 被收集到 `assistantMessages[]` 数组
- **tool_use 块** 被提取到 `toolUseBlocks[]`,设置 `needsFollowUp = true`
@@ -47,8 +48,8 @@ messagesForQuery处理后的消息→ 发往 API
- 可恢复的错误prompt-too-long、max-output-tokens被**暂扣**withheld先尝试恢复
流式回调中的关键守卫:
- `backfillObservableInput()`(第 763 行)—— 为 tool_use 块回填可观察字段(如文件路径展开),但只在添加了新字段时才克隆消息,避免破坏 prompt cache 的字节一致性
- 流式降级检测——如果 `streamingFallbackOccured`,已收集的消息被标记为 tombstone(第 717 行),清空后重试
- `backfillObservableInput()` —— 为 tool_use 块回填可观察字段(如文件路径展开),但只在添加了新字段时才克隆消息,避免破坏 prompt cache 的字节一致性
- 流式降级检测——如果 `streamingFallbackOccured`,已收集的消息被标记为 tombstone清空后重试
### 阶段 3工具执行Tool Execution
@@ -67,42 +68,50 @@ const toolUpdates = streamingToolExecutor
每次迭代结束时,根据条件决定 `return`(终止)或 `continue`(继续):
## 7 种终止条件(源码级)
## 终止条件(源码级)
循环有多种终止路径,按触发时机排列:
| 终止原因 | 触发位置 | 机制 |
|----------|---------|------|
| **completed** | 第 1360 行 | AI 未发出 tool_use → `needsFollowUp = false` → 经过 stop hooks → 返回 |
| **blocking_limit** | 第 646 行 | Token 计数超过硬限制(非 autocompact 模式)→ 生成 PTL 错误消息 → 返回 |
| **aborted_streaming** | 第 1054 行 | `abortController.signal.aborted` → 为未完成的 tool_use 生成合成 tool_result → 返回 |
| **model_error** | 第 999 行 | `callModel()` 抛出异常 → 生成错误消息 → 返回 |
| **prompt_too_long** | 第 1178 行 | 413 错误且 reactive compact 无法恢复 → 暂扣的错误消息被释放 → 返回 |
| **image_error** | 第 980/1178 行 | 图片尺寸/大小错误直接返回 |
| **stop_hook_prevented** | 第 1282 行 | Stop hook 返回 `preventContinuation: true` → 返回 |
| **blocking_limit** | 第 686 行 | Token 计数超过硬限制(非 autocompact 模式)→ 生成 PTL 错误消息 → 返回 |
| **image_error** | 第 1021 行 | `ImageSizeError` / `ImageResizeError` 异常直接返回 |
| **model_error** | 第 1040 行 | `callModel()` 抛出不可恢复异常 → 生成错误消息 → 返回 |
| **aborted_streaming** | 第 1095 行 | `abortController.signal.aborted`(流式阶段)→ 为未完成的 tool_use 生成合成 tool_result → 返回 |
| **prompt_too_long** | 第 1219/1226 行 | 413 错误且 reactive compact 无法恢复 → 暂扣的错误消息被释放 → 返回 |
| **completed** | 第 1308 行 | API 错误(限流、认证失败等)导致无法继续 → 返回 |
| **stop_hook_prevented** | 第 1323 行 | Stop hook 返回 `preventContinuation: true` → 返回 |
| **completed** | 第 1401 行 | 正常完成AI 未发出 tool_use → `needsFollowUp = false` → 经过 stop hooks → 返回 |
| **aborted_tools** | 第 1559 行 | `abortController.signal.aborted`(工具执行阶段)→ 返回 |
| **hook_stopped** | 第 1564 行 | 工具执行期间 hook 返回 `shouldPreventContinuation` → 返回 |
| **max_turns** | 第 1755 行 | 轮次计数超过 `maxTurns` 限制 → 返回 |
## 4 种继续条件(恢复路径)
## 继续条件(恢复路径)
循环不仅是一个简单的"有 tool_use 就继续",它还包含多种恢复/重试路径:
### 1. 正常工具循环
`needsFollowUp = true` → 执行工具 → 新消息追加到 `messagesForQuery` → `continue`
### 1. 正常工具循环`next_turn`
`needsFollowUp = true` → 执行工具 → 新消息追加到 `messagesForQuery` → state 重新赋值 → `continue`
### 2. max_output_tokens 恢复(第 1191-1255 行
当 AI 输出被截断时(`apiError === 'max_output_tokens'`
- **首次**:尝试将 `maxOutputTokens` 从默认值提升到 `ESCALATED_MAX_TOKENS`64K,无 meta 消息,静默重试
- **后续**注入恢复消息"Output token limit hit. Resume directly...",最多重试 `MAX_OUTPUT_TOKENS_RECOVERY_LIMIT = 3` 次
- 恢复耗尽后,暂扣的错误消息被释放
### 2. max_output_tokens 恢复(`max_output_tokens_escalate` / `max_output_tokens_recovery`
当 AI 输出被截断时(`apiError === 'max_output_tokens'`,分两阶段恢复
- **提升阶段**`max_output_tokens_escalate`):首次截断时,将 `maxOutputTokens` 从默认值提升到 `ESCALATED_MAX_TOKENS`64K。静默重试,不注入 meta 消息
- **恢复阶段**`max_output_tokens_recovery`):提升后仍然截断时,注入恢复消息"Output token limit hit. Resume directly...",最多重试 `MAX_OUTPUT_TOKENS_RECOVERY_LIMIT = 3` 次。恢复耗尽后,暂扣的错误消息被释放。
### 3. Prompt-Too-Long 恢复(第 1088-1186 行
当遇到 413 错误时,有两个恢复阶段
- **Context Collapse Drain**第 1097 行):提交所有已暂存的折叠,释放空间后重试。如果上一轮已经是 collapse_drain_retry 则跳过
- **Reactive Compact**第 1123 行):触发即时压缩,生成摘要后重试。`hasAttemptedReactiveCompact` 防止无限循环
### 3. Prompt-Too-Long 恢复(`collapse_drain_retry` / `reactive_compact_retry`
当遇到 413 错误时,按优先级尝试两种压缩策略
- **Context Collapse Drain**`collapse_drain_retry`):提交所有已暂存的折叠collapse,释放空间后重试。如果上一轮已经是 `collapse_drain_retry` 则跳过,避免无限循环。
- **Reactive Compact**`reactive_compact_retry`):如果 collapse drain 无法恢复触发即时压缩reactive compact,生成摘要后重试。`hasAttemptedReactiveCompact` 标志防止无限循环
### 4. Stop Hook 阻塞重试(第 1285-1308 行
### 4. Stop Hook 阻塞重试(`stop_hook_blocking`
Stop hook 可以注入阻塞错误消息,强制 AI 重新思考。新的消息(包含阻塞错误)被追加到对话中,`stopHookActive = true`,进入下一轮迭代。
### 5. Token Budget 继续提示(`token_budget_continuation`
当 `TOKEN_BUDGET` feature 启用时,如果 token 消耗达到阈值但未超出预算,注入 nudge 消息让 AI 加速收尾,然后继续。
## 模型降级Fallback
当主模型不可用时(`FallbackTriggeredError`第 897 行
当主模型不可用时(`FallbackTriggeredError``src/query.ts` 中 `attemptWithFallback` 循环的 catch 分支
1. 已收集的 `assistantMessages` 被清空tool_use 块收到合成 tool_result"Model fallback triggered"
2. 思维签名块被移除(`stripSignatureBlocks`)—— 因为思维签名与模型绑定,跨模型回放会 400
@@ -112,13 +121,14 @@ Stop hook 可以注入阻塞错误消息,强制 AI 重新思考。新的消息
## 状态机State 对象
每次迭代的状态通过 `State` 类型(第 204 行)传递:
每次迭代的状态通过 `State` 类型(`src/query.ts`,类型定义)传递:
```typescript
// src/query.ts — State 类型定义
type State = {
messages: Message[] // 当前对话消息
toolUseContext: ToolUseContext // 工具上下文(含权限)
autoCompactTracking: AutoCompactTrackingState // 压缩跟踪
autoCompactTracking: AutoCompactTrackingState | undefined // 压缩跟踪
maxOutputTokensRecoveryCount: number // 输出截断恢复计数
hasAttemptedReactiveCompact: boolean // 是否已尝试即时压缩
maxOutputTokensOverride: number | undefined // 输出 token 上限覆盖
@@ -133,7 +143,7 @@ type State = {
## Token Budget实验性
当 `TOKEN_BUDGET` feature 启用时(第 1311 行),循环在终止前会检查 token 消耗:
当 `TOKEN_BUDGET` feature 启用时(`src/query.ts` 中 `!needsFollowUp` 分支内的预算检查逻辑),循环在终止前会检查 token 消耗:
- **continuation**:未达到预算但超过阈值 → 注入 nudge 消息,让 AI 加速收尾
- **diminishing_returns**:检测到收益递减 → 提前终止
@@ -148,7 +158,7 @@ type State = {
- **每一步都产生真实信息**`runTools()` 返回的 `toolResults` 是 API 不可能预知的——命令输出、文件内容、错误信息
- **动态上下文管理**每轮迭代前都重新评估压缩需求autocompact → microcompact → snip基于最新的 token 计数
- **错误即时恢复**工具失败不需要推倒重来——stop hook 可以注入阻塞错误让 AI 修正策略
- **用户可控**`abortController.signal` 在循环的多个检查点被检测(第 1018、1048、1488 行),用户按 ESC 可以优雅中断
- **用户可控**`abortController.signal` 在循环的多个检查点被检测(第 1059、1095、1529 行),用户按 ESC 可以优雅中断
- **成本控制**Token Budget 在每轮终止前检查,防止 AI 无效循环
## 一个完整的迭代示例
@@ -157,26 +167,31 @@ type State = {
```
迭代 1: 思考→行动
预处理: 无需压缩(上下文很短)
预处理管道: applyToolResultBudget → snipCompact(HISTORY_SNIP feature) → microcompact → applyCollapses(CONTEXT_COLLAPSE feature) → autocompact
→ 上下文很短,无需压缩
API 调用: 返回 tool_use(Glob, "**/*.ts")
工具执行: 返回 42 个文件路径
→ needsFollowUp = true, continue
→ needsFollowUp = true
→ transition: { reason: 'next_turn' }, continue
迭代 2: 思考→行动
预处理: 42 个文件结果仍在预算内
预处理管道: 42 个文件结果仍在预算内
API 调用: 返回 tool_use(Grep, "import.*from")
工具执行: 在 15 个文件中找到 120 条 import
→ needsFollowUp = true, continue
→ needsFollowUp = true
→ transition: { reason: 'next_turn' }, continue
迭代 3: 思考→行动(多轮)
预处理: 120 条 Grep 结果触发 microcompact → 摘要化
预处理管道: 120 条 Grep 结果触发 microcompact → 摘要化
API 调用: 返回 3 个 tool_use(FileEdit, ...)
工具执行: 删除 5 条未使用导入
→ needsFollowUp = true, continue
→ needsFollowUp = true
→ transition: { reason: 'next_turn' }, continue
迭代 4: 总结
API 调用: 返回纯文本"已清理 3 个文件中的 5 条未使用导入"
→ needsFollowUp = false
→ Stop hooks 通过
→ Token Budget 检查通过(如果启用)
→ return { reason: 'completed' }
```

View File

@@ -0,0 +1,17 @@
flowchart TB
START((输入)) --> CTX["Context 管理"]
CTX --> LLM["LLM 流式输出"]
LLM --> TC{tool_use?}
TC --> |是| EXEC["执行工具"]
EXEC --> CTX
TC --> |否| DONE((完成))
classDef proc fill:#eef,stroke:#66c,color:#224
classDef decision fill:#fee,stroke:#c66,color:#422
classDef io fill:#eff,stroke:#6cc,color:#244
class CTX,LLM,EXEC proc
class TC decision
class START,DONE io

View File

@@ -0,0 +1,40 @@
flowchart TB
START((输入)) --> CTX["Context 管理"]
CTX --> PRE["Pre-sampling Hook"]
PRE --> LLM["LLM 流式输出"]
LLM --> TC{tool_use?}
TC --> |是| PERM{需权限?}
PERM --> |是| USER["👤 用户审批"]
USER --> |allow| TOOL_PRE
USER --> |deny| DENIED["拒绝"]
PERM --> |否| TOOL_PRE["Pre-tool Hook"]
TOOL_PRE --> EXEC["并发执行工具"]
EXEC --> TOOL_POST["Post-tool Hook"]
TOOL_POST --> CTX
DENIED --> CTX
TC --> |否| POST["Post-sampling Hook"]
POST --> STOP{"Stop Hook"}
STOP --> |不通过| CTX
STOP --> |通过| BUDGET{"Token Budget"}
BUDGET --> |继续| CTX
BUDGET --> |完成| DONE((完成))
subgraph SUB["子 Agent"]
FORK["AgentTool"] --> RECURSE["递归调用"]
end
EXEC -.-> FORK
classDef proc fill:#eef,stroke:#66c,color:#224
classDef decision fill:#fee,stroke:#c66,color:#422
classDef hook fill:#ffe,stroke:#cc6,color:#442
classDef io fill:#eff,stroke:#6cc,color:#244
classDef sub fill:#efe,stroke:#6a6,color:#242
class CTX,LLM,EXEC proc
class TC,PERM,STOP,BUDGET decision
class PRE,TOOL_PRE,TOOL_POST,POST hook
class START,DONE,USER,DENIED io
class FORK,RECURSE sub

View File

@@ -12,7 +12,7 @@ Claude Code 的 Agent 不仅仅来自用户自定义——系统有三类来源
| 来源 | 位置 | 优先级 |
|------|------|--------|
| **Built-in** | `src/tools/AgentTool/built-in/` 硬编码 | 最低(可被覆盖) |
| **Built-in** | `packages/builtin-tools/src/tools/AgentTool/built-in/` 硬编码 | 最低(可被覆盖) |
| **Plugin** | 通过插件系统注册 | 中 |
| **User/Project/Policy** | `.claude/agents/*.md` 或 settings.json | 最高 |
@@ -127,7 +127,7 @@ color: "blue" # 终端中的 Agent 颜色标识
以内置 Explore Agent 为例:
```typescript
// src/tools/AgentTool/built-in/exploreAgent.ts
// packages/builtin-tools/src/tools/AgentTool/built-in/exploreAgent.ts
disallowedTools: [
'Agent', // 不能嵌套调用 Agent
'ExitPlanMode', // 不需要 plan mode

View File

@@ -1,14 +1,14 @@
---
title: "Hooks 生命周期钩子 - 执行引擎与拦截协议"
description: "从源码角度解析 Claude Code Hooks 系统22 种 Hook 事件、6 种 Hook 类型、同步/异步执行协议、JSON 输出 schema、if 条件匹配、以及 Hook 如何注入上下文和拦截工具调用。"
description: "从源码角度解析 Claude Code Hooks 系统27 种 Hook 事件、6 种 Hook 类型、同步/异步执行协议、JSON 输出 schema、if 条件匹配、以及 Hook 如何注入上下文和拦截工具调用。"
keywords: ["Hooks", "生命周期钩子", "拦截器", "PreToolUse", "Hook 协议"]
---
{/* 本章目标:从源码角度揭示 Hook 的执行引擎、匹配机制、返回值协议和生命周期管理 */}
## 22 种 Hook 事件
## 27 种 Hook 事件
Claude Code 定义了 22 种 Hook 事件(`coreTypes.ts:25-53`),覆盖完整的 Agent 生命周期:
Claude Code 定义了 27 种 Hook 事件(`HOOK_EVENTS` 数组,`src/entrypoints/sdk/coreTypes.ts`),覆盖完整的 Agent 生命周期:
| 阶段 | 事件 | 触发时机 | 匹配字段 |
|------|------|---------|---------|
@@ -32,6 +32,7 @@ Claude Code 定义了 22 种 Hook 事件(`coreTypes.ts:25-53`),覆盖完
| | `TaskCompleted` | 任务完成 | — |
| **MCP** | `Elicitation` | MCP 服务器请求用户输入 | `mcp_server_name` |
| | `ElicitationResult` | Elicitation 结果返回 | `mcp_server_name` |
| **通知** | `Notification` | 系统通知事件 | `notification_type` |
| **环境** | `ConfigChange` | 配置变更 | `source` |
| | `CwdChanged` | 工作目录变更 | — |
| | `FileChanged` | 文件变更 | `file_path` |
@@ -40,7 +41,11 @@ Claude Code 定义了 22 种 Hook 事件(`coreTypes.ts:25-53`),覆盖完
## 6 种 Hook 类型
Hooks 配置支持 6 种执行方式`src/types/hooks.ts`
Hooks 配置支持 6 种执行方式,类型定义分布在 3 个文件中
- **可持久化类型**`command`、`prompt`、`agent`、`http`)— Zod schema 定义在 `src/schemas/hooks.ts`,通过 `z.discriminatedUnion('type', [...])` 声明
- **callback 类型** — TypeScript 接口定义在 `src/types/hooks.ts`,用于 SDK 注册的内部 JS 函数
- **function 类型** — 定义在 `src/utils/hooks/sessionHooks.ts`,用于运行时动态注册的函数 Hook
| 类型 | 执行方式 | 适用场景 |
|------|---------|---------|
@@ -53,7 +58,7 @@ Hooks 配置支持 6 种执行方式(`src/types/hooks.ts`
## 执行引擎execCommandHook
`execCommandHook()``src/utils/hooks.ts:829-1417`)是命令型 Hook 的执行核心:
`execCommandHook()``src/utils/hooks.ts``execCommandHook` 函数)是命令型 Hook 的执行核心:
```
execCommandHook(hook, hookEvent, hookName, jsonInput, signal)
@@ -75,7 +80,7 @@ execCommandHook(hook, hookEvent, hookName, jsonInput, signal)
### 异步 Hook 的检测协议
Hook 进程的 stdout 第一行如果是 `{"async":true}`,系统将其转为后台任务(`hooks.ts:1199-1246`
Hook 进程的 stdout 第一行如果是 `{"async":true}`,系统将其转为后台任务(`isAsyncHookJSONOutput` 检测 + `executeInBackground` 调用
```typescript
const firstLine = firstLineOf(stdout).trim()
@@ -96,7 +101,7 @@ if (isAsyncHookJSONOutput(parsed)) {
## Hook 输出的 JSON Schema
同步 Hook 的输出遵循严格的 Zod schema`src/types/hooks.ts:49-567`
同步 Hook 的输出遵循严格的 Zod schema`syncHookResponseSchema`,定义在 `src/types/hooks.ts``hookJSONOutputSchema` 定义在 `src/schemas/hooks.ts`
```json
{
@@ -120,16 +125,25 @@ if (isAsyncHookJSONOutput(parsed)) {
| 事件 | 专有字段 | 作用 |
|------|---------|------|
| `PreToolUse` | `permissionDecision`, `updatedInput`, `additionalContext` | 拦截/修改工具输入 |
| `UserPromptSubmit` | `additionalContext` | 注入额外上下文 |
| `PreToolUse` | `permissionDecision`, `permissionDecisionReason`, `updatedInput`, `additionalContext` | 拦截/修改工具输入 |
| `PostToolUse` | `additionalContext`, `updatedMCPToolOutput` | 修改 MCP 工具输出 |
| `SessionStart` | `initialUserMessage`, `watchPaths` | 设置初始消息和文件监控 |
| `PostToolUseFailure` | `additionalContext` | 失败后注入上下文 |
| `UserPromptSubmit` | `additionalContext` | 注入额外上下文 |
| `SessionStart` | `additionalContext`, `initialUserMessage`, `watchPaths` | 设置初始消息和文件监控 |
| `PermissionRequest` | `decision`(含 `allow`/`deny` 子字段) | 权限请求的 Hook 决策 |
| `PermissionDenied` | `retry` | 指示是否重试 |
| `SubagentStart` | `additionalContext` | 子 Agent 启动时注入上下文 |
| `Elicitation` | `action`, `content` | 控制用户输入对话框 |
| `ElicitationResult` | `action`, `content` | Elicitation 结果处理 |
| `Notification` | `additionalContext` | 通知事件注入上下文 |
| `Setup` | `additionalContext` | 初始化时注入上下文 |
| `CwdChanged` | `watchPaths` | 目录变更后更新监控路径 |
| `FileChanged` | `watchPaths` | 文件变更后更新监控路径 |
| `WorktreeCreate` | `worktreePath` | Worktree 创建通知 |
## Hook 匹配机制getMatchingHooks
`getMatchingHooks()``hooks.ts:1685-1956`)负责从所有来源中查找匹配的 Hook
`getMatchingHooks()``src/utils/hooks.ts``getMatchingHooks` 函数)负责从所有来源中查找匹配的 Hook
### 多来源合并
@@ -143,7 +157,7 @@ getHooksConfig()
### 匹配规则
`matcher` 字段支持三种模式(`matchesPattern()`, `hooks.ts:1428-1463`
`matcher` 字段支持三种模式(`matchesPattern()` 函数,`src/utils/hooks.ts`
```
"Write" → 精确匹配
@@ -154,7 +168,7 @@ getHooksConfig()
### if 条件过滤
Hook 可以指定 `if` 条件,只在特定输入时触发。`prepareIfConditionMatcher()``hooks.ts:1472-1503`)预编译匹配器:
Hook 可以指定 `if` 条件,只在特定输入时触发。`prepareIfConditionMatcher()``src/utils/hooks.ts``prepareIfConditionMatcher` 函数)预编译匹配器:
```json
{
@@ -169,11 +183,11 @@ Hook 可以指定 `if` 条件,只在特定输入时触发。`prepareIfConditio
### Hook 去重
同一个 Hook 命令在不同配置层级user/project/local可能重复。系统按 `pluginRoot\0command` 做 Map 去重,保留**最后合并的层级**。
同一个 Hook 命令在不同配置层级user/project/local可能重复。系统按四部分复合键做 Map 去重:`${pluginRoot}\0${shell}\0${command}\0${ifCondition}`(由 `hookDedupKey()` 函数构建),保留**最后合并的层级**。
## 工作区信任检查
**所有 Hook 都要求工作区信任**`shouldSkipHookDueToTrust()`, `hooks.ts:286-296`)。这是纵深防御措施——防止恶意仓库的 `.claude/settings.json` 在未信任的情况下执行任意命令。
**所有 Hook 都要求工作区信任**`shouldSkipHookDueToTrust()` 函数,`src/utils/hooks.ts`)。这是纵深防御措施——防止恶意仓库的 `.claude/settings.json` 在未信任的情况下执行任意命令。
```typescript
// 交互模式下,所有 Hook 要求信任
@@ -226,13 +240,13 @@ SDK 非交互模式下信任是隐式的(`getIsNonInteractiveSession()` 为 tr
## Session Hook 的生命周期
Agent 和 Skill 的前置 Hook 通过 `registerFrontmatterHooks()` 注册(`runAgent.ts:567-575`),绑定到 agent 的 session ID。Agent 结束时通过 `clearSessionHooks()` 清理。
Agent 和 Skill 的前置 Hook 通过 `registerFrontmatterHooks()` 注册(调用位置:`packages/builtin-tools/src/tools/AgentTool/runAgent.ts`;定义位置:`src/utils/hooks/registerFrontmatterHooks.ts`),绑定到 agent 的 session ID。Agent 结束时通过 `clearSessionHooks()`(定义位置:`src/utils/hooks/sessionHooks.ts`清理。
```typescript
// runAgent.ts:567 — 注册 agent 的前置 Hook
// runAgent.ts — 注册 agent 的前置 Hook
registerFrontmatterHooks(rootSetAppState, agentId, agentDefinition.hooks, ...)
// runAgent.ts:820 — finally 块清理
// runAgent.ts — finally 块清理
clearSessionHooks(rootSetAppState, agentId)
```

View File

@@ -0,0 +1,346 @@
---
title: "MCP 配置 - 多来源合并、作用域与策略管控"
description: "详细说明 Claude Code MCP 配置的来源层次、合并优先级、传输类型、企业策略管控、插件集成和保留名称机制。"
keywords: ["MCP", "配置", "settings.json", ".mcp.json", "企业策略", "插件"]
---
## 配置来源与作用域
Claude Code 的 MCP 配置来自多个来源,每个来源对应一个 `scope`(作用域)。配置按优先级合并,高优先级来源的同名配置覆盖低优先级。
### 来源列表
| 来源 | Scope | 文件/接口 | 说明 |
|------|-------|----------|------|
| 企业管控 | `enterprise` | 系统管理路径 `managed-mcp.json` | **排他模式**:存在时忽略所有其他来源 |
| 本地项目 | `local` | `<project>/.claude/settings.local.json` | 项目级私有配置(不提交到 VCS |
| 项目配置 | `project` | `<project>/.mcp.json` | 项目级共享配置(可提交到 VCS |
| 用户全局 | `user` | `~/.claude/settings.json` | 用户级配置,所有项目共享 |
| 插件 | `dynamic` | 插件 manifest 中 `.mcp.json` / `.mcpb` | 插件提供的 MCP 服务器 |
| claude.ai | `claudeai` | 通过 API 获取 | claude.ai 网页端配置的连接器 |
| 内置动态 | `dynamic` | 代码中注册 | Computer Use / Chrome 等内置服务器 |
| IDE SDK | `sdk` | IDE 传入 | VS Code / JetBrains 嵌入模式 |
### 合并优先级(从低到高)
```
claude.ai 连接器 ← 最低优先级
↓ 去重
插件服务器
↓ 去重
用户全局配置
项目配置(.mcp.json ← 需要用户审批
本地项目配置
动态配置(内置 MCP ← 最高优先级
```
`Object.assign({}, dedupedPluginServers, userServers, approvedProjectServers, localServers)` 实现合并——后出现的同名键覆盖前者。
## 企业管控模式
当 `managed-mcp.json` 文件存在时,进入 **排他模式**
```typescript
// config.ts:1084
if (doesEnterpriseMcpConfigExist()) {
// 只返回企业配置,忽略所有用户/项目/插件/claude.ai 配置
return { servers: filtered, errors: [] }
}
```
特性:
- 路径由系统管理决定(`getManagedFilePath()` + `managed-mcp.json`
- 覆盖所有用户级、项目级、插件和 claude.ai 配置
- 仍然应用策略过滤allowlist/denylist
- 无法通过 CLI 添加新服务器(`addMcpConfig` 会拒绝)
## 传输类型与配置 Schema
### stdio默认
启动子进程,通过 stdin/stdout JSON-RPC 通信。
```json
{
"my-server": {
"command": "npx",
"args": ["-y", "@my-org/mcp-server"],
"env": { "API_KEY": "..." }
}
}
```
`type` 字段可省略(默认为 `stdio`)。环境变量通过 `env` 传递给子进程,会与当前进程环境合并。
**Windows 注意**:使用 `npx` 需要包装为 `cmd /c npx`,否则会报错。
### SSEServer-Sent Events
通过 HTTP SSE 连接远程 MCP 服务器。
```json
{
"my-remote": {
"type": "sse",
"url": "https://mcp.example.com/sse",
"headers": { "Authorization": "Bearer ..." },
"oauth": {
"clientId": "...",
"authServerMetadataUrl": "https://auth.example.com/.well-known/oauth-authorization-server"
}
}
}
```
支持 OAuth 认证流程。认证失败时进入 `needs-auth` 状态15 分钟 TTL 缓存避免重复提示。
### HTTPStreamable HTTP
HTTP 流式传输。
```json
{
"my-http": {
"type": "http",
"url": "https://mcp.example.com/mcp",
"headers": { "X-API-Key": "..." }
}
}
```
支持与 SSE 相同的 OAuth 配置。
### WebSocket
```json
{
"my-ws": {
"type": "ws",
"url": "wss://mcp.example.com/ws"
}
}
```
### IDE 专用类型(内部)
`sse-ide` 和 `ws-ide` 是 IDE 扩展专用类型,不由用户直接配置。
- `sse-ide`:使用 lockfile token 认证
- `ws-ide`:使用 `X-Claude-Code-Ide-Authorization` header
### SDK 类型(内部)
`type: "sdk"` 由 IDE 嵌入模式传入,不经过保留名称检查和企业管控排他限制。
### claude.ai 代理类型(内部)
`type: "claudeai-proxy"` 由 claude.ai 网页端配置的连接器使用,通过 OAuth bearer token 认证并支持 401 重试。
## 配置操作
### 添加 MCP 服务器
通过 CLI 命令 `claude mcp add` 或 API 调用 `addMcpConfig()`
```bash
# 添加到用户配置
claude mcp add my-server -s user -- npx @my-org/mcp-server
# 添加到项目配置
claude mcp add my-server -s project -- npx @my-org/mcp-server
# 添加 HTTP 类型
claude mcp add my-remote -s user -t http -u https://mcp.example.com/mcp
```
添加时的验证流程:
1. **名称校验**:只允许字母、数字、连字符和下划线
2. **保留名检查**`claude-in-chrome` 和 `computer-use` 被保留
3. **企业管控检查**:企业模式下拒绝添加
4. **Schema 验证**Zod 校验配置格式
5. **策略检查**denylist 拒绝、allowlist 验证
### 移除 MCP 服务器
```bash
claude mcp remove my-server -s user
```
### 列出 MCP 服务器
```bash
claude mcp list
```
## 项目配置审批
`.mcp.json` 中的项目配置需要用户显式审批才能生效:
```typescript
// config.ts:1166
const approvedProjectServers: Record<string, ScopedMcpServerConfig> = {}
for (const [name, config] of Object.entries(projectServers)) {
if (getProjectMcpServerStatus(name) === 'approved') {
approvedProjectServers[name] = config
}
}
```
首次打开项目时Claude Code 会提示用户审批 `.mcp.json` 中的每个服务器。审批状态持久化在本地配置中。
## 插件 MCP 集成
插件通过 manifest 中的 `.mcp.json` 或 `.mcpb` 文件声明 MCP 服务器:
```typescript
// 插件 MCP 加载流程
const pluginResult = await loadAllPluginsCacheOnly()
const pluginServerResults = await Promise.all(
pluginResult.enabled.map(plugin => getPluginMcpServers(plugin, mcpErrors))
)
```
### 插件命名空间
插件 MCP 服务器名格式为 `plugin:<pluginName>:<serverName>`,不会与手动配置的名称冲突。
### 去重机制
插件服务器通过内容签名去重(`dedupPluginMcpServers`
- **stdio 类型**:签名 = `stdio:` + JSON.stringify([command, ...args])
- **URL 类型**:签名 = `url:` + 原始 URLunwrap CCR proxy URL
- **sdk 类型**:签名为 null不去重
去重规则:
1. 手动配置优先于插件配置
2. 先加载的插件优先于后加载的
3. 被抑制的插件服务器在 `/plugin` UI 中显示提示
### claude.ai 连接器去重
claude.ai 连接器使用相同的内容签名机制去重(`dedupClaudeAiMcpServers`
- 仅启用的手动配置参与去重(禁用的手动配置不应抑制连接器)
- 连接器名格式为 `claude.ai <DisplayName>`
## 策略管控
### Allowlist / Denylist
企业策略通过 allowlist 和 denylist 控制可用的 MCP 服务器:
```typescript
// config.ts:1243 - 最终策略过滤
for (const [name, serverConfig] of Object.entries(configs)) {
if (!isMcpServerAllowedByPolicy(name, serverConfig)) {
continue // 跳过策略禁止的服务器
}
filtered[name] = serverConfig
}
```
策略检查考虑:
- 服务器名称匹配
- stdio 类型的 command + args 匹配
- URL 类型的 URL 模式匹配(支持通配符)
### 插件专用模式
`isRestrictedToPluginOnly('mcp')` 启用时,只允许插件提供的 MCP 服务器——用户/项目级配置被忽略。
## 环境变量展开
MCP 配置中的环境变量支持 `$VAR` 和 `${VAR}` 语法展开:
```json
{
"my-server": {
"command": "npx",
"args": ["@my-org/mcp-server"],
"env": {
"API_KEY": "$MY_API_KEY",
"DB_URL": "${DATABASE_URL}"
}
}
}
```
展开时缺失的变量会生成警告信息,但不阻止配置加载。
## 内置 MCP 动态注册
内置 MCP 服务器在 `main.tsx` 启动流程中动态注入配置:
### Computer Use MCP
```typescript
// src/utils/computerUse/setup.ts
export function setupComputerUseMCP(): {
mcpConfig: Record<string, ScopedMcpServerConfig>
allowedTools: string[]
} {
return {
mcpConfig: {
"computer-use": {
type: "stdio",
command: process.execPath,
args: ["--computer-use-mcp"],
scope: "dynamic",
}
},
allowedTools: ["mcp__computer-use__screenshot", ...]
}
}
```
启用条件:
- Feature flag `CHICAGO_MCP` 开启
- `getPlatform() !== "unknown"`macOS/Windows/Linux
- 非非交互式会话
- GrowthBook gate `getChicagoEnabled()` 返回 true
### Claude in Chrome MCP
```typescript
// 类似 Computer Use在 main.tsx 中注册
const { mcpConfig, allowedTools, systemPrompt } = setupClaudeInChrome()
dynamicMcpConfig = { ...dynamicMcpConfig, ...mcpConfig }
```
启用条件:
- `--chrome` 参数或 `claudeInChromeDefaultEnabled` 配置
- Chrome 扩展已安装
### VSCode SDK MCP
IDE 嵌入模式通过初始化消息传入 `type:'sdk'` 的配置,由 `setupVscodeSdkMcp()` 设置双向通知。
## 保留名称
以下 MCP 服务器名称被保留,用户无法手动配置同名服务器:
| 名称 | 用途 | 检查条件 |
|------|------|---------|
| `claude-in-chrome` | Chrome 浏览器控制 | 始终检查 |
| `computer-use` | 桌面自动化 | `CHICAGO_MCP` feature flag 开启时检查 |
| `claude-vscode` | VSCode IDE 集成 | 由 SDK 传入,不经过名称检查 |
保留名检查在两个位置:
1. `addMcpConfig()``config.ts:636-648`)— 运行时拒绝
2. `main.tsx` 启动检查(`main.tsx:2351-2368`)— 启动时退出
## 关键源文件索引
| 文件 | 职责 |
|------|------|
| `src/services/mcp/config.ts` | 配置管理核心:合并、去重、策略、添加/删除 |
| `src/services/mcp/types.ts` | Zod Schema 定义、类型声明 |
| `src/services/mcp/client.ts` | 连接管理、传输层选择 |
| `src/utils/plugins/mcpPluginIntegration.ts` | 插件 MCP 配置加载 |
| `src/utils/computerUse/setup.ts` | Computer Use 动态注册 |
| `src/utils/claudeInChrome/common.ts` | Chrome MCP 保留名与工具名 |
| `src/services/mcp/vscodeSdkMcp.ts` | VSCode SDK 双向通知 |

View File

@@ -1,25 +1,32 @@
---
title: "MCP 协议 - 连接管理、工具发现与执行链路"
description: "从源码角度解析 Claude Code 的 MCP 集成7 种传输层实现、connectToServer 的 memoize 缓存、工具发现的 LRU 策略、认证状态机、以及 MCP 工具如何进入权限检查链路。"
keywords: ["MCP", "Model Context Protocol", "工具扩展", "MCP 客户端", "工具发现"]
description: "从源码角度解析 Claude Code 的 MCP 集成:内置 MCP 与外部 MCP 的区别、7 种传输层实现、connectToServer 的 memoize 缓存、工具发现的 LRU 策略、认证状态机、以及 MCP 工具如何进入权限检查链路。"
keywords: ["MCP", "Model Context Protocol", "工具扩展", "MCP 客户端", "工具发现", "内置 MCP", "外部 MCP"]
---
{/* 本章目标:从源码角度揭示 MCP 客户端的连接管理、工具发现协议和执行链路 */}
{/* 本章目标:从源码角度揭示 MCP 客户端的两种运行模式(内置/外部)、连接管理、工具发现协议和执行链路 */}
## 架构总览:从配置到可用工具
```
settings.json: { mcpServers: { "my-db": { command: "npx", args: [...] } } }
配置层(多来源合并)
├── settings.json: { mcpServers: { "my-db": { command: "npx", args: [...] } } } ← 外部
├── .mcp.json: 项目级 MCP 配置 ← 外部
├── 插件 manifest (.mcp.json / .mcpb) ← 外部(插件)
├── claude.ai connectors ← 外部(远程)
├── enterprise managed-mcp.json ← 外部(企业管控)
├── setupComputerUseMCP() / setupClaudeInChrome() ← 内置(动态注册)
└── SDK 传入 (type:'sdk') ← 内置IDE 嵌入)
getAllMcpConfigs() ← 合并 user/project/local 三级配置
getAllMcpConfigs() ← enterprise 独占 或 合并 user/project/local + plugin + claude.ai
useManageMCPConnections() ← React Hook 管理连接生命周期
connectToServer(name, config) ← memoize 缓存lodash memoize
├── 创建 Transportstdio/sse/http/...
├── new Client() ← @modelcontextprotocol/sdk
├── client.connect(transport) ← 超时控制MCP_TIMEOUT, 默认 30s
└── 返回 MCPServerConnection ← { connected | failed | needs-auth | pending }
├── 判断:内置 MCP → InProcessTransport同进程
├── 判断:外部 stdio → StdioClientTransport子进程
├── 判断:远程 SSE/HTTP/WS → 网络传输
└── 返回 MCPServerConnection ← { connected | failed | needs-auth | pending | disabled }
fetchToolsForClient(client) ← LRU(20) 缓存
├── client.request({ method: 'tools/list' })
@@ -30,19 +37,208 @@ assembleToolPool() ← 合并内置工具 + MCP 工具
工具名格式: mcp__<serverName>__<toolName> ← buildMcpToolName()
```
## 两种 MCP 模式:内置 vs 外部
Claude Code 的 MCP 实现区分 **内置 MCP 服务器** 和 **外部 MCP 服务器**。两者使用相同的客户端协议和工具发现机制,但在连接方式、生命周期管理和配置来源上完全不同。
### 内置 MCP 服务器
内置 MCP 服务器由 Claude Code 自身提供,无需用户手动配置。它们在启动时自动注册为 `dynamic` scope 的配置,并在同进程内运行。
| 服务器 | 名称 | 包路径 | Feature Flag | 启用方式 |
|--------|------|--------|-------------|---------|
| Computer Use | `computer-use` | `@ant/computer-use-mcp` | `CHICAGO_MCP` | GrowthBook gate + macOS + interactive |
| Claude in Chrome | `claude-in-chrome` | `@ant/claude-for-chrome-mcp` | — | `--chrome` 参数或 `claudeInChromeDefaultEnabled` 配置 |
| VSCode SDK | `claude-vscode` | — | — | IDE 嵌入模式 (type:`sdk`) |
#### InProcessTransport零开销同进程通信
内置服务器通过 `InProcessTransport``src/services/mcp/InProcessTransport.ts`)运行,**不启动子进程**
```typescript
// 创建一对 linked transport —— 消息在两端之间直接传递
const [clientTransport, serverTransport] = createLinkedTransportPair()
// server 端连接到 serverTransport
inProcessServer = createComputerUseMcpServerForCli()
await inProcessServer.connect(serverTransport)
// client 端使用 clientTransport与外部 MCP 的 Client 相同接口)
transport = clientTransport
```
`InProcessTransport` 的核心设计:
- `send()` 通过 `queueMicrotask()` 异步投递消息到对端,避免同步请求/响应的栈深度问题
- `close()` 双向关闭,任一端关闭都会触发两端的 `onclose` 回调
- 无网络开销、无 IPC 序列化、无进程启动时间
#### 动态注册流程
内置服务器在 `main.tsx` 的启动流程中注册,注入 `dynamicMcpConfig`
```typescript
// main.tsx: Computer Use MCP 动态注册
if (feature("CHICAGO_MCP") && getPlatform() !== "unknown" && !getIsNonInteractiveSession()) {
const { getChicagoEnabled } = await import("src/utils/computerUse/gates.js")
if (getChicagoEnabled()) {
const { setupComputerUseMCP } = await import("src/utils/computerUse/setup.js")
const { mcpConfig, allowedTools } = setupComputerUseMCP()
dynamicMcpConfig = { ...dynamicMcpConfig, ...mcpConfig }
allowedTools.push(...cuTools)
}
}
```
`setupComputerUseMCP()` 返回的配置(`src/utils/computerUse/setup.ts`
```typescript
{
"computer-use": {
type: "stdio", // 类型标记为 stdio但 client.ts 会拦截为 InProcessTransport
command: process.execPath,
args: ["--computer-use-mcp"],
scope: "dynamic", // 动态作用域,不持久化
}
}
```
#### 连接时拦截
`connectToServer()` 在 `client.ts:906-944` 中根据服务器名拦截内置服务器:
```typescript
// Chrome MCP — 在 process 内运行,避免 ~325MB 子进程
if (isClaudeInChromeMCPServer(name)) {
const { createChromeContext } = await import('../../utils/claudeInChrome/mcpServer.js')
const { createClaudeForChromeMcpServer } = await import('@ant/claude-for-chrome-mcp')
const { createLinkedTransportPair } = await import('./InProcessTransport.js')
const context = createChromeContext(config.env)
inProcessServer = createClaudeForChromeMcpServer(context)
const [clientTransport, serverTransport] = createLinkedTransportPair()
await inProcessServer.connect(serverTransport)
transport = clientTransport
}
// Computer Use MCP — 同理
if (feature('CHICAGO_MCP') && isComputerUseMCPServer(name)) {
const { createComputerUseMcpServerForCli } = await import('../../utils/computerUse/mcpServer.js')
const { createLinkedTransportPair } = await import('./InProcessTransport.js')
inProcessServer = await createComputerUseMcpServerForCli()
const [clientTransport, serverTransport] = createLinkedTransportPair()
await inProcessServer.connect(serverTransport)
transport = clientTransport
}
```
#### 保留名称保护
内置服务器的名称被保留,用户无法手动添加同名配置(`config.ts:636-648`
```typescript
// 添加 MCP 配置时检查保留名
if (isClaudeInChromeMCPServer(name)) {
throw new Error(`Cannot add MCP server "${name}": this name is reserved.`)
}
if (feature('CHICAGO_MCP') && isComputerUseMCPServer(name)) {
throw new Error(`Cannot add MCP server "${name}": this name is reserved.`)
}
```
启动时也有全局检查(`main.tsx:2351-2368`):如果用户配置中包含保留名(非 `type:'sdk'`),直接 `process.exit(1)`。
#### VSCode SDK MCP
VSCode SDK MCP 是特殊的内置模式。IDE如 VS Code、JetBrains通过嵌入方式启动 Claude Code并传入 `type:'sdk'` 的 MCP 配置。这类配置:
- 不经过保留名称检查IDE 可以使用任意名称)
- 不参与 enterprise MCP 的排他控制
- 通过 VSCode SDK transport 连接
- 支持双向通知(如 `file_updated`、`experiment_gates`
```typescript
// src/services/mcp/vscodeSdkMcp.ts
export function setupVscodeSdkMcp(sdkClients: MCPServerConnection[]): void {
const client = sdkClients.find(client => client.name === 'claude-vscode')
if (client && client.type === 'connected') {
// 注册 log_event 通知处理器
client.client.setNotificationHandler(LogEventNotificationSchema(), ...)
// 发送实验门控到 VSCode
client.client.notification({ method: 'experiment_gates', params: { gates } })
}
}
```
### 外部 MCP 服务器
外部 MCP 服务器由用户在配置文件中声明,通过子进程或网络连接运行。
#### 配置来源
| 来源 | Scope | 文件位置 | 优先级 |
|------|-------|---------|--------|
| 项目配置 | `project` | `<project>/.mcp.json` | 最高(同名覆盖) |
| 本地配置 | `local` | `<project>/.claude/settings.local.json` | 高 |
| 用户配置 | `user` | `~/.claude/settings.json` | 中 |
| 插件 | `dynamic` | 插件 manifest 中 `.mcp.json` | 中 |
| claude.ai | `claudeai` | 通过 API 获取 | 低 |
| 企业管控 | `enterprise` | 系统管理路径 `managed-mcp.json` | 排他(存在时覆盖全部) |
#### 配置示例
```json
// settings.json / .mcp.json 中的 MCP 配置
{
"mcpServers": {
// stdio 类型 — 启动子进程
"my-database": {
"command": "npx",
"args": ["@my-org/db-mcp-server"],
"env": { "DB_URL": "postgres://..." }
},
// HTTP 流类型 — 远程服务器
"remote-api": {
"type": "http",
"url": "https://api.example.com/mcp"
},
// SSE 类型 — Server-Sent Events
"realtime-feed": {
"type": "sse",
"url": "https://feed.example.com/sse"
},
// WebSocket 类型
"ws-service": {
"type": "ws",
"url": "wss://ws.example.com/mcp"
}
}
}
```
#### 配置合并与去重
`getAllMcpConfigs()``config.ts`)按优先级合并多个来源的配置:
1. 企业管控配置存在时,**独占返回**(忽略所有其他来源)
2. 否则合并user → project → local → plugin → claude.ai
3. 插件与手动配置去重:通过 `getMcpServerSignature()` 生成内容签名(基于 command/args/url插件配置被同名手动配置抑制
4. `addScopeToServers()` 为每个配置项标注来源 scope
## 7 种传输层实现
`connectToServer()``client.ts:596-1643`)根据 `config.type` 分发到不同的 Transport 实现:
| 传输类型 | Transport 类 | 适用场景 | 认证方式 |
|----------|-------------|---------|---------|
| `stdio`(默认) | `StdioClientTransport` | 本地子进程 | 无 |
| `stdio`(默认) | `StdioClientTransport` | 外部本地子进程 | 无 |
| `sse` | `SSEClientTransport` | 远程 SSE 服务 | `ClaudeAuthProvider` + OAuth |
| `http` | `StreamableHTTPClientTransport` | HTTP 流 | `ClaudeAuthProvider` + OAuth |
| `sse-ide` | `SSEClientTransport` | IDE 集成 | lockfile token |
| `ws-ide` | `WebSocketTransport` | IDE WebSocket | `X-Claude-Code-Ide-Authorization` |
| `ws` | `WebSocketTransport` | WebSocket 服务 | session ingress token |
| `claudeai-proxy` | `StreamableHTTPClientTransport` | claude.ai 代理 | OAuth bearer + 401 重试 |
| InProcess内置 | `InProcessTransport` | Computer Use / Chrome | 无(同进程) |
### stdio 传输的进程管理
@@ -108,13 +304,21 @@ timer.unref?.() // 不阻止进程退出
## 工具发现:从 MCP 到 Tool 接口
`fetchToolsForClient()``client.ts:1745-2000`)使用 `memoizeWithLRU` 缓存(上限 20将 MCP 工具转换为 Claude Code 的统一 Tool 接口:
`fetchToolsForClient()``client.ts:1744-2000`)使用 `memoizeWithLRU` 缓存(上限 100将 MCP 工具转换为 Claude Code 的统一 Tool 接口:
```typescript
const fullyQualifiedName = buildMcpToolName(client.name, tool.name)
// 结果: "mcp__my-db__query"
// 结果: "mcp__my-database__query"
```
### 内置 MCP 的工具发现
内置 MCP 服务器虽然使用 InProcessTransport但工具发现流程与外部服务器完全一致
- **Computer Use**`createComputerUseMcpServerForCli()` 在 `src/utils/computerUse/mcpServer.ts` 中构建 MCP Server 对象,注册 `ListToolsRequestSchema` handler。工具描述包含平台特定的已安装应用列表1s 超时枚举)。
- **Claude in Chrome**`createClaudeForChromeMcpServer()` 在 `@ant/claude-for-chrome-mcp` 包中构建 Server提供 17+ 个浏览器控制工具。
- **VSCode SDK**:由 IDE 端提供工具列表,通过 SDK transport 传递。
### 工具描述截断
MCP 工具描述上限 2048 字符(`MAX_MCP_DESCRIPTION_LENGTH`。OpenAPI 生成的 MCP 服务器曾观察到 15-60KB 的描述文档。
@@ -134,6 +338,8 @@ MCP 工具描述上限 2048 字符(`MAX_MCP_DESCRIPTION_LENGTH`。OpenAPI
MCP 工具默认返回 `{ behavior: 'passthrough' }``client.ts:1816-1834`),意味着它们始终进入权限确认流程。工具名使用 `mcp__` 前缀精确匹配权限规则。
内置 MCP 服务器的工具通过 `allowedTools` 列表自动授权——在 `main.tsx` 启动时加入,绕过普通权限提示。例如 Computer Use 工具的 `request_access` 自行处理会话级审批。
## MCP 工具的执行链路
```
@@ -169,23 +375,33 @@ getRemoteMcpServerConnectionBatchSize() // 默认 20
本地 MCP 服务器stdio是重量级的子进程默认限制 3 个并发连接。远程服务器是轻量级 HTTP 请求,允许 20 个并发。
## 实际配置示例
## 内置 vs 外部 MCP 对比总结
```json
// settings.json 中的 MCP 配置
{
"mcpServers": {
"my-database": {
"command": "npx",
"args": ["@my-org/db-mcp-server"],
"env": { "DB_URL": "postgres://..." }
},
"remote-api": {
"type": "http",
"url": "https://api.example.com/mcp"
}
}
}
```
| 维度 | 内置 MCP | 外部 MCP |
|------|---------|---------|
| **Transport** | `InProcessTransport`(同进程) | stdio / SSE / HTTP / WebSocket |
| **配置来源** | `setupComputerUseMCP()` / `setupClaudeInChrome()` 等动态注册 | settings.json / .mcp.json / 插件 / claude.ai |
| **Scope** | `dynamic` | `user` / `project` / `local` / `enterprise` / `claudeai` |
| **进程模型** | 同进程,零开销 | 子进程stdio或网络连接 |
| **名称保护** | 保留名,用户不可添加同名 | 自由命名(字母数字 + `-_` |
| **生命周期** | 随 CLI 启停 | 连接缓存 + 按需重连 |
| **权限** | `allowedTools` 自动授权 | `passthrough` 进入权限确认 |
| **Feature Flag** | `CHICAGO_MCP`Computer Use等 | 无(始终可用) |
| **工具发现** | 与外部相同MCP 协议) | 标准 MCP `tools/list` |
| **清理** | `inProcessServer.close()` | 信号升级策略 SIGINT→SIGTERM→SIGKILL |
配置后AI 的工具列表中会出现 `mcp__my-database__query` 和 `mcp__remote-api__*` 工具——与内置工具使用相同的权限检查链路和 UI 渲染。
## 关键源文件索引
| 文件 | 职责 |
|------|------|
| `src/services/mcp/client.ts` | 核心客户端connectToServer、fetchToolsForClient、MCPTool.call |
| `src/services/mcp/config.ts` | 配置管理getAllMcpConfigs、addMcpConfig、removeMcpConfig |
| `src/services/mcp/types.ts` | 类型定义:配置 Schema、连接状态类型 |
| `src/services/mcp/InProcessTransport.ts` | 内置 MCP 传输层linked transport pair |
| `src/services/mcp/vscodeSdkMcp.ts` | VSCode SDK MCP双向通知、实验门控 |
| `src/services/mcp/useManageMCPConnections.ts` | React Hook连接生命周期、重连 |
| `src/utils/computerUse/mcpServer.ts` | Computer Use MCP Server 构建 |
| `src/utils/computerUse/setup.ts` | Computer Use 动态注册 |
| `src/utils/claudeInChrome/mcpServer.ts` | Chrome MCP Server 构建 + Bridge 配置 |
| `src/tools/MCPTool/MCPTool.ts` | MCP 工具包装:统一 Tool 接口 |
| `src/entrypoints/mcp.ts` | MCP server 入口Claude Code 作为 MCP server |

View File

@@ -22,7 +22,7 @@ Skill 的核心洞见:**复杂任务的关键不在代码逻辑,而在 Promp
### 1. 内置命令Built-in Commands
硬编码在 `src/commands.ts:258` 的 `COMMANDS` memoize 数组中,包含 70+ 条命令(`/commit`、`/review`、`/compact` 等)。这些是 TypeScript 模块而非 Markdown但实现了相同的 `Command` 接口(`src/types/command.ts`)。
硬编码在 `src/commands.ts:299` 的 `COMMANDS` memoize 数组中,包含 70+ 条命令(`/commit`、`/review`、`/compact` 等)。这些是 TypeScript 模块而非 Markdown但实现了相同的 `Command` 接口(`src/types/command.ts`)。
### 2. Bundled Skills编译时打包
@@ -48,7 +48,7 @@ Skill 的核心洞见:**复杂任务的关键不在代码逻辑,而在 Promp
1. `readdir` 扫描目录 → 仅保留 `isDirectory()` 或 `isSymbolicLink()` 的条目
2. 在每个子目录中查找 `SKILL.md`,未找到则跳过
3. `parseFrontmatter()` 解析 YAML 头部,提取 `whenToUse`、`allowedTools`、`context` 等字段
4. `parseSkillFrontmatterFields()`(第 185 行)统一解析 17 个 frontmatter 字段
4. `parseSkillFrontmatterFields()`(第 185 行)统一解析 16 个 frontmatter 字段
5. `createSkillCommand()`(第 270 行)构造 `Command` 对象
**去重机制**:使用 `realpath()` 解析符号链接获得规范路径(`getFileIdentity`,第 118 行),避免通过符号链接或重叠父目录导致的重复加载。
@@ -94,11 +94,11 @@ shell: ["bash"] # Shell 执行环境
---
```
解析后有 17 个字段被提取,其中 `allowedTools`、`model`、`effort` 在执行时动态修改 `toolPermissionContext`。
解析后有 16 个字段被提取,其中 `allowedTools`、`model`、`effort` 在执行时动态修改 `toolPermissionContext`。
## 两条执行路径Inline vs Fork
SkillTool`src/tools/SkillTool/SkillTool.ts:332`)在 `call()` 中根据 `command.context` 分流:
SkillTool`packages/builtin-tools/src/tools/SkillTool/SkillTool.ts:332`)在 `call()` 中根据 `command.context` 分流:
### Inline 模式(默认)
@@ -128,12 +128,12 @@ Fork 模式适用于需要强隔离的场景(如长时间运行的审查任务
## 权限模型Safe Properties 白名单
`checkPermissions()`(第 433 行)实现了一个层权限检查:
`checkPermissions()`(第 433 行)实现了一个层权限检查:
```
1. Deny 规则匹配(支持精确匹配和 prefix:* 通配符)
↓ 未命中
2. 官方市场 Skill 自动放行plugin + isOfficialMarketplaceName
2. 远程 canonical Skill 自动放行EXPERIMENTAL_SKILL_SEARCH + USER_TYPE === 'ant'
↓ 未命中
3. Allow 规则匹配
↓ 未命中
@@ -142,7 +142,7 @@ Fork 模式适用于需要强隔离的场景(如长时间运行的审查任务
5. Ask 用户确认(附带精确匹配和前缀匹配两条建议规则)
```
**Safe Properties**`SAFE_SKILL_PROPERTIES`,第 876 行)是一个包含 28 个属性名的白名单。任何不在白名单中的**有意义的属性值**(排除 `undefined`、`null`、空数组、空对象)都会触发权限请求。这是**正向安全**设计——未来新增的属性默认需要权限。
**Safe Properties**`SAFE_SKILL_PROPERTIES`,第 876 行)是一个包含 30 个属性名的白名单(覆盖 `PromptCommand` 和 `CommandBase` 两个类型的所有安全属性)。任何不在白名单中的**有意义的属性值**(排除 `undefined`、`null`、空数组、空对象)都会触发权限请求。这是**正向安全**设计——未来新增的属性默认需要权限。
## Prompt 预算1% 上下文窗口的截断策略
@@ -205,7 +205,7 @@ score = usageCount × max(0.5^(daysSinceUse / 7), 0.1)
```
磁盘 SKILL.md
↓ parseFrontmatter()
↓ parseSkillFrontmatterFields() → 17 个字段
↓ parseSkillFrontmatterFields() → 16 个字段
↓ createSkillCommand() → Command 对象
↓ 去重realpath + seenFileIds
↓ 条件 Skill → conditionalSkills Map等待路径匹配激活
@@ -214,7 +214,7 @@ score = usageCount × max(0.5^(daysSinceUse / 7), 0.1)
↓ formatCommandsWithinBudget() → 截断后的 Skill 列表注入 System Prompt
↓ AI 选择匹配的 Skill
↓ SkillTool.validateInput() → 名称校验 + 存在性检查
↓ SkillTool.checkPermissions() → 层权限检查
↓ SkillTool.checkPermissions() → 层权限检查
↓ SkillTool.call() → inline 或 fork 执行
↓ contextModifier() → 注入 allowedTools + model + effort
↓ recordSkillUsage() → 更新使用频率排名

View File

@@ -19,7 +19,7 @@
| 11 | BigQuery Metrics | `api.anthropic.com/api/claude_code/metrics` | HTTPS | 默认启用 |
| 12 | MCP Proxy | `mcp-proxy.anthropic.com` | HTTPS+WS | 使用 MCP 工具时 |
| 13 | MCP Registry | `api.anthropic.com/mcp-registry` | HTTPS | 查询 MCP 服务器时 |
| 14 | Bing Search | `www.bing.com` | HTTPS | WebSearch 工具 |
| 14 | Web Search Pages | `www.bing.com`, `search.brave.com` | HTTPS | WebSearch 工具,可通过 `WEB_SEARCH_ADAPTER=bing|brave` 切换 |
| 15 | Google Cloud Storage (更新) | `storage.googleapis.com` | HTTPS | 版本检查 |
| 16 | GitHub Raw (Changelog/Stats) | `raw.githubusercontent.com` | HTTPS | 更新提示 |
| 17 | Claude in Chrome Bridge | `bridge.claudeusercontent.com` | WSS | Chrome 集成 |
@@ -50,7 +50,7 @@
- **端点**: `{region}-aiplatform.googleapis.com`
- **认证**: `GoogleAuth` + `cloud-platform` scope
- **文件**: `src/services/api/client.ts:228-298`
- **文件**: `src/services/api/client.ts:221-298`
### 4. Azure Foundry
@@ -121,16 +121,20 @@ Anthropic 托管的 MCP 服务器代理。
- **端点**: `https://api.anthropic.com/mcp-registry/v0/servers?version=latest&visibility=commercial`
- **文件**: `src/services/mcp/officialRegistry.ts`
### 14. Bing Search
### 14. Web Search Pages
WebSearch 工具的默认适配器,抓取 Bing 搜索结果
WebSearch 工具支持直接抓取 Bing 搜索结果页面,也支持通过 Brave 的 LLM Context API
获取搜索上下文;可通过 `WEB_SEARCH_ADAPTER=bing|brave` 显式切换后端。
- **端点**: `https://www.bing.com/search?q={query}&setmkt=en-US`
- **文件**: `src/tools/WebSearchTool/adapters/bingAdapter.ts`
- **Bing 端点**: `https://www.bing.com/search?q={query}&setmkt=en-US`
- **Brave 端点**: `https://api.search.brave.com/res/v1/llm/context?q={query}`
- **文件**:
- `packages/builtin-tools/src/tools/WebSearchTool/adapters/bingAdapter.ts`
- `packages/builtin-tools/src/tools/WebSearchTool/adapters/braveAdapter.ts`
另外还有 Domain Blocklist 查询:
- **端点**: `https://api.anthropic.com/api/web/domain_info?domain={domain}`
- **文件**: `src/tools/WebFetchTool/utils.ts`
- **文件**: `packages/builtin-tools/src/tools/WebFetchTool/utils.ts`
### 15. Google Cloud Storage (自动更新)
@@ -201,6 +205,7 @@ WebSearch 工具的默认适配器,抓取 Bing 搜索结果。
| `{region}-aiplatform.googleapis.com` | Google Vertex AI | HTTPS |
| `{resource}.services.ai.azure.com` | Azure Foundry | HTTPS |
| `www.bing.com` | Bing 搜索 | HTTPS |
| `search.brave.com` | Brave 搜索 | HTTPS |
| `storage.googleapis.com` | 自动更新 | HTTPS |
| `raw.githubusercontent.com` | Changelog / 插件统计 | HTTPS |
| `bridge.claudeusercontent.com` | Chrome Bridge | WSS |

View File

@@ -1,457 +0,0 @@
# Feature 探索计划书
> 生成日期2026-04-02
> 代码库中已识别 89 个 feature flag本文档按实现完整度和探索价值分级制定探索优先级和路线图。
>
> **已完成**BUDDY✅ 2026-04-02、TRANSCRIPT_CLASSIFIER / Auto Mode✅ 2026-04-02
---
## 一、总览
### 按实现状态分类
| 状态 | 数量 | 说明 |
|------|------|------|
| 已实现/可用 | 11 | 代码完整,开启 feature 后可运行(可能需要 OAuth 等外部依赖) |
| 部分实现 | 8 | 核心逻辑存在但关键模块为 stub需要补全 |
| 纯 Stub | 15 | 所有函数/工具返回空值,需要从零实现 |
| N/A | 55+ | 内部基础设施、低引用量辅助功能,或反编译丢失过多 |
### 启用方式
所有 feature 通过环境变量启用:
```bash
# 单个 feature
FEATURE_BUDDY=1 bun run dev
# 多个 feature 组合
FEATURE_KAIROS=1 FEATURE_PROACTIVE=1 FEATURE_FORK_SUBAGENT=1 bun run dev
```
---
## 二、Tier 1 — 已实现/可用(优先探索)
### 2.1 KAIROS常驻助手模式⭐ 最高优先级
- **引用数**154全库最大
- **功能**:将 CLI 变为常驻后台助手,支持:
- 持久化 bridge 会话(跨重启复用 session
- 后台执行任务(用户离开终端时继续工作)
- 推送通知到移动端(任务完成/需要输入时)
- 每日记忆日志 + `/dream` 知识蒸馏
- 外部频道消息接入Slack/Discord/Telegram
- **子 Feature**
| 子 Feature | 引用 | 功能 |
|-----------|------|------|
| `KAIROS_BRIEF` | 39 | Brief 工具(`SendUserMessage`),结构化消息输出 |
| `KAIROS_CHANNELS` | 19 | 外部频道消息接入 |
| `KAIROS_PUSH_NOTIFICATION` | 4 | 移动端推送通知 |
| `KAIROS_GITHUB_WEBHOOKS` | 3 | GitHub PR webhook 订阅 |
| `KAIROS_DREAM` | 1 | 夜间记忆蒸馏 |
- **关键文件**`src/assistant/``src/tools/BriefTool/``src/services/mcp/channelNotification.ts``src/memdir/memdir.ts`
- **外部依赖**Anthropic OAuthclaude.ai 订阅、GrowthBook 特性门控
- **探索命令**`FEATURE_KAIROS=1 FEATURE_KAIROS_BRIEF=1 FEATURE_PROACTIVE=1 bun run dev`
**探索步骤**
1. 开启 feature观察启动行为变化
2. 测试 `/assistant``/brief` 命令
3. 验证 BriefTool 输出模式
4. 尝试频道消息接入
5. 测试 `/dream` 记忆蒸馏
---
### ~~2.2 TRANSCRIPT_CLASSIFIERAuto Mode 分类器)~~ ✅ 已完成
- **引用数**108
- **功能**:使用 LLM 对用户意图进行分类,实现 auto mode自动决定工具权限
- **状态**:✅ prompt 模板已重建功能完整可用2026-04-02 完成)
---
### 2.3 VOICE_MODE语音输入
- **引用数**46
- **功能**按键说话Push-to-Talk音频流式传输到 Anthropic STT 端点Nova 3实时转录显示
- **当前状态****完整实现**包括录音、WebSocket 流、转录插入
- **关键文件**`src/voice/voiceModeEnabled.ts``src/hooks/useVoice.ts``src/services/voiceStreamSTT.ts`
- **外部依赖**Anthropic OAuth非 API key、macOS 原生音频或 SoX
- **探索命令**`FEATURE_VOICE_MODE=1 bun run dev`
- **默认快捷键**:长按空格键录音
**探索步骤**
1. 确认 OAuth token 可用
2. 测试按住空格录音 → 释放后转录
3. 验证实时中间转录显示
4. 测试 `/voice` 命令切换
---
### 2.4 TEAMMEM团队共享记忆
- **引用数**51
- **功能**:基于 GitHub 仓库的团队共享记忆系统,`memory/team/` 目录双向同步到 Anthropic 服务器
- **当前状态****完整实现**,包括增量同步、冲突解决、密钥扫描、路径穿越防护
- **关键文件**`src/services/teamMemorySync/`index、watcher、secretScanner`src/memdir/teamMemPaths.ts`
- **外部依赖**Anthropic OAuth + GitHub remote`getGithubRepo()`
- **探索命令**`FEATURE_TEAMMEM=1 bun run dev`
**探索步骤**
1. 确认项目有 GitHub remote
2. 开启后观察 `memory/team/` 目录创建
3. 测试团队记忆写入和同步
4. 验证密钥扫描防护
---
### 2.5 COORDINATOR_MODE多 Agent 编排)
- **引用数**32
- **功能**CLI 变为编排者,通过 AgentTool 派发任务给多个 worker 并行执行
- **当前状态**核心逻辑实现worker agent 模块为 stub
- **关键文件**`src/coordinator/coordinatorMode.ts`(系统 prompt 完整)、`src/coordinator/workerAgent.ts`stub
- **限制**:编排者只能使用 AgentTool/TaskStop/SendMessage不能直接操作文件
- **探索命令**`FEATURE_COORDINATOR_MODE=1 CLAUDE_CODE_COORDINATOR_MODE=1 bun run dev`
**探索步骤**
1. 补全 `workerAgent.ts` stub
2. 测试多 worker 并行任务派发
3. 验证 worker 结果汇总
---
### 2.6 BRIDGE_MODE远程控制
- **引用数**28
- **功能**:本地 CLI 注册为 bridge 环境,可从 claude.ai 或其他控制面远程驱动
- **当前状态**v1env-based和 v2env-less实现均存在
- **关键文件**`src/bridge/bridgeEnabled.ts``src/bridge/replBridge.ts`v1`src/bridge/remoteBridgeCore.ts`v2
- **外部依赖**claude.ai OAuth、GrowthBook 门控 `tengu_ccr_bridge`
- **探索命令**`FEATURE_BRIDGE_MODE=1 bun run dev`
---
### 2.7 FORK_SUBAGENT上下文继承子 Agent
- **引用数**4
- **功能**AgentTool 生成 fork 子 agent继承父级完整对话上下文优化 prompt cache
- **当前状态****完整实现**`forkSubagent.ts`),支持 worktree 隔离通知、递归防护
- **关键文件**`src/tools/AgentTool/forkSubagent.ts`
- **探索命令**`FEATURE_FORK_SUBAGENT=1 bun run dev`
---
### 2.8 TOKEN_BUDGETToken 预算控制)
- **引用数**9
- **功能**:解析用户指定的 token 预算(如 "spend 2M tokens"),自动持续工作直到达到目标
- **当前状态**:解析器**完整实现**支持简写和详细语法QueryEngine 中的周转逻辑已连接
- **关键文件**`src/utils/tokenBudget.ts``src/QueryEngine.ts`
- **探索命令**`FEATURE_TOKEN_BUDGET=1 bun run dev`
---
### 2.9 MCP_SKILLSMCP 技能发现)
- **引用数**9
- **功能**:将 MCP 服务器提供的 prompt 类型命令筛选为可调用技能
- **当前状态****功能性实现**config 门控筛选器)
- **关键文件**`src/commands.ts``getMcpSkillCommands()`
- **探索命令**`FEATURE_MCP_SKILLS=1 bun run dev`
---
### 2.10 TREE_SITTER_BASHBash AST 解析)
- **引用数**3
- **功能**:纯 TypeScript bash 命令 AST 解析器,用于 fail-closed 权限匹配
- **当前状态****完整实现**`bashParser.ts` ~2000行 + `ast.ts` ~400行
- **关键文件**`src/utils/vendor/tree-sitter-bash/`
- **探索命令**`FEATURE_TREE_SITTER_BASH=1 bun run dev`
---
### ~~2.11 BUDDY虚拟伙伴~~ ✅ 已完成
- **引用数**16
- **功能**`/buddy` 命令,支持 hatch/rehatch/pet/mute/unmute
- **状态**:✅ 已合入功能完整可用2026-04-02 完成)
---
## 三、Tier 2 — 部分实现(需要补全)
### 3.1 PROACTIVE主动模式
- **引用数**37
- **功能**Tick 驱动的自主代理,定时唤醒执行工作,配合 SleepTool 控制节奏
- **当前状态**:核心模块 `src/proactive/index.ts` **全部 stub**activate/deactivate/pause 返回 false 或空操作)
- **依赖**:与 KAIROS 强绑定(所有检查都是 `feature('PROACTIVE') || feature('KAIROS')`
- **补全工作量**:中等 — 需要实现 tick 生成、SleepTool 集成、暂停/恢复逻辑
### 3.2 BASH_CLASSIFIERBash 命令分类器)
- **引用数**45
- **功能**LLM 驱动的 bash 命令意图分类(允许/拒绝/询问)
- **当前状态**`bashClassifier.ts` **全部 stub**`matches: false`
- **补全工作量**:大 — 需要 LLM 调用实现、prompt 设计
### 3.3 ULTRAPLAN增强规划
- **引用数**10
- **功能**:关键字触发增强计划模式,输入 "ultraplan" 自动转为 plan
- **当前状态**:关键字检测**完整实现**`/ultraplan` 命令**为 stub**
- **补全工作量**:小 — 只需实现命令处理逻辑
### 3.4 EXPERIMENTAL_SKILL_SEARCH技能语义搜索
- **引用数**21
- **功能**DiscoverSkills 工具,根据当前任务语义搜索可用技能
- **当前状态**:布线完整,核心搜索逻辑 stub
- **补全工作量**:中等 — 需要实现搜索引擎和索引
### 3.5 CONTEXT_COLLAPSE上下文折叠
- **引用数**20
- **功能**CtxInspectTool 让模型内省上下文窗口大小,优化压缩决策
- **当前状态**:工具 stubHISTORY_SNIP 子功能也 stub
- **补全工作量**:中等
### 3.6 WORKFLOW_SCRIPTS工作流自动化
- **引用数**10
- **功能**:基于文件的自动化工作流 + `/workflows` 命令
- **当前状态**WorkflowTool、命令、加载器全部 stub
- **补全工作量**:大 — 需要从零设计工作流 DSL
### 3.7 WEB_BROWSER_TOOL浏览器工具
- **引用数**4
- **功能**:模型可调用浏览器工具导航和交互网页
- **当前状态**:工具注册存在,实现 stub
- **补全工作量**:大
### 3.8 DAEMON后台守护进程
- **引用数**3
- **功能**:后台守护进程 + 远程控制服务器
- **当前状态**:只有条件导入布线,无实现
- **补全工作量**:极大
---
## 四、Tier 3 — 纯 Stub / N/A低优先级
| Feature | 引用 | 状态 | 说明 |
|---------|------|------|------|
| CHICAGO_MCP | 16 | N/A | Anthropic 内部 MCP 基础设施 |
| UDS_INBOX | 17 | Stub | Unix 域套接字对等消息 |
| MONITOR_TOOL | 13 | Stub | 文件/进程监控工具 |
| BG_SESSIONS | 11 | Stub | 后台会话管理 |
| SHOT_STATS | 10 | 无实现 | 逐 prompt 统计 |
| EXTRACT_MEMORIES | 7 | 无实现 | 自动记忆提取 |
| TEMPLATES | 6 | Stub | 项目/提示模板 |
| LODESTONE | 6 | N/A | 内部基础设施 |
| STREAMLINED_OUTPUT | 1 | — | 精简输出模式 |
| HOOK_PROMPTS | 1 | — | Hook 提示词 |
| CCR_AUTO_CONNECT | 3 | — | CCR 自动连接 |
| CCR_MIRROR | 4 | — | CCR 镜像模式 |
| CCR_REMOTE_SETUP | 1 | — | CCR 远程设置 |
| NATIVE_CLIPBOARD_IMAGE | 2 | — | 原生剪贴板图片 |
| CONNECTOR_TEXT | 7 | — | 连接器文本 |
以及其余 40+ 个低引用量 feature。
---
## 五、探索路线图
### Phase 1快速验证无外部依赖
> 目标:确认代码可以正常运行,体验基本功能
| 优先级 | Feature | 命令 | 预期效果 |
|--------|---------|------|----------|
| 1 | BUDDY | `FEATURE_BUDDY=1 bun run dev` | `/buddy hatch` 生成伙伴 |
| 2 | FORK_SUBAGENT | `FEATURE_FORK_SUBAGENT=1 bun run dev` | Agent 可生成上下文继承的子任务 |
| 3 | TOKEN_BUDGET | `FEATURE_TOKEN_BUDGET=1 bun run dev` | 输入 "spend 500k tokens" 测试自动持续 |
| 4 | TREE_SITTER_BASH | `FEATURE_TREE_SITTER_BASH=1 bun run dev` | 更精确的 bash 权限匹配 |
| 5 | MCP_SKILLS | `FEATURE_MCP_SKILLS=1 bun run dev` | MCP 服务器 prompt 提升为技能 |
### Phase 2核心功能探索需要 OAuth
> 目标:体验 KAIROS 全套能力
| 优先级 | Feature | 命令 | 预期效果 |
|--------|---------|------|----------|
| 1 | TRANSCRIPT_CLASSIFIER | `FEATURE_TRANSCRIPT_CLASSIFIER=1 bun run dev` | Auto mode 自动激活 |
| 2 | KAIROS 全套 | `FEATURE_KAIROS=1 FEATURE_KAIROS_BRIEF=1 FEATURE_KAIROS_CHANNELS=1 FEATURE_PROACTIVE=1 bun run dev` | 常驻助手 + Brief 输出 + 频道消息 |
| 3 | VOICE_MODE | `FEATURE_VOICE_MODE=1 bun run dev` | 按空格说话 |
| 4 | TEAMMEM | `FEATURE_TEAMMEM=1 bun run dev` | 团队记忆同步 |
| 5 | COORDINATOR_MODE | `FEATURE_COORDINATOR_MODE=1 CLAUDE_CODE_COORDINATOR_MODE=1 bun run dev` | 多 agent 编排 |
### Phase 3Stub 补全开发
> 目标:将高价值 stub 实现为可用功能
| 优先级 | Feature | 补全难度 | 价值 |
|--------|---------|----------|------|
| 1 | PROACTIVE | 中 | 自主工作能力 |
| 2 | ULTRAPLAN | 小 | 增强规划 |
| 3 | CONTEXT_COLLAPSE | 中 | 长对话优化 |
| 4 | EXPERIMENTAL_SKILL_SEARCH | 中 | 技能发现 |
| 5 | BASH_CLASSIFIER | 大 | 安全增强 |
---
## 六、推荐组合方案
### "全功能助手"组合
```bash
FEATURE_KAIROS=1 \
FEATURE_KAIROS_BRIEF=1 \
FEATURE_KAIROS_CHANNELS=1 \
FEATURE_KAIROS_PUSH_NOTIFICATION=1 \
FEATURE_PROACTIVE=1 \
FEATURE_FORK_SUBAGENT=1 \
FEATURE_TOKEN_BUDGET=1 \
FEATURE_TRANSCRIPT_CLASSIFIER=1 \
FEATURE_BUDDY=1 \
bun run dev
```
### "多 Agent 协作"组合
```bash
FEATURE_COORDINATOR_MODE=1 \
FEATURE_FORK_SUBAGENT=1 \
FEATURE_BRIDGE_MODE=1 \
FEATURE_BG_SESSIONS=1 \
CLAUDE_CODE_COORDINATOR_MODE=1 \
bun run dev
```
### "开发者增强"组合
```bash
FEATURE_TRANSCRIPT_CLASSIFIER=1 \
FEATURE_TREE_SITTER_BASH=1 \
FEATURE_TOKEN_BUDGET=1 \
FEATURE_MCP_SKILLS=1 \
FEATURE_CONTEXT_COLLAPSE=1 \
bun run dev
```
---
## 七、风险与注意事项
1. **OAuth 依赖**KAIROS、VOICE_MODE、TEAMMEM、BRIDGE_MODE 需要 Anthropic OAuth 认证claude.ai 订阅API key 用户无法使用
2. **GrowthBook 门控**部分功能VOICE_MODE 的 `tengu_cobalt_frost`、TEAMMEM 的 `tengu_herring_clock`)即使 feature flag 开启,还需要服务端 GrowthBook 开关
3. **反编译不完整**:所有"已实现"功能均为反编译产物,可能存在运行时错误,需要逐个验证
4. **Proactive stub**KAIROS 的自主工作能力依赖 PROACTIVE但 PROACTIVE 核心是 stub需先补全
5. **tsc 错误**:代码库有 ~1341 个 TypeScript 编译错误(来自反编译),不影响 Bun 运行时但在 IDE 中会有大量红线
---
## 附录Feature Flag 完整列表
共 89 个 feature flag按引用数降序
| Feature | 引用 | Tier |
|---------|------|------|
| KAIROS | 154 | 1 |
| TRANSCRIPT_CLASSIFIER | 108 | 1 |
| TEAMMEM | 51 | 1 |
| VOICE_MODE | 46 | 1 |
| BASH_CLASSIFIER | 45 | 2 |
| KAIROS_BRIEF | 39 | 1 |
| PROACTIVE | 37 | 2 |
| COORDINATOR_MODE | 32 | 1 |
| BRIDGE_MODE | 28 | 1 |
| EXPERIMENTAL_SKILL_SEARCH | 21 | 2 |
| CONTEXT_COLLAPSE | 20 | 2 |
| KAIROS_CHANNELS | 19 | 1 |
| UDS_INBOX | 17 | 3 |
| CHICAGO_MCP | 16 | 3 |
| BUDDY | 16 | 1 |
| HISTORY_SNIP | 15 | 2 |
| MONITOR_TOOL | 13 | 3 |
| COMMIT_ATTRIBUTION | 12 | — |
| CACHED_MICROCOMPACT | 12 | — |
| BG_SESSIONS | 11 | 3 |
| WORKFLOW_SCRIPTS | 10 | 2 |
| ULTRAPLAN | 10 | 2 |
| SHOT_STATS | 10 | 3 |
| TOKEN_BUDGET | 9 | 1 |
| PROMPT_CACHE_BREAK_DETECTION | 9 | — |
| MCP_SKILLS | 9 | 1 |
| EXTRACT_MEMORIES | 7 | 3 |
| CONNECTOR_TEXT | 7 | — |
| TEMPLATES | 6 | 3 |
| LODESTONE | 6 | 3 |
| TREE_SITTER_BASH_SHADOW | 5 | — |
| QUICK_SEARCH | 5 | — |
| MESSAGE_ACTIONS | 5 | — |
| DOWNLOAD_USER_SETTINGS | 5 | — |
| DIRECT_CONNECT | 5 | — |
| WEB_BROWSER_TOOL | 4 | 2 |
| VERIFICATION_AGENT | 4 | — |
| TERMINAL_PANEL | 4 | — |
| SSH_REMOTE | 4 | — |
| REVIEW_ARTIFACT | 4 | — |
| REACTIVE_COMPACT | 4 | — |
| KAIROS_PUSH_NOTIFICATION | 4 | 1 |
| HISTORY_PICKER | 4 | — |
| FORK_SUBAGENT | 4 | 1 |
| CCR_MIRROR | 4 | — |
| TREE_SITTER_BASH | 3 | 1 |
| MEMORY_SHAPE_TELEMETRY | 3 | — |
| MCP_RICH_OUTPUT | 3 | — |
| KAIROS_GITHUB_WEBHOOKS | 3 | 1 |
| FILE_PERSISTENCE | 3 | — |
| DAEMON | 3 | 2 |
| CCR_AUTO_CONNECT | 3 | — |
| UPLOAD_USER_SETTINGS | 2 | — |
| POWERSHELL_AUTO_MODE | 2 | — |
| OVERFLOW_TEST_TOOL | 2 | — |
| NEW_INIT | 2 | — |
| NATIVE_CLIPBOARD_IMAGE | 2 | — |
| HARD_FAIL | 2 | — |
| ENHANCED_TELEMETRY_BETA | 2 | — |
| COWORKER_TYPE_TELEMETRY | 2 | — |
| BREAK_CACHE_COMMAND | 2 | — |
| AWAY_SUMMARY | 2 | — |
| AUTO_THEME | 2 | — |
| ALLOW_TEST_VERSIONS | 2 | — |
| AGENT_TRIGGERS_REMOTE | 2 | — |
| AGENT_MEMORY_SNAPSHOT | 2 | — |
| UNATTENDED_RETRY | 1 | — |
| ULTRATHINK | 1 | — |
| TORCH | 1 | — |
| STREAMLINED_OUTPUT | 1 | — |
| SLOW_OPERATION_LOGGING | 1 | — |
| SKILL_IMPROVEMENT | 1 | — |
| SELF_HOSTED_RUNNER | 1 | — |
| RUN_SKILL_GENERATOR | 1 | — |
| PERFETTO_TRACING | 1 | — |
| NATIVE_CLIENT_ATTESTATION | 1 | — |
| KAIROS_DREAM | 1 | 1 |
| IS_LIBC_MUSL | 1 | — |
| IS_LIBC_GLIBC | 1 | — |
| HOOK_PROMPTS | 1 | — |
| DUMP_SYSTEM_PROMPT | 1 | — |
| COMPACTION_REMINDERS | 1 | — |
| CCR_REMOTE_SETUP | 1 | — |
| BYOC_ENVIRONMENT_RUNNER | 1 | — |
| BUILTIN_EXPLORE_PLAN_AGENTS | 1 | — |
| BUILDING_CLAUDE_APPS | 1 | — |
| ANTI_DISTILLATION_CC | 1 | — |
| AGENT_TRIGGERS | 1 | — |
| ABLATION_BASELINE | 1 | — |

File diff suppressed because it is too large Load Diff

201
docs/features/acp-link.md Normal file
View File

@@ -0,0 +1,201 @@
# acp-link — ACP 代理服务器
> 源码目录:`packages/acp-link/`
> PR: #292
> 新增时间2026-04-18
## 一、功能概述
`acp-link` 是一个 ACP (Agent Client Protocol) 代理服务器,将 WebSocket 客户端桥接到 ACP agent 的 stdio 接口。它让 ACP agent如 Claude Code可以通过 WebSocket 远程访问,而不仅限于本地 stdio。
### 核心特性
- **WebSocket → stdio 桥接**:将浏览器/远程客户端的 WebSocket 连接转换为 ACP agent 的 stdin/stdout NDJSON 流
- **会话管理**:创建、加载、恢复、列出、关闭会话
- **权限审批流程**:客户端可远程审批 agent 的工具权限请求
- **RCS 集成**:可与 Remote Control Server (RCS) 连接,将 ACP agent 注册到 RCS 并通过 Web UI 交互
- **HTTPS 支持**:内置自签名证书生成,支持安全连接
- **Token 认证**:自动生成或通过环境变量配置认证 token
## 二、架构
### 独立模式
```
┌──────────────────┐ WebSocket ┌──────────────────┐ stdio/NDJSON ┌──────────────┐
│ 浏览器/客户端 │ ◄──────────────►│ acp-link │ ◄────────────────►│ ACP Agent │
│ (WS Client) │ ws://host:port │ (Proxy Server) │ spawn subprocess │ (Claude等) │
└──────────────────┘ └──────────────────┘ └──────────────┘
```
### RCS 集成模式
```
┌──────────────┐ WebSocket ┌──────────────────┐ stdio/NDJSON ┌──────────────┐
│ RCS Web UI │ ◄──────────────►│ Remote Control │ ◄─────────────────►│ acp-link │
│ (/code/*) │ ACP Relay WS │ Server (RCS) │ ACP events │ + Agent │
└──────────────┘ └──────────────────┘ └──────────────┘
```
### 文件结构
```
packages/acp-link/
├── src/
│ ├── server.ts # 主服务器WS 连接管理、会话管理、权限处理、消息桥接
│ ├── rcs-upstream.ts # RCS 上游客户端REST 注册 + WS identify 两步流程
│ ├── cert.ts # TLS 证书生成(自签名)
│ ├── logger.ts # 日志模块
│ ├── types.ts # JSON-RPC 和 ACP 协议类型定义
│ ├── cli/
│ │ ├── bin.ts # CLI 入口
│ │ ├── command.ts # 命令行参数解析
│ │ ├── app.ts # 应用启动
│ │ └── context.ts # 上下文配置
│ └── __tests__/ # 测试cert, server, types
├── package.json
└── tsconfig.json
```
## 三、安装与使用
### 基本用法
```bash
# 直接运行(在 monorepo 中)
# 注意claude 本身不支持 ACP需要用 ccb-bun --acp 启动 ACP agent
bun packages/acp-link/src/cli/bin.ts ccb-bun -- --acp
# 指定端口和主机
acp-link --port 9000 --host 0.0.0.0 ccb-bun -- --acp
# 启用 HTTPS自签名证书
acp-link --https ccb-bun -- --acp
# 调试模式
acp-link --debug ccb-bun -- --acp
```
### CLI 参考
```
USAGE
acp-link [--port value] [--host value] [--debug] [--no-auth] [--https] <command>...
acp-link --help
acp-link --version
FLAGS
[--port] Port to listen on [default = 9315]
[--host] Host to bind to [default = localhost]
[--debug] Enable debug logging to file
[--no-auth] Disable authentication (dangerous)
[--https] Enable HTTPS with self-signed cert
-h --help Print help information and exit
-v --version Print version information and exit
ARGUMENTS
command... Agent command followed by its arguments (e.g. "ccb-bun -- --acp")
```
## 四、认证
默认启动时自动生成随机 token。客户端连接时需通过 query 参数传递:
```
ws://localhost:9315/ws?token=<your-token>
```
配置固定 token
```bash
ACP_AUTH_TOKEN=my-fixed-token acp-link ccb-bun -- --acp
```
禁用认证(不推荐,仅用于开发):
```bash
acp-link --no-auth ccb-bun -- --acp
```
## 五、RCS 集成
acp-link 支持将 ACP agent 注册到 Remote Control Server通过 Web UI 远程操控。
### 连接方式
```bash
# 通过环境变量配置 RCS 连接
ACP_RCS_URL=http://localhost:3000 \
ACP_RCS_TOKEN=sk-rcs-your-key \
acp-link ccb-bun -- --acp
```
### 注册流程(两步)
1. **REST 注册**:通过 `POST /v1/environments/bridge` 向 RCS 注册环境
2. **WS identify**:建立 WebSocket 连接后发送 `identify` 消息(携带 agentId替代完整 `register`
```
acp-link RCS
│ │
│── POST /v1/environments/bridge ──►│ (REST 注册)
│◄── { agentId, sessionId } ───────│
│ │
│── WS connect ─────────────────►│ (WebSocket)
│── identify { agentId } ────────►│ (WS 标识)
│◄── identified ─────────────────│
│ │
│── ACP events ─────────────────►│ (双向消息转发)
│◄── user prompts/permissions ───│
```
## 六、权限模式
### permissionMode 传递链
权限模式通过整条链路传递Web UI → RCS → acp-link → ACP agent。
支持的权限模式:
- `default` — 每次请求权限确认
- `auto` — 自动判断
- `acceptEdits` — 自动接受编辑
- `plan` — 规划模式
- `dontAsk` — 不询问
- `bypassPermissions` — 绕过权限(需 sandbox 环境)
### fallback 链
当客户端未显式传递 permissionMode 时,使用以下 fallback 链:
```
客户端传值 > config.permissionMode > ACP_PERMISSION_MODE 环境变量
```
示例:
```bash
ACP_PERMISSION_MODE=auto acp-link ccb-bun -- --acp
```
## 七、权限管道2026-04-18 改进)
### 模式同步
`applySessionMode` 在 agent 切换权限模式时同步 `appState.toolPermissionContext.mode`,确保内部权限上下文与 ACP 客户端状态一致。
### 统一权限流水线
`createAcpCanUseTool` 接入 `hasPermissionsToUseTool` 统一权限流水线,替代原来分散的处理逻辑。支持 `onModeChange` 回调,模式变更时实时同步。
### bypass 检测
`bypassPermissions` 模式增加可用性检测 — 仅在非 root 或 sandbox 环境中允许启用,防止权限绕过的安全风险。
## 八、环境变量
| 变量 | 说明 |
|------|------|
| `ACP_AUTH_TOKEN` | 固定认证 token默认自动生成 |
| `ACP_PERMISSION_MODE` | 默认权限模式 fallback |
| `ACP_RCS_URL` | RCS 服务器地址(启用 RCS 集成) |
| `ACP_RCS_TOKEN` | RCS API token |

189
docs/features/acp-zed.md Normal file
View File

@@ -0,0 +1,189 @@
# ACP (Agent Client Protocol) — Zed / IDE 集成
> Feature Flag: `FEATURE_ACP=1`build 和 dev 模式默认启用)
> 实现状态:可用(支持 Zed、Cursor 等 ACP 客户端)
> 源码目录:`src/services/acp/`
## 一、功能概述
ACP (Agent Client Protocol) 是一种标准化的 stdio 协议,允许 IDE 和编辑器通过 stdin/stdout 的 NDJSON 流驱动 AI Agent。CCB 实现了完整的 ACP agent 端,可以被 Zed、Cursor 等支持 ACP 的客户端直接调用。
### 核心特性
- **会话管理**:新建 / 恢复 / 加载 / 分叉 / 关闭会话
- **历史回放**:恢复会话时自动加载并回放对话历史
- **权限桥接**ACP 客户端的权限决策映射到 CCB 的工具权限系统
- **斜杠命令 & Skills**:加载真实命令列表,支持 `/commit``/review` 等 prompt 型 skill
- **Context Window 跟踪**:精确的 usage_update含 model prefix matching
- **Prompt 排队**:支持连续发送多条 prompt自动排队处理
- **模式切换**auto / default / acceptEdits / plan / dontAsk / bypassPermissions
- **模型切换**:运行时切换 AI 模型
## 二、架构
```
┌──────────────┐ NDJSON/stdio ┌──────────────────┐
│ Zed / IDE │ ◄────────────────► │ CCB ACP Agent │
│ (Client) │ stdin / stdout │ (Agent) │
└──────────────┘ │ │
│ entry.ts │ ← stdio → NDJSON stream
│ agent.ts │ ← ACP protocol handler
│ bridge.ts │ ← SDKMessage → ACP SessionUpdate
│ permissions.ts │ ← 权限桥接
│ utils.ts │ ← 通用工具
│ │
│ QueryEngine │ ← 内部查询引擎
└──────────────────┘
```
### 文件职责
| 文件 | 职责 |
|------|------|
| `entry.ts` | 入口,创建 stdio → NDJSON stream启动 `AgentSideConnection` |
| `agent.ts` | 实现 ACP `Agent` 接口:会话 CRUD、prompt、cancel、模式/模型切换 |
| `bridge.ts` | `SDKMessage` → ACP `SessionUpdate` 转换:文本/思考/工具/用量/编辑 diff |
| `permissions.ts` | ACP `requestPermission()` → CCB `CanUseToolFn` 桥接 |
| `utils.ts` | Pushable、流转换、权限模式解析、session fingerprint、路径显示 |
## 三、配置 Zed 编辑器
### 3.1 Zed settings.json 配置
打开 Zed 的 `settings.json``Cmd+,` → Open Settings添加 `agent_servers` 配置:
```json
{
"agent_servers": {
"ccb": {
"type": "custom",
"command": "ccb",
"args": ["--acp"]
}
}
}
```
### 3.3 API 认证配置
CCB 的 ACP agent 在启动时会自动加载 `settings.json` 中的环境变量(`ANTHROPIC_BASE_URL``ANTHROPIC_AUTH_TOKEN` 等)。确保已通过 `/login` 配置好 API 供应商。
也可通过环境变量传入:
```json
{
"agent_servers": {
"claude-code": {
"command": "ccb",
"args": ["--acp"],
"env": {
"ANTHROPIC_BASE_URL": "https://api.example.com/v1",
"ANTHROPIC_AUTH_TOKEN": "sk-xxx"
}
}
}
}
```
### 3.4 在 Zed 中使用
1. 配置完成后重启 Zed
2. 打开任意项目目录
3.`Cmd+'`macOS`Ctrl+'`Linux打开 Agent Panel
4. 在 Agent Panel 顶部的下拉菜单中选择 **claude-code**
5. 开始对话
### 3.5 功能说明
| 功能 | 操作 |
|------|------|
| 对话 | 在 Agent Panel 中直接输入消息 |
| 斜杠命令 | 输入 `/` 查看可用 skills 列表(如 `/commit``/review` |
| 工具权限 | 弹出权限请求时选择 Allow / Reject / Always Allow |
| 模式切换 | 通过 Agent Panel 的设置菜单切换 auto/default/plan 等模式 |
| 模型切换 | 通过 Agent Panel 的设置菜单切换 AI 模型 |
| 会话恢复 | 关闭重开 Zed 后,之前的会话可自动恢复(含历史消息) |
## 四、配置其他 ACP 客户端
ACP 是开放协议,任何支持 ACP 的客户端都可以连接 CCB。通用配置模式
```
命令: ccb --acp
参数: ["--acp"]
通信: stdin/stdout NDJSON
协议版本: ACP v1
```
### 4.1 Cursor
在 Cursor 的设置中配置 MCP / Agent Server使用同样的 `ccb --acp` 命令。
### 4.2 自定义客户端
使用 `@agentclientprotocol/sdk` 可以快速构建 ACP 客户端:
```typescript
import { ClientSideConnection, ndJsonStream } from '@agentclientprotocol/sdk'
// 创建连接(将 ccb --acp 作为子进程启动)
const child = spawn('ccb', ['--acp'])
const stream = ndJsonStream(
Writable.toWeb(child.stdin),
Readable.toWeb(child.stdout),
)
const client = new ClientSideConnection(stream)
// 初始化
await client.initialize({ clientCapabilities: {} })
// 创建会话
const { sessionId } = await client.newSession({
cwd: '/path/to/project',
})
// 发送 prompt
const response = await client.prompt({
sessionId,
prompt: [{ type: 'text', text: 'Hello, explain this project' }],
})
// 监听 session 更新
client.on('sessionUpdate', (update) => {
console.log('Update:', update)
})
```
## 五、ACP 协议支持矩阵
| 方法 | 状态 | 说明 |
|------|------|------|
| `initialize` | ✅ | 返回 agent 信息和能力 |
| `authenticate` | ✅ | 无需认证(自托管) |
| `newSession` | ✅ | 创建新会话 |
| `resumeSession` | ✅ | 恢复已有会话(含历史回放) |
| `loadSession` | ✅ | 加载指定会话(含历史回放) |
| `listSessions` | ✅ | 列出可用会话 |
| `forkSession` | ✅ | 分叉会话 |
| `closeSession` | ✅ | 关闭会话 |
| `prompt` | ✅ | 发送消息,支持排队 |
| `cancel` | ✅ | 取消当前/排队的 prompt |
| `setSessionMode` | ✅ | 切换权限模式 |
| `setSessionModel` | ✅ | 切换 AI 模型 |
| `setSessionConfigOption` | ✅ | 动态修改配置 |
### SessionUpdate 类型
| 类型 | 状态 | 说明 |
|------|------|------|
| `agent_message_chunk` | ✅ | 助手文本消息 |
| `agent_thought_chunk` | ✅ | 思考/推理内容 |
| `user_message_chunk` | ✅ | 用户消息(历史回放) |
| `tool_call` | ✅ | 工具调用开始 |
| `tool_call_update` | ✅ | 工具调用结果/状态更新 |
| `usage_update` | ✅ | token 用量 + context window |
| `plan` | ✅ | TodoWrite → plan entries |
| `available_commands_update` | ✅ | 斜杠命令 & skills 列表 |
| `current_mode_update` | ✅ | 模式切换通知 |
| `config_option_update` | ✅ | 配置更新通知 |

View File

@@ -0,0 +1,574 @@
# Claude Code Best (CCB) — 全功能使用指南
本文档覆盖我们通过 13 个 PR 为 CCB 恢复/新增的**全部功能**,按类别组织,每个功能包含说明、使用方法和示例。
---
## 目录
1. [Buddy 伴侣系统](#1-buddy-伴侣系统)
2. [Remote Control 远程控制](#2-remote-control-远程控制)
3. [定时任务 /schedule](#3-定时任务-schedule)
4. [Voice Mode 语音模式](#4-voice-mode-语音模式)
5. [Chrome 浏览器控制](#5-chrome-浏览器控制)
6. [Computer Use 屏幕操控](#6-computer-use-屏幕操控)
7. [Feature Flags 与 GrowthBook](#7-feature-flags-与-growthbook)
8. [/ultraplan 高级规划](#8-ultraplan-高级规划)
9. [Daemon 后台守护](#9-daemon-后台守护)
10. [Pipe IPC 多实例协作](#10-pipe-ipc-多实例协作)
11. [LAN Pipes 局域网群控](#11-lan-pipes-局域网群控)
12. [Monitor 后台监控](#12-monitor-后台监控)
13. [Workflow 工作流脚本](#13-workflow-工作流脚本)
14. [Coordinator 多Worker协调](#14-coordinator-多worker协调)
15. [Proactive 自主模式](#15-proactive-自主模式)
16. [History / Snip 历史管理](#16-history--snip-历史管理)
17. [Fork 子Agent](#17-fork-子agent)
18. [其他恢复的工具](#18-其他恢复的工具)
---
## 1. Buddy 伴侣系统
**PR**: #82 `refactor(buddy): align companion system with official CLI`
**Feature Flag**: `BUDDY`
### 说明
Buddy 是一个后台运行的伴侣 AI在你主对话进行的同时异步观察会话内容并提供建议。
### 使用
```bash
# 启动时自动加载feature 默认开启)
bun run dev
# 在对话中Buddy 会在适当时机自动提供建议
# 例如当你在调试时Buddy 可能提示你检查日志
```
---
## 2. Remote Control 远程控制
**PR**: #60 `feat: enable Remote Control (BRIDGE_MODE)` + #170 `feat: restore daemon supervisor`
**Feature Flag**: `BRIDGE_MODE`
### 说明
通过 WebSocket 远程控制 Claude Code 会话。支持自托管私有部署。
### 使用
```bash
# 启动远程控制模式
bun run dev -- remote-control
# 使用自托管服务器
CLAUDE_BRIDGE_BASE_URL=https://your-server.com CLAUDE_BRIDGE_OAUTH_TOKEN=your-token bun run dev --remote-control
# 或通过 /remote-control 命令在会话中启动
/remote-control
```
### 命令
- `claude remote-control` / `claude rc` — 启动远程控制客户端
- `claude bridge` — 同上(别名)
---
## 3. 定时任务 /schedule
**PR**: #88 `feat: enable /schedule by adding AGENT_TRIGGERS_REMOTE`
**Feature Flag**: `AGENT_TRIGGERS_REMOTE`
### 说明
创建定时执行的远程 agent 任务,支持 cron 表达式。
### 使用
```
/schedule create "每天检查依赖更新" --cron "0 9 * * *" --prompt "检查 package.json 中的过期依赖并创建更新 PR"
/schedule list — 列出所有定时任务
/schedule delete <id> — 删除指定任务
```
---
## 4. Voice Mode 语音模式
**PR**: #92 `feat: enable /voice mode with native audio binaries`
**Feature Flag**: `VOICE_MODE`
### 说明
Push-to-Talk 语音输入,音频通过 WebSocket 流式传输到 Anthropic STTNova 3。需要 Anthropic OAuth 认证(非 API key
### 使用
```bash
# 确保已通过 OAuth 登录
claude auth login
# 在会话中按住指定键说话
# 松开后自动转写为文字输入
```
### 前提条件
- Anthropic OAuth 认证(不支持 API key 模式)
- 系统麦克风权限
---
## 5. Chrome 浏览器控制
**PR**: #93 `feat: enable Claude in Chrome MCP with full browser control`
**Feature Flag**: `CHICAGO_MCP`
### 说明
通过 Chrome 扩展控制浏览器:导航、点击、填表、截图、执行 JS。
### 使用
```bash
# 启动带 Chrome 控制的模式
bun run dev -- --chrome
# 安装 Chrome 扩展后AI 可以:
# - 打开网页、点击按钮
# - 填写表单
# - 截取页面内容
# - 执行 JavaScript
```
### AI 可用工具
- `navigate` — 导航到 URL
- `click` / `find` / `form_input` — 页面交互
- `get_page_text` / `read_page` — 读取内容
- `javascript_tool` — 执行 JS
- `gif_creator` — 录制操作 GIF
---
## 6. Computer Use 屏幕操控
**PR**: #98 + #137 `feat: Computer Use — 跨平台 Executor + Python Bridge + GUI 无障碍`
**Feature Flag**: `CHICAGO_MCP`
### 说明
跨平台屏幕操控:截图、键鼠模拟、应用管理。支持 macOS + WindowsLinux 后端待完成。
### 使用
```bash
# 启动后 AI 可自动调用屏幕操控工具
bun run dev
# AI 可以:
# - 截取屏幕/窗口截图
# - 模拟键盘输入和鼠标操作
# - 列出运行的应用
# - 使用剪贴板
```
### 平台支持
| 平台 | 截图 | 键鼠 | 应用管理 |
|------|------|------|----------|
| macOS | ✅ | ✅ | ✅ |
| Windows | ✅ | ✅ | ✅ |
| Linux | ⏳ | ⏳ | ⏳ |
---
## 7. Feature Flags 与 GrowthBook
**PR**: #140 + #153 `feat: enable GrowthBook local gate defaults`
**Feature Flags**: `SHOT_STATS`, `PROMPT_CACHE_BREAK_DETECTION`, `TOKEN_BUDGET`
### 说明
本地 GrowthBook gate defaults 机制,绕过远程 feature flag 服务,确保功能在无网络时也可使用。
### 使用
```bash
# 通过环境变量启用任意 feature
FEATURE_PROACTIVE=1 bun run dev
# dev/build 模式有各自的默认启用列表
# 查看 scripts/dev.ts 中的 DEFAULT_FEATURES
```
### 关键 feature flags
| Flag | 说明 |
|------|------|
| `SHOT_STATS` | API 调用统计 |
| `TOKEN_BUDGET` | Token 预算控制 |
| `PROMPT_CACHE_BREAK_DETECTION` | Prompt 缓存命中检测 |
---
## 8. /ultraplan 高级规划
**PR**: #156 `feat: enable /ultraplan and harden GrowthBook fallback chain`
**Feature Flag**: `ULTRAPLAN`
### 说明
高级多 agent 规划模式。将复杂任务分解为多个阶段,每阶段可分配给不同 agent 并行执行。
### 使用
```
/ultraplan 实现一个完整的用户认证系统包括注册、登录、密码重置、OAuth 集成
```
AI 会生成:
1. 任务分解(多阶段)
2. 每阶段的 agent 分配
3. 依赖关系图
4. 并行执行计划
---
## 9. Daemon 后台守护
**PR**: #170 `feat: restore daemon supervisor and remoteControlServer command`
**Feature Flag**: `DAEMON`
### 说明
Daemon 模式允许 Claude Code 作为后台长驻进程运行,管理多个 worker。
### 使用
```bash
# 启动 daemon
claude daemon start
# 查看状态
claude daemon status
# 停止
claude daemon stop
# 启动远程控制服务器
bun run rcs
```
---
## 10. Pipe IPC 多实例协作
**PR**: #241 `feat: restore pipe IPC, LAN pipes, monitor tool`
**Feature Flag**: `UDS_INBOX`
### 说明
同一台机器上的多个 Claude Code 实例通过 UDSUnix Domain Socket / Windows Named Pipe自动发现并协作。首个启动的实例成为 main后续自动注册为 sub。
### 使用
**启动多实例**
```bash
# 终端 1
bun run dev
# → 自动成为 main
# 终端 2
bun run dev
# → 自动成为 sub-1被 main attach
```
**管理实例**
```
/pipes — 显示所有实例Shift+↓ 展开选择面板
/pipes select <name> — 选中实例
/pipes all — 全选
/pipes none — 取消全选
/attach <name> — 手动 attach 某实例
/detach <name> — 断开连接
/send <name> <msg> — 向指定实例发送消息
/claim-main — 强制声明为 main
/pipe-status — 显示详细状态
/peers — 列出所有已发现的 peer
```
**选择面板操作**
1.`Shift+↓` 展开面板
2. `↑/↓` 移动光标
3. `Space` 选中/取消 pipe
4. `Enter` 确认关闭
5. `←/→` 切换路由模式selected pipes ↔ local main
**消息广播**
选中 pipe 后,输入的消息自动路由到所有选中的 slave 执行,结果流式回传到 main。
**权限转发**
slave 执行需要权限的工具时(如 BashTool权限请求自动转发到 main 的确认队列。
---
## 11. LAN Pipes 局域网群控
**PR**: #241(同上)
**Feature Flag**: `LAN_PIPES`
### 说明
在 Pipe IPC 基础上增加 TCP 传输层和 UDP Multicast 发现,实现跨机器零配置协作。
### 使用
**局域网多机器**
```bash
# 机器 A (192.168.50.22)
bun run dev
# 机器 B (192.168.50.27)
bun run dev
# 两边启动后 3-5 秒自动发现和 attach
# /pipes 显示 [LAN] 标记的远端实例
```
**防火墙配置**(每台机器都需要):
Windows管理员 PowerShell
```powershell
New-NetFirewallRule -DisplayName "CCB LAN Beacon (UDP)" -Direction Inbound -Protocol UDP -LocalPort 7101 -Action Allow -Profile Private
New-NetFirewallRule -DisplayName "CCB LAN Pipes (TCP)" -Direction Inbound -Protocol TCP -LocalPort 1024-65535 -Program (Get-Command bun).Source -Action Allow -Profile Private
New-NetFirewallRule -DisplayName "CCB LAN Beacon Out (UDP)" -Direction Outbound -Protocol UDP -RemotePort 7101 -Action Allow -Profile Private
```
macOS
```bash
# 首次运行时系统弹对话框,点"允许"即可
```
Linux
```bash
sudo firewall-cmd --zone=trusted --add-port=7101/udp --permanent
sudo firewall-cmd --zone=trusted --add-port=1024-65535/tcp --permanent
sudo firewall-cmd --reload
```
**通知显示格式**
```
# 本机 sub
Routed to [sub-1]; main can continue other tasks
# LAN peer
Routed to [main] vmwin11/192.168.50.27; main can continue other tasks
```
---
## 12. Monitor 后台监控
**PR**: #241(同上)
**Feature Flag**: `MONITOR_TOOL`
### 说明
在后台运行 shell 命令持续监控输出(类似 `watch` 命令。AI 也可自主调用 MonitorTool。
### 使用
**用户命令**
```
/monitor tail -f /var/log/syslog
/monitor watch -n 5 docker ps
/monitor "while true; do curl -s localhost:3000/health; sleep 10; done"
```
**查看监控**
-`Shift+Down` 展开后台任务面板
- 查看监控输出和状态
**Windows 兼容**
`watch -n <sec> <cmd>` 自动转为 PowerShell 循环:
```powershell
while($true){ <cmd>; Start-Sleep -Seconds <sec> }
```
**AI 调用**
AI 可在对话中自动调用 `MonitorTool` 监控日志、构建输出等。
---
## 13. Workflow 工作流脚本
**PR**: #241(同上)
**Feature Flag**: `WORKFLOW_SCRIPTS`
### 说明
执行 `.claude/workflows/` 目录下的用户定义工作流脚本。
### 使用
**创建工作流**
```bash
mkdir -p .claude/workflows
cat > .claude/workflows/deploy.sh << 'EOF'
#!/bin/bash
echo "Running tests..."
bun test
echo "Building..."
bun run build
echo "Deploying..."
EOF
chmod +x .claude/workflows/deploy.sh
```
**列出可用工作流**
```
/workflows
```
**AI 调用**
AI 可通过 `WorkflowTool` 自动执行工作流:
```
请执行 deploy 工作流
```
---
## 14. Coordinator 多Worker协调
**PR**: #241(同上)
**Feature Flag**: `COORDINATOR_MODE`
### 说明
启用 coordinator 模式后AI 可自动将任务分配给多个 worker 并行执行。
### 使用
```
/coordinator — 切换 coordinator 模式开/关
```
启用后AI 在处理复杂任务时会:
1. 分析任务可并行的部分
2. 自动创建 worker 分支
3. 分配子任务
4. 汇总结果
---
## 15. Proactive 自主模式
**PR**: #241(同上)
**Feature Flag**: `PROACTIVE` / `KAIROS`
### 说明
启用后 AI 会主动发起操作(而不仅回应用户输入),例如自动检测文件变更、主动提出优化建议。
### 使用
```
/proactive — 切换 proactive 模式开/关
```
---
## 16. History / Snip 历史管理
**PR**: #241(同上)
**Feature Flag**: `HISTORY_SNIP`
### 说明
查看和管理对话历史,支持手动截断以释放上下文窗口空间。
### 使用
```
/history — 显示对话历史摘要
/force-snip — 强制在当前位置截断历史
```
AI 也可通过 `SnipTool` 自动截断过长的对话:
```
对话太长了,请帮我截断历史
```
---
## 17. Fork 子Agent
**PR**: #241(同上)
**Feature Flag**: `FORK_SUBAGENT`
### 说明
在当前对话上下文中 fork 一个独立的子 agent继承完整会话状态独立执行。
### 使用
```
/fork — 基于当前上下文 fork 子 agent
```
子 agent 会:
- 继承当前的全部对话历史
- 在独立的执行环境中运行
- 不影响主会话状态
---
## 18. 其他恢复的工具
以下工具从 stub 恢复为完整实现:
| 工具 | 说明 | 使用 |
|------|------|------|
| `SleepTool` | 暂停执行指定时间 | AI 在轮询场景自动调用 |
| `WebBrowserTool` | 终端内网页交互 | AI 需要查看网页时调用 |
| `SubscribePRTool` | 订阅 GitHub PR 变更 | `/subscribe-pr` 或 AI 调用 |
| `PushNotificationTool` | 推送桌面通知 | AI 在长任务完成时调用 |
| `CtxInspectTool` | 检查上下文窗口使用 | AI 判断上下文剩余空间 |
| `TerminalCaptureTool` | 截取终端屏幕 | AI 需要看终端输出时调用 |
| `SendUserFileTool` | 向用户发送文件 | AI 导出文件时调用 |
| `REPLTool` | 启动子 REPL 会话 | AI 需要独立交互环境时调用 |
| `VerifyPlanExecutionTool` | 验证执行计划完成度 | AI 完成计划后自动验证 |
| `SuggestBackgroundPRTool` | 建议创建后台 PR | AI 发现可独立的变更时提议 |
| `ListPeersTool` | 列出已发现的 peer | AI 查询多实例状态时调用 |
---
## 附录:全部 Feature Flags
| Flag | 默认 | 说明 |
|------|------|------|
| `BUDDY` | ✅ dev only | 伴侣系统 |
| `BRIDGE_MODE` | ✅ dev only | 远程控制 |
| `VOICE_MODE` | ✅ dev+build | 语音模式 |
| `CHICAGO_MCP` | ✅ dev+build | Computer Use + Chrome |
| `AGENT_TRIGGERS_REMOTE` | ✅ dev+build | 定时任务 |
| `SHOT_STATS` | ✅ dev+build | API 统计 |
| `TOKEN_BUDGET` | ✅ dev+build | Token 预算 |
| `PROMPT_CACHE_BREAK_DETECTION` | ✅ dev+build | 缓存检测 |
| `ULTRAPLAN` | ✅ dev+build | 高级规划 |
| `DAEMON` | ✅ dev+build | 后台守护 |
| `UDS_INBOX` | ✅ dev only | Pipe IPC |
| `LAN_PIPES` | ✅ dev only | LAN 群控 |
| `MONITOR_TOOL` | ✅ dev+build | 后台监控 |
| `WORKFLOW_SCRIPTS` | ✅ dev+build | 工作流脚本 |
| `FORK_SUBAGENT` | ✅ dev+build | 子 Agent |
| `KAIROS` | ✅ dev+build | Kairos 调度 |
| `COORDINATOR_MODE` | ✅ dev+build | 多 Worker |
| `HISTORY_SNIP` | ✅ dev+build | 历史管理 |
| `CONTEXT_COLLAPSE` | ✅ dev+build | 上下文折叠 |
| `ULTRATHINK` | ✅ dev+build | 扩展思考 |
| `EXTRACT_MEMORIES` | ✅ dev+build | 自动记忆提取 |
| `VERIFICATION_AGENT` | ✅ dev+build | 验证 Agent |
| `KAIROS_BRIEF` | ✅ dev+build | Brief 模式 |
| `AWAY_SUMMARY` | ✅ dev+build | 离开摘要 |
| `ACP` | ✅ dev+build | ACP 协议 |
| `LODESTONE` | ✅ dev+build | 深度链接 |
| `BUILTIN_EXPLORE_PLAN_AGENTS` | ✅ dev+build | 内置 Explore/Plan agent |
| `AGENT_TRIGGERS` | ✅ dev+build | 本地定时任务 |
| `BG_SESSIONS` | ✅ dev only | 后台会话 |
| `TEMPLATES` | ✅ dev only | 模板系统 |
| `TRANSCRIPT_CLASSIFIER` | ✅ dev only | 对话分类 |
手动启用任意 flag
```bash
FEATURE_FLAG_NAME=1 bun run dev
```
---
## 附录PR 列表
| PR | 日期 | 标题 |
|----|------|------|
| #60 | 2026-04-02 | feat: enable Remote Control (BRIDGE_MODE) |
| #82 | 2026-04-03 | refactor(buddy): align companion system |
| #88 | 2026-04-03 | feat: enable /schedule (AGENT_TRIGGERS_REMOTE) |
| #89 | 2026-04-03 | feat: built-in status line |
| #92 | 2026-04-03 | feat: enable /voice mode |
| #93 | 2026-04-03 | feat: enable Chrome MCP |
| #98 | 2026-04-03 | feat: enable Computer Use (macOS + Windows + Linux) |
| #137 | 2026-04-05 | feat: Computer Use v2 — 跨平台 Executor |
| #140 | 2026-04-05 | feat: enable SHOT_STATS, TOKEN_BUDGET |
| #153 | 2026-04-06 | feat: enable GrowthBook local gate defaults |
| #156 | 2026-04-06 | feat: enable /ultraplan |
| #170 | 2026-04-07 | feat: restore daemon supervisor |
| #241 | 2026-04-11 | feat: restore pipe IPC, LAN pipes, monitor tool |

View File

@@ -102,6 +102,6 @@ FEATURE_BASH_CLASSIFIER=1 FEATURE_TREE_SITTER_BASH=1 bun run dev
| `src/utils/permissions/bashClassifier.ts` | — | Bash 分类器stubANT-ONLY |
| `src/utils/permissions/yoloClassifier.ts` | 1496 | YOLO 分类器(完整参考实现) |
| `src/utils/classifierApprovals.ts` | — | 分类器审批信号管理 |
| `src/components/permissions/BashPermissionRequest.tsx:261-469` | — | 分类器 UI |
| `src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx` | — | 分类器 UI |
| `src/hooks/toolPermission/handlers/interactiveHandler.ts` | — | 交互式权限处理 |
| `src/services/api/withRetry.ts:81` | — | API beta 标头 |
| `src/services/api/withRetry.ts` | — | API beta 标头 |

View File

@@ -30,7 +30,7 @@ BRIDGE_MODE 将本地 CLI 注册为"bridge 环境",可从 claude.ai 或其他
文件:`src/bridge/bridgeApi.ts`
Bridge API Client 提供 7 个核心操作:
Bridge API Client 提供 9 个核心操作:
| 操作 | HTTP | 说明 |
|------|------|------|
@@ -137,7 +137,7 @@ FEATURE_BRIDGE_MODE=1 FEATURE_DAEMON=1 bun run dev
| 文件 | 行数 | 职责 |
|------|------|------|
| `src/bridge/bridgeApi.ts` | 540 | API Client核心 |
| `src/bridge/bridgeApi.ts` | 541 | API Client核心 |
| `src/bridge/sessionRunner.ts` | — | 会话运行器 |
| `src/bridge/bridgeConfig.ts` | — | 配置管理 |
| `src/bridge/replBridgeTransport.ts` | — | 传输层 |

View File

@@ -78,10 +78,13 @@ FEATURE_BUDDY=1 bun run dev
| 文件 | 说明 |
|---|---|
| `src/commands/buddy/index.ts` | `/buddy` 命令注册 |
| `src/commands/buddy/buddy.ts` | `/buddy` 命令处理 |
| `src/buddy/companion.ts` | 宠物生成与加载 |
| `src/buddy/companionReact.ts` | 宠物反应系统REPL 每轮查询后触发) |
| `src/buddy/types.ts` | 类型定义(物种、稀有度、属性) |
| `src/buddy/sprites.ts` | 终端像素画渲染 |
| `src/buddy/CompanionSprite.tsx` | React 组件(输入框旁显示) |
| `src/buddy/CompanionCard.tsx` | 宠物信息卡片(`/buddy` 无参数时展示) |
| `src/buddy/useBuddyNotification.tsx` | 启动提示通知 |
| `src/buddy/prompt.ts` | 宠物相关 prompt 模板 |

89
docs/features/channels.md Normal file
View File

@@ -0,0 +1,89 @@
# Channels — 外部频道消息接入
> 启动参数:`--channels` / `--dangerously-load-development-channels`
> 状态:已解除 feature flag 和 OAuth 限制,可直接使用
## 概述
Channel 是一个 MCP 服务器,它将外部事件推送到你运行中的 Claude Code 会话中,以便 Claude 可以在你不在终端时做出反应。详细使用说明请参考以下文档:
- **官方文档**[使用 channels 将事件推送到运行中的会话](https://code.claude.com/docs/zh-CN/channels)
- **飞书插件**[claude-code-feishu-channel](https://github.com/whobot-ai/claude-code-feishu-channel) — 社区首个飞书 Channel 插件,支持双向消息、配对认证、群组聊天、文件附件
本仓库现在内置了 **微信 WeChat channel**,不需要单独安装外部 marketplace 插件。
## 快速开始
```bash
# 启用频道监听plugin 格式)
ccb --channels plugin:feishu@claude-code-feishu-channel
# 启用内置微信 channel
ccb weixin login
ccb --channels plugin:weixin@builtin
# 启用频道监听server 格式)
ccb --channels server:my-slack-bridge
# 同时启用多个频道
ccb --channels plugin:feishu@claude-code-feishu-channel --channels server:discord-bot
# 开发模式(跳过 allowlist 检查,用于测试自定义 channel
ccb --dangerously-load-development-channels server:my-custom-channel
```
## 支持的 Channel
| Channel | 说明 | 来源 |
|---------|------|------|
| **Telegram** | 官方 Telegram Bot 集成 | `/plugin install telegram@claude-plugins-official` |
| **Discord** | 官方 Discord Bot 集成 | `/plugin install discord@claude-plugins-official` |
| **iMessage** | macOS 原生消息 | `/plugin install imessage@claude-plugins-official` |
| **飞书 (Feishu/Lark)** | 双向消息、群组聊天、文件附件 | `/plugin install feishu@claude-code-feishu-channel` |
| **微信 (WeChat)** | 内置 channel支持扫码登录、双向消息、附件透传 | `ccb weixin login` + `ccb --channels plugin:weixin@builtin` |
## 微信内置 Channel
### 登录
```bash
ccb weixin login
```
已登录状态可清除:
```bash
ccb weixin login clear
```
### 会话启用
```bash
ccb --channels plugin:weixin@builtin
```
### 配对授权
首次收到未授权微信用户消息时weixin channel 会回一条 6 位 pairing code。运营侧可在终端执行
```bash
ccb weixin access pair <code>
```
确认后,该微信用户后续消息才会进入 Claude Code 会话。
## 相关文件
| 文件 | 职责 |
|------|------|
| `src/services/mcp/channelNotification.ts` | 频道 gate 逻辑、消息包装 |
| `src/services/mcp/channelAllowlist.ts` | 频道开关(已默认开启) |
| `src/services/mcp/useManageMCPConnections.ts` | MCP 连接管理中的频道注册 |
| `src/components/LogoV2/ChannelsNotice.tsx` | 启动时频道状态提示 |
| `src/main.tsx` | `--channels` 参数解析 |
| `src/interactiveHelpers.tsx` | Dev channels 确认对话框 |
## 参考链接
- [官方 Channels 文档](https://code.claude.com/docs/zh-CN/channels) — 完整使用说明、安全性、Enterprise 控制
- [飞书 Channel 插件](https://github.com/whobot-ai/claude-code-feishu-channel) — 安装配置教程、MCP 工具、Skill 命令参考

View File

@@ -0,0 +1,30 @@
# Chrome Use — 浏览器自动化快速指南
让 Claude Code 直接控制你的 Chrome 浏览器,用自然语言完成网页操作。
## 快速开始3 分钟)
### 第一步:安装 Chrome 扩展
1. 下载扩展https://github.com/hangwin/mcp-chrome/releases
2. 解压 zip 文件
3. 打开 Chrome 访问 `chrome://extensions/`
4. 开启右上角「开发者模式」
5. 点击「加载已解压的扩展程序」,选择解压后的文件夹
### 第二步:启动 Claude Code
```bash
bun run dev
ccb # 或者 ccb 安装版也行
```
### 第三步:启用 Chrome MCP
1. 在 REPL 中输入 `/mcp` 打开 MCP 面板
2. 找到 `mcp-chrome`,按空格键启用
3. 按 Enter 确认
## 相关文档
- GitHub 仓库https://github.com/hangwin/mcp-chrome

View File

@@ -2,12 +2,12 @@
## 概览
Computer Use 提供 37 个工具,分为三类:
Computer Use 提供 38 个工具,分为三类:
| 分类 | 平台 | 工具数 | 说明 |
|------|------|--------|------|
| 通用工具 | 全平台 | 24 | 官方 Computer Use 标准能力 |
| Windows 专属工具 | Win32 | 10 | 绑定窗口模式下的增强能力 |
| Windows 专属工具 | Win32 | 11 | 绑定窗口模式下的增强能力 |
| 教学工具 | 全平台 | 3 | 分步引导模式(需 teachMode 开启) |
---
@@ -82,7 +82,7 @@ Computer Use 提供 37 个工具,分为三类:
---
## 二、Windows 专属工具10 个)
## 二、Windows 专属工具12 个)
仅 Windows 平台可见。核心能力:**绑定窗口后的独立操作——不抢占用户鼠标键盘**。
@@ -235,8 +235,19 @@ Computer Use 提供 37 个工具,分为三类:
| 工具 | 参数 | 说明 |
|------|------|------|
| `open_terminal` | `agent`, `command?` | 打开新终端窗口并启动 AI agentclaude/codex/gemini/custom。自动绑定窗口并截图验证 |
| `activate_window` | `click_x?`, `click_y?` | 激活绑定窗口SetForegroundWindow + BringWindowToTop + 点击确保焦点 |
| `prompt_respond` | `response_type`, `arrow_direction?`, `arrow_count?`, `text?` | 处理终端 Yes/No/选择提示 |
**open_terminal agent 类型:**
| agent | 命令 | 说明 |
|-------|------|------|
| `claude` | `claude` | 启动 Claude Code |
| `codex` | `codex` | 启动 Codex |
| `gemini` | `gemini` | 启动 Gemini |
| `custom` | 用户指定 | 自定义命令 |
**response_type 详情:**
| response_type | 操作 | 场景 |

View File

@@ -11,7 +11,7 @@
-`@ant/computer-use-input` 拆为 dispatcher + backendsdarwin + win32
-`@ant/computer-use-swift` 拆为 dispatcher + backendsdarwin + win32
-`CHICAGO_MCP` 编译开关已开
- `src/`有 6 处 macOS 硬编码阻塞
- `src/` 层 macOS 硬编码已移除Phase 2 已完成)
## 2. 阻塞点全景
@@ -19,25 +19,25 @@
| # | 文件:行号 | 阻塞代码 | 影响 |
|---|----------|---------|------|
| 1 | `src/main.tsx:1605` | `getPlatform() === 'macos'` | 整个 CU 初始化被跳过 |
| 1 | `src/main.tsx:2366` | `feature("CHICAGO_MCP")` 门控 | CU 初始化入口 |
### 2.2 加载层
| # | 文件:行号 | 阻塞代码 | 影响 |
|---|----------|---------|------|
| 2 | `src/utils/computerUse/swiftLoader.ts:16` | `process.platform !== 'darwin'` → throw | 截图、应用管理全部不可用 |
| 3 | `src/utils/computerUse/executor.ts:263` | `process.platform !== 'darwin'`throw | 整个 executor 工厂函数不可用 |
| 2 | `src/utils/computerUse/swiftLoader.ts` | macOS-only loader已改为仅 darwin 加载) | 非 darwin 使用 platforms/ 替代 |
| 3 | `src/utils/computerUse/executor.ts:302` | `process.platform !== 'darwin'`cross-platform executor | 非 darwin 走跨平台路径 |
### 2.3 macOS 特有依赖
| # | 文件:行号 | 依赖 | macOS 实现 | 需要替代方案 |
|---|----------|------|-----------|------------|
| 4 | `executor.ts:70-88` | 剪贴板 | `pbcopy`/`pbpaste` | Win: PowerShell `Get/Set-Clipboard`Linux: `xclip`/`wl-copy` |
| 5 | `drainRunLoop.ts:21` | CFRunLoop pump | `cu._drainMainRunLoop()` | 非 darwin直接执行 fn(),不需要 pump |
| 6 | `escHotkey.ts:28` | ESC 热键 | CGEventTap | 非 darwin返回 false已有 Ctrl+C fallback |
| 7 | `hostAdapter.ts:48-54` | 系统权限 | TCC accessibility + screenRecording | Win直接 grantedLinux检查 xdotool |
| 8 | `common.ts:56` | 平台标识 | `platform: 'darwin'` 硬编码 | 动态获取 |
| 9 | `executor.ts:180` | 粘贴快捷键 | `command+v` | Win/Linux`ctrl+v` |
| 4 | `executor.ts:72-96` | 剪贴板 | `pbcopy`/`pbpaste` / PowerShell / xclip | Win: PowerShell `Get/Set-Clipboard`Linux: `xclip`/`wl-copy` |
| 5 | `drainRunLoop.ts` | CFRunLoop pump | `cu._drainMainRunLoop()` | 非 darwin直接执行 fn(),不需要 pump |
| 6 | `escHotkey.ts` | ESC 热键 | CGEventTap | 非 darwin返回 false已有 Ctrl+C fallback |
| 7 | `hostAdapter.ts` | 系统权限 | TCC accessibility + screenRecording | Win直接 grantedLinux检查 xdotool |
| 8 | `common.ts:55-58` | 平台标识 | 动态获取 | 已改为 `process.platform` 分发 |
| 9 | `executor.ts:232` | 粘贴快捷键 | `command`/`ctrl` 分发 | 已按平台分发粘贴快捷键 |
### 2.4 缺失的 Linux 后端
@@ -100,19 +100,19 @@
| 步骤 | 文件 | 改动 |
|------|------|------|
| 2.1 | `src/main.tsx:1605` | `getPlatform() === 'macos'` → 去掉平台限制,或改为 `!== 'unknown'` |
| 2.2 | `src/utils/computerUse/swiftLoader.ts:16-18` | 移除 `process.platform !== 'darwin'` throw。`@ant/computer-use-swift/index.ts` 已有跨平台 dispatch |
| 2.3 | `src/utils/computerUse/executor.ts:263-267` | 移除 `process.platform !== 'darwin'` throw。改为检查 input/swift isSupported |
| 2.4 | `src/utils/computerUse/executor.ts:70-88` | 剪贴板函数按平台分发darwin→pbcopy/pbpastewin32→PowerShell Get/Set-Clipboardlinux→xclip |
| 2.5 | `src/utils/computerUse/executor.ts:180` | `typeViaClipboard``command+v` → 非 darwin 时用 `ctrl+v` |
| 2.6 | `src/utils/computerUse/executor.ts:273` | `const cu = requireComputerUseSwift()` → 改为 `new ComputerUseAPI()`(从 package 直接实例化,不走 swiftLoader throw |
| 2.7 | `src/utils/computerUse/drainRunLoop.ts` | 开头加 `if (process.platform !== 'darwin') return fn()` |
| 2.8 | `src/utils/computerUse/escHotkey.ts` | `registerEscHotkey` 非 darwin 返回 false已有 Ctrl+C fallback |
| 2.9 | `src/utils/computerUse/hostAdapter.ts:48-54` | `ensureOsPermissions` 非 darwin 返回 `{ granted: true }` |
| 2.10 | `src/utils/computerUse/common.ts:56` | `platform: 'darwin'``platform: process.platform === 'win32' ? 'windows' : process.platform === 'linux' ? 'linux' : 'darwin'` |
| 2.11 | `src/utils/computerUse/common.ts:55` | `screenshotFiltering: 'native'` → 非 darwin 时 `'none'`Windows/Linux 截图不支持 per-app 过滤) |
| 2.12 | `src/utils/computerUse/gates.ts:13` | `enabled: false``enabled: true`(无 GrowthBook 时默认可用 |
| 2.13 | `src/utils/computerUse/gates.ts:39-43` | `hasRequiredSubscription()` → 直接返回 `true` |
| 2.1 | `src/main.tsx:2366` | `feature("CHICAGO_MCP")` → 已为跨平台入口 |
| 2.2 | `src/utils/computerUse/swiftLoader.ts` | 已改为仅 darwin 加载,非 darwin 使用 platforms/ |
| 2.3 | `src/utils/computerUse/executor.ts:302-309` | 已改为 cross-platform dispatch非 darwin → createCrossPlatformExecutor |
| 2.4 | `src/utils/computerUse/executor.ts:72-96` | 剪贴板按平台分发darwin→pbcopy/pbpastewin32→PowerShelllinux→xclip |
| 2.5 | `src/utils/computerUse/executor.ts:232` | 粘贴快捷键已按平台分发darwin→command其他→ctrl |
| 2.6 | `src/utils/computerUse/executor.ts:302-309` | 非 darwin 已改为 `createCrossPlatformExecutor()` |
| 2.7 | `src/utils/computerUse/drainRunLoop.ts` | 非 darwin 无需 pump直接执行 fn |
| 2.8 | `src/utils/computerUse/escHotkey.ts` | 非 darwin 返回 false已有 Ctrl+C fallback |
| 2.9 | `src/utils/computerUse/hostAdapter.ts` | 非 darwin 权限检查逻辑已实现 |
| 2.10 | `src/utils/computerUse/common.ts:58` | 已改为动态 `process.platform` 分发 |
| 2.11 | `src/utils/computerUse/common.ts:55` | 已改为 darwin→'native',其他→'none' |
| 2.12 | `src/utils/computerUse/gates.ts:55` | 已更新(需验证 enabled 默认值 |
| 2.13 | `src/utils/computerUse/gates.ts:39` | `hasRequiredSubscription()` 已更新 |
### Phase 3新增 Linux 后端

View File

@@ -25,7 +25,7 @@ CONTEXT_COLLAPSE 让模型内省上下文窗口使用情况,并智能压缩旧
| 折叠核心 | `src/services/contextCollapse/index.ts` | **Stub** — 接口完整(`ContextCollapseStats``CollapseResult``DrainResult`),函数全部空操作 |
| 折叠操作 | `src/services/contextCollapse/operations.ts` | **Stub**`projectView` 为恒等函数 |
| 折叠持久化 | `src/services/contextCollapse/persist.ts` | **Stub**`restoreFromEntries` 为空操作 |
| CtxInspectTool | `src/tools/CtxInspectTool/` | **缺失**目录不存在 |
| CtxInspectTool | `packages/builtin-tools/src/tools/CtxInspectTool/CtxInspectTool.ts` | **实现**上下文内省工具 |
| SnipTool 提示 | `src/tools/SnipTool/prompt.ts` | **Stub** — 空工具名 |
| SnipTool 实现 | `src/tools/SnipTool/SnipTool.ts` | **缺失** |
| force-snip 命令 | `src/commands/force-snip.js` | **缺失** |
@@ -106,7 +106,7 @@ SnipTool 提供手动折叠能力:
| 1 | `services/contextCollapse/index.ts` | 大 | 折叠状态机、LLM 调用、消息压缩 |
| 2 | `services/contextCollapse/operations.ts` | 中 | `projectView()` 消息过滤 |
| 3 | `services/contextCollapse/persist.ts` | 小 | `restoreFromEntries()` 磁盘持久化 |
| 4 | `tools/CtxInspectTool/` | | 上下文内省工具token 计数、已折叠范围 |
| 4 | `tools/CtxInspectTool/` | 已完成 | 上下文内省工具已实现(`packages/builtin-tools/src/tools/CtxInspectTool/` |
| 5 | `tools/SnipTool/SnipTool.ts` | 中 | Snip 工具实现 |
| 6 | `commands/force-snip.js` | 小 | `/force-snip` 命令 |

View File

@@ -0,0 +1,318 @@
# Daemon 重构设计方案
> 分支: `feat/integrate-5-branches`
> 基于: `f41745cb` (= main `11bb3f62` 内容)
> 日期: 2026-04-13
## 一、问题概述
### 1.1 命令结构散乱
当前后台进程相关的命令分布在三个不同的位置,没有统一的命名空间:
| 命令 | 注册位置 | 入口 |
|------|---------|------|
| `claude daemon start/status/stop` | `cli.tsx` 快速路径 L203 | `daemon/main.ts` |
| `claude ps` | `cli.tsx` 快速路径 L220 | `cli/bg.ts` |
| `claude logs <x>` | `cli.tsx` 快速路径 L232 | `cli/bg.ts` |
| `claude attach <x>` | `cli.tsx` 快速路径 L236 | `cli/bg.ts` |
| `claude kill <x>` | `cli.tsx` 快速路径 L238 | `cli/bg.ts` |
| `claude --bg` | `cli.tsx` 快速路径 L244 | `cli/bg.ts` |
| `claude new/list/reply` | `cli.tsx` 快速路径 L250 | `cli/handlers/templateJobs.ts` |
| `claude rollback` | `main.tsx` Commander.js L6525 | `cli/rollback.ts` |
| `claude up` | `main.tsx` Commander.js L6511 | `cli/up.ts` |
**问题**:
- `ps/logs/attach/kill``daemon` 逻辑上都是后台进程管理,但互不关联
- 这些命令都**只有 CLI 入口**REPL 里输入 `/daemon``/ps` 不存在
- `new/list/reply` 是模板任务系统的顶级命令,容易与其他命令冲突(特别是 `list`
### 1.2 Windows 不支持
`--bg``attach` 硬依赖 tmux
- `bg.ts:handleBgFlag()` 第一步就检查 tmux不可用直接报错退出
- `bg.ts:attachHandler()``tmux attach-session`,无 tmux 替代方案
- Windows (包括 VS Code 终端) 完全无法使用后台会话功能
### 1.3 无 REPL 入口
对比 `/mcp` 的双注册模式:
- **CLI**: `claude mcp serve/add/remove/list` (Commander.js, `main.tsx:5760`)
- **REPL**: `/mcp enable/disable/reconnect` (slash command, `commands/mcp/index.ts`)
`daemon`/`bg`/`job` 系列只有 CLI 快速路径REPL 中完全不可用。
## 二、目标
1. **层级化命令结构**: 参照 `/mcp` 模式,将后台管理收归 `/daemon`,模板任务收归 `/job`
2. **跨平台后台会话**: Windows / macOS / Linux 都能启动、附着、终止后台会话
3. **双注册**: CLI (`claude daemon ...`) + REPL (`/daemon ...`) 同时可用
4. **向后兼容**: 旧命令保留但输出 deprecation 提示
## 三、命令结构设计
### 3.1 `/daemon` — 后台进程管理
合并 daemon supervisor + bg sessions 为统一命名空间:
```
claude daemon <subcommand> ← CLI 入口 (cli.tsx 快速路径)
/daemon <subcommand> ← REPL 入口 (slash command, local-jsx)
子命令:
status 综合状态面板 (daemon + 所有会话)
start [--dir <path>] 启动 daemon supervisor
stop 停止 daemon
bg [args...] 启动后台会话
attach [target] 附着到后台会话
logs [target] 查看会话日志
kill [target] 终止会话
(无参数) 等同于 status
```
**CLI 快速路径路由** (`cli.tsx`):
```typescript
// 新: 统一入口
if (feature('DAEMON') && args[0] === 'daemon') {
const sub = args[1] || 'status'
switch (sub) {
case 'start': case 'stop': case 'status':
await daemonMain([sub, ...args.slice(2)])
break
case 'bg':
await bg.handleBgStart(args.slice(2))
break
case 'attach': case 'logs': case 'kill':
await bg[`${sub}Handler`](args[2])
break
}
}
// 向后兼容 (deprecated)
if (feature('BG_SESSIONS') && ['ps','logs','attach','kill'].includes(args[0])) {
console.warn(`[deprecated] Use: claude daemon ${args[0] === 'ps' ? 'status' : args[0]}`)
// ... delegate to daemon subcommand
}
```
**REPL 斜杠命令** (`commands/daemon/index.ts`):
```typescript
const daemon = {
type: 'local-jsx',
name: 'daemon',
description: 'Manage background sessions and daemon',
argumentHint: '[status|start|stop|bg|attach|logs|kill]',
isEnabled: () => feature('DAEMON') || feature('BG_SESSIONS'),
load: () => import('./daemon.js'),
} satisfies Command
```
### 3.2 `/job` — 模板任务管理
```
claude job <subcommand> ← CLI 入口
/job <subcommand> ← REPL 入口
子命令:
list 列出模板和活跃任务
new <template> [args] 从模板创建任务
reply <id> <text> 回复任务
status <id> 查看任务状态
(无参数) 等同于 list
```
### 3.3 独立命令 (不变)
```
claude up 保持顶级 (简短的 bootstrap 命令)
claude rollback [target] 保持顶级 (低频运维命令)
```
## 四、跨平台后台引擎
### 4.1 引擎抽象
```typescript
// src/cli/bg/engine.ts
export interface BgEngine {
readonly name: string
/** 当前平台是否可用 */
available(): Promise<boolean>
/** 启动后台会话 */
start(opts: BgStartOptions): Promise<BgStartResult>
/** 附着到后台会话blocking */
attach(session: SessionEntry): Promise<void>
}
export interface BgStartOptions {
sessionName: string
args: string[]
env: Record<string, string | undefined>
logPath: string
cwd: string
}
export interface BgStartResult {
pid: number
sessionName: string
logPath: string
engineUsed: string
}
```
### 4.2 三种引擎实现
| 引擎 | 平台 | 启动方式 | attach 方式 |
|------|------|---------|------------|
| TmuxEngine | macOS/Linux (有 tmux) | `tmux new-session -d` | `tmux attach-session` |
| DetachedEngine | Windows / 无 tmux 的 macOS/Linux | `spawn({ detached, stdio→logFile })` | `tail -f` 日志文件 |
#### DetachedEngine 详细设计
**启动 (`start`)**:
```typescript
// 1. 打开日志文件 fd
const logFd = fs.openSync(logPath, 'a')
// 2. detached spawn, stdout/stderr 重定向到日志
const child = spawn(process.execPath, execArgs, {
detached: true,
stdio: ['ignore', logFd, logFd],
env,
cwd,
})
child.unref()
fs.closeSync(logFd)
// 3. 写 sessions/<PID>.json
```
**附着 (`attach`)**:
```typescript
// 跨平台 tail -f 实现
// 1. 读取已有日志内容输出到 stdout
// 2. fs.watch(logPath) 监听变化
// 3. 每次变化读取新增内容
// 4. Ctrl+C 退出 tail不杀后台进程
```
#### 引擎选择逻辑
```typescript
// src/cli/bg/engines/index.ts
export async function selectEngine(): Promise<BgEngine> {
if (process.platform === 'win32') {
return new DetachedEngine()
}
const tmux = new TmuxEngine()
if (await tmux.available()) {
return tmux
}
return new DetachedEngine()
}
```
### 4.3 SessionEntry 扩展
```typescript
interface SessionEntry {
// ... 现有字段
engine: 'tmux' | 'detached' // 新增: 记录使用的引擎
tmuxSessionName?: string // tmux 引擎才有
logPath?: string // 两种引擎都有
}
```
`attach` 时根据 `session.engine` 选择对应的 attach 策略。
## 五、文件变更清单
### 新增文件 (10 个)
```
src/cli/bg/engine.ts BgEngine 接口定义
src/cli/bg/engines/tmux.ts TmuxEngine (从 bg.ts 提取)
src/cli/bg/engines/detached.ts DetachedEngine (新实现)
src/cli/bg/engines/index.ts 引擎选择 + re-export
src/cli/bg/tail.ts 跨平台日志 tail (用于 detached attach)
src/commands/daemon/index.ts /daemon REPL 斜杠命令注册
src/commands/daemon/daemon.tsx /daemon 子命令路由 + status UI
src/commands/job/index.ts /job REPL 斜杠命令注册
src/commands/job/job.tsx /job 子命令路由 + UI
docs/features/daemon-restructure-design.md 本设计文档
```
### 修改文件 (6 个)
```
src/cli/bg.ts 重构: handler 函数改为调用 BgEngine
src/entrypoints/cli.tsx 快速路径: daemon 统一入口 + 向后兼容
src/commands.ts 注册 /daemon 和 /job 斜杠命令
src/daemon/main.ts daemonMain() 增加 bg/ps/logs 子命令分发
src/main.tsx Commander.js: 可选注册 daemon/job 子命令
src/cli/handlers/templateJobs.ts 适配 /job 入口 (可能不需改)
```
### 不动的文件
```
src/daemon/state.ts daemon PID 状态管理 (无需改)
src/jobs/state.ts job 状态管理 (无需改)
src/jobs/templates.ts 模板发现 (无需改)
src/jobs/classifier.ts 任务分类器 (无需改)
src/cli/rollback.ts 保持顶级命令 (无需改)
src/cli/up.ts 保持顶级命令 (无需改)
```
## 六、可行性分析
### 6.1 风险评估
| 风险 | 级别 | 缓解措施 |
|------|------|---------|
| cli.tsx 快速路径修改影响启动性能 | 低 | 仅改路由逻辑import 仍然 lazy |
| DetachedEngine 的 attach 在 Windows 上 fs.watch 不可靠 | 中 | 使用轮询 fallback (setInterval + fs.stat) |
| 向后兼容的 deprecation 可能破坏脚本 | 低 | 旧命令保持可用,仅输出 stderr 警告 |
| REPL 中 /daemon bg 需要 spawn 子进程 | 中 | 参考 /assistant 的 NewInstallWizard (已有 spawn 先例) |
| tsc 类型兼容 | 低 | 接口定义清晰,不引入 any |
### 6.2 工作量估计
| Task | 文件数 | 复杂度 |
|------|--------|--------|
| Task 013: BgEngine 抽象 + 引擎实现 | 5 新增 + 1 修改 | 中 |
| Task 014: /daemon 命令层级化 | 3 新增 + 3 修改 | 中 |
| Task 015: /job 命令层级化 | 2 新增 + 2 修改 | 低 |
| Task 016: 向后兼容 + 测试 | 0 新增 + 2 修改 | 低 |
### 6.3 依赖关系
```
Task 013 (BgEngine) ← 无依赖,可独立开发
Task 014 (/daemon) ← 依赖 Task 013 (引擎选择)
Task 015 (/job) ← 无依赖,可与 013 并行
Task 016 (兼容) ← 依赖 Task 014 + 015
```
## 七、设计决策记录
### D1: 为什么 daemon + bg sessions 合为一个命名空间?
用户视角:都是"后台运行的东西"。分开会导致 `claude daemon status` 看 supervisor + `claude ps` 看会话,割裂感强。合并后 `claude daemon status` 一次性展示 supervisor 状态 + 所有会话列表。
### D2: 为什么 rollback/up 不收入 daemon
它们本质是**版本管理/环境初始化**,不是后台进程管理。`claude up` 是同步阻塞的 setup 脚本,不涉及 daemon 或后台会话。保持顶级更直观。
### D3: 为什么 DetachedEngine 的 attach 用 tail 而不是 IPC
1. 日志文件是最简单的跨平台方案,无需额外依赖
2. UDS Pipe IPC 系统 (usePipeIpc) 设计用于实例间通信,不是终端附着
3. tmux attach 的体验(完整 PTY无法在纯 detached 模式下复制tail 是最诚实的替代
### D4: 为什么不用 Windows Terminal 的 tab/pane API
Windows Terminal 的 `wt.exe` 新窗口/标签功能不够通用——用户可能在 VS Code、ConEmu、cmder 等终端中。detached + log 是唯一跨终端方案。

View File

@@ -1,12 +1,12 @@
# DAEMON — 后台守护进程
> Feature Flag: `FEATURE_DAEMON=1`
> 实现状态:主进程和 worker 注册为 StubCLI 路由完整
> 实现状态:Supervisor 和 remoteControl Worker 已实现
> 引用数3
## 一、功能概述
DAEMON 将 Claude Code 变为后台守护进程。主进程supervisor管理多个 worker 进程的生命周期,通过 Unix 域套接字进行 IPC。适用于持续运行的后台服务场景(如配合 BRIDGE_MODE 提供远程控制服务)。
DAEMON 将 Claude Code 变为后台守护进程。主进程supervisor管理多个 worker 进程的生命周期,通过文件系统状态文件进行通信。适用于持续运行的后台服务场景(如配合 BRIDGE_MODE 提供远程控制服务)。
## 二、实现架构
@@ -14,8 +14,9 @@ DAEMON 将 Claude Code 变为后台守护进程。主进程supervisor
| 模块 | 文件 | 状态 |
|------|------|------|
| 守护主进程 | `src/daemon/main.ts` | **Stub**`daemonMain: () => Promise.resolve()` |
| Worker 注册 | `src/daemon/workerRegistry.ts` | **Stub**`runDaemonWorker: () => Promise.resolve()` |
| 守护主进程 | `src/daemon/main.ts` | **已实现**Supervisor 含子命令、Worker 生命周期管理、指数退避重启 |
| Worker 注册 | `src/daemon/workerRegistry.ts` | **已实现**remoteControl Workerheadless bridge |
| Daemon 状态 | `src/daemon/state.ts` | **已实现** — PID/状态文件的读写与查询 |
| CLI 路由 | `src/entrypoints/cli.tsx` | **布线**`--daemon-worker``daemon` 子命令 |
| 命令注册 | `src/commands.ts` | **布线** — DAEMON + BRIDGE_MODE 门控 |
@@ -23,34 +24,49 @@ DAEMON 将 Claude Code 变为后台守护进程。主进程supervisor
```
# 启动守护进程
claude daemon
claude daemon start
# 以 worker 身份启动
claude --daemon-worker=<kind>
# 查看状态(默认子命令)
claude daemon status
claude daemon ps
# 停止守护进程
claude daemon stop
# 以 worker 身份启动(由 supervisor 自动调用)
claude --daemon-worker=remoteControl
# 后台会话管理
claude daemon bg
claude daemon attach <session>
claude daemon logs <session>
claude daemon kill <session>
```
### 2.3 预期架构
### 2.3 架构
```
Supervisor (daemonMain)
├── Worker 1: assistant-mode
│ └── 接收和处理 assistant 会话
├── Worker 2: bridge-sync
│ └── bridge 消息同步
└── Worker 3: proactive
└── 主动任务执行
├── Worker: remoteControl
│ └── runBridgeHeadless() — 远程控制 headless 模式
接收远程会话、处理消息、权限审批
IPC via Unix Domain Sockets
- 生命周期管理(启动、停止、重启)
- 工作分发
- 状态报告
文件系统状态文件 (daemon-state.json)
- PID、CWD、启动时间、Worker 类型
- queryDaemonStatus() / stopDaemonByPid()
```
### 2.4 与 BRIDGE_MODE 的关系
### 2.4 Worker 生命周期管理
Supervisor 为每个 worker 实现:
- **指数退避重启**:初始 2s上限 120s倍数 ×2
- **快速失败检测**10s 内连续崩溃 5 次则 parking不再重启
- **永久错误退出码**78 (EXIT_CODE_PERMANENT) 导致直接 parking
- **优雅关闭**SIGTERM/SIGINT → abort signal → 30s 强制 SIGKILL
### 2.5 与 BRIDGE_MODE 的关系
DAEMON 和 BRIDGE_MODE 常组合使用:
@@ -63,40 +79,39 @@ if (feature('DAEMON') && feature('BRIDGE_MODE')) {
双重门控:两个 feature 都需要开启才能使用远程控制服务器。
## 三、需要补全的内容
| 模块 | 工作量 | 说明 |
|------|--------|------|
| `daemon/main.ts` | 大 | Supervisor 主进程:启动 worker、生命周期管理、IPC |
| `daemon/workerRegistry.ts` | 中 | Worker 类型分发assistant/bridge-sync/proactive |
| Worker 实现 | 大 | 各类型 worker 的具体实现 |
| IPC 协议 | 中 | Supervisor-Worker 通信层 |
## 四、关键设计决策
## 三、关键设计决策
1. **多进程架构**:一个 supervisor + 多个 worker进程隔离
2. **Unix 域套接字 IPC**:本地进程间通信,低延迟
2. **文件系统状态通信**:通过 `daemon-state.json` 文件进行状态共享(非 Unix 域套接字)
3. **与 BRIDGE_MODE 强绑定**:守护进程最常见的用途是提供远程控制服务
4. **CLI 子命令路由**`daemon` 子命令和 `--daemon-worker` 参数在 `cli.tsx` 中路由
5. **Worker 环境变量**supervisor 通过环境变量(`DAEMON_WORKER_*`)向 worker 传递配置
## 、使用方式
## 、使用方式
```bash
# 启用守护进程模式
FEATURE_DAEMON=1 FEATURE_BRIDGE_MODE=1 bun run dev
# 启动守护进程
claude daemon
claude daemon start
# 以特定 worker 启动
claude --daemon-worker=assistant
# 查看状态
claude daemon status
# 停止守护进程
claude daemon stop
# 以特定 worker 启动(通常由 supervisor 自动调用)
claude --daemon-worker=remoteControl
```
## 、文件索引
## 、文件索引
| 文件 | 职责 |
|------|------|
| `src/daemon/main.ts` | Supervisor 主进程stub |
| `src/daemon/workerRegistry.ts` | Worker 注册stub |
| `src/entrypoints/cli.tsx:95,149` | CLI 路由 |
| `src/commands.ts:77` | 命令注册(双重门控) |
| `src/daemon/main.ts` | Supervisor 主进程子命令分发、Worker 生命周期管理、退避重启 |
| `src/daemon/workerRegistry.ts` | Worker 入口remoteControl worker 实现 |
| `src/daemon/state.ts` | Daemon 状态管理PID 文件读写、状态查询 |
| `src/entrypoints/cli.tsx` | CLI 路由 |
| `src/commands.ts` | 命令注册(双重门控) |

View File

@@ -27,13 +27,15 @@ bun run dev:inspect
## 原理
`dev:inspect` 脚本实际执行的是:
`dev:inspect` 脚本实际执行的是 `scripts/dev-debug.ts`
```bash
bun --inspect-wait=localhost:8888/<token> run scripts/dev.ts
```typescript
// scripts/dev-debug.ts
process.env.BUN_INSPECT = "localhost:8888/<token>"
await import("./dev")
```
Bun 的 `--inspect-wait` 参数启动一个 Chrome DevTools Protocol 兼容的 inspect 服务,等待调试器连接后才开始执行。VS Code 的 `bun` 扩展通过 WebSocket 连接到这个地址实现 attach。
通过设置 `BUN_INSPECT` 环境变量启动一个 Chrome DevTools Protocol 兼容的 inspect 服务,然后导入 dev 模式入口。VS Code 的 `bun` 扩展通过 WebSocket 连接到输出的地址实现 attach。
## JetBrains IDE

File diff suppressed because it is too large Load Diff

View File

@@ -1,160 +0,0 @@
# Feature Flags 审查报告 — Codex 复核
> 审查日期: 2026-04-05
> 审查工具: Codex CLI v0.118.0 (本地, full-auto mode)
> 消耗 tokens: 240,306
> 审查范围: docs/feature-flags-audit-complete.md 中标记为 COMPLETE 的 22 个编译时 feature flag
---
## 审查背景
原始审计报告 (`docs/feature-flags-audit-complete.md`) 声称 22 个 feature flag 被标记为 "COMPLETE",只需在 `build.ts` / `scripts/dev.ts` 中启用即可工作。
Claude Code 团队通过 6 个并行子代理实际读取源码后初步发现大量误判,随后将分析结果传递给 Codex CLI 进行独立二次验证。
---
## Codex 发现摘要
### High 级发现
1. **`CONTEXT_COLLAPSE` 不是 COMPLETE**
- `src/services/contextCollapse/index.ts:43``isContextCollapseEnabled()` 硬编码为 `false`
- `src/services/contextCollapse/index.ts:47``applyCollapsesIfNeeded()` 只是原样返回消息
- `src/services/contextCollapse/index.ts:59``recoverFromOverflow()` 也是 no-op
- `src/services/contextCollapse/operations.ts:3``persist.ts:3` 同样是 stub
- 审计报告把 UI/命令文件算进去了,但真正被查询循环消费的是 stub 后端
2. **原分类"真正只需编译开关"的 7 个 flag只有 3 个准确**
-`SHOT_STATS` — 零额外门控compile-only
-`PROMPT_CACHE_BREAK_DETECTION` — 有 try-catch 兜底compile-only
-`TOKEN_BUDGET` — 纯本地计算compile-only
-`TEAMMEM` — 还要求 AutoMem + GrowthBook `tengu_herring_clock` + GitHub repo (`teamMemPaths.ts:73`, `watcher.ts:256`, `watcher.ts:259`)
-`AGENT_TRIGGERS` — 受 `isKairosCronEnabled()` GrowthBook 控制 (`useScheduledTasks.ts:61`, `useScheduledTasks.ts:119`)
-`EXTRACT_MEMORIES` — 受 `tengu_passport_quail` + AutoMem + 非 remote 限制 (`extractMemories.ts:536`, `:545`, `:550`)
-`KAIROS_BRIEF` — 受 `tengu_kairos_brief` + opt-in/kairosActive 限制 (`BriefTool.ts:95`, `:126`, `:132`)
### Medium 级发现
3. **`BG_SESSIONS``BASH_CLASSIFIER` 不适合简单归为"全 stub"**
- `BG_SESSIONS` — 会话注册/清理是真实现 (`concurrentSessions.ts:44`, `:55`),但任务摘要核心是 stub (`taskSummary.ts:2`)
- `BASH_CLASSIFIER` — 权限编排很大一块是真实现 (`bashPermissions.ts` 2621行),但分类后端 `bashClassifier.ts:24` 永远返回 disabled
4. **审计口径问题**
- 把"代码量/周边 UI 很多"误当成"可独立启用"
- `PROACTIVE``index.ts:3` 只有 state stub`commands.ts:64``REPL.tsx:415` 引用缺失文件
- `REACTIVE_COMPACT``reactiveCompact.ts:13` 整块是 stub
- `CACHED_MICROCOMPACT``cachedMicrocompact.ts:22` 全部 stub
---
## Codex 修正后的分类
### 第一类:真正 compile-only3 个)
| Flag | 说明 | Crash 风险 |
|------|------|-----------|
| **SHOT_STATS** | 纯本地 shot 分布统计ant-only 数据路径 | 低 |
| **PROMPT_CACHE_BREAK_DETECTION** | 本地 cache key 变化检测,写 diff 有兜底 | 低 |
| **TOKEN_BUDGET** | 本地 token 预算追踪,纯计算逻辑 | 低 |
### 第二类compile + 运行时条件7 个)
| Flag | 条件 | Crash 风险 |
|------|------|-----------|
| **TEAMMEM** | AutoMem + GrowthBook `tengu_herring_clock` + GitHub repo | 低 (clean no-op) |
| **AGENT_TRIGGERS** | GrowthBook `isKairosCronEnabled()` | 低 (clean no-op) |
| **EXTRACT_MEMORIES** | `tengu_passport_quail` + AutoMem + 非 remote | 低 (clean no-op) |
| **KAIROS_BRIEF** | `tengu_kairos_brief` + opt-in/kairosActive可用 `CLAUDE_CODE_BRIEF=1` 绕过 | 低 |
| **COORDINATOR_MODE** | 需 `CLAUDE_CODE_COORDINATOR_MODE=1``workerAgent.ts` 是 stub 但不阻塞 | 低 |
| **COMMIT_ATTRIBUTION** | 仅对 `isInternal=true` 的 repo 生效 | 低 |
| **VERIFICATION_AGENT** | 受 GrowthBook `tengu_hive_evidence` 双重门控 | 低 |
### 第三类:混合型 — 部分实现 + stub 核心5 个)
| Flag | 真实现部分 | Stub 核心 |
|------|-----------|----------|
| **BG_SESSIONS** | 会话注册/清理 (`concurrentSessions.ts`) | `bg.ts`/`taskSummary.ts`/`udsClient.ts` 全 stub + 依赖 tmux |
| **BASH_CLASSIFIER** | 权限编排 (`bashPermissions.ts` 2621行) | `bashClassifier.ts` 分类后端 stub + 需 API beta |
| **PROACTIVE** | REPL/命令注册框架 | `index.ts` stub + 3 文件缺失 |
| **REACTIVE_COMPACT** | 调用点已在主查询环路 | `reactiveCompact.ts` 22行全 no-op |
| **CACHED_MICROCOMPACT** | 调用点已布线 | `cachedMicrocompact.ts` 全 stub + 需未公开 API |
### 第四类:纯 stub1 个)
| Flag | 问题 |
|------|------|
| **CONTEXT_COLLAPSE** | 3 核心文件全 stub + CtxInspectTool 目录不存在 |
### 第五类依赖远程服务3 个)
| Flag | 依赖 |
|------|------|
| **ULTRAPLAN** | CCR 远程 agent 基础设施 + OAuth |
| **CCR_REMOTE_SETUP** | claude.ai OAuth + GitHub CLI + CCR 后端 |
| **BRIDGE_MODE** (build端) | claude.ai 订阅 + GrowthBook + WebSocket 后端 |
---
## 第三类恢复优先级建议
Codex 推荐的恢复顺序:
1. **REACTIVE_COMPACT** — 收益最直接,调用点在主查询环路,改完最容易立刻见效
2. **BG_SESSIONS** — 已有会话注册基础,补齐摘要和后台运行链路的 ROI 高
3. **PROACTIVE** — 产品面大,但缺文件比 stub 更严重,范围比前两项大
4. **CONTEXT_COLLAPSE** — collapse engine 全 stub恢复成本和设计不确定性都高
5. **BASH_CLASSIFIER** — 若无 API beta 能力不值得优先;若有则升到第 2
6. **CACHED_MICROCOMPACT** — 受未公开 API 约束,最后做
---
## 审计报告分类标准修正建议
Codex 建议将原来的单轴分类COMPLETE/PARTIAL/STUB改为**三轴**
| 轴 | 取值 | 说明 |
|----|------|------|
| **实现完整度** | `full` / `mixed` / `stub` | 活跃调用链上的核心模块是否有真实现 |
| **激活条件** | `compile-only` / `compile+env` / `compile+GrowthBook` / `compile+remote` / `compile+private API` | 启用需要什么 |
| **运行风险** | `safe no-op` / `background IO` / `startup critical` | 启用后条件不满足时的行为 |
**COMPLETE 的最低标准应满足:**
1. 活跃调用链上的核心模块不能是 stub
2. "可启用"不能只看编译 flag还要单列运行时 gate
按此标准,`CONTEXT_COLLAPSE``BG_SESSIONS``BASH_CLASSIFIER``PROACTIVE``REACTIVE_COMPACT``CACHED_MICROCOMPACT` 都应从 COMPLETE 降级。
---
## 已采取的行动
基于审查结果,已将以下 3 个确认安全的 flag 加入默认构建:
**build.ts:**
```typescript
const DEFAULT_BUILD_FEATURES = [
"AGENT_TRIGGERS_REMOTE", "CHICAGO_MCP", "VOICE_MODE",
"SHOT_STATS", "PROMPT_CACHE_BREAK_DETECTION", "TOKEN_BUDGET"
];
```
**scripts/dev.ts:**
```typescript
const DEFAULT_FEATURES = [
"BUDDY", "TRANSCRIPT_CLASSIFIER", "BRIDGE_MODE",
"AGENT_TRIGGERS_REMOTE", "CHICAGO_MCP", "VOICE_MODE",
"SHOT_STATS", "PROMPT_CACHE_BREAK_DETECTION", "TOKEN_BUDGET"
];
```
### 验证结果
| 项目 | 结果 |
|------|------|
| `bun run build` | ✅ 成功 (475 files) |
| `bun test` | ✅ 无新增失败 (23 fail 为已有问题) |
| SHOT_STATS 代码路径 | ✅ 完整 — stats 面板显示 shot 分布 |
| TOKEN_BUDGET 代码路径 | ✅ 完整 — 支持 `+500k` 语法,带进度条 |
| PROMPT_CACHE_BREAK_DETECTION 代码路径 | ✅ 完整 — 内部诊断debug 模式可见 |

View File

@@ -37,7 +37,7 @@ Agent({ subagent_type: "general-purpose", prompt: "..." })
### 3.1 门控与互斥
文件:`src/tools/AgentTool/forkSubagent.ts:32-39`
文件:`packages/builtin-tools/src/tools/AgentTool/forkSubagent.ts:32-39`
```ts
export function isForkSubagentEnabled(): boolean {
@@ -105,7 +105,7 @@ isForkSubagentEnabled() && !subagent_type?
### 3.4 消息构建buildForkedMessages
文件:`src/tools/AgentTool/forkSubagent.ts:107-169`
文件:`packages/builtin-tools/src/tools/AgentTool/forkSubagent.ts:107-169`
构建的消息结构:
@@ -185,11 +185,11 @@ FEATURE_FORK_SUBAGENT=1 bun run dev
| 文件 | 行数 | 职责 |
|------|------|------|
| `src/tools/AgentTool/forkSubagent.ts` | ~210 | 核心定义 + 消息构建 + 递归防护 |
| `src/tools/AgentTool/AgentTool.tsx` | — | Fork 路由 + 强制异步 |
| `src/tools/AgentTool/prompt.ts` | — | "When to Fork" 提示词段落 |
| `src/tools/AgentTool/runAgent.ts` | — | useExactTools 路径 |
| `src/tools/AgentTool/resumeAgent.ts` | — | Fork agent 恢复 |
| `packages/builtin-tools/src/tools/AgentTool/forkSubagent.ts` | ~210 | 核心定义 + 消息构建 + 递归防护 |
| `packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` | — | Fork 路由 + 强制异步 |
| `packages/builtin-tools/src/tools/AgentTool/prompt.ts` | — | "When to Fork" 提示词段落 |
| `packages/builtin-tools/src/tools/AgentTool/runAgent.ts` | — | useExactTools 路径 |
| `packages/builtin-tools/src/tools/AgentTool/resumeAgent.ts` | — | Fork agent 恢复 |
| `src/constants/xml.ts` | — | XML 标签常量 |
| `src/utils/forkedAgent.ts` | — | CacheSafeParams + ContentReplacementState 克隆 |
| `src/commands/fork/index.ts` | — | /fork 命令stub |

View File

@@ -1,7 +1,7 @@
# KAIROS — 常驻助手模式
> Feature Flag: `FEATURE_KAIROS=1`(及子 Feature
> 实现状态:核心框架完整,部分子模块为 stub
> 实现状态:核心框架完整,部分子模块为 stubproactive/sleep 节奏控制已可用
> 引用数154全库最大
## 一、功能概述
@@ -34,13 +34,13 @@ KAIROS 在系统提示中注入两大段落:
### 2.1 Brief 段落 (`getBriefSection`)
文件:`src/constants/prompts.ts:843-858`
文件:`src/constants/prompts.ts:847-858`
`feature('KAIROS') || feature('KAIROS_BRIEF')` 时注入。Brief 工具(`SendUserMessage`)的结构化消息输出指令。`/brief` toggle 和 `--brief` flag 只控制显示过滤,不影响模型行为。
### 2.2 Proactive/Autonomous Work 段落 (`getProactiveSection`)
文件:`src/constants/prompts.ts:860-914`
文件:`src/constants/prompts.ts:864-918`
`feature('PROACTIVE') || feature('KAIROS')``isProactiveActive()` 时注入。核心行为指令:
@@ -74,8 +74,9 @@ KAIROS 在系统提示中注入两大段落:
SleepTool 是 KAIROS/Proactive 的节奏控制核心。工具描述让模型理解"休眠"概念:
- 工具名:`Sleep`
- 功能:等待指定时间后响应 tick prompt
- 功能:等待指定时间后响应 tick prompt;若队列出现新工作或 proactive 被关闭,会提前唤醒
-`<tick_tag>` 配合实现心跳式自主工作
- 远程控制 surfaces 可通过 `automation_state` 看到 `standby` / `sleeping` 两种状态
### 3.3 Bridge 集成
@@ -172,8 +173,10 @@ FEATURE_KAIROS=1 FEATURE_TOKEN_BUDGET=1 bun run dev
| `src/assistant/AssistantSessionChooser.ts` | — | Session 选择 UIstub |
| `src/tools/BriefTool/` | — | BriefTool 实现stub |
| `src/tools/SleepTool/prompt.ts` | ~30 | SleepTool 工具提示 |
| `src/tools/SleepTool/SleepTool.ts` | ~200 | 休眠/唤醒与 automation metadata |
| `src/services/mcp/channelNotification.ts` | 5 | 频道消息接入stub |
| `src/memdir/memdir.ts` | — | 记忆目录管理stub |
| `src/constants/prompts.ts:552-554,843-914` | 72 | 系统提示注入 |
| `src/constants/prompts.ts:557,847-918` | 72 | 系统提示注入 |
| `src/components/tasks/src/tasks/DreamTask/` | 3 | Dream 任务stub |
| `src/proactive/index.ts` | — | Proactive 核心(stubKAIROS 共享) |
| `src/proactive/index.ts` | — | Proactive 核心KAIROS 共享) |
| `src/utils/sessionState.ts` | — | 向 bridge/CCR 暴露 automation 状态 |

View File

@@ -0,0 +1,321 @@
# LAN Pipes — 技术实现文档
面向开发者的实现细节。用户指南见 [lan-pipes.md](./lan-pipes.md)。
---
## 架构
```
Machine A (192.168.50.22) Machine B (192.168.50.27)
┌───────────────────────────┐ ┌───────────────────────────┐
│ PipeServer │ │ PipeServer │
│ UDS: ~/.claude/pipes/ │ │ UDS: ~/.claude/pipes/ │
│ cli-abc.sock │ │ cli-def.sock │
│ TCP: 0.0.0.0:<random> │◄──TCP───►│ TCP: 0.0.0.0:<random> │
├───────────────────────────┤ ├───────────────────────────┤
│ LanBeacon │ │ LanBeacon │
│ UDP 224.0.71.67:7101 │◄──UDP───►│ UDP 224.0.71.67:7101 │
├───────────────────────────┤ ├───────────────────────────┤
│ usePipeIpc (hook) │ │ usePipeIpc (hook) │
│ initPipeServer │ │ initPipeServer │
│ registerMessageHandlers │ │ registerMessageHandlers │
│ runMainHeartbeat │ │ runSubHeartbeat │
│ cleanupPipeIpc │ │ cleanupPipeIpc │
└───────────────────────────┘ └───────────────────────────┘
```
## Feature Flag
`LAN_PIPES` — 在 `scripts/dev.ts``build.ts``DEFAULT_FEATURES` 中启用。
所有 LAN 代码路径通过 `feature('LAN_PIPES')` 编译时门控。`feature()` 只能在 `if` 或三元中使用Bun 编译时常量约束)。
---
## 核心文件
| 文件 | 说明 |
|------|------|
| `src/utils/pipeTransport.ts` | PipeServer/PipeClientUDS + TCP 双模式) |
| `src/utils/lanBeacon.ts` | UDP multicast beacon + module singleton |
| `src/utils/ndjsonFramer.ts` | 共享 NDJSON socket 帧解析 |
| `src/utils/pipeRegistry.ts` | 文件注册表 + `mergeWithLanPeers()` |
| `src/utils/peerAddress.ts` | 地址解析uds/bridge/tcp scheme |
| `src/utils/pipePermissionRelay.ts` | 权限转发 + `setPipeRelay`/`getPipeRelay` singleton |
| `src/hooks/usePipeIpc.ts` | 生命周期 hook从 REPL.tsx 提取) |
| `src/hooks/usePipeRelay.ts` | 消息回传 hook |
| `src/hooks/usePipePermissionForward.ts` | 权限转发 hook |
| `src/hooks/usePipeRouter.ts` | 输入路由 hook |
| `src/hooks/useMasterMonitor.ts` | slave 注册表 + 消息订阅 |
---
## PipeServer TCP 扩展
`src/utils/pipeTransport.ts`
### 类型
```typescript
export type PipeTransportMode = 'uds' | 'tcp'
export type TcpEndpoint = { host: string; port: number }
export type PipeServerOptions = { enableTcp?: boolean; tcpPort?: number }
```
### PipeServer 变更
- `setupSocket(socket)` — 从 start() 提取的共享方法UDS 和 TCP 共用
- `start(options?)` — 可选启用 TCPport=0 让 OS 分配
- 内部维护两个 `net.Server`,共享同一组 `clients: Set<Socket>``handlers`
- `tcpAddress` getter 暴露 TCP 端口
- `close()` 同时关闭两个 server
socket 帧解析使用 `attachNdjsonFramer()` from `ndjsonFramer.ts`(替代原先 3 份重复代码)。
### PipeClient 变更
- 构造函数新增可选 `TcpEndpoint` 参数
- `connect()` 根据 tcpEndpoint 分派到 `connectTcp()``connectUds()`
- TCP 不需要文件存在轮询,直接建连
---
## LAN Beacon
`src/utils/lanBeacon.ts`
### 协议参数
| 参数 | 值 |
|------|-----|
| Multicast 组 | `224.0.71.67` |
| 端口 | `7101` |
| 广播间隔 | `3000ms` |
| Peer 超时 | `15000ms` |
| TTL | `1` |
### Announce 包
```typescript
type LanAnnounce = {
proto: 'claude-pipe-v1'
pipeName: string
machineId: string
hostname: string
ip: string
tcpPort: number
role: 'main' | 'sub'
ts: number
}
```
### API
```typescript
class LanBeacon extends EventEmitter {
constructor(announce: Omit<LanAnnounce, 'proto' | 'ts'>)
start(): void
stop(): void
getPeers(): Map<string, LanAnnounce> // 防御性拷贝
updateAnnounce(partial): void // 使用 spread不可变更新
on('peer-discovered', (peer: LanAnnounce) => void)
on('peer-lost', (pipeName: string) => void)
}
```
### 存储
module-level singleton`getLanBeacon()` / `setLanBeacon()`。不挂在 Zustand state 上(避免 `setState` 展开时丢失引用)。
### 网卡绑定
`addMembership(group, localIp)` + `setMulticastInterface(localIp)` 指定 LAN 网卡。解决 Windows 上 WSL/Docker 虚拟网卡劫持 multicast 的问题。
---
## Hook 架构
从 REPL.tsx 提取的 ~830 行 Pipe IPC 代码:
### usePipeIpc生命周期
`src/hooks/usePipeIpc.ts`623 行)
在 REPL.tsx 顶层通过 feature-gated require 加载:
```typescript
const usePipeIpc = feature('UDS_INBOX')
? require('../hooks/usePipeIpc.js').usePipeIpc
: () => undefined;
// 组件内
usePipeIpc({ store, handleIncomingPrompt });
```
内部使用 **lazy getter** 函数加载依赖(避免循环依赖导致 Bun 运行时崩溃):
```typescript
const pt = () => require('../utils/pipeTransport.js')
const pr = () => require('../utils/pipeRegistry.js')
const mm = () => require('./useMasterMonitor.js')
// ...
```
`import type` 用于静态类型(不会触发模块加载)。
### 四个阶段函数
| 函数 | 职责 |
|------|------|
| `initPipeServer` | 角色判定 + server 创建 + beacon 启动 |
| `registerMessageHandlers` | ping、attach、prompt、permission、detach 五个 handler |
| `runMainHeartbeat` | cleanup + 发现 + auto-attach + 清理死连接 |
| `runSubHeartbeat` | 检测 main 是否存活,死亡则接管或独立 |
### usePipeRelay消息回传
`src/hooks/usePipeRelay.ts`38 行)
提供 `relayPipeMessage()``pipeReturnHadErrorRef`。relay 函数通过 `getPipeRelay()` module singleton 读取(替代 `globalThis.__pipeSendToMaster`)。
### usePipePermissionForward权限转发
`src/hooks/usePipePermissionForward.ts`159 行)
订阅 `subscribePipeEntries()`,处理:
- `permission_request` → 解析 payload → 查找 tool → 加入确认队列
- `permission_cancel` → 从队列移除
- `stream/error/done` → 转为系统消息显示(含 role + IP 标签)
### usePipeRouter输入路由
`src/hooks/usePipeRouter.ts`130 行)
提供 `routeToSelectedPipes(input): boolean`。读取 `selectedPipes` + `routeMode`,逐个发送到已连接目标。通知显示 `[role] hostname/ip`LAN peer`[role]`(本机)。
---
## Registry 并行探测
`src/utils/pipeRegistry.ts`
### getAliveSubs()
```typescript
export async function getAliveSubs(): Promise<PipeRegistrySub[]> {
const registry = await readRegistry()
const results = await Promise.all(
registry.subs.map(sub =>
isPipeAlive(sub.pipeName, 1000).then(alive => alive ? sub : null)
)
)
return results.filter(Boolean)
}
```
### cleanupStaleEntries()
两阶段:
1. **无锁并行探测**`Promise.all` 探测 main + 所有 subs
2. **短暂持锁写入**`acquireLock()` → 重新读取 → 应用变更 → 写入 → `releaseLock()`
持锁时间从 N 秒降至 ~10ms。
### getMachineId()
Windows/macOS 使用 `execFile`(异步),不阻塞主线程。结果缓存,仅首次调用执行。
---
## NDJSON 协议
### 消息类型
| 类型 | 方向 | 数据 |
|------|------|------|
| `ping` / `pong` | 双向 | 无 |
| `attach_request` | M→S | `meta: { machineId }` |
| `attach_accept` / `attach_reject` | S→M | `data: reason` |
| `detach` | M→S | 无 |
| `prompt` | M→S | `data: prompt_text` |
| `prompt_ack` | S→M | `data: 'accepted'` |
| `stream` | S→M | `data: partial_text` |
| `done` | S→M | 无 |
| `error` | 双向 | `data: error_message` |
| `permission_request` | S→M | `data: JSON(PipePermissionRequestPayload)` |
| `permission_response` | M→S | `data: JSON(PipePermissionResponsePayload)` |
| `permission_cancel` | M→S | `data: JSON({ requestId, reason })` |
### 帧格式
每行一个 JSON 对象,`\n` 分隔:
```
{"type":"ping","from":"cli-abc","ts":"2026-04-11T00:00:00.000Z"}\n
{"type":"prompt","data":"检查 git status","from":"cli-abc"}\n
```
---
## 跨机器 Attach 流程
```
CLI-B (192.168.50.27) 心跳循环
→ beacon.getPeers() 发现 CLI-A (192.168.50.22)
→ connectToPipe(pName, myName, 3000, { host: '192.168.50.22', port: 58853 })
→ PipeClient.connectTcp() → net.createConnection({ host, port })
→ client.send({ type: 'attach_request', meta: { machineId } })
→ CLI-A 收到:
isLanPeer = (msg.meta.machineId !== myMachineId) → true
→ 不检查 role直接 reply({ type: 'attach_accept' })
→ setPipeRelay(socket.write)
→ CLI-B 收到 attach_accept
→ addSlaveClient(pName, client)
→ store.setState: role='master', slaves[pName] = { status: 'idle' }
```
关键:跨机器 attach 不要求对方是 sub 角色。通过 `machineId` 区分 LAN peer。
---
## SendMessageTool TCP 支持
`packages/builtin-tools/src/tools/SendMessageTool/SendMessageTool.ts`
- `to` 字段支持 `tcp:host:port` 格式
- `checkPermissions``tcp:` scheme 返回 `behavior: 'ask'``classifierApprovable: false`
- `call()`:创建临时 `PipeClient` → connect → send → disconnect
---
## 测试
| 文件 | 测试数 | 覆盖 |
|------|--------|------|
| `lanBeacon.test.ts` | 7 | socket 初始化、announce、peer 发现/过滤/清理 |
| `peerAddress.test.ts` | 8 | scheme 解析、parseTcpTarget、端口范围验证 |
| `pipePermissionRelay.test.ts` | 2 | setPipeRelay singleton、权限请求/响应 |
| `pipeTransport.test.ts` | 2 | UDS 基础行为 |
| `useMasterMonitor.test.ts` | 5 | slave 注册/移除、事件发射 |
全量2190 pass / 0 fail
---
## 已知限制
1. **TCP 无认证** — 同 LAN 内知道端口号即可连接
2. **Beacon 明文广播** — IP/hostname/machineId 未 hash
3. **单网卡选择**`getLocalIp()` 返回首个非内部 IPv4可能选到 VPN
4. **端口随机** — 每次启动不同端口,依赖 beacon 发现
5. **SendMessageTool 每次创建新连接** — 未复用已有 slave client
## 后续改进方向
1. HMAC-SHA256 TCP 握手认证
2. machineId hash 后再广播
3. 多网卡选择(优先 RFC 1918 地址)
4. 固定端口范围配置
5. TLS 加密传输
6. SendMessageTool 复用已连接的 slave client

193
docs/features/lan-pipes.md Normal file
View File

@@ -0,0 +1,193 @@
# LAN Pipes — 局域网多机器群控指南
## 什么是 LAN Pipes
LAN Pipes 让多台机器上的 Claude Code 实例通过局域网自动发现并协作。你可以在一台机器main上操控其他机器sub上的 Claude Code发送 prompt、查看执行结果、审批权限请求——全程零配置。
基于本机 Pipe IPC`UDS_INBOX`)扩展,新增 TCP 传输层 + UDP Multicast 发现。
## 前置条件
- 两台或以上机器在同一局域网
- 每台机器安装了 CCB 并能 `bun run dev`
- Feature flag `LAN_PIPES`dev/build 默认开启)
- 防火墙允许 UDP 7101 + TCP 动态端口(见下方配置)
## 快速开始
### 第一步:配置防火墙
**每台机器都需要执行。**
**Windows**(管理员 PowerShell
```powershell
New-NetFirewallRule -DisplayName "CCB LAN Beacon (UDP)" -Direction Inbound -Protocol UDP -LocalPort 7101 -Action Allow -Profile Private
New-NetFirewallRule -DisplayName "CCB LAN Pipes (TCP)" -Direction Inbound -Protocol TCP -LocalPort 1024-65535 -Program (Get-Command bun).Source -Action Allow -Profile Private
New-NetFirewallRule -DisplayName "CCB LAN Beacon Out (UDP)" -Direction Outbound -Protocol UDP -RemotePort 7101 -Action Allow -Profile Private
```
验证网络为"专用"(非公共):`Get-NetConnectionProfile`
**macOS**
首次运行时系统弹出"允许接受传入连接"对话框,点击"允许"。
如果使用 pf 防火墙:
```bash
echo "pass in proto udp from any to any port 7101" | sudo pfctl -ef -
```
**Linux**firewalld
```bash
sudo firewall-cmd --zone=trusted --add-port=7101/udp --permanent
sudo firewall-cmd --zone=trusted --add-port=1024-65535/tcp --permanent
sudo firewall-cmd --reload
```
**Linux**iptables
```bash
sudo iptables -A INPUT -p udp --dport 7101 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 1024:65535 -m owner --uid-owner $(id -u) -j ACCEPT
```
### 第二步:启动
```bash
# 机器 A例如 192.168.50.22
bun run dev
# 机器 B例如 192.168.50.27
bun run dev
```
启动后等待 3-5 秒beacon 广播间隔),两边自动发现并连接。
### 第三步:查看和操作
在任一台机器上:
```
/pipes
```
输出示例:
```
pipe: cli-a91bad56 (main) 192.168.50.22 2/3 selected
Main machine: 205d6c3a... (this machine)
[main] cli-a91bad56 XC/192.168.50.22 [alive] (you)
☑ [sub-1] cli-da029538 XC/192.168.50.22 [alive] [connected]
LAN Peers:
☐ [main] cli-04d67950 vmwin11/192.168.50.27 tcp:192.168.50.27:58853 [LAN]
```
### 第四步:选中目标并发送任务
1.`Shift+↓` 展开选择面板
2. `↑↓` 移动到 LAN peer
3. `Space` 选中
4. `Enter` 确认
5. 输入 prompt自动路由到远端执行
远端执行结果会流式回传到你的消息列表:
```
[main vmwin11/192.168.50.27 / cli-04d67950] 正在检查 git status...
[main vmwin11/192.168.50.27 / cli-04d67950] Completed
```
## 完整命令参考
| 命令 | 说明 |
|------|------|
| `/pipes` | 显示所有实例(本机 + LANShift+↓ 展开选择面板 |
| `/pipes select <name>` | 选中某实例 |
| `/pipes all` | 全选 |
| `/pipes none` | 取消全选 |
| `/attach <name>` | 手动 attach自动识别 LAN peer 并通过 TCP 连接) |
| `/detach <name>` | 断开连接 |
| `/send <name> <msg>` | 向指定 pipe 发送消息 |
| `/send tcp:host:port <msg>` | 直接通过 TCP 地址发送 |
| `/claim-main` | 强制声明为 main |
| `/pipe-status` | 显示详细状态 |
| `/peers` | 列出所有已发现的 peer |
## 快捷键
| 快捷键 | 场景 | 作用 |
|--------|------|------|
| `Shift+↓` | 状态栏可见时 | 展开/收起选择面板 |
| `↑ / ↓` | 面板展开时 | 移动光标 |
| `Space` | 面板展开时 | 选中/取消 |
| `Enter` | 面板展开时 | 确认关闭 |
| `Esc` | 面板展开时 | 取消关闭 |
| `← / →` | 有选中 pipe 时 | 切换路由模式 |
| `M` | 面板展开时 | 同 ←/→ 切换路由模式 |
## 路由模式
| 模式 | 显示 | 行为 |
|------|------|------|
| `selected pipes only` | 绿色 | prompt 仅发送到选中的 pipe本地不执行 |
| `local main` | 灰色 | prompt 仅在本地执行,不转发 |
切换路由模式不会清空选择。
## 权限转发
当远端 slave 执行需要权限的工具(如 BashTool
1. slave 发送 `permission_request` 到 main
2. main 弹出权限确认对话框,显示 `[role hostname/ip / pipeName]`
3. 用户确认/拒绝
4. 结果发回 slave继续或中断
## 工作原理
### 发现机制
- 每台机器启动时创建 UDP multicast beacon
- 组地址 `224.0.71.67`,端口 `7101`TTL=1不跨路由器
- 每 3 秒广播一次自身信息pipeName、IP、TCP 端口、角色)
- 15 秒未收到广播则标记 peer 丢失
### 通信机制
- 本机实例UDSUnix Domain Socket / Named Pipe
- 跨机器TCP动态端口通过 beacon 发现)
- 协议NDJSON每行一个 JSON 对象)
- 消息类型ping/pong、attach/detach、prompt/stream/done/error、permission
### 角色模型
| 角色 | 说明 |
|------|------|
| `main` | 首个启动的实例 |
| `sub` | 同机后续启动的实例 |
| `master` | attach 了至少一个 slave 的实例 |
| `slave` | 被 master attach 的实例 |
跨机器 attach 时,两边都可以是 main——不要求对方必须是 sub。
## 常见问题
### 看不到 LAN peer
1. 检查防火墙是否放行 UDP 7101
2. `Get-NetConnectionProfile`Windows确认网络为"专用"
3. 确认两台机器在同一子网(`ping` 能通)
4. 路由器未开启 AP 隔离
### 连接超时
1. 检查 TCP 入站防火墙规则
2. 确认没有 VPN 劫持流量
3. 尝试 `/send tcp:ip:port hello` 直接测试
### beacon 绑到了错误网卡
Windows 上 WSL/Docker 虚拟网卡可能劫持 multicast。beacon 会自动选择非内部 IPv4 接口。如果选错,检查 `getLocalIp()` 返回值。
## 安全说明
- TCP 连接当前**无认证**——同 LAN 内知道端口号即可连接
- Multicast TTL=1不跨路由器
- AI 通过 `SendMessageTool` 发送 `tcp:` 消息时需**用户显式确认**
- 建议仅在信任的局域网中使用

View File

@@ -0,0 +1,205 @@
# Langfuse 监控集成
> 实现状态:已完成,通过环境变量启用
> 依赖:`@langfuse/otel`、`@langfuse/tracing`、`@opentelemetry/sdk-trace-base`
## 一、功能概述
Langfuse 是一个开源的 LLM 可观测性平台,用于追踪、监控和调试 AI 应用的请求链路。CCB 通过 OpenTelemetry (OTel) 桥接层将 Langfuse 集成到查询流程中,实现:
- **LLM 调用追踪** — 记录每次 API 请求的模型、Provider、输入/输出、Token 用量
- **工具执行追踪** — 记录每个工具调用的名称、输入、输出、耗时和错误
- **多 Agent 追踪** — 主 Agent 和子 Agent 各自独立的 Trace 链路
- **数据脱敏** — 自动遮蔽敏感信息API Key、文件内容、Shell 输出等)
## 二、启用方式
Langfuse 是开源项目,你可以 **自部署**Docker / Kubernetes也可以使用官方提供的 **[Langfuse Cloud](https://cloud.langfuse.com)** 免费测试。注册后在 Project Settings → API Keys 页面获取密钥。
核心只需要三个环境变量:
| 环境变量 | 说明 |
|---------|------|
| `LANGFUSE_PUBLIC_KEY` | Langfuse 公钥(必填) |
| `LANGFUSE_SECRET_KEY` | Langfuse 密钥(必填) |
| `LANGFUSE_BASE_URL` | 服务地址,默认 `https://cloud.langfuse.com`;自部署时改为你的地址(必填) |
未配置时所有追踪函数为 no-op零开销。
### 通过 settings.json 配置(推荐)
`.claude/settings.json``env` 字段中添加,这样每次启动自动生效:
```json
{
"env": {
"LANGFUSE_PUBLIC_KEY": "pk-xxx",
"LANGFUSE_SECRET_KEY": "sk-xxx",
"LANGFUSE_BASE_URL": "https://cloud.langfuse.com"
}
}
```
### 其他可选参数
| 环境变量 | 默认值 | 说明 |
|---------|--------|------|
| `LANGFUSE_TRACING_ENVIRONMENT` | `development` | 环境标签,用于 Langfuse 面板筛选 |
| `LANGFUSE_FLUSH_AT` | `20` | 批量发送的 span 数量阈值 |
| `LANGFUSE_FLUSH_INTERVAL` | `10` | 定时刷新间隔(秒) |
| `LANGFUSE_EXPORT_MODE` | `batched` | 导出模式:`batched`(批量)或 `immediate`(即时) |
| `LANGFUSE_TIMEOUT` | `5` | 请求超时(秒) |
## 四、架构
### 4.1 模块结构
```
src/services/langfuse/
├── index.ts # 统一导出
├── client.ts # OTel Provider + LangfuseSpanProcessor 初始化
├── tracing.ts # Trace/Span 创建、LLM 和工具观察记录
├── convert.ts # 内部 Message 类型 → Langfuse OpenAI 兼容格式转换
└── sanitize.ts # 数据脱敏(敏感字段、文件路径、工具输出)
```
### 4.2 追踪层级
```
Trace (Agent Span) ← createTrace() / createSubagentTrace()
├── Generation (LLM 调用) ← recordLLMObservation()
├── Tool Observation (工具调用) ← recordToolObservation()
├── Tool Observation (工具调用) ← recordToolObservation()
└── ...
```
### 4.3 数据流
```
query.ts ──→ createTrace() # 每个 query turn 创建根 trace
├── claude.ts ──→ recordLLMObservation() # API 调用完成后记录 LLM 观察
├── toolExecution.ts ──→ recordToolObservation() # 每个工具执行记录
└── query.ts ──→ endTrace() # turn 结束时关闭 trace
runAgent.ts ──→ createSubagentTrace() # 子 Agent 有独立 trace
```
## 五、追踪详情
### 5.1 主 Agent Trace
每次 `query()` 调用(即用户一次对话 turn创建一个类型为 `agent` 的根 Span
- **名称**: `agent-run``agent-run:<querySource>`
- **元数据**: `provider``model``agentType: "main"`
- **Session ID**: 关联到 Langfuse 的 Session 功能,支持按会话聚合
### 5.2 子 Agent Trace
通过 `AgentTool` 启动的子 Agent 创建独立 Trace
- **名称**: `agent:<agentType>`
- **元数据**: `provider``model``agentType``agentId`
- 独立于主 Trace有自己的 Session 关联
### 5.3 LLM Generation
每次 API 调用记录为一个 `generation` 类型的 Span
- **名称**: 按 Provider 映射(如 `ChatAnthropic``ChatOpenAI``ChatBedrockAnthropic` 等)
- **记录内容**: 输入消息、输出消息、Token 用量input/output
- **时间**: 精确记录 `startTime``endTime``completionStartTime`TTFT 指标)
Provider 名称映射:
| Provider | Generation 名称 |
|----------|-----------------|
| `firstParty` | `ChatAnthropic` |
| `bedrock` | `ChatBedrockAnthropic` |
| `vertex` | `ChatVertexAnthropic` |
| `foundry` | `ChatFoundry` |
| `openai` | `ChatOpenAI` |
| `gemini` | `ChatGoogleGenerativeAI` |
| `grok` | `ChatXAI` |
### 5.4 工具执行
每个工具调用记录为一个 `tool` 类型的 Span
- **名称**: 工具名(如 `FileEditTool``BashTool`
- **记录内容**: 输入(经脱敏)、输出(经脱敏)、`toolUseId`
- **错误标记**: `isError` 标志 + `level: ERROR`
## 六、数据脱敏
所有上传到 Langfuse 的数据都会经过脱敏处理(`sanitize.ts`),确保敏感信息不会泄露:
### 6.1 全局脱敏(`sanitizeGlobal`
- **Home 路径替换** — `/Users/xxx``~`
- **敏感字段遮蔽** — 匹配 `api_key``token``secret``password``credential``auth_header` 等关键字的字段值替换为 `[REDACTED]`
### 6.2 工具输入脱敏(`sanitizeToolInput`
- 敏感字段遮蔽(同全局)
- `file_path``path``directory` 路径中的 Home 目录替换
### 6.3 工具输出脱敏(`sanitizeToolOutput`
| 工具 | 脱敏策略 |
|------|---------|
| `FileReadTool``FileWriteTool``FileEditTool` | 完全遮蔽,仅保留字符数:`[file content redacted, N chars]` |
| `BashTool``PowerShellTool` | 截断至 500 字符 |
| `ConfigTool``MCPTool` | 完全遮蔽 |
| 其他工具 | 原样保留 |
## 七、消息格式转换
`convert.ts` 将 CCB 内部的 Message 类型转换为 Langfuse 期望的 OpenAI 兼容格式:
- **输入**: `UserMessage | AssistantMessage[]` + 可选 system prompt → `{ role, content }[]`
- **输出**: `AssistantMessage[]``{ role: 'assistant', content }`
- **Content Block 映射**:
- `text``{ type: 'text', text }`
- `thinking` / `redacted_thinking``{ type: 'thinking', thinking }`
- `tool_use``{ type: 'tool_use', id, name, input }`
- `tool_result``{ type: 'tool_result', tool_use_id, content }`
- `image` / `document` → 占位标记 `[image]` / `[document: name]`
## 八、生命周期
1. **初始化**`initLangfuse()``src/entrypoints/init.ts` 启动时调用,创建 `LangfuseSpanProcessor``BasicTracerProvider`
2. **运行时** — 各追踪函数通过 `isLangfuseEnabled()` 检查,未配置时直接返回 `null`/跳过
3. **关闭**`shutdownLangfuse()` 在进程退出时调用,强制 flush 并关闭 Processor
## 九、自部署 Langfuse
Langfuse 是开源项目,支持 Docker / Kubernetes 自部署:
```bash
docker run -d \
--name langfuse \
-p 3000:3000 \
-e DATABASE_URL=postgresql://... \
langfuse/langfuse:latest
```
自部署后,将 `LANGFUSE_BASE_URL` 指向你的实例地址即可。详见 [Langfuse 自部署文档](https://langfuse.com/docs/deployment/self-host)。
如果没有自部署需求,可以直接使用 [Langfuse Cloud](https://cloud.langfuse.com),提供免费额度可用于测试。
## 十、相关文件
| 文件 | 说明 |
|------|------|
| `src/services/langfuse/client.ts` | OTel Provider 初始化、生命周期管理 |
| `src/services/langfuse/tracing.ts` | Trace/Span 创建和观察记录 |
| `src/services/langfuse/convert.ts` | Message 格式转换 |
| `src/services/langfuse/sanitize.ts` | 数据脱敏 |
| `src/services/langfuse/__tests__/langfuse.test.ts` | 测试568 行) |
| `src/query.ts` | 主查询流程中的 Trace 集成 |
| `src/services/tools/toolExecution.ts` | 工具执行中的观察记录 |
| `packages/builtin-tools/src/tools/AgentTool/runAgent.ts` | 子 Agent Trace 创建 |

View File

@@ -41,7 +41,7 @@ getMcpSkillCommands() 过滤 → SkillTool 调用
### 2.2 技能筛选
文件:`src/commands.ts:547-558`
文件:`src/commands.ts:604-616`
`getMcpSkillCommands(mcpCommands)` 过滤条件:
@@ -54,7 +54,7 @@ feature('MCP_SKILLS') // feature flag 必须开启
### 2.3 条件加载
文件:`src/services/mcp/client.ts:117-121`
文件:`src/services/mcp/client.ts:129-133`
`fetchMcpSkillsForClient` 通过 `require()` 条件加载feature flag 关闭时不加载任何模块:
@@ -79,8 +79,8 @@ const fetchMcpSkillsForClient = feature('MCP_SKILLS')
| 文件 | 行 | 说明 |
|------|------|------|
| `src/commands.ts` | 547-558, 561-608 | 命令过滤和 SkillTool 命令收集 |
| `src/services/mcp/client.ts` | 117-121, 1394, 1672, 2173-2181, 2346-2358 | 技能获取、缓存清除、连接时获取 |
| `src/commands.ts` | 604-616, 620-633 | 命令过滤和 SkillTool 命令收集 |
| `src/services/mcp/client.ts` | 129-133, 1394, 1672, 2176 | 技能获取、缓存清除、连接时获取 |
| `src/services/mcp/useManageMCPConnections.ts` | 22-26, 682-740 | 实时刷新prompts/resources 变化) |
## 三、关键设计决策

View File

@@ -0,0 +1,342 @@
# Pipes + LAN Pipes 完整功能指南
## 概述
Pipes 系统提供 Claude Code CLI 实例之间的通讯能力,分两层:
1. **Pipes本机**:同一台机器上的多个 CLI 实例通过 UDSUnix Domain Socket / Windows Named Pipe协作
2. **LAN Pipes局域网**:不同机器上的 CLI 实例通过 TCP + UDP Multicast 协作
两层使用同一套协议NDJSON和同一套命令`/pipes``/attach``/send` 等),对用户透明。
## Feature Flags
| Flag | 控制范围 | 默认 |
|------|----------|------|
| `UDS_INBOX` | 本机 Pipe IPC 全部功能 | dev/build 启用 |
| `LAN_PIPES` | 局域网 TCP + beacon 扩展 | dev/build 启用 |
手动启用:`FEATURE_UDS_INBOX=1 FEATURE_LAN_PIPES=1 bun run dev`
## 快速上手
### 本机多实例
```bash
# 终端 1
bun run dev
# 启动后自动注册为 main
# 终端 2
bun run dev
# 自动注册为 sub-1被 main 自动 attach
```
在终端 1 中输入 `/pipes`,可以看到两个实例。选中 sub-1 后,输入的消息会自动转发到 sub-1 执行。
### 局域网多机器
```bash
# 机器 A (192.168.50.22)
bun run dev
# 机器 B (192.168.50.27)
bun run dev
```
两边启动后等 3-5 秒beacon 广播间隔LAN peers 会自动发现并 attach。输入 `/pipes` 可看到标记 `[LAN]` 的远端实例。
### 防火墙配置(两台机器都需要)
**Windows**(管理员 PowerShell
```powershell
New-NetFirewallRule -DisplayName "Claude Code LAN Beacon (UDP)" -Direction Inbound -Protocol UDP -LocalPort 7101 -Action Allow -Profile Private
New-NetFirewallRule -DisplayName "Claude Code LAN Pipes (TCP)" -Direction Inbound -Protocol TCP -LocalPort 1024-65535 -Program (Get-Command bun).Source -Action Allow -Profile Private
New-NetFirewallRule -DisplayName "Claude Code LAN Beacon Out (UDP)" -Direction Outbound -Protocol UDP -RemotePort 7101 -Action Allow -Profile Private
# 确认网络为"专用"Get-NetConnectionProfile
```
**macOS**(首次运行时系统弹出对话框,点击"允许"即可):
```bash
# 如果需要手动放行 pf 防火墙:
echo "pass in proto udp from any to any port 7101" | sudo pfctl -ef -
```
**Linux**firewalld / iptables
```bash
# firewalld
sudo firewall-cmd --zone=trusted --add-port=7101/udp --permanent
sudo firewall-cmd --zone=trusted --add-port=1024-65535/tcp --permanent
sudo firewall-cmd --reload
# 或 iptables
sudo iptables -A INPUT -p udp --dport 7101 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 1024:65535 -m owner --uid-owner $(id -u) -j ACCEPT
```
确认:网络为局域网(非公共 WiFi路由器未开启 AP 隔离。
## 交互面板与快捷键
### 状态栏
执行 `/pipes` 后,输入框底部出现 pipe 状态栏(单行):
```
pipe: cli-a91bad56 (main) 192.168.50.22 2/3 selected selected pipes only · ←/→ or m switch · Shift+↓ edit
```
状态栏始终可见(直到会话结束),显示:当前 pipe 名、角色、IP、已选数/总数、路由模式。
### 展开选择面板
**Shift+↓**Shift + 下箭头)展开选择面板:
```
pipe: cli-a91bad56 (main) 192.168.50.22 ↑↓ move Space select ←/→ or m route Enter/Esc close Shift+↓ toggle
当前普通 prompt 走 已选 sub切换不会清空选择
☑ cli-da029538 (sub-1 XC/192.168.50.22)
☐ cli-04d67950 (main vmwin11/192.168.50.27)
☑ cli-893747d3 [offline] (sub-2 vmwin11/192.168.50.27)
```
### 面板内快捷键
| 快捷键 | 场景 | 作用 |
|--------|------|------|
| **Shift+↓** | 状态栏可见时 | 展开/收起选择面板 |
| **↑ / ↓** | 面板展开时 | 上下移动光标 |
| **Space** | 面板展开时 | 切换当前光标所在 pipe 的选中状态(☑ ↔ ☐) |
| **Enter** | 面板展开时 | 确认并关闭面板 |
| **Esc** | 面板展开时 | 取消并关闭面板 |
| **← / → 或 M** | 状态栏可见且有选中 pipe 时 | 切换路由模式(`selected pipes only``local main` |
### M 键 — 路由模式切换
M 键(或 ← / →)用于在两种路由模式之间切换,**无需展开面板**
| 模式 | 状态栏显示 | 行为 |
|------|-----------|------|
| `selected pipes only` | 绿色高亮 | 输入的 prompt **仅**发送到选中的 pipe本地不执行 |
| `local main` | 灰色 | 输入的 prompt 在**本地 main** 执行,不转发到任何 pipe |
切换路由模式**不会清空选择**。你可以在 `local main` 模式下保持选择,随时按 M 切回 `selected pipes only` 继续向远端发送。
### 完整操作流程示例
```
1. 输入 /pipes → 状态栏出现,显示发现的实例
2. 按 Shift+↓ → 展开选择面板
3. 按 ↓ 移动到目标 pipe → 光标移到 cli-04d67950
4. 按 Space → 选中 ☑ cli-04d67950
5. 按 Enter → 确认,面板收起
6. 输入 "帮我检查 git status" → prompt 自动发送到 cli-04d67950 执行
7. 按 M → 切换到 local main 模式
8. 输入 "本地做点什么" → 仅在本地执行
9. 按 M → 切回 selected pipes only
10. 输入 "继续远端任务" → 又发送到 cli-04d67950
```
## 命令参考
### /pipes
显示所有发现的实例,管理选择状态。再次执行 `/pipes` 切换面板展开/收起。
```
/pipes — 显示所有实例 + 切换选择面板
/pipes select <name> — 选中某实例(消息会广播到它)
/pipes deselect <name> — 取消选中
/pipes all — 全选
/pipes none — 全部取消
```
输出示例:
```
Your pipe: cli-a91bad56
Role: main
Machine ID: 205d6c3a...
IP: 192.168.50.22
Host: XC
Main machine: 205d6c3a... (this machine)
[main] cli-a91bad56 XC/192.168.50.22 [alive] (you)
☑ [sub-1] cli-da029538 XC/192.168.50.22 [alive] [connected]
LAN Peers:
☐ [main] cli-04d67950 vmwin11/192.168.50.27 tcp:192.168.50.27:58853 [LAN]
Selected: cli-da029538
```
### /attach <name>
手动 attach 到一个实例,使其成为你的 slave。
```
/attach cli-04d67950 — 连接到指定 pipe自动解析 LAN TCP 端点)
```
attach 后,对方变为 slave你变为 master。可以向它发送 prompt。通常不需要手动 attach——heartbeat 会自动发现并连接。
### /detach <name>
断开与某个 slave 的连接。
```
/detach cli-04d67950
```
### /send <name> <message>
向指定 pipe 发送消息(不依赖选择状态,直接指定目标)。
```
/send cli-04d67950 请帮我检查一下日志
/send tcp:192.168.50.27:58853 hello — 直接通过 TCP 地址发送
```
### /claim-main
强制声明当前机器为 main用于 main 意外退出后的恢复)。
## 消息路由
### 选中 pipe 后的自动路由
1. 通过 `/pipes select` 或 Shift+Down 面板选中一个或多个 pipe
2. 在输入框中正常输入消息
3. 消息自动发送到所有选中的已连接 pipe
4. 每个 pipe 独立执行,结果流式回传到 main 的消息列表
### 路由模式
| 模式 | 行为 |
|------|------|
| `selected`(默认) | 消息发送到选中的 pipe |
| `local` | 消息仅在本地执行,不转发 |
## 架构
### 通信协议
所有通讯使用 NDJSONNewline-Delimited JSON每行一个消息
```json
{"type":"ping","from":"cli-abc","ts":"2026-04-11T00:00:00.000Z"}
{"type":"prompt","data":"帮我查看 git status","from":"cli-abc","ts":"..."}
{"type":"stream","data":"正在执行...","from":"cli-def","ts":"..."}
{"type":"done","data":"","from":"cli-def","ts":"..."}
```
### 消息类型
| 类型 | 方向 | 说明 |
|------|------|------|
| `ping`/`pong` | 双向 | 健康检查 |
| `attach_request`/`accept`/`reject` | M→S/S→M | 连接控制 |
| `detach` | M→S | 断开连接 |
| `prompt` | M→S | 主向从发送 prompt |
| `prompt_ack` | S→M | 从确认接收 |
| `stream` | S→M | 从流式回传 AI 输出 |
| `tool_start`/`tool_result` | S→M | 工具执行通知 |
| `done` | S→M | 本轮完成 |
| `error` | 双向 | 错误通知 |
| `permission_request`/`response`/`cancel` | 双向 | 权限审批转发 |
### 传输层
```
本机 LAN
┌──────────────┐ ┌──────────────┐
│ PipeServer │ │ PipeServer │
│ UDS sock │ │ UDS sock │
│ TCP :rand │◄───TCP───►│ TCP :rand │
├──────────────┤ ├──────────────┤
│ LanBeacon │◄──UDP────►│ LanBeacon │
│ 224.0.71.67 │ mcast │ 224.0.71.67 │
└──────────────┘ └──────────────┘
```
- **UDS**:本机实例间通讯,通过文件系统路径寻址(`~/.claude/pipes/cli-xxx.sock`
- **TCP**LAN 实例间通讯,动态端口,通过 beacon 发现
- **UDP Multicast**peer 发现3 秒广播一次 announce 包
### 角色模型
| 角色 | 说明 |
|------|------|
| `main` | 首个启动的实例,管理 registry |
| `sub` | 后续启动的同机实例(或被 attach 的 LAN 实例) |
| `master` | attach 了至少一个 slave 的实例 |
| `slave` | 被 master attach 控制的实例 |
角色转换:
- 首个启动 → `main`
- 同机后续启动 → `sub`(自动被 main attach → `slave`
- LAN 发现 → 两边都是 `main`heartbeat 自动互相 attach
- 被 attach → 变为 `slave`(可通过 `/detach` 恢复)
### 发现机制
**本机**:通过 `~/.claude/pipes/registry.json` 文件(带文件锁),`machineId` 绑定主机身份。
**LAN**:通过 UDP multicast beacon
1. 每 3 秒广播 `{ proto, pipeName, machineId, ip, tcpPort, role }`
2. 收到其他实例的 announce → 记入 peers Map
3. 15 秒未收到 → 标记 peer lost
4. Heartbeat 合并 local registry + beacon peers → 统一 attach 目标列表
### Heartbeat 循环5 秒间隔)
```
main/master 角色:
1. cleanupStaleEntries() — 清理 registry 中死掉的条目
2. getAliveSubs() — 获取存活的本地 subs
3. refreshDiscoveredPipes() — 刷新 discoveredPipes包含 LAN peers
4. 合并 LAN peers 到 state
5. 构建统一 attach 目标列表 — 本地 subs + LAN peers
6. 遍历未连接的目标 → 自动 attach
7. 清理断开的 slave 连接 — 同时检查 local registry 和 beacon
sub 角色:
1. 检测 main 是否存活
2. main 死亡 → 同机则接管 main 角色,跨机则独立
```
## 关键文件
| 文件 | 职责 |
|------|------|
| `src/utils/pipeTransport.ts` | PipeServer双模 UDS+TCP、PipeClient、类型定义 |
| `src/utils/lanBeacon.ts` | UDP multicast beacon、singleton 管理 |
| `src/utils/pipeRegistry.ts` | Registry CRUD、角色判定、machineId、LAN merge |
| `src/utils/peerAddress.ts` | 地址解析uds:/bridge:/tcp: scheme |
| `src/screens/REPL.tsx` | Bootstrap、heartbeat、cleanup、prompt 路由 |
| `src/hooks/useMasterMonitor.ts` | Slave client registry、消息订阅 |
| `src/hooks/useSlaveNotifications.ts` | Slave 端通知处理 |
| `src/commands/pipes/pipes.ts` | /pipes 命令 |
| `src/commands/attach/attach.ts` | /attach 命令 |
| `src/commands/send/send.ts` | /send 命令 |
| `packages/builtin-tools/src/tools/SendMessageTool/SendMessageTool.ts` | AI 发消息工具(含 tcp: 支持) |
## 后续优化方向
### 安全P0
1. **TCP 认证**:首次连接时交换 HMAC-SHA256 token基于 machineId + session secret防止未授权设备连接
2. **JSON schema 验证**:在所有 `JSON.parse` 入口点增加 Zod 校验,防止 prototype pollution
3. **Beacon 信息脱敏**hash machineId 后再广播,不暴露硬件序列号
### 可靠性P1
4. **多网卡选择**`getLocalIp()` 应优先选择 RFC 1918 地址,排除 VPN/Docker 接口
5. **TCP target 验证**`parseTcpTarget()` 应限制目标为已知 beacon peers 或 RFC 1918 范围
6. **PipeServer close()**:改为 `Promise.allSettled` 并行关闭 UDS + TCP`_closing` guard
### 功能P2
7. **mDNS/DNS-SD**:作为 multicast 受限环境下的 beacon 替代方案
8. **固定端口配置**:允许用户指定 TCP 端口范围,便于防火墙精确配置
9. **TLS 加密**TCP 传输加密,防中间人窃听
10. **双向 prompt**:当前只有 master → slave 方向,可考虑 slave 主动向 master 发送结果/请求

View File

@@ -1,7 +1,7 @@
# PROACTIVE — 主动模式
> Feature Flag: `FEATURE_PROACTIVE=1`(与 `FEATURE_KAIROS=1` 共享功能)
> 实现状态:核心模块全部 Stub布线完整
> 实现状态:核心循环与 SleepTool 已落地,部分外围文档仍在补齐
> 引用数37
## 一、功能概述
@@ -21,13 +21,13 @@ PROACTIVE 实现 Tick 驱动的自主代理。CLI 在用户不输入时也能持
| 模块 | 文件 | 状态 | 说明 |
|------|------|------|------|
| 核心逻辑 | `src/proactive/index.ts` | **Stub** | `activateProactive()``deactivateProactive()``isProactiveActive() => false` |
| 核心逻辑 | `src/proactive/index.ts` | **已实现** | `activateProactive()``deactivateProactive()``pause/resume``nextTickAt` 调度状态 |
| SleepTool 提示 | `src/tools/SleepTool/prompt.ts` | **完整** | 工具提示定义(工具名:`Sleep` |
| 命令注册 | `src/commands.ts:62-65` | **布线** | 动态加载 `./commands/proactive.js` |
| 工具注册 | `src/tools.ts:26-28` | **布线** | SleepTool 动态加载 |
| REPL 集成 | `src/screens/REPL.tsx` | **布线** | tick 驱动逻辑、占位符、页脚 UI |
| 系统提示 | `src/constants/prompts.ts:860-914` | **完整** | 自主工作行为指令(~55 行详细 prompt |
| 会话存储 | `src/utils/sessionStorage.ts:4892-4912` | **布线** | tick 消息注入对话流 |
| REPL 集成 | `src/screens/REPL.tsx` | **已实现** | tick 驱动、standby/sleeping 状态、页脚与 bridge automation metadata 上报 |
| 系统提示 | `src/constants/prompts.ts:864-918` | **完整** | 自主工作行为指令(~55 行详细 prompt |
| 远控状态镜像 | `src/utils/sessionState.ts` | **已实现** | 向 remote-control/CCR 暴露 `automation_state` 元数据 |
### 2.2 系统提示内容
@@ -46,7 +46,7 @@ PROACTIVE 实现 Tick 驱动的自主代理。CLI 在用户不输入时也能持
### 2.3 数据流
```
activateProactive() [需要实现]
activateProactive()
Tick 调度器启动
@@ -62,20 +62,22 @@ Tick 调度器启动
└── 无事可做 → 必须调用 SleepTool
SleepTool 等待 [需要实现]
SleepTool 等待
├── 用户插入新工作 / 队列中有命令 → 立即唤醒
├── proactive 被关闭 → 立即中断
└── 进入休眠时向远端 surfaces 上报 `automation_state = sleeping`
下一个 tick 到达
```
## 三、需要补全的内容
## 三、当前行为补充
| 优先级 | 模块 | 工作量 | 说明 |
|--------|------|--------|------|
| 1 | `src/proactive/index.ts` | 中 | Tick 调度器、activate/deactivate 状态机、pause/resume |
| 2 | `src/tools/SleepTool/SleepTool.ts` | 小 | 工具执行(等待指定时间后触发 tick |
| 3 | `src/commands/proactive.js` | 小 | `/proactive` 斜杠命令处理器 |
| 4 | `src/hooks/useProactive.ts` | 中 | React hookREPL 引用但不存在) |
- `standby`proactive 已开启,当前没有执行中的 turn且已调度下一个 tick。
- `sleeping`:模型显式调用 `SleepTool` 进入等待窗口。
- remote-control/CCR 通过 `external_metadata.automation_state` 接收这两个状态,用于 Web UI 的 Autopilot 状态显示。
- `SleepTool` 现在不是纯定时器;它会在共享命令队列出现新工作时提前醒来。
## 四、关键设计决策
@@ -101,9 +103,11 @@ FEATURE_PROACTIVE=1 FEATURE_KAIROS=1 FEATURE_KAIROS_BRIEF=1 bun run dev
| 文件 | 职责 |
|------|------|
| `src/proactive/index.ts` | 核心逻辑stub |
| `src/proactive/index.ts` | 核心逻辑与 next-tick 状态 |
| `src/tools/SleepTool/prompt.ts` | SleepTool 工具提示 |
| `src/constants/prompts.ts:860-914` | 自主工作系统提示 |
| `src/screens/REPL.tsx` | REPL tick 集成 |
| `src/tools/SleepTool/SleepTool.ts` | 休眠/唤醒执行逻辑 |
| `src/constants/prompts.ts:864-918` | 自主工作系统提示 |
| `src/screens/REPL.tsx` | REPL tick 集成与 automation 状态上报 |
| `src/utils/sessionStorage.ts:4892-4912` | Tick 消息注入 |
| `src/utils/sessionState.ts` | bridge/CCR metadata 镜像 |
| `src/components/PromptInput/PromptInputFooterLeftSide.tsx` | 页脚 UI 状态 |

View File

@@ -0,0 +1,352 @@
# Remote Control Server 私有化部署指南
本指南说明如何将 Remote Control Server (RCS) 部署到私有环境,并通过 Claude Code CLI 连接使用。
## 架构概览
```
┌──────────────────┐ ┌──────────────────────┐
│ Claude Code CLI │ ◄── HTTP/SSE/WS ─►│ Remote Control │
│ (Bridge Worker) │ 长轮询 + 心跳 │ Server (RCS) │
└──────────────────┘ │ │
│ ┌──────────────┐ │
┌──────────────────┐ HTTP/SSE │ │ In-Memory │ │
│ Web UI 控制面板 │ ◄─────────────── │ │ Store │ │
│ (/code/*) │ │ └──────────────┘ │
│ (React + Vite) │ │ ┌──────────────┐ │
└──────────────────┘ │ │ JWT Auth │ │
│ └──────────────┘ │
┌──────────────────┐ │ ┌──────────────┐ │
│ acp-link │ ◄── ACP Relay ─── │ │ ACP Handler │ │
│ + ACP Agent │ WebSocket │ └──────────────┘ │
└──────────────────┘ └──────────────────────┘
```
**RCS 是一个纯内存的中间服务**,它的职责是:
- 接收 Claude Code CLI 的环境注册和工作轮询
- 接收 acp-link 的 ACP agent 注册,支持 WebSocket relay 桥接
- 提供 Web UI 供操作者远程监控和审批
- 通过 WebSocket/SSE 双向传输消息
- 管理会话、环境、权限请求
- 提供 ACP SSE event stream 供外部消费者订阅 channel group 事件
## 前置条件
- 一台可被 Claude Code CLI 和 Web 浏览器同时访问的服务器物理机、VM、容器均可
- [Docker](https://www.docker.com/)
- 启用 `BRIDGE_MODE` feature flag 的 Claude Code 构建
## 部署
### 构建 Docker 镜像
在项目根目录执行:
```bash
docker build -t rcs:latest -f packages/remote-control-server/Dockerfile .
```
### 启动容器
```bash
docker run -d \
--name rcs \
-p 3000:3000 \
-e RCS_API_KEYS=sk-rcs-your-secret-key-here \
-e RCS_BASE_URL=https://rcs.example.com \
-v rcs-data:/app/data \
--restart unless-stopped \
rcs:latest
```
### Docker Compose
```yaml
version: "3.8"
services:
rcs:
build:
context: .
dockerfile: packages/remote-control-server/Dockerfile
args:
VERSION: "0.1.0"
ports:
- "3000:3000"
environment:
- RCS_API_KEYS=sk-rcs-your-secret-key-here
- RCS_BASE_URL=https://rcs.example.com
volumes:
- rcs-data:/app/data
restart: unless-stopped
volumes:
rcs-data:
```
启动:
```bash
docker compose up -d
```
## 环境变量参考
### 服务器端
| 变量 | 必填 | 默认值 | 说明 |
|------|------|--------|------|
| `RCS_API_KEYS` | **是** | _(空)_ | API 密钥列表,逗号分隔。用于客户端认证和 JWT 签名。**务必设置强密钥** |
| `RCS_PORT` | 否 | `3000` | 服务监听端口 |
| `RCS_HOST` | 否 | `0.0.0.0` | 服务监听地址 |
| `RCS_BASE_URL` | 否 | `http://localhost:3000` | 外部访问 URL。用于生成 WebSocket 连接地址,必须与客户端实际访问的地址一致 |
| `RCS_VERSION` | 否 | `0.1.0` | 版本号,显示在 `/health` 响应中 |
| `RCS_POLL_TIMEOUT` | 否 | `8` | V1 工作轮询超时(秒) |
| `RCS_HEARTBEAT_INTERVAL` | 否 | `20` | 心跳间隔(秒) |
| `RCS_JWT_EXPIRES_IN` | 否 | `3600` | JWT 令牌有效期(秒) |
| `RCS_DISCONNECT_TIMEOUT` | 否 | `300` | 断线判定超时(秒) |
| `RCS_WS_IDLE_TIMEOUT` | 否 | `30` | WebSocket 空闲超时Bun 发送协议级 ping |
| `RCS_WS_KEEPALIVE_INTERVAL` | 否 | `20` | 服务端→客户端 keep_alive 帧间隔(秒),防止反向代理关闭空闲连接 |
### 客户端Claude Code CLI
| 变量 | 必填 | 说明 |
|------|------|------|
| `CLAUDE_BRIDGE_BASE_URL` | **是** | RCS 服务器地址,例如 `https://rcs.example.com`。设置此变量即启用自托管模式,跳过 GrowthBook 门控 |
| `CLAUDE_BRIDGE_OAUTH_TOKEN` | **是** | 认证令牌,必须与服务器端 `RCS_API_KEYS` 中的某个值匹配 |
| `CLAUDE_BRIDGE_SESSION_INGRESS_URL` | 否 | WebSocket 入口地址(默认与 `CLAUDE_BRIDGE_BASE_URL` 相同) |
| `CLAUDE_CODE_REMOTE` | 否 | 设为 `1` 时标记为远程执行模式 |
## Claude Code 客户端连接
### 1. 设置环境变量
在运行 Claude Code 的机器上设置:
```bash
export CLAUDE_BRIDGE_BASE_URL="https://rcs.example.com"
export CLAUDE_BRIDGE_OAUTH_TOKEN="sk-rcs-your-secret-key-here"
```
### 2. 启动 Claude Code
```bash
# 使用 dev 模式BRIDGE_MODE 默认启用)
bun run dev
# 或使用构建产物
bun run dist/cli.js
```
### 3. 执行 /remote-control 命令
在 Claude Code 的 REPL 中输入:
```
/remote-control
```
环境型 Remote Control例如 `claude remote-control` 子命令)会向 RCS 注册环境,注册成功后在终端显示连接 URL
```
https://rcs.example.com/code?bridge=<environmentId>
```
交互式 REPL 方式(`--remote-control``/remote-control`)在某些桥接模式下也可能直接给出会话 URL
```
https://rcs.example.com/code/session_<id>
```
两种 URL 都可以直接在浏览器打开并远程操控当前会话;只有 environment 模式才会出现在 Web UI 的环境列表中。
若已连接,再次执行 `/remote-control` 会显示对话框,包含以下选项:
- **Disconnect this session** — 断开远程连接
- **Show QR code** — 显示/隐藏二维码
- **Continue** — 保持连接,继续使用
也可通过 CLI 参数直接启动:
```bash
claude remote-control
# 或简写
claude rc
# 或
claude bridge
```
## Web UI 控制面板
通过 `/remote-control` 命令获取 URL 后,在浏览器打开即可使用。
### 技术栈v22026-04-18 重构)
Web UI 已从原生 JS 重构为 **React + Vite + Radix UI**
- **框架**: React 19 + Vite 构建TypeScript
- **UI 组件**: Radix UI primitivesDialog、Tabs、Select、Popover 等)
- **聊天组件**: 完整的 ACP 聊天界面,支持 Plan 可视化、工具调用展示、权限审批
- **AI Elements**: 独立的 AI 交互组件库message、reasoning、tool、code-block、prompt-input 等)
- **ACP 直连**: 支持 QR 码扫描自动跳转 ACP 直连视图(`ACPDirectView`
- **主题系统**: 暗色/亮色主题切换,遵循 Impeccable 设计系统
### 功能
- 查看已注册的运行环境environment 模式),区分 ACP Agent 和 Claude Code 类型
- 创建和管理会话
- 实时查看对话消息和工具调用
- 查看 Autopilot 状态(`standby` / `sleeping`)和自动运行指示
- 查看 authoritative task snapshots 驱动的 Tasks 面板
- 审批 Claude Code 的工具权限请求
- 权限模式选择器6 种模式:默认/自动接受编辑/跳过权限/规划/不询问/自动判断)
- 模型选择器(可选可用模型)
- Plan 可视化(进度条、状态图标、优先级标签)
- ACP QR 扫描自动跳转到 ACP 聊天界面
Web UI 使用 UUID 认证(无需用户账户),适合受信任网络环境。
## ACP 支持
RCS 支持 ACP (Agent Client Protocol) agent 通过 `acp-link` 包接入。
### 架构
```
acp-link ──REST注册──► RCS POST /v1/environments/bridge
acp-link ──WS identify──► RCS WebSocket (携带 agentId)
acp-link ◄──ACP relay──► RCS ◄──Web UI WS──► 浏览器
```
### 后端组件
| 文件 | 职责 |
|------|------|
| `src/routes/acp/index.ts` | ACP REST 路由agents 列表、channel groups、relay |
| `src/transport/acp-ws-handler.ts` | ACP WebSocket 处理agent 注册、心跳、消息转发 |
| `src/transport/acp-relay-handler.ts` | 前端 WS → acp-link 透传 + EventBus inbound 转发 |
| `src/transport/acp-sse-writer.ts` | SSE event stream 供外部消费者订阅 |
### acp-link 连接
详见 [acp-link 文档](./acp-link.md)。
```bash
# 在 RCS 环境中启动 acp-link
# 注意claude 本身不支持 ACP需要用 ccb-bun --acp
ACP_RCS_URL=http://localhost:3000 \
ACP_RCS_TOKEN=sk-rcs-your-key \
acp-link ccb-bun -- --acp
```
ACP session 在 Web UI 中显示品牌色标签,与普通 Claude Code session 区分。
## 工作流程详解
```
┌──────────────────────────────────────────────────────────┐
│ 完整工作流程 │
└──────────────────────────────────────────────────────────┘
1. Claude Code CLI 启动,设置环境变量指向自托管 RCS
2. 用户执行 /remote-control 命令
3. 注册环境
CLI ──POST /v1/environments/bridge──► RCS
CLI ◄── { environment_id, environment_secret } ── RCS
4. 终端显示连接 URL
https://rcs.example.com/code?bridge=<environmentId>
5. 开始工作轮询(循环)
CLI ──GET /v1/environments/:id/work/poll──► RCS
(长轮询,等待任务分配,超时 8 秒后重试)
6. 浏览器打开 URL → Web UI 创建任务
Browser ──POST /web/sessions──► RCS
RCS 分配 work 给正在轮询的 CLI
7. CLI 收到任务并确认
CLI ◄── { id, data: { type, sessionId } } ── RCS
CLI ──POST /v1/environments/:id/work/:workId/ack──► RCS
8. 建立会话连接
CLI ──WebSocket /v1/session_ingress──► RCS
(或使用 V2 的 SSE + HTTP POST
9. 双向通信
CLI ──消息/工具调用结果──► RCS ──► Browser
CLI ◄──权限审批/指令───── RCS ◄──── Browser
CLI ──automation_state / task_state──► RCS ──► Browser
10. 心跳保活(每 20 秒)
CLI ──POST /v1/environments/:id/work/:workId/heartbeat──► RCS
11. 任务完成 → 归档会话 → 注销环境
```
## 故障排查
### Web UI 看不到当前 Autopilot 状态
- `standby`proactive 已开启,正在等待下一个 tick
- `sleeping`:模型正在 `SleepTool` 等待窗口中
这两个状态通过 worker `external_metadata.automation_state` 上报。如果页面只显示普通 working spinner优先检查 CLI 和 RCS 之间的 worker metadata PUT 是否成功。
### CLI 无法连接
```
Error: Remote Control is not available in this build.
```
**原因**`BRIDGE_MODE` feature flag 未启用。
**解决**:使用 dev 模式(默认启用)或确保构建时包含 `BRIDGE_MODE` flag。
### 认证失败 (401)
```
Error: Unauthorized
```
**检查项**
1. `CLAUDE_BRIDGE_OAUTH_TOKEN` 是否与 `RCS_API_KEYS` 中的值匹配
2. API Key 是否包含多余的空格或换行
3. 两个环境变量是否都已正确设置
### WebSocket 连接中断
**检查项**
1. 如果使用反向代理,确认已正确配置 WebSocket 升级(`Upgrade` / `Connection` 头)
2. 代理的 `proxy_read_timeout` 是否足够大(建议 86400 秒)
3. 网络防火墙是否允许 WebSocket 流量
### 健康检查
```bash
curl https://rcs.example.com/health
# 预期: {"status":"ok","version":"0.1.0"}
```
## 限制与注意事项
| 项目 | 说明 |
|------|------|
| 存储 | 纯内存存储Map服务器重启后所有会话和环境数据丢失 |
| 扩展 | 不支持水平扩展(无共享状态),单实例部署 |
| 并发 | 适合中小规模使用,大量并发会话可能需要性能调优 |
| 数据持久化 | `/app/data` 卷已预留但当前未使用,未来可能用于持久化 |
| Web UI 认证 | 基于 UUID无用户账户系统适合受信任网络环境 |
## 与云端模式对比
| 特性 | 云端 (Anthropic CCR) | 自托管 (RCS) |
|------|---------------------|--------------|
| 认证方式 | claude.ai OAuth 订阅 | API Key |
| GrowthBook 门控 | 需要 `tengu_ccr_bridge` 通过 | 自动跳过 |
| 功能标志 | 需要 `BRIDGE_MODE=1` | 同样需要 |
| 部署位置 | Anthropic 云端 | 用户自有服务器 |
| 数据流经 | Anthropic 基础设施 | 用户私有网络 |
| 依赖 | claude.ai 订阅 + OAuth | 仅需 API Key |
自托管模式的核心优势是:设置 `CLAUDE_BRIDGE_BASE_URL` 后,代码自动调用 `isSelfHostedBridge()` 返回 `true`,跳过所有 GrowthBook 和订阅检查,无需 claude.ai 账户即可使用。

426
docs/features/ssh-remote.md Normal file
View File

@@ -0,0 +1,426 @@
# SSH Remote — 远程主机运行 Claude Code
## 概述
SSH Remote 提供两种方式在远程 Linux 主机上运行 Claude Code
1. **SSH Remote 模块**`ccb ssh <host>`)— 本地 REPL + 远程工具执行,自动部署二进制 + 认证隧道
2. **直接 SSH 运行**`ssh <host> -t ccb`)— 远程已安装 ccb直接启动交互式会话
## 架构
### 方式一SSH Remote 模块(完整模式)
适用场景:远端没有 API 凭据或没有安装 ccb。
```
┌──────────────── 本地 Windows/Mac/Linux ───────────┐
│ │
│ ccb ssh <host> [dir] │
│ │ │
│ ├── 1. SSHProbe: 探测远端平台/架构/已有二进制 │
│ ├── 2. SSHDeploy: 部署 dist/ 到远端 │
│ ├── 3. SSHAuthProxy: 启动本地认证代理 │
│ │ ├─ Unix Socket (Linux/Mac) │
│ │ └─ TCP 127.0.0.1:<port> (Windows) │
│ │ │
│ └── 4. SSH -R 反向隧道 + 启动远端 CLI │
│ ssh -R <remote>:<local> <host> \ │
│ ANTHROPIC_BASE_URL=... \ │
│ ANTHROPIC_AUTH_NONCE=... \ │
│ ccb --output-format stream-json │
│ │
│ ┌─────── 本地 REPL (Ink TUI) ───────┐ │
│ │ 用户输入 → NDJSON → SSH stdin │ │
│ │ SSH stdout → NDJSON → 渲染消息 │ │
│ │ 工具权限请求 → 本地审批 → 回传 │ │
│ └────────────────────────────────────┘ │
└────────────────────────────────────────────────────┘
│ SSH 连接 (加密通道)
┌───────────────── 远端 Linux ──────────────────────┐
│ │
│ ccb (自动部署或已存在) │
│ ├── --output-format stream-json │
│ ├── --input-format stream-json │
│ ├── --verbose -p │
│ │ │
│ ├── API 请求 → ANTHROPIC_BASE_URL │
│ │ → SSH 反向隧道 → 本地 AuthProxy │
│ │ → 注入真实凭据 → api.anthropic.com │
│ │ │
│ └── 工具执行 (Bash/Read/Write/...) │
│ 直接在远端文件系统上操作 │
└────────────────────────────────────────────────────┘
```
### 方式二:直接 SSH 运行(简单模式)
适用场景:远端已安装 ccb 且已有 API 凭据(订阅或 API Key
```
┌─────── 本地终端 ───────┐ ┌──────── 远端 Linux ────────┐
│ │ SSH │ │
│ ssh <host> -t ccb │ ──────→ │ ccb (全局安装) │
│ │ │ ├── 使用远端自身凭据 │
│ 终端直接显示远端 TUI │ ←────── │ ├── 远端文件系统操作 │
│ │ TTY │ └── API 直连 Anthropic │
└─────────────────────────┘ └─────────────────────────────┘
```
### 适用场景对比
| | SSH Remote 模块 | 直接 SSH 运行 |
|---|---|---|
| 远端需要安装 ccb | 不需要(自动部署) | 需要 |
| 远端需要 API 凭据 | 不需要(本地隧道) | 需要 |
| 本地需要安装 ccb | 需要 | 不需要(任何终端) |
| 斜杠命令 | 本地处理 | 远端处理 |
| 网络延迟敏感 | 高NDJSON 双向) | 低(仅 TTY |
| 推荐场景 | 远端无凭据/无安装 | 远端已配置完整 |
---
## 前置准备SSH 密钥配置
两种方式都依赖 SSH 免密连接。以下是完整的密钥配置步骤。
### 1. 生成 SSH 密钥对(本地)
```bash
# 生成 Ed25519 密钥(推荐)
ssh-keygen -t ed25519 -C "your-email@example.com" -f ~/.ssh/id_remote
# 或 RSA 4096 位
ssh-keygen -t rsa -b 4096 -C "your-email@example.com" -f ~/.ssh/id_remote
```
生成两个文件:
- `~/.ssh/id_remote` — 私钥(不可泄露)
- `~/.ssh/id_remote.pub` — 公钥(部署到远端)
### 2. 将公钥部署到远端
```bash
# 方式 Assh-copy-id推荐
ssh-copy-id -i ~/.ssh/id_remote.pub user@remote-host
# 方式 B手动复制
cat ~/.ssh/id_remote.pub | ssh user@remote-host "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
```
### 3. 配置 SSH Config本地
编辑 `~/.ssh/config`(不存在则创建):
```
Host my-server
HostName 192.168.1.100 # 远端 IP 或域名
User root # 远端用户名
IdentityFile ~/.ssh/id_remote # 私钥路径
ServerAliveInterval 60 # 防止连接超时断开
ServerAliveCountMax 3
```
配置后可直接用别名连接:
```bash
ssh my-server # 等同于 ssh -i ~/.ssh/id_remote root@192.168.1.100
```
### 4. 文件权限设置
#### Linux / macOS
```bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/config
chmod 600 ~/.ssh/id_remote
chmod 644 ~/.ssh/id_remote.pub
```
#### WindowsOpenSSH 强制 ACL 检查)
```powershell
# 重置 .ssh 目录权限:仅允许当前用户 + SYSTEM
icacls "$env:USERPROFILE\.ssh" /inheritance:r /grant:r "$($env:USERNAME):(OI)(CI)F" /grant "SYSTEM:(OI)(CI)F"
# 修复 config 文件权限
icacls "$env:USERPROFILE\.ssh\config" /inheritance:r /grant:r "$($env:USERNAME):F" /grant "SYSTEM:F"
# 修复私钥权限
icacls "$env:USERPROFILE\.ssh\id_remote" /inheritance:r /grant:r "$($env:USERNAME):F" /grant "SYSTEM:F"
```
> **Windows 常见错误**:如果 `icacls` 显示 `UNKNOWN\UNKNOWN` ACL 条目,需要先移除再重新授权。权限错误会导致 SSH 拒绝使用密钥。
### 5. 验证免密连接
```bash
ssh my-server "echo 'SSH connection OK'"
# 应直接输出 "SSH connection OK",不要求输入密码
```
---
## 使用方式
### 方式一SSH Remote 模块
```bash
# 基本用法 — 自动探测、部署、启动
ccb ssh user@remote-host
# 使用 SSH Config 别名
ccb ssh my-server
# 指定远端工作目录
ccb ssh my-server /home/user/project
# 使用自定义远端二进制(跳过探测/部署)
ccb ssh my-server --remote-bin "bun /opt/ccb/dist/cli.js"
# 权限控制
ccb ssh my-server --permission-mode auto
ccb ssh my-server --dangerously-skip-permissions
# 恢复远端会话
ccb ssh my-server --continue
ccb ssh my-server --resume <session-uuid>
# 选择模型
ccb ssh my-server --model claude-sonnet-4-6-20250514
# 本地测试模式(不连接远端,测试 auth proxy 管道)
ccb ssh localhost --local
```
### 方式二:直接 SSH 运行
```bash
# 启动交互式会话
ssh my-server -t ccb
# 指定工作目录
ssh my-server -t "ccb --cwd /home/user/project"
# 使用特定模型
ssh my-server -t "ccb --model claude-sonnet-4-6-20250514"
```
---
## 构建与部署
### 构建产物
```bash
# 安装依赖
bun install
# 构建(输出到 dist/
bun run build
```
产物说明:
| 文件 | 说明 |
|------|------|
| `dist/cli.js` | Bun 入口(`#!/usr/bin/env bun` |
| `dist/cli-node.js` | Node.js 入口(`#!/usr/bin/env node``import ./cli.js` |
| `dist/cli-bun.js` | Bun 专用入口 |
| `dist/chunk-*.js` | 代码分割 chunk 文件(约 668 个) |
### 运行方式
```bash
# 方式 A通过 bun 直接运行(开发/调试)
bun run dev
# 方式 B运行构建产物bun 运行时)
bun dist/cli.js
# 方式 C运行构建产物node 运行时)
node dist/cli-node.js
# 方式 D全局安装后使用命令名
ccb
```
### 全局安装
在项目根目录执行:
```bash
# bun 全局安装(推荐)
bun install -g .
# 创建的命令:
# ccb → dist/cli-node.js
# ccb-bun → dist/cli-bun.js
# claude-code-best → dist/cli-node.js
# 安装位置:~/.bun/bin/ccb
```
或使用 npm
```bash
npm install -g .
```
验证:
```bash
ccb --version
# → x.x.x (Claude Code)
```
### 远端部署(全流程)
```bash
# 1. 登录远端
ssh my-server
# 2. 克隆或同步项目代码
git clone <repo-url> ~/ccb-project
cd ~/ccb-project
# 3. 安装运行时(如果没有 bun
curl -fsSL https://bun.sh/install | bash
source ~/.bashrc
# 4. 安装依赖 + 构建
bun install
bun run build
# 5. 全局安装
bun install -g .
# 6. 确保非交互式 SSH 可访问 ccb 命令
# bun install -g 安装到 ~/.bun/bin/,但非交互式 SSH 不加载 .bashrc
# 所以 PATH 中不包含 ~/.bun/bin/
# 解决方式(任选其一):
# 方式 A符号链接到系统 PATH推荐
ln -sf ~/.bun/bin/ccb /usr/local/bin/ccb
# 方式 B添加到 /etc/profile.d/(所有用户生效)
echo 'export PATH="$HOME/.bun/bin:$PATH"' > /etc/profile.d/bun-path.sh
# 方式 C添加到 ~/.bash_profile当前用户ssh -t 时生效)
echo 'export PATH="$HOME/.bun/bin:$PATH"' >> ~/.bash_profile
# 7. 验证
ccb --version
# 8. 从本地测试
# (在本地终端)
ssh my-server -t ccb
```
### SSH Remote 自动部署
使用 `ccb ssh <host>` 时,模块自动处理:
1. **SSHProbe** 探测远端 `~/.local/bin/claude``command -v claude`
2. 若二进制不存在或版本不匹配,**SSHDeploy** 通过 `scp` 传输 `dist/` 目录
3. 在远端创建 wrapper 脚本(`~/.local/bin/claude`
4. 无需手动安装
---
## 模块结构
```
src/ssh/
├── createSSHSession.ts — 会话工厂:编排 probe → deploy → proxy → spawn
├── SSHSessionManager.ts — 双向 NDJSON 通信管理 + 权限转发 + 重连
├── SSHAuthProxy.ts — 本地认证代理API 凭据隧道)
├── SSHProbe.ts — 远端主机探测(平台/架构/已有二进制)
├── SSHDeploy.ts — 远端二进制部署scp + wrapper 脚本)
└── __tests__/
└── SSHSessionManager.test.ts — 17 个单元测试
```
## 关键技术细节
### 认证隧道
- **AuthProxy** 在本地监听Unix socket 或 TCP接收远端 CLI 的 API 请求
- 通过 SSH `-R` 反向端口转发隧道到远端
- AuthProxy 注入本地真实凭据API key 或 OAuth token转发到 `api.anthropic.com`
- `ANTHROPIC_AUTH_NONCE` header 防止未授权访问nonce 通过环境变量传递给远端 CLI远端 CLI 在每个 API 请求中携带此 header
### waitForInit vs 存活检查
- **标准模式**`waitForInit` 等待远端 CLI 发送 `{type:'system', subtype:'init'}` JSON 消息
- **`--remote-bin` 模式**:跳过 `waitForInit`print+stream-json 模式下 init 只在首次查询后发送),改用 3 秒进程存活检查
### 重连机制
- `SSHSessionManager` 检测 SSH 连接断开后自动重连
- 重连时在远端 CLI 命令中追加 `--continue` 恢复会话
- 指数退避重试(最多 5 次,间隔 1s → 2s → 4s → 8s → 16s
## Feature Flag
SSH Remote 功能受 `SSH_REMOTE` feature flag 控制:
- **Dev 模式**:默认启用
- **Build 模式**:需在 `build.ts``DEFAULT_BUILD_FEATURES` 中添加 `'SSH_REMOTE'`
- **运行时**`FEATURE_SSH_REMOTE=1` 环境变量
---
## 常见问题
### `ccb: command not found`SSH 远程执行时)
非交互式 SSH 不加载 `.bashrc``~/.bun/bin` 不在 PATH 中。
```bash
# 解决:创建符号链接
ln -sf ~/.bun/bin/ccb /usr/local/bin/ccb
```
### SSH 密钥被拒绝
```
Permission denied (publickey)
```
1. 确认公钥已添加到远端 `~/.ssh/authorized_keys`
2. 确认本地私钥文件权限正确(`chmod 600`
3. 确认 `~/.ssh/config``IdentityFile` 路径正确
4. Windows 用户检查 ACL 权限(见上方 Windows 权限设置)
### SSH 连接超时
```
ssh: connect to host x.x.x.x port 22: Connection timed out
```
1. 确认远端 SSH 服务正在运行:`systemctl status sshd`
2. 确认防火墙允许 22 端口
3. 确认 IP 地址/域名正确
4.`~/.ssh/config` 中添加 `ConnectTimeout 10`
### 403 ForbiddenSSH Remote 模块)
AuthProxy 的 nonce 验证失败。确认:
1. 远端 CLI 版本包含 nonce header 注入修复
2. `ANTHROPIC_AUTH_NONCE` 环境变量正确传递到远端
3. `src/services/api/client.ts``x-auth-nonce` header 已启用
### 远端 CLI 启动后立即退出
```
Remote process exited immediately (code 1)
```
1. 确认远端 `bun` / `node` 运行时可用
2. 手动在远端执行 `ccb --version` 验证安装
3. 检查 `--remote-bin` 路径是否正确
4. 查看 stderr 输出获取详细错误信息

View File

@@ -0,0 +1,310 @@
# Stub 恢复设计 1-4
> 日期2026-04-12
> 目标:基于当前代码边界,为下一阶段 4 个 stub/半 stub 命令面给出可实施的设计方案。
> 排序原则:按建议实施顺序排序,不按问题严重性排序。
## 设计原则
- 先做能独立闭环、收益明确、改动边界清晰的项。
- 大项拆成 `MVP``Phase 2+`,避免一次性掉进大范围恢复。
- 优先复用已有状态、传输层、日志与配置能力,不重造协议。
- 设计以当前仓库实际代码为准,不以旧文档的理想状态为准。
## 1. `claude daemon status` / `claude daemon stop`
### 现状
- `start` 路径已有完整 supervisor + worker 生命周期:
`src/daemon/main.ts`
`src/daemon/workerRegistry.ts`
- `status` / `stop` 目前只是占位输出:
`src/daemon/main.ts`
- `/remote-control-server` 有自己的命令内 UI 状态,但只维护当前进程内的 `daemonProcess`,并不适合作为跨进程 CLI 管理基础:
`src/commands/remoteControlServer/remoteControlServer.tsx`
### 目标
-`claude daemon status``claude daemon stop` 在另一个 CLI 进程中也能正确工作。
- 不依赖 TUI 内存态,不要求当前命令进程就是启动 daemon 的那个进程。
### MVP 方案
- 新增 daemon 状态文件,例如:
`~/.claude/daemon/remote-control.json`
- `start` 时写入:
- supervisor pid
- cwd
- startedAt
- worker kinds
- 最近状态
- `status`
- 读取状态文件
- 用现有进程探测能力验证 pid 是否存活
- 输出 `running / stopped / stale`
- stale 时自动清理状态文件
- `stop`
- 读取 pid
- 发送 `SIGTERM`
- 等待退出
- 超时后 `SIGKILL`
- 清理状态文件
### 代码范围
- 新增 `src/daemon/state.ts`
- 修改 `src/daemon/main.ts`
- 轻量修改 `src/commands/remoteControlServer/remoteControlServer.tsx`,让 UI 尽量读取同一份状态文件
### 验证
1. `claude daemon start`
2. 新开终端执行 `claude daemon status`
3. 执行 `claude daemon stop`
4. 再次执行 `claude daemon status`,确认返回 `stopped` 或清晰的 `stale cleaned`
### 风险
- Windows 信号模型和 Unix 不同,`stop` 需要超时兜底。
- 当前设计默认单 supervisor不处理多实例并发。
### 工作量判断
-
- 适合作为下一步的首选实现项
## 2. `BG_SESSIONS`
### 现状
- fast-path 已接好:
`src/entrypoints/cli.tsx`
- session registry 已有真实实现:
`src/utils/concurrentSessions.ts`
- `exit` 在 bg session 内已会 `tmux detach-client`
`src/commands/exit/exit.tsx`
- 但 CLI handler 仍全空:
`src/cli/bg.ts`
- task summary 仍然是 stub
`src/utils/taskSummary.ts`
### 目标
- 先把 `ps` / `logs` / `kill` 做成真正有用的 session 管理命令。
- 不在第一阶段就强行补完 `attach` / `--bg`
### Phase 2AMVP
- 实现 `ps`
- 从 registry 读取 live sessions
- 展示 pid、kind、sessionId、cwd、name、startedAt、bridgeSessionId
- 如果有 activity/status则一并展示
- 实现 `logs`
- 支持按 `sessionId / pid / name` 查找
- 优先复用本地 transcript/log 读取能力
- 如果 registry 里存在 `logPath`,支持 tail 文件
- 实现 `kill`
- 解析目标 session
- 发退出信号
- 清理 stale registry
### Phase 2B后续
- 实现 `attach`
- 实现 `--bg`
- 实现 `taskSummary` 的中途状态更新
### 为什么要拆
- 现有 registry 记录了 `pid / sessionId / name / logPath`
- 但没有可靠的 tmux attach target
- 所以 `attach``--bg` 不是简单补 handler而是需要补启动/附着元数据设计
### 代码范围
- 修改 `src/cli/bg.ts`
- 修改 `src/utils/concurrentSessions.ts` 以便后续 attach/--bg 扩展
- 修改 `src/utils/taskSummary.ts`
- 复用:
`src/utils/sessionStorage.ts`
`src/utils/udsClient.ts`
### 验证
1. `ps` 能列出 live sessions
2. `logs <sessionId|pid|name>` 能输出对应日志
3. `kill <sessionId|pid|name>` 能结束目标 session
### 风险
- `attach` / `--bg` 第二阶段需要 tmux 元数据设计
- Windows 下 tmux 路径需要明确降级策略
### 工作量判断
- `ps/logs/kill` 中等
- `attach/--bg` 明显更大,应分阶段
## 3. `TEMPLATES`
### 现状
- 命令入口只有 fast-path
`src/entrypoints/cli.tsx`
- handler 是空的:
`src/cli/handlers/templateJobs.ts`
- `markdownConfigLoader` 已把 `templates` 纳入配置目录:
`src/utils/markdownConfigLoader.ts`
- `query / stopHooks` 已预留 job classifier 链路:
`src/query/stopHooks.ts`
- `jobs/classifier.ts` 仍是 stub
`src/jobs/classifier.ts`
### 目标
-`new / list / reply` 做成可用的模板任务系统。
- 第一阶段不碰复杂的自动分类与自动执行。
### MVP 方案
- 模板来源:
`.claude/templates/*.md`
- 模板格式:
复用现有 markdown + frontmatter 解析,不另外设计 DSL
- `list`
- 列出所有模板
- 显示模板名、description、路径
- `new <template> [args...]`
- 解析模板
-`~/.claude/jobs/<job-id>/` 下创建 job 目录
- 写入 `template.md``input.txt``state.json`
- 返回 job id 与目录
- `reply <job-id> <text>`
- 将回复写入 `replies.jsonl``input.txt`
- 更新 `state.json`
### Phase 2
- 恢复 `src/jobs/classifier.ts`
- 让带 `CLAUDE_JOB_DIR` 的 job session 在 turn 完成后自动更新 `state.json`
- 再决定是否补自动 job runner
### 为什么要拆
- 当前证据表明这是“template job commands”不是单纯模板列表
- 但自动 job 运行链路没有足够现成实现,先做文件系统 job lifecycle 更稳
### 代码范围
- 修改 [src/cli/handlers/templateJobs.ts](</e:/Source_code/Claude-code-bast/src/cli/handlers/templateJobs.ts:1>)
- 新增 `src/jobs/state.ts`
- 新增 `src/jobs/templates.ts`
- Phase 2 再改 [src/jobs/classifier.ts](</e:/Source_code/Claude-code-bast/src/jobs/classifier.ts:1>)
### 验证
1. `list` 能列出 `.claude/templates`
2. `new` 能创建 job 目录和状态文件
3. `reply` 能更新 job 内容和状态
4. Phase 2 再验证 classifier 写状态
### 风险
- frontmatter schema 需要先定义最小字段集
- 一旦扩展到“自动运行 job”范围会明显膨胀
### 工作量判断
- MVP 中等
- 完整 job 系统偏大
## 4. `assistant [sessionId]`
### 现状
- attach 主流程其实已经存在:
[src/main.tsx](</e:/Source_code/Claude-code-bast/src/main.tsx:4708>)
- 远端 viewer 所需基础模块已存在:
[src/remote/RemoteSessionManager.ts](</e:/Source_code/Claude-code-bast/src/remote/RemoteSessionManager.ts:1>)
[src/hooks/useAssistantHistory.ts](</e:/Source_code/Claude-code-bast/src/hooks/useAssistantHistory.ts:1>)
[src/assistant/sessionHistory.ts](</e:/Source_code/Claude-code-bast/src/assistant/sessionHistory.ts:1>)
- 真正 stub 的主要是:
[src/assistant/sessionDiscovery.ts](</e:/Source_code/Claude-code-bast/src/assistant/sessionDiscovery.ts:1>)
[src/assistant/AssistantSessionChooser.ts](</e:/Source_code/Claude-code-bast/src/assistant/AssistantSessionChooser.ts:1>)
[src/commands/assistant/assistant.ts](</e:/Source_code/Claude-code-bast/src/commands/assistant/assistant.ts:7>)
[src/assistant/index.ts](</e:/Source_code/Claude-code-bast/src/assistant/index.ts:1>)
### 目标
- 不一次性恢复整个 KAIROS 助手系统。
- 先做“明确 sessionId 的 viewer attach 可用”,再逐步补 discovery / chooser / install。
### Phase 4AMVP
- 只支持 `claude assistant <sessionId>`
-`claude assistant` 无参数模式,先返回明确提示:
- 当前版本需要显式 `sessionId`
- discovery 尚未启用
- 这样可以直接复用现有 attach 分支,不必先恢复 chooser/install wizard
### Phase 4B
- 恢复 `discoverAssistantSessions()`
- 数据来源优先复用现有 sessions / bridge / teleport API而不是新协议
-`claude assistant` 无参数时能拿到候选 session 列表
### Phase 4C
- 恢复 `AssistantSessionChooser`
- 多 session 时可交互选择
### Phase 4D
- 最后考虑 install wizard 辅助函数
- 这部分属于“没有 session 时如何引导”,不是 attach 核心路径
### 为什么要拆
- attach 渲染层与远端消息通道大部分已经在
- 真正缺的是“如何发现目标 session”和“如何交互选择”
- 如果把 `src/assistant/index.ts` 的整套 KAIROS 正常模式也一起拉进来,范围会失控
### 代码范围
- Phase 4A
- [src/main.tsx](</e:/Source_code/Claude-code-bast/src/main.tsx:4708>)
- [src/commands/assistant/index.ts](</e:/Source_code/Claude-code-bast/src/commands/assistant/index.ts:1>)
- Phase 4B
- [src/assistant/sessionDiscovery.ts](</e:/Source_code/Claude-code-bast/src/assistant/sessionDiscovery.ts:1>)
- Phase 4C
- [src/assistant/AssistantSessionChooser.ts](</e:/Source_code/Claude-code-bast/src/assistant/AssistantSessionChooser.ts:1>)
- Phase 4D
- [src/commands/assistant/assistant.ts](</e:/Source_code/Claude-code-bast/src/commands/assistant/assistant.ts:7>)
### 验证
1. `claude assistant <sessionId>` 能进入 remote viewer
2. 历史懒加载工作正常
3. 无参数模式先给出明确提示
4. 后续阶段再分别验证 discovery / chooser / install
### 风险
- 这是四项里范围最大的
- 一旦把 KAIROS 正常模式整体拉入会从“viewer attach”膨胀成“完整 assistant mode 恢复”
### 工作量判断
- Phase 4A 中等
- 4A-4D 全做完很大
## 建议执行顺序
1. `claude daemon status` / `claude daemon stop`
2. `BG_SESSIONS` 先做 `ps/logs/kill`
3. `TEMPLATES` 先做 job 文件系统 MVP
4. `assistant [sessionId]` 先做显式 sessionId attach再补 discovery/chooser/install
## 简短结论
这四项里,最适合立刻实现的是 `daemon status/stop``BG_SESSIONS``TEMPLATES` 适合按 MVP 先补 handler 与文件系统闭环。`assistant [sessionId]` 不能整块硬上应该按“attach → discovery → chooser → install”拆开恢复。

View File

@@ -7,51 +7,13 @@
| Feature | 引用 | 状态 | 类别 | 简要说明 |
|---------|------|------|------|---------|
| CHICAGO_MCP | 16 | N/A | 内部基础设施 | Anthropic 内部 MCP 基础设施,非外部可用 |
| UDS_INBOX | 17 | Stub | 消息通信 | Unix 域套接字对等消息,进程间消息传递 |
| MONITOR_TOOL | 13 | Stub | 工具 | 文件/进程监控工具,检测变更并通知 |
| BG_SESSIONS | 11 | Stub | 会话管理 | 后台会话管理,支持多会话并行 |
| SHOT_STATS | 10 | 实现 | 统计 | 逐 prompt 统计信息收集 |
| EXTRACT_MEMORIES | 7 | 实现 | 记忆 | 自动从对话中提取重要信息作为记忆 |
| TEMPLATES | 6 | Stub | 项目管理 | 项目/提示模板系统 |
| LODESTONE | 6 | N/A | 内部基础设施 | 内部基础设施模块 |
| STREAMLINED_OUTPUT | 1 | — | 输出 | 精简输出模式,减少终端输出量 |
| HOOK_PROMPTS | 1 | — | 钩子 | Hook 提示词,自定义钩子的提示注入 |
| CCR_AUTO_CONNECT | 3 | — | 远程控制 | CCR 自动连接,自动建立远程控制会话 |
| CCR_MIRROR | 4 | — | 远程控制 | CCR 镜像模式,会话状态同步 |
| CCR_REMOTE_SETUP | 1 | — | 远程控制 | CCR 远程设置,初始化远程控制配置 |
| NATIVE_CLIPBOARD_IMAGE | 2 | — | 系统集成 | 原生剪贴板图片,从剪贴板读取图片 |
| CONNECTOR_TEXT | 7 | — | 连接器 | 连接器文本,外部系统文本适配 |
| COMMIT_ATTRIBUTION | 12 | — | Git | Commit 归因,标记 commit 来源 |
| CACHED_MICROCOMPACT | 12 | — | 压缩 | 缓存微压缩,优化 compaction 性能 |
| PROMPT_CACHE_BREAK_DETECTION | 9 | — | 性能 | Prompt cache 中断检测,监控 cache miss |
| MEMORY_SHAPE_TELEMETRY | 3 | — | 遥测 | 记忆形态遥测,记忆使用模式追踪 |
| MCP_RICH_OUTPUT | 3 | — | MCP | MCP 富输出,增强 MCP 工具输出格式 |
| FILE_PERSISTENCE | 3 | — | 持久化 | 文件持久化,跨会话保持状态 |
| TREE_SITTER_BASH_SHADOW | 5 | Shadow | 安全 | Bash AST Shadow 模式(见 tree-sitter-bash.md |
| QUICK_SEARCH | 5 | — | 搜索 | 快速搜索,优化的文件/内容搜索 |
| MESSAGE_ACTIONS | 5 | — | UI | 消息操作,对消息执行后处理动作 |
| DOWNLOAD_USER_SETTINGS | 5 | — | 配置 | 下载用户设置,从服务端同步配置 |
| DIRECT_CONNECT | 5 | — | 网络 | 直连模式,绕过代理直接连接 API |
| VERIFICATION_AGENT | 4 | — | Agent | 验证 Agent专门用于验证代码变更 |
| TERMINAL_PANEL | 4 | — | UI | 终端面板,嵌入式终端输出显示 |
| SSH_REMOTE | 4 | — | 远程 | SSH 远程,通过 SSH 连接远程 Claude |
| REVIEW_ARTIFACT | 4 | — | 审查 | Review Artifact代码审查产出物 |
| REACTIVE_COMPACT | 4 | — | 压缩 | 响应式压缩,基于上下文变化触发 compaction |
| HISTORY_PICKER | 4 | — | UI | 历史选择器,浏览和选择历史对话 |
| UPLOAD_USER_SETTINGS | 2 | — | 配置 | 上传用户设置,同步配置到服务端 |
| POWERSHELL_AUTO_MODE | 2 | — | 平台 | PowerShell 自动模式Windows 权限自动化 |
| OVERFLOW_TEST_TOOL | 2 | — | 测试 | 溢出测试工具,测试上下文溢出处理 |
| NEW_INIT | 2 | — | 初始化 | 新版初始化流程 |
| HARD_FAIL | 2 | — | 错误处理 | 硬失败模式,不可恢复错误直接终止 |
| ENHANCED_TELEMETRY_BETA | 2 | — | 遥测 | 增强遥测 Beta详细的性能指标收集 |
| COWORKER_TYPE_TELEMETRY | 2 | — | 遥测 | 协作者类型遥测,追踪协作模式 |
| BREAK_CACHE_COMMAND | 2 | — | 缓存 | 中断缓存命令,强制刷新 prompt cache |
| AWAY_SUMMARY | 2 | — | 摘要 | 离开摘要,用户返回时总结期间工作 |
| AUTO_THEME | 2 | — | UI | 自动主题,根据终端设置切换主题 |
| ALLOW_TEST_VERSIONS | 2 | — | 版本 | 允许测试版本,跳过版本检查 |
| AGENT_TRIGGERS_REMOTE | 2 | — | Agent | Agent 远程触发,从远程触发 Agent 任务 |
| AGENT_MEMORY_SNAPSHOT | 2 | — | Agent | Agent 记忆快照,保存/恢复 Agent 状态 |
| CHICAGO_MCP | 16 | 已实现 | 工具 | Computer Use + Chrome MCP 控制build 默认启用) |
| MONITOR_TOOL | 13 | 已实现 | 工具 | 后台监控工具,持续监视 shell 输出build 默认启用) |
| BG_SESSIONS | 11 | 部分实现 | 会话管理 | 后台会话注册/清理已实现,任务摘要是 stubdev 默认启用) |
| SHOT_STATS | 10 | 已实现 | 统计 | API 调用统计面板build 默认启用) |
| EXTRACT_MEMORIES | 7 | 实现 | 记忆 | 自动记忆提取build 默认启用,受 GrowthBook 门控) |
| TEMPLATES | 6 | 部分实现 | 项目管理 | 项目/提示模板系统dev 默认启用) |
| LODESTONE | 6 | 已实现 | 深度链接 | URL 协议处理器build 默认启用) |
## 单引用 Feature40+ 个)
@@ -67,10 +29,9 @@ BUILDING_CLAUDE_APPS, ANTI_DISTILLATION_CC, AGENT_TRIGGERS, ABLATION_BASELINE
这些 feature 被列为 Tier 3 的原因:
1. **内部基础设施**CHICAGO_MCP, LODESTONEAnthropic 内部使用,外部无法运行
2. **纯 Stub 且引用低**UDS_INBOX, MONITOR_TOOL, BG_SESSIONS需要大量工作才能实现
3. **实验性功能**SHOT_STATS, EXTRACT_MEMORIES尚在概念阶段
4. **辅助功能**STREAMLINED_OUTPUT, HOOK_PROMPTS影响范围小
5. **CCR 系列**:依赖远程控制基础设施,需要 BRIDGE_MODE 先完善
1. **已实现但影响范围小**CHICAGO_MCP, LODESTONE, SHOT_STATS, EXTRACT_MEMORIES, MONITOR_TOOL已在 build/dev 默认启用,主要作为其他功能的基础设施
2. **部分实现**BG_SESSIONS, TEMPLATES核心注册已实现但部分功能如任务摘要仍是 stub
3. **辅助功能**STREAMLINED_OUTPUT, HOOK_PROMPTS影响范围小
4. **CCR 系列**:依赖远程控制基础设施,需要 BRIDGE_MODE 先完善
如需深入了解某个 Tier 3 feature可以在代码库中搜索 `feature('FEATURE_NAME')` 查看具体使用场景。

View File

@@ -191,7 +191,7 @@ FEATURE_TOKEN_BUDGET=1 bun run dev
| `src/query/tokenBudget.ts` | 93 | 预算追踪器 + continue/stop 决策 |
| `src/bootstrap/state.ts:724-743` | 20 | turn 级 token 快照状态 |
| `src/constants/prompts.ts:538-551` | 14 | 系统提示注入 |
| `src/utils/attachments.ts:3829-3845` | 17 | API attachment 附加 |
| `src/utils/attachments.ts:3830-3844` | 17 | API attachment 附加 |
| `src/query.ts:280,1311-1358` | 48 | 主循环集成 |
| `src/screens/REPL.tsx:2897,2963,2138` | 20 | REPL 提交/完成/取消处理 |
| `src/components/Spinner.tsx:319-338` | 20 | 进度条 UI |

View File

@@ -158,4 +158,4 @@ FEATURE_TREE_SITTER_BASH_SHADOW=1 bun run dev
| `src/utils/bash/bashParser.ts` | 4437 | 纯 TS bash 解析器 |
| `src/utils/bash/ast.ts` | 2680 | 安全分析器(核心) |
| `src/utils/bash/treeSitterAnalysis.ts` | 507 | AST 分析辅助 |
| `src/tools/BashTool/bashPermissions.ts:1670-1810` | ~140 | 权限集成 + Shadow 遥测 |
| `packages/builtin-tools/src/tools/BashTool/bashPermissions.ts` | ~140 | 权限集成 + Shadow 遥测 |

114
docs/features/uds-inbox.md Normal file
View File

@@ -0,0 +1,114 @@
# UDS_INBOX / pipes
## 概述
`UDS_INBOX` 现在不是一个“空壳 flag”而是一套已经落地的本机 IPC 能力。但它同时承载了两层不同目标,必须拆开理解:
1. **UDS peer messaging**
- 面向任意 Claude Code 进程。
- 使用 `src/utils/udsMessaging.ts``src/utils/udsClient.ts`
- 对外入口是 `/peers``SendMessageTool``uds:<socket-path>` 地址。
2. **pipes control plane**
- 面向交互式 REPL 会话之间的主从协作。
- 使用 `src/utils/pipeTransport.ts``src/utils/pipeRegistry.ts``src/screens/REPL.tsx` 中的内联 bootstrap。
- 对外入口是 `/pipes``/attach``/detach``/send``/pipe-status``/history``/claim-main`
这两层都依赖本机 socket但职责不同。`/peers` 解决“找到其他会话并发消息”,`/pipes` 解决“把一个 REPL 变成另一个 REPL 的受控 worker”。
## 为什么要有单独的 `pipes`
单独的 `pipes` 层有三个实际理由:
1. **命名与角色模型不同**
- UDS peer 层按 `messagingSocketPath` 寻址。
- pipes 层按 `cli-xxxxxxxx` 会话名、`main/sub/master/slave` 角色和 `machineId` 注册表工作。
2. **交互语义不同**
- peer 层是通用消息投递。
- pipes 层需要 attach、detach、历史收集、选择性广播、状态栏和 REPL 快捷键。
3. **UI 集成不同**
- peer 层主要服务工具调用。
- pipes 层直接影响 REPL 提交路径和 PromptInput 页脚。
如果把两者硬合并,`SendMessageTool` 的通用寻址和 REPL 的主从控制会互相污染,命令语义也会变得混乱。
## 当前通信模型
### 1. UDS peer messaging
- 服务端:`src/utils/udsMessaging.ts`
- 客户端:`src/utils/udsClient.ts`
- 发现方式:读取 `~/.claude/sessions/*.json`
- 地址方式:`uds:<socket-path>`
- 传输方式:**本机 Unix socket / Windows named pipe**
这层是真正的“通用收件箱”。
### 2. pipes control plane
- 服务端/客户端:`src/utils/pipeTransport.ts`
- 注册表:`src/utils/pipeRegistry.ts`
- 生效入口:`src/screens/REPL.tsx`
- 发现方式:扫描 `~/.claude/pipes/` + `registry.json`
- 会话名:`cli-${sessionId.slice(0, 8)}`
- 传输方式:**本机 Unix socket / Windows named pipe**
这层是真正的“主从 REPL 协调平面”。
## 关于“局域网通信”的事实
当前实现**不是**真正的局域网传输。
代码里虽然保存了这些字段:
- `localIp`
- `hostname`
- `machineId`
- `mac`
但这些字段当前只用于:
1. 注册表展示
2. main/sub 身份判定
3. `claim-main` 的机器级归属切换
4. 状态输出与排障信息
它们**没有**被用于创建 TCP/WebSocket 连接。真正的传输仍然是 `getPipePath(name)` 返回的本机 socket 路径。
所以目前更准确的描述应该是:
- `pipes` 支持 **本机多实例协作**
- `registry` 带有 **机器身份元数据**
-**尚未实现跨机器局域网 transport**
如果未来要做真局域网版本,至少还需要:
1. TCP/WebSocket transport
2. 认证与会话授权
3. 发现与地址交换
4. 超时、重连和安全边界
## 当前 REPL 行为
当前线上行为由 `src/screens/REPL.tsx` 的内联实现负责:
1. 启动时创建当前 REPL 的 pipe server
2. 通过 `pipeRegistry` 判定 `main` / `sub`
3. 处理 `attach_request` / `detach` / `prompt`
4. 主实例心跳探测并维护 `slaves`
5. `/pipes` 打开状态栏并维护选择器
6. 提交普通消息时,仅向**已连接**的 selected pipes 广播
最近的收敛点:
- 过去遗留了一套未接线的 hook 方案
- 当前已明确以 `REPL.tsx` 内联 bootstrap 为唯一生效实现
- 选中但未连接的 pipe 不再导致本地处理被错误跳过
## 文档与代码对齐约定
后续关于 `UDS_INBOX` / `pipes` 的说明应遵守以下表述:
1. 默认称为“本机 IPC / 本机多实例协作”
2. 不把 `localIp` / `hostname` 元数据表述成已完成的 LAN transport
3. 明确区分 `/peers``/pipes` 的两层职责
4.`src/screens/REPL.tsx``src/utils/pipeTransport.ts``src/utils/pipeRegistry.ts` 为事实来源

View File

@@ -22,16 +22,16 @@ ULTRAPLAN 在用户输入中检测 "ultraplan" 关键字时,自动进入增强
| 模块 | 文件 | 行数 | 状态 |
|------|------|------|------|
| 命令处理器 | `src/commands/ultraplan.tsx` | 472 | **完整** |
| CCR 会话 | `src/utils/ultraplan/ccrSession.ts` | 350 | **完整** |
| 关键字检测 | `src/utils/ultraplan/keyword.ts` | 128 | **完整** |
| 命令处理器 | `src/commands/ultraplan.tsx` | 525 | **完整** |
| CCR 会话 | `src/utils/ultraplan/ccrSession.ts` | 349 | **完整** |
| 关键字检测 | `src/utils/ultraplan/keyword.ts` | 127 | **完整** |
| 嵌入式提示 | `src/utils/ultraplan/prompt.txt` | 1 | **完整** |
| REPL 对话框 | `src/screens/REPL.tsx` | — | **布线** |
| 关键字高亮 | `src/components/PromptInput/PromptInput.tsx` | — | **布线** |
### 2.2 关键字检测
文件:`src/utils/ultraplan/keyword.ts`128 行)
文件:`src/utils/ultraplan/keyword.ts`127 行)
`findUltraplanTriggerPositions(text)` 智能过滤:
- 排除引号内的 "ultraplan"
@@ -41,7 +41,7 @@ ULTRAPLAN 在用户输入中检测 "ultraplan" 关键字时,自动进入增强
### 2.3 CCR 远程会话
文件:`src/utils/ultraplan/ccrSession.ts`350 行)
文件:`src/utils/ultraplan/ccrSession.ts`349 行)
`ExitPlanModeScanner` 类实现完整的事件状态机:
- `pollForApprovedExitPlanMode()` — 3 秒轮询间隔
@@ -99,9 +99,9 @@ FEATURE_ULTRAPLAN=1 bun run dev
| 文件 | 行数 | 职责 |
|------|------|------|
| `src/commands/ultraplan.tsx` | 472 | 斜杠命令处理器 |
| `src/utils/ultraplan/ccrSession.ts` | 350 | CCR 远程会话管理 |
| `src/utils/ultraplan/keyword.ts` | 128 | 关键字检测和替换 |
| `src/commands/ultraplan.tsx` | 525 | 斜杠命令处理器 |
| `src/utils/ultraplan/ccrSession.ts` | 349 | CCR 远程会话管理 |
| `src/utils/ultraplan/keyword.ts` | 127 | 关键字检测和替换 |
| `src/utils/ultraplan/prompt.txt` | 1 | 嵌入式提示 |
| `src/utils/processUserInput/processUserInput.ts:468` | — | 关键字重定向 |
| `src/components/PromptInput/PromptInput.tsx` | — | 彩虹高亮 |

View File

@@ -1,27 +1,32 @@
# VOICE_MODE — 语音输入
> Feature Flag: `FEATURE_VOICE_MODE=1`
> 实现状态:完整可用(需要 Anthropic OAuth
> 实现状态:完整可用(双后端:Anthropic OAuth / 豆包 ASR
> 引用数46
## 一、功能概述
VOICE_MODE 实现"按键说话"Push-to-Talk语音输入。用户按住空格键录音音频通过 WebSocket 流式传输到 Anthropic STT 端点Nova 3,实时转录显示在终端中。
VOICE_MODE 实现"按键说话"Push-to-Talk语音输入。用户按住空格键录音音频流式传输到 STT 后端,实时转录显示在终端中。支持两个后端:
- **Anthropic STT默认**:通过 WebSocket 流式传输到 Nova 3 端点,需要 Anthropic OAuth
- **豆包 ASRDoubao**:通过 `doubaoime-asr` 包的 AsyncGenerator 协议流式识别,使用独立凭证文件,无需 Anthropic OAuth
### 核心特性
- **Push-to-Talk**:长按空格键录音,释放后自动发送
- **流式转录**:录音过程中实时显示中间转录结果
- **无缝集成**:转录文本直接作为用户消息提交到对话
- **双后端切换**:通过 `/voice` 命令参数选择 STT 后端,持久化到 settings.json
## 二、用户交互
| 操作 | 行为 |
|------|------|
| 长按空格 | 开始录音,显示录音状态 |
| 释放空格 | 停止录音,等待最终转录 |
| 转录完成 | 自动插入到输入框并提交 |
| `/voice` 命令 | 切换语音模式开关 |
| 释放空格 | 停止录音,转录结果自动提交 |
| `/voice` | 切换语音模式开关(默认使用 Anthropic 后端) |
| `/voice doubao` | 启用语音模式并使用豆包 ASR 后端 |
| `/voice anthropic` | 切换回 Anthropic STT 后端 |
### UI 反馈
@@ -35,26 +40,37 @@ VOICE_MODE 实现"按键说话"Push-to-Talk语音输入。用户按住空
文件:`src/voice/voiceModeEnabled.ts`
层检查:
层检查函数
```ts
// Anthropic 后端(需要 OAuth
isVoiceModeEnabled() = hasVoiceAuth() && isVoiceGrowthBookEnabled()
// 豆包后端 / 通用可用性检查(不需要 OAuth
isVoiceAvailable() = isVoiceGrowthBookEnabled()
```
1. **Feature Flag**`feature('VOICE_MODE')` — 编译时/运行时开关
2. **GrowthBook Kill-Switch**`!getFeatureValue_CACHED_MAY_BE_STALE('tengu_amber_quartz_disabled', false)` — 紧急关闭开关(默认 false = 未禁用)
3. **Auth 检查**`hasVoiceAuth()` — 需要 Anthropic OAuth token非 API key
3. **Auth 检查(仅 Anthropic**`hasVoiceAuth()` — 需要 Anthropic OAuth token非 API key
4. **Provider 检查**`voiceProvider` 设置决定使用哪个后端,豆包后端跳过 OAuth 检查
### 3.2 核心模块
| 模块 | 职责 |
|------|------|
| `src/voice/voiceModeEnabled.ts` | Feature flag + GrowthBook + Auth 三层门控 |
| `src/hooks/useVoice.ts` | React hook 管理录音状态和 WebSocket 连接 |
| `src/services/voiceStreamSTT.ts` | WebSocket 流式传输到 Anthropic STT |
| `src/hooks/useVoice.ts` | React hook 管理录音状态和后端连接 |
| `src/services/voiceStreamSTT.ts` | Anthropic WebSocket 流式 STT |
| `src/services/doubaoSTT.ts` | 豆包 ASR 适配器AsyncGenerator → VoiceStreamConnection |
| `src/commands/voice/voice.ts` | `/voice` 命令实现,处理后端选择和持久化 |
| `src/hooks/useVoiceEnabled.ts` | 语音启用状态 hook根据 provider 决定是否跳过 OAuth |
| `src/utils/settings/types.ts` | `voiceProvider: 'anthropic' | 'doubao'` 设置类型定义 |
### 3.3 数据流
#### Anthropic 后端
```
用户按下空格键
@@ -79,20 +95,108 @@ WebSocket 连接到 Anthropic STT 端点
转录文本 → 插入输入框 → 自动提交
```
#### 豆包 ASR 后端
```
用户按下空格键
useVoice hook 激活(检测到 voiceProvider === 'doubao'
macOS 原生音频 / SoX 开始录音
connectDoubaoStream() 创建 AudioChunkQueue + VoiceStreamConnection
├──→ onReady 立即触发(无需等待握手)
音频数据通过 AudioChunkQueue 传入 transcribeRealtime()
├──→ INTERIM_RESULT → 实时显示中间转录
├──→ FINAL_RESULT → 显示最终转录
用户释放空格键
finalize() 立即返回(豆包在录音过程中已返回结果,无需等待)
转录文本 → 插入输入框 → 自动提交
```
### 3.4 音频录制
支持两种音频后端:
支持两种音频后端(两个 STT 后端共享)
- **macOS 原生音频**:优先使用,低延迟
- **SoXSound eXchange**:回退方案,跨平台
音频流通过 WebSocket 发送到 Anthropic 的 Nova 3 STT 模型。
### 3.5 豆包 ASR 适配器设计
文件:`src/services/doubaoSTT.ts`
豆包后端使用适配器模式,将 `doubaoime-asr` 的 AsyncGenerator 协议桥接到 `VoiceStreamConnection` 接口:
**AudioChunkQueue** — push 式异步队列:
- 实现 `AsyncIterable<Uint8Array>` 接口
- `push(chunk)` 将音频数据入队,`push(null)` 发送结束信号
- 内部维护等待者waiting和缓冲队列chunks两个状态
**connectDoubaoStream()** — 连接入口:
- 动态导入 `doubaoime-asr`optionalDependencies
-`~/.claude/tts/doubao/credentials.json` 加载凭证
- 创建 AudioChunkQueue 和 VoiceStreamConnection
- 立即触发 `onReady`(避免与 useVoice 的音频缓冲死锁)
- `finalize()` 立即返回(豆包在录音过程中已返回结果)
- 后台 async IIFE 消费 `transcribeRealtime` generator映射响应类型到回调
**响应类型映射**
| doubaoime-asr ResponseType | 回调映射 |
|----------------------------|----------|
| SESSION_STARTED | 日志记录 |
| VAD_START | 日志记录 |
| INTERIM_RESULT | `onTranscript(text, false)` |
| FINAL_RESULT | `onTranscript(text, true)` |
| ERROR | `onError(errorMsg)` |
| SESSION_FINISHED | 日志记录 |
### 3.6 后端选择逻辑
文件:`src/hooks/useVoice.ts`
```ts
// 判断当前 provider
isDoubaoProvider() settings.voiceProvider
// handleKeyEvent 中的可用性检查
const sttAvailable = isDoubaoProvider()
? isDoubaoAvailableSync() // 乐观检查(首次返回 true
: isVoiceStreamAvailable() // Anthropic WebSocket 检查
// attemptConnect 中的连接函数选择
const connectFn = isDoubaoProvider()
? connectDoubaoStream
: connectVoiceStream
```
豆包后端的特殊处理:
- 跳过 `getVoiceKeyterms()` 调用(豆包无需关键词提示)
- 跳过 Focus Mode`if (!enabled || !focusMode || isDoubaoProvider())`
## 四、关键设计决策
1. **OAuth 独占**:语音模式使用 `voice_stream` 端点claude.ai仅 Anthropic OAuth 用户可用。API key、Bedrock、Vertex 用户无法使用
2. **GrowthBook 负向门控**`tengu_amber_quartz_disabled` 默认 `false`,新安装自动可用(无需等 GrowthBook 初始化)
3. **Keychain 缓存**`getClaudeAIOAuthTokens()` 首次调用访问 macOS keychain~20-50ms后续缓存命中
4. **独立于主 feature flag**`isVoiceGrowthBookEnabled()` 在 feature flag 关闭时短路返回 `false`,不触发任何模块加载
1. **双后端共存**:豆包后端作为独立适配器与 Anthropic 后端并存,不替换原有流程,通过 `voiceProvider` 设置切换
2. **设置持久化**`voiceProvider` 存储在 `settings.json`,通过 `/voice` 命令修改,跨会话生效
3. **OAuth 独占Anthropic**Anthropic 后端使用 `voice_stream` 端点claude.ai仅 OAuth 用户可用
4. **豆包无需 OAuth**:豆包后端使用独立凭证文件,不依赖 Anthropic 认证,通过 `isVoiceAvailable()` 放宽门控
5. **GrowthBook 负向门控**`tengu_amber_quartz_disabled` 默认 `false`,新安装自动可用
6. **onReady 立即触发**:豆包后端在连接建立后立即触发 `onReady`,避免与 useVoice 音频缓冲的时序死锁Anthropic 需要等待 WebSocket 握手)
7. **finalize() 立即返回**:豆包在录音过程中已返回所有结果,用户抬手时无需等待处理
8. **乐观可用性检查**`isDoubaoAvailableSync()` 在首次调用时返回 `true`,实际导入错误在 `connectDoubaoStream` 中处理
9. **optionalDependencies**`doubaoime-asr` 作为可选依赖,安装失败不影响 Anthropic 后端
## 五、使用方式
@@ -100,26 +204,60 @@ WebSocket 连接到 Anthropic STT 端点
# 启用 feature
FEATURE_VOICE_MODE=1 bun run dev
# 在 REPL 中使用
# 在 REPL 中使用 Anthropic 后端
# 1. 确保已通过 OAuth 登录claude.ai 订阅)
# 2. 按住空格键说话
# 3. 释放空格键等待转录
# 4. 或使用 /voice 命令切换开关
# 2. 输入 /voice 启用
# 3. 按住空格键说话
# 4. 释放空格键等待转录
# 在 REPL 中使用豆包 ASR 后端
# 1. 确保 doubaoime-asr 已安装bun add doubaoime-asr
# 2. 配置凭证文件:~/.claude/tts/doubao/credentials.json
# 3. 输入 /voice doubao 启用
# 4. 按住空格键说话
# 5. 释放空格键,转录结果即刻显示
# 切换后端
/voice doubao # 切换到豆包 ASR
/voice anthropic # 切换回 Anthropic STT
/voice # 关闭语音模式
```
### 豆包凭证配置
凭证文件路径:`~/.claude/tts/doubao/credentials.json`
```json
{
"deviceId": "...",
"installId": "...",
"cdid": "...",
"openudid": "...",
"clientudid": "...",
"token": "..."
}
```
## 六、外部依赖
| 依赖 | 说明 |
|------|------|
| Anthropic OAuth | claude.ai 订阅登录,非 API key |
| GrowthBook | `tengu_amber_quartz_disabled` 紧急关闭 |
| macOS 原生音频 或 SoX | 音频录制 |
| Nova 3 STT | 语音转文本模型 |
| 依赖 | 说明 | 适用后端 |
|------|------|----------|
| Anthropic OAuth | claude.ai 订阅登录,非 API key | Anthropic |
| GrowthBook | `tengu_amber_quartz_disabled` 紧急关闭 | 通用 |
| macOS 原生音频 或 SoX | 音频录制 | 通用 |
| Nova 3 STT | Anthropic 语音转文本模型 | Anthropic |
| doubaoime-asr | 豆包 ASR SDKoptionalDependencies | 豆包 |
| 凭证文件 | `~/.claude/tts/doubao/credentials.json` | 豆包 |
## 七、文件索引
| 文件 | 行数 | 职责 |
|------|------|------|
| `src/voice/voiceModeEnabled.ts` | 55 | 三层门控逻辑 |
| `src/hooks/useVoice.ts` | — | React hook录音状态 + WebSocket |
| `src/services/voiceStreamSTT.ts` | — | STT WebSocket 流式传输 |
| 文件 | 职责 |
|------|------|
| `src/voice/voiceModeEnabled.ts` | 三层门控逻辑 + `isVoiceAvailable()` |
| `src/hooks/useVoice.ts` | React hook录音状态 + 后端选择 + 连接管理 |
| `src/hooks/useVoiceEnabled.ts` | 语音启用状态 hook按 provider 决定 OAuth 检查) |
| `src/services/voiceStreamSTT.ts` | Anthropic STT WebSocket 流式传输 |
| `src/services/doubaoSTT.ts` | 豆包 ASR 适配器AudioChunkQueue + connectDoubaoStream |
| `src/commands/voice/voice.ts` | `/voice` 命令(开关 + 后端选择) |
| `src/commands/voice/index.ts` | 命令注册(去除 availability 限制) |
| `src/utils/settings/types.ts` | `voiceProvider` 类型定义 |

View File

@@ -1,7 +1,7 @@
# WEB_BROWSER_TOOL — 浏览器工具
> Feature Flag: `FEATURE_WEB_BROWSER_TOOL=1`
> 实现状态:核心实现缺失,面板为 Stub布线完整
> 实现状态:核心工具已实现,面板为 Stub布线完整
> 引用数4
## 一、功能概述
@@ -14,8 +14,8 @@ WEB_BROWSER_TOOL 让模型可以启动浏览器实例、导航网页、与页面
| 模块 | 文件 | 状态 |
|------|------|------|
| 浏览器面板 | `src/tools/WebBrowserTool/WebBrowserPanel.ts` | **Stub** — 返回 null |
| 浏览器工具 | `src/tools/WebBrowserTool/WebBrowserTool.ts` | **缺失** |
| 浏览器面板 | `packages/builtin-tools/src/tools/WebBrowserTool/WebBrowserPanel.ts` | **Stub** — 返回 null |
| 浏览器工具 | `packages/builtin-tools/src/tools/WebBrowserTool/WebBrowserTool.ts` | **已实现** |
| REPL 集成 | `src/screens/REPL.tsx` | **布线** — 渲染 WebBrowserPanel |
| 工具注册 | `src/tools.ts` | **布线** — 动态加载 |
| WebView 检测 | `src/main.tsx` | **布线**`'WebView' in Bun` 检测 |
@@ -44,8 +44,8 @@ WebBrowserPanel 在 REPL 侧边显示浏览器状态
| 模块 | 工作量 | 说明 |
|------|--------|------|
| `WebBrowserTool.ts` | | 工具 schema + Bun WebView API 执行 |
| `WebBrowserPanel.tsx` | 中 | REPL 侧边栏浏览器状态面板 |
| `WebBrowserTool.ts` | ✅ 已实现 | 工具 schema + Bun WebView API 执行 |
| `WebBrowserPanel.tsx` | 中 | REPL 侧边栏浏览器状态面板(仍为 Stub |
## 四、关键设计决策
@@ -63,7 +63,7 @@ FEATURE_WEB_BROWSER_TOOL=1 bun run dev
| 文件 | 职责 |
|------|------|
| `src/tools/WebBrowserTool/WebBrowserPanel.ts` | 面板组件stub |
| `src/tools/WebBrowserTool/WebBrowserTool.ts` | 工具实现(缺失 |
| `src/screens/REPL.tsx:273,4582` | 面板渲染 |
| `packages/builtin-tools/src/tools/WebBrowserTool/WebBrowserPanel.ts` | 面板组件stub |
| `packages/builtin-tools/src/tools/WebBrowserTool/WebBrowserTool.ts` | 工具实现(已实现 |
| `src/screens/REPL.tsx:471,5676` | 面板渲染 |
| `src/tools.ts:115-116` | 工具注册 |

View File

@@ -1,11 +1,11 @@
# WEB_SEARCH_TOOL — 网页搜索工具
> 实现状态:适配器架构完成,Bing 适配器为当前默认后端
> 实现状态:适配器架构完成,支持 API / Bing / Brave 三种后端
> 引用数:核心工具,无 feature flag 门控(始终启用)
## 一、功能概述
WebSearchTool 让模型可以搜索互联网获取最新信息。原始实现仅支持 Anthropic API 服务端搜索(`web_search_20250305` server tool在第三方代理端点下不可用。现已重构为适配器架构新增 Bing 搜索页面解析作为 fallback,确保任何 API 端点都能使用搜索功能。
WebSearchTool 让模型可以搜索互联网获取最新信息。原始实现仅支持 Anthropic API 服务端搜索(`web_search_20250305` server tool在第三方代理端点下不可用。现已重构为适配器架构支持 API 服务端搜索,以及 Bing / Brave 两个 HTML 解析后端,确保任何 API 端点都能使用搜索功能。
## 二、实现架构
@@ -21,24 +21,29 @@ WebSearchTool.call()
│ └── 使用 web_search_20250305 server tool
│ 通过 queryModelWithStreaming 二次调用 API
── BingSearchAdapter — Bing HTML 抓取 + 正则提取(当前默认)
└── 直接抓取 Bing 搜索页 HTML
正则提取 b_algo 块中的标题/URL/摘要
── BingSearchAdapter — Bing HTML 抓取 + 正则提取
└── 直接抓取 Bing 搜索页 HTML
正则提取 b_algo 块中的标题/URL/摘要
└── BraveSearchAdapter — Brave LLM Context API
└── 调用 Brave HTTPS GET 接口
将 grounding payload 映射为标题/URL/摘要
```
### 2.2 模块结构
| 模块 | 文件 | 说明 |
|------|------|------|
| 工具入口 | `src/tools/WebSearchTool/WebSearchTool.ts` | `buildTool()` 定义schema、权限、执行、输出格式化 |
| 工具 prompt | `src/tools/WebSearchTool/prompt.ts` | 搜索工具的系统提示词 |
| UI 渲染 | `src/tools/WebSearchTool/UI.tsx` | 搜索结果的终端渲染组件 |
| 适配器接口 | `src/tools/WebSearchTool/adapters/types.ts` | `WebSearchAdapter` 接口、`SearchResult`/`SearchOptions`/`SearchProgress` 类型 |
| 适配器工厂 | `src/tools/WebSearchTool/adapters/index.ts` | `createAdapter()` 工厂函数,选择后端 |
| API 适配器 | `src/tools/WebSearchTool/adapters/apiAdapter.ts` | 封装原有 `queryModelWithStreaming` 逻辑,使用 server tool |
| Bing 适配器 | `src/tools/WebSearchTool/adapters/bingAdapter.ts` | Bing HTML 抓取 + 正则解析 |
| 单元测试 | `src/tools/WebSearchTool/__tests__/bingAdapter.test.ts` | 32 个测试用例 |
| 集成测试 | `src/tools/WebSearchTool/__tests__/bingAdapter.integration.ts` | 真实网络请求验证 |
| 工具入口 | `packages/builtin-tools/src/tools/WebSearchTool/WebSearchTool.ts` | `buildTool()` 定义schema、权限、执行、输出格式化 |
| 工具 prompt | `packages/builtin-tools/src/tools/WebSearchTool/prompt.ts` | 搜索工具的系统提示词 |
| UI 渲染 | `packages/builtin-tools/src/tools/WebSearchTool/UI.tsx` | 搜索结果的终端渲染组件 |
| 适配器接口 | `packages/builtin-tools/src/tools/WebSearchTool/adapters/types.ts` | `WebSearchAdapter` 接口、`SearchResult`/`SearchOptions`/`SearchProgress` 类型 |
| 适配器工厂 | `packages/builtin-tools/src/tools/WebSearchTool/adapters/index.ts` | `createAdapter()` 工厂函数,选择后端 |
| API 适配器 | `packages/builtin-tools/src/tools/WebSearchTool/adapters/apiAdapter.ts` | 封装原有 `queryModelWithStreaming` 逻辑,使用 server tool |
| Bing 适配器 | `packages/builtin-tools/src/tools/WebSearchTool/adapters/bingAdapter.ts` | Bing HTML 抓取 + 正则解析 |
| Brave 适配器 | `packages/builtin-tools/src/tools/WebSearchTool/adapters/braveAdapter.ts` | Brave LLM Context API 适配与结果映射 |
| 单元测试 | `packages/builtin-tools/src/tools/WebSearchTool/__tests__/bingAdapter.test.ts`, `packages/builtin-tools/src/tools/WebSearchTool/__tests__/braveAdapter*.test.ts`, `packages/builtin-tools/src/tools/WebSearchTool/__tests__/adapterFactory.test.ts` | Bing / Brave 解析与工厂逻辑测试 |
| 集成测试 | `packages/builtin-tools/src/tools/WebSearchTool/__tests__/bingAdapter.integration.ts`, `packages/builtin-tools/src/tools/WebSearchTool/__tests__/braveAdapter.integration.ts` | 真实网络请求验证 |
### 2.3 数据流
@@ -49,20 +54,18 @@ WebSearchTool.call()
validateInput() — 校验 query 非空、allowed/block 不共存
createAdapter() → BingSearchAdapter当前硬编码
createAdapter() → ApiSearchAdapter | BingSearchAdapter | BraveSearchAdapter
adapter.search(query, { allowedDomains, blockedDomains, signal, onProgress })
├── onProgress({ type: 'query_update', query })
├── axios.get(bing.com/search?q=...&setmkt=en-US)
│ └── 13 个 Edge 浏览器请求头
├── axios.get(search-engine-url)
│ └── API 鉴权请求头
├── extractBingResults(html) — 正则提取 <li class="b_algo"> 块
── resolveBingUrl() — 解码 base64 重定向 URL
│ ├── extractSnippet() — 三级降级摘要提取
│ └── decodeHtmlEntities() — he.decode
├── extractResults(payload) — 按后端提取结果
── grounding → SearchResult[] 映射
├── 客户端域名过滤 (allowedDomains / blockedDomains)
@@ -117,19 +120,18 @@ Bing 返回的重定向 URL 格式:`bing.com/ck/a?...&u=a1aHR0cHM6Ly9...`
## 四、适配器选择逻辑
当前 `createAdapter()` 硬编码返回 `BingSearchAdapter`,原逻辑已注释保留
`createAdapter()` 按以下优先级选择后端,并按选中的后端 key 缓存适配器实例
```typescript
export function createAdapter(): WebSearchAdapter {
return new BingSearchAdapter()
// 注释保留的选择逻辑:
// 1. WEB_SEARCH_ADAPTER 环境变量强制指定 api|bing
// 2. isFirstPartyAnthropicBaseUrl() → API 适配器
// 3. 第三方端点 → Bing 适配器
// 1. WEB_SEARCH_ADAPTER=api|bing|brave 显式指定
// 2. Anthropic 官方 API Base URL → ApiSearchAdapter
// 3. 第三方代理 / 非官方端点 → BingSearchAdapter
}
```
恢复自动选择:取消 `index.ts` 中的注释即可。
显式指定 `WEB_SEARCH_ADAPTER=brave` 时,会改用 Brave LLM Context API 后端,并要求
`BRAVE_SEARCH_API_KEY``BRAVE_API_KEY`
## 五、接口定义
@@ -174,13 +176,13 @@ interface SearchProgress {
| 文件 | 职责 |
|------|------|
| `src/tools/WebSearchTool/WebSearchTool.ts` | 工具定义入口 |
| `src/tools/WebSearchTool/prompt.ts` | 搜索工具 prompt |
| `src/tools/WebSearchTool/UI.tsx` | 终端 UI 渲染 |
| `src/tools/WebSearchTool/adapters/types.ts` | 适配器接口 |
| `src/tools/WebSearchTool/adapters/index.ts` | 适配器工厂 |
| `src/tools/WebSearchTool/adapters/apiAdapter.ts` | API 服务端搜索适配器 |
| `src/tools/WebSearchTool/adapters/bingAdapter.ts` | Bing HTML 解析适配器 |
| `src/tools/WebSearchTool/__tests__/bingAdapter.test.ts` | 单元测试 (32 cases) |
| `src/tools/WebSearchTool/__tests__/bingAdapter.integration.ts` | 集成测试 |
| `packages/builtin-tools/src/tools/WebSearchTool/WebSearchTool.ts` | 工具定义入口 |
| `packages/builtin-tools/src/tools/WebSearchTool/prompt.ts` | 搜索工具 prompt |
| `packages/builtin-tools/src/tools/WebSearchTool/UI.tsx` | 终端 UI 渲染 |
| `packages/builtin-tools/src/tools/WebSearchTool/adapters/types.ts` | 适配器接口 |
| `packages/builtin-tools/src/tools/WebSearchTool/adapters/index.ts` | 适配器工厂 |
| `packages/builtin-tools/src/tools/WebSearchTool/adapters/apiAdapter.ts` | API 服务端搜索适配器 |
| `packages/builtin-tools/src/tools/WebSearchTool/adapters/bingAdapter.ts` | Bing HTML 解析适配器 |
| `packages/builtin-tools/src/tools/WebSearchTool/__tests__/bingAdapter.test.ts` | 单元测试 (32 cases) |
| `packages/builtin-tools/src/tools/WebSearchTool/__tests__/bingAdapter.integration.ts` | 集成测试 |
| `src/tools.ts` | 工具注册 |

View File

@@ -14,17 +14,17 @@ WORKFLOW_SCRIPTS 实现基于文件的多步自动化工作流。用户可以定
| 模块 | 文件 | 状态 |
|------|------|------|
| WorkflowTool | `src/tools/WorkflowTool/WorkflowTool.ts` | **Stub**空对象 |
| Workflow 权限 | `src/tools/WorkflowTool/WorkflowPermissionRequest.ts` | **Stub**返回 null |
| 常量 | `src/tools/WorkflowTool/constants.ts` | **Stub**工具名 |
| 命令创建 | `src/tools/WorkflowTool/createWorkflowCommand.ts` | **Stub**空操作 |
| 捆绑工作流 | `src/tools/WorkflowTool/bundled/` | **缺失**目录不存在 |
| WorkflowTool | `packages/builtin-tools/src/tools/WorkflowTool/WorkflowTool.ts` | **部分实现**tool schema + 渲染完整call 返回运行时缺失提示 |
| Workflow 权限 | `packages/builtin-tools/src/tools/WorkflowTool/WorkflowPermissionRequest.tsx` | **部分实现**权限请求组件 |
| 常量 | `packages/builtin-tools/src/tools/WorkflowTool/constants.ts` | **实现** — 工具名 + 目录名 + 文件扩展名常量 |
| 命令创建 | `packages/builtin-tools/src/tools/WorkflowTool/createWorkflowCommand.ts` | **实现**扫描 .claude/workflows/ 目录创建 Command 对象 |
| 捆绑工作流 | `packages/builtin-tools/src/tools/WorkflowTool/bundled/index.ts` | **实现**内置工作流初始化 |
| 本地工作流任务 | `src/tasks/LocalWorkflowTask/LocalWorkflowTask.ts` | **Stub** — 类型 + 空操作 |
| UI 任务组件 | `src/components/tasks/src/tasks/LocalWorkflowTask/` | **Stub** — 空导出 |
| 详情对话框 | `src/components/tasks/WorkflowDetailDialog.ts` | **Stub** — 返回 null |
| 任务注册 | `src/tasks.ts` | **布线** — 动态加载 |
| 工具注册 | `src/tools.ts` | **布线**包含 bundled 工作流初始化 |
| 命令注册 | `src/commands.ts` | **布线**`/workflows` 命令 |
| 工具注册 | `src/tools.ts` | **布线**动态加载 + bundled 工作流初始化 (行 131-134,235) |
| 命令注册 | `src/commands.ts` | **布线**`/workflows` 命令 (行 93-95,395,460) |
### 2.2 预期数据流
@@ -69,13 +69,9 @@ steps:
| 优先级 | 模块 | 工作量 | 说明 |
|--------|------|--------|------|
| 1 | `WorkflowTool.ts` | 大 | Schema 定义 + 多步执行引擎 |
| 2 | `bundled/index.js` | | 内置工作流定义initBundledWorkflows |
| 3 | `createWorkflowCommand.ts` | 中 | 从文件解析创建命令对象 |
| 4 | `LocalWorkflowTask.ts` | 大 | 步骤协调、kill/skip/retry |
| 5 | `WorkflowDetailDialog.ts` | 中 | 进度详情 UI |
| 6 | `WorkflowPermissionRequest.ts` | 小 | 权限对话框 |
| 7 | `constants.ts` | 小 | 工具名常量 |
| 1 | `WorkflowTool.ts` call 方法 | 中 | 实际工作流执行逻辑(当前返回运行时缺失提示) |
| 2 | `LocalWorkflowTask.ts` | | 步骤协调、kill/skip/retry |
| 3 | `WorkflowDetailDialog.ts` | 中 | 进度详情 UI |
## 四、关键设计决策
@@ -95,11 +91,12 @@ FEATURE_WORKFLOW_SCRIPTS=1 bun run dev
| 文件 | 职责 |
|------|------|
| `src/tools/WorkflowTool/WorkflowTool.ts` | 工具定义(stub |
| `src/tools/WorkflowTool/WorkflowPermissionRequest.ts` | 权限对话框stub |
| `src/tools/WorkflowTool/constants.ts` | 常量stub |
| `src/tools/WorkflowTool/createWorkflowCommand.ts` | 命令创建(stub |
| `packages/builtin-tools/src/tools/WorkflowTool/WorkflowTool.ts` | 工具定义(部分实现 |
| `packages/builtin-tools/src/tools/WorkflowTool/WorkflowPermissionRequest.tsx` | 权限请求组件 |
| `packages/builtin-tools/src/tools/WorkflowTool/constants.ts` | 常量定义 |
| `packages/builtin-tools/src/tools/WorkflowTool/createWorkflowCommand.ts` | 命令创建(已实现 |
| `packages/builtin-tools/src/tools/WorkflowTool/bundled/index.ts` | 内置工作流初始化 |
| `src/tasks/LocalWorkflowTask/LocalWorkflowTask.ts` | 任务协调stub |
| `src/components/tasks/WorkflowDetailDialog.ts` | 详情对话框stub |
| `src/tools.ts:127-132` | 工具注册 |
| `src/commands.ts:86-89` | 命令注册 |
| `src/tools.ts:131-134,235` | 工具注册 |
| `src/commands.ts:93-95,395,460` | 命令注册 |

View File

@@ -17,7 +17,7 @@ keywords: ["Ant 特权", "USER_TYPE", "身份门控", "内部功能", "Anthropic
`BUILD_TARGET` 等构建时常量在反编译版本中已被移除。`USER_TYPE` 通过 Bun 的 `--define` 或环境变量注入Bun 会进行**常量折叠**——所有 `process.env.USER_TYPE === 'ant'` 在外部构建中直接变为 `false`,后续代码被 DCE 移除。但在反编译版本中,这些代码保留完整。
`USER_TYPE === 'ant'` 在代码库中出现 **377+ 次**含 `=== 'ant'` 291 次、`(process.env.USER_TYPE) === 'ant'` 86 次),另有 `!== 'ant'` 53、其他引用约 35 次,总计 **465 处引用**控制着工具、命令、API、UI 等方方面面。
`USER_TYPE === 'ant'` 在代码库中出现 **351+ 次**跨 163 个文件),另有 `!== 'ant'` 59(跨 38 个文件),总计 **410+ 处引用**控制着工具、命令、API、UI 等方方面面。
## Ant-Only 工具
@@ -25,10 +25,10 @@ keywords: ["Ant 特权", "USER_TYPE", "身份门控", "内部功能", "Anthropic
| 工具 | 代码位置 | 用途 |
|------|---------|------|
| **REPLTool** | `src/tools/REPLTool/` | 高级 REPL 模式——在 VM 中包装 Bash/Read/Edit/Glob/Grep/Agent 等工具 |
| **SuggestBackgroundPRTool** | `src/tools/SuggestBackgroundPRTool/` | 建议在后台创建 PR |
| **ConfigTool** | `src/tools/ConfigTool/` | 交互式配置编辑器,包含 Gates 标签页用于覆盖 GrowthBook flags |
| **TungstenTool** | `src/tools/TungstenTool/` | 基于 tmux 的终端面板工具(反编译版中已 stub |
| **REPLTool** | `packages/builtin-tools/src/tools/REPLTool/` | 高级 REPL 模式——在 VM 中包装 Bash/Read/Edit/Glob/Grep/Agent 等工具 |
| **SuggestBackgroundPRTool** | `packages/builtin-tools/src/tools/SuggestBackgroundPRTool/` | 建议在后台创建 PR |
| **ConfigTool** | `packages/builtin-tools/src/tools/ConfigTool/` | 交互式配置编辑器,包含 Gates 标签页用于覆盖 GrowthBook flags |
| **TungstenTool** | `packages/builtin-tools/src/tools/TungstenTool/` | 基于 tmux 的终端面板工具(反编译版中已 stub |
```typescript
// src/tools.ts 第 14-24 行——条件导入 + Dead Code Elimination 标记
@@ -36,18 +36,18 @@ keywords: ["Ant 特权", "USER_TYPE", "身份门控", "内部功能", "Anthropic
/* eslint-disable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */
const REPLTool =
process.env.USER_TYPE === 'ant'
? require('./tools/REPLTool/REPLTool.js').REPLTool
? require('@claude-code-best/builtin-tools/tools/REPLTool/REPLTool.js').REPLTool
: null
const SuggestBackgroundPRTool =
process.env.USER_TYPE === 'ant'
? require('./tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool.js')
? require('@claude-code-best/builtin-tools/tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool.js')
.SuggestBackgroundPRTool
: null
```
## Ant-Only 命令
`src/commands.ts` 注册了 **28** 个仅在内部构建中可用的斜杠命令(`INTERNAL_ONLY_COMMANDS`lines 225-254),在 `USER_TYPE === 'ant' && !IS_DEMO` 时才加载line 343-345
`src/commands.ts` 注册了 **24+** 个仅在内部构建中可用的斜杠命令(`INTERNAL_ONLY_COMMANDS`lines 267-295),在 `USER_TYPE === 'ant' && !IS_DEMO` 时才加载line 400-401
<AccordionGroup>
<Accordion title="调试类">
@@ -74,7 +74,7 @@ const SuggestBackgroundPRTool =
- `summary` — 生成摘要
- `subscribePr` — 订阅 PR需要 `KAIROS_GITHUB_WEBHOOKS` feature flag
- `forceSnip` — 强制截断历史(需要 `HISTORY_SNIP` feature flag
- `ultraplan` — 超级规划(需要 `ULTRAPLAN` feature flag
- `ultraplan` — 超级规划(需要 `ULTRAPLAN` feature flag,单独注册于 `commands.ts:396`
</Accordion>
<Accordion title="基础设施类">
- `backfillSessions` — 回填会话数据

View File

@@ -15,17 +15,19 @@ Claude Code 使用 Bun 打包器的 `bun:bundle` 模块提供编译时特性门
import { feature } from 'bun:bundle'
const SleepTool = feature('PROACTIVE') || feature('KAIROS')
? require('./tools/SleepTool/SleepTool.js').SleepTool
? require('@claude-code-best/builtin-tools/tools/SleepTool/SleepTool.js').SleepTool
: null
```
在 Anthropic 的内部构建中,`feature()` 在打包时被求值——返回 `true` 的代码会被保留,返回 `false` 的代码会被 **Dead Code Elimination (DCE)** 彻底移除。
在我们的反编译版本中,这个函数被兜底为
在我们的反编译版本中,`feature` 从 `bun:bundle` 导入(声明在 `src/types/internal-modules.d.ts`),在运行时始终返回 `false`
```typescript
// src/entrypoints/cli.tsx 第 3 行
const feature = (_name: string) => false;
// src/types/internal-modules.d.ts
declare module 'bun:bundle' {
export function feature(name: string): boolean;
}
```
这意味着所有 88+ 个 feature flag 后的代码**在运行时永远不会执行**,但代码本身完整保留,可以阅读和分析。
@@ -79,7 +81,7 @@ Feature flags 在代码中主要有三种使用模式:
```typescript
// src/tools.ts — 最常见的模式
const MonitorTool = feature('MONITOR_TOOL')
? require('./tools/MonitorTool/MonitorTool.js').MonitorTool
? require('@claude-code-best/builtin-tools/tools/MonitorTool/MonitorTool.js').MonitorTool
: null
```

View File

@@ -19,7 +19,7 @@ keywords: ["GrowthBook", "A/B 测试", "运行时门控", "tengu", "渐进式发
## 集成架构
GrowthBook 的完整实现位于 `src/services/analytics/growthbook.ts`1156 行),工作流程如下:
GrowthBook 的完整实现位于 `src/services/analytics/growthbook.ts`1258 行),工作流程如下:
<Steps>
<Step title="启动时获取远程配置">

View File

@@ -84,7 +84,7 @@ keywords: ["隐藏功能", "未公开功能", "秘密功能", "Claude Code 彩
<Accordion title="VOICE_MODE语音交互">
**门控**: `feature('VOICE_MODE')`
代码中存在语音输入模式的注册点,核心实现依赖 `audio-napi` 包(在反编译版本中已 stub
代码中存在语音输入模式的注册点,核心实现依赖 `audio-capture-napi` 包(已恢复
- 通过 `/voice` 命令激活
- "按住说话"hold-to-talk交互模式

View File

@@ -64,24 +64,27 @@ Claude Code 从上到下分为五个层次,每一层职责清晰、边界分
needsFollowUp ? continue : return { reason }
```
完整的状态机通过 `State` 类型(`src/query.ts:204`)在迭代间传递,包含 10 个字段messages、autoCompactTracking、maxOutputTokensRecoveryCount 等)。
完整的状态机通过 `State` 类型(`src/query.ts:207`)在迭代间传递,包含 10 个字段messages、autoCompactTracking、maxOutputTokensRecoveryCount 等)。
### 4. 工具层(`src/tools.ts` → `src/Tool.ts`
`getAllBaseTools()``src/tools.ts:191`)组装 50+ 工具列表,经过 `filterToolsByDenyRules()` 权限过滤后传给 API。
`getAllBaseTools()``src/tools.ts:195`)组装 50+ 工具列表,经过 `filterToolsByDenyRules()` 权限过滤后传给 API。
每个工具实现 `Tool<Input, Output, Progress>` 接口(`src/Tool.ts:362`),核心方法链:
每个工具实现 `Tool<Input, Output, Progress>` 接口(`src/Tool.ts:368`),核心方法链:
```
validateInput() → canUseTool()UI 层)→ checkPermissions() → call() → ToolResult
```
### 5. 通信层(`src/services/api/claude.ts`
API 客户端支持 4 种 Provider
- **Anthropic Direct**:默认
API 客户端支持 7 种 Provider
- **Anthropic Direct (firstParty)**:默认
- **AWS Bedrock**`ANTHROPIC_BEDROCK_BASE_URL`
- **Google Vertex**`ANTHROPIC_VERTEX_PROJECT_ID`
- **Azure**:通过自定义 base URL
- **Foundry**`ANTHROPIC_CODE_USE_FOUNDRY`
- **OpenAI**:兼容层
- **Gemini**:兼容层
- **Grok (xAI)**:兼容层
`deps.callModel()` 发起流式请求,返回 `BetaRawMessageStreamEvent` 事件流。支持 Prompt Cache`cache_control`、thinking blocks、multi-turn tool use。

View File

@@ -53,7 +53,7 @@ Claude Code 是一个**运行在本地终端中的 agentic coding system**。它
│ 实际执行: 读文件、运行命令、搜索代码... │
├─────────────────────────────────────────────────────────┤
│ 6. 通信层 (claude.ts → Anthropic API) │
│ 流式 HTTP, 支持 Bedrock/Vertex/Azure 多 provider │
│ 流式 HTTP, 支持 Bedrock/Vertex/Foundry 等 7 种 provider │
└─────────────────────────────────────────────────────────┘
```

View File

@@ -49,7 +49,7 @@ AI 没有真正的"记忆"Claude Code 通过精心分层营造了这个幻觉
### 3. 工具系统的权限双轨制
`src/tools/BashTool/shouldUseSandbox.ts` 展示了一个精巧的双重安全模型:
`packages/builtin-tools/src/tools/BashTool/shouldUseSandbox.ts` 展示了一个精巧的双重安全模型:
- **应用层**:权限规则决定"能不能执行"(白名单/黑名单/用户确认)
- **OS 层**:沙箱决定"执行时能做什么"(文件系统/网络/进程隔离)

View File

@@ -65,7 +65,7 @@ ENABLE_LSP_TOOL=1 bun run dev
```
┌─────────────────────────────────────────────────────┐
│ LSP Tool │
│ src/tools/LSPTool/LSPTool.ts
packages/builtin-tools/src/tools/LSPTool/LSPTool.ts│
│ (Claude 可调用的工具9 种操作) │
└──────────────────────┬──────────────────────────────┘
@@ -128,10 +128,10 @@ LSP 服务器会异步推送 `textDocument/publishDiagnostics` 通知,经去
| `src/services/lsp/config.ts` | 从插件加载 LSP 服务器配置 |
| `src/services/lsp/LSPDiagnosticRegistry.ts` | 诊断信息注册、去重、容量限制 |
| `src/services/lsp/passiveFeedback.ts` | 注册 `publishDiagnostics` 通知处理器 |
| `src/tools/LSPTool/LSPTool.ts` | LSP Tool 实现(暴露给 Claude |
| `src/tools/LSPTool/schemas.ts` | 输入 schema9 种操作的 discriminated union |
| `src/tools/LSPTool/formatters.ts` | 各操作结果的格式化 |
| `src/tools/LSPTool/prompt.ts` | Tool 描述文本 |
| `packages/builtin-tools/src/tools/LSPTool/LSPTool.ts` | LSP Tool 实现(暴露给 Claude |
| `packages/builtin-tools/src/tools/LSPTool/schemas.ts` | 输入 schema9 种操作的 discriminated union |
| `packages/builtin-tools/src/tools/LSPTool/formatters.ts` | 各操作结果的格式化 |
| `packages/builtin-tools/src/tools/LSPTool/prompt.ts` | Tool 描述文本 |
| `src/utils/plugins/lspPluginIntegration.ts` | 从插件加载、验证、环境变量解析、作用域管理 |
## LSP Tool 支持的操作

View File

@@ -1,190 +0,0 @@
# OpenAI兼容模型中task工具使用指南
## 问题描述
当使用OpenAI兼容模型如DeepSeek、Ollama、vLLM等调用task工具TaskGet、TaskCreate、TaskUpdate、TaskList可能会出现以下错误
```
Error: InputValidationError: TaskGet failed due to the following issues:
The required parameter `taskId` is missing
An unexpected parameter `task_id` was provided
This tool's schema was not sent to the API — it was not in the discovered-tool set derived from message history. Without the schema in your prompt, typed parameters (arrays, numbers, booleans) get emitted as strings and the client-side parser rejects them. Load the tool first: call ToolSearch with query "select:TaskGet", then retry this call.
```
## 问题原因
### 1. 延迟加载工具Deferred Tools
task工具都是延迟加载的`shouldDefer: true`),这意味着:
- 工具的模式schema不会在初始API调用中发送
- 需要先通过`ToolSearch`工具发现
- 只有在被发现后工具模式才会被发送给API
### 2. 参数名转换问题
- task工具使用驼峰命名`taskId`
- OpenAI兼容模型可能输出蛇形命名`task_id`
- 当工具模式没有被发送时,模型会猜测参数名,可能导致不匹配
## 解决方案
### 方案1先使用ToolSearch推荐
在使用task工具之前先调用`ToolSearch`工具:
```javascript
// 第一步发现task工具
ToolSearch("select:TaskGet,TaskCreate,TaskUpdate,TaskList")
// 第二步正常使用task工具
TaskCreate({ subject: "任务标题", description: "任务描述" })
TaskGet({ taskId: "1" })
TaskUpdate({ taskId: "1", status: "completed" })
TaskList()
```
### 方案2批量发现所有task工具
```javascript
// 一次性发现所有task工具
ToolSearch("select:TaskGet,TaskCreate,TaskUpdate,TaskList")
// 然后可以任意使用task工具
const task = await TaskCreate({ subject: "新任务", description: "任务描述" })
console.log(`创建的任务ID: ${task.id}`)
const taskList = await TaskList()
console.log(`当前有 ${taskList.tasks.length} 个任务`)
```
### 方案3单独发现特定工具
```javascript
// 只发现需要的工具
ToolSearch("select:TaskGet")
// 然后使用该工具
TaskGet({ taskId: "1" })
```
## 参数名注意事项
在使用OpenAI兼容模型时请注意参数名格式
### ✅ 正确(驼峰命名)
```javascript
TaskGet({ taskId: "1" })
TaskCreate({ subject: "标题", description: "描述" })
TaskUpdate({ taskId: "1", status: "completed" })
```
### ❌ 错误(蛇形命名)
```javascript
TaskGet({ task_id: "1" }) // 错误应该使用taskId
TaskCreate({ subject: "标题", description: "描述" }) // 正确
TaskUpdate({ task_id: "1", status: "completed" }) // 错误应该使用taskId
```
## 常见问题解答
### Q1: 为什么需要先使用ToolSearch
A: task工具是延迟加载的它们的模式只有在被`ToolSearch`工具发现后才会发送给API。没有工具模式模型无法知道正确的参数名和类型。
### Q2: 每次会话都需要使用ToolSearch吗
A: 是的每次新的会话都需要先使用ToolSearch发现工具。工具发现状态不会在会话之间保留。
### Q3: 使用Anthropic官方模型也需要这样吗
A: 通常不需要。Anthropic官方模型对延迟加载工具的处理更智能但为了兼容性建议在使用task工具前都先使用ToolSearch。
### Q4: 可以一次性发现所有工具吗?
A: 可以,使用`ToolSearch("select:TaskGet,TaskCreate,TaskUpdate,TaskList")`可以一次性发现所有task工具。
### Q5: 如果忘记使用ToolSearch会怎样
A: 会收到参数验证错误提示需要先使用ToolSearch。按照错误信息的指导操作即可。
## 最佳实践
1. **会话开始时发现工具**在开始使用task工具前先调用ToolSearch
2. **批量发现**一次性发现所有需要的task工具
3. **检查参数名**:确保使用正确的驼峰命名参数
4. **查看错误信息**:如果遇到错误,仔细阅读错误信息中的指导
## 示例工作流
```javascript
// 1. 开始新会话
// 2. 发现task工具
ToolSearch("select:TaskGet,TaskCreate,TaskUpdate,TaskList")
// 3. 创建任务
const newTask = await TaskCreate({
subject: "修复OpenAI兼容性问题",
description: "解决task工具在OpenAI兼容模型下的参数名问题"
})
// 4. 获取任务详情
const taskDetails = await TaskGet({ taskId: newTask.id })
// 5. 更新任务状态
await TaskUpdate({
taskId: newTask.id,
status: "in_progress",
activeForm: "修复OpenAI兼容性问题"
})
// 6. 查看所有任务
const allTasks = await TaskList()
console.log(`当前有 ${allTasks.tasks.length} 个任务`)
// 7. 完成任务
await TaskUpdate({
taskId: newTask.id,
status: "completed"
})
```
## 故障排除
### 错误:参数名不匹配
**症状**`taskId`参数缺失,发现`task_id`参数
**解决**:确保使用驼峰命名的`taskId`,而不是蛇形命名的`task_id`
### 错误:工具模式未发送
**症状**`This tool's schema was not sent to the API`
**解决**:先使用`ToolSearch("select:工具名")`发现工具
### 错误:工具不可用
**症状**:工具调用失败,没有具体错误信息
**解决**:检查工具是否启用(通过`isTodoV2Enabled()`),确保环境变量设置正确
## 相关配置
### 环境变量
```bash
# 启用OpenAI兼容模式
export CLAUDE_CODE_USE_OPENAI=1
export OPENAI_API_KEY=your-api-key
export OPENAI_BASE_URL=https://api.deepseek.com
# 配置模型映射
export OPENAI_DEFAULT_SONNET_MODEL=deepseek-chat
export OPENAI_DEFAULT_OPUS_MODEL=deepseek-chat
export OPENAI_DEFAULT_HAIKU_MODEL=deepseek-chat
```
### 设置文件
通过`/login`命令配置OpenAI兼容模式后设置会保存在`~/.claude/settings.json`
```json
{
"modelType": "openai",
"openai": {
"baseURL": "https://api.deepseek.com",
"apiKey": "your-api-key",
"models": {
"haiku": "deepseek-chat",
"sonnet": "deepseek-chat",
"opus": "deepseek-chat"
}
}
}
```
## 总结
在使用OpenAI兼容模型时task工具需要先通过`ToolSearch`发现才能正常使用。遵循"先发现,后使用"的原则并注意参数名的正确格式驼峰命名可以确保task工具在OpenAI兼容模型下正常工作。

View File

@@ -1,425 +0,0 @@
# OpenAI 协议兼容层
## 概述
claude-code 支持通过 OpenAI Chat Completions API`/v1/chat/completions`)兼容任意 OpenAI 协议端点,包括 Ollama、DeepSeek、vLLM、One API、LiteLLM 等。
核心策略为**流适配器模式**:在 `queryModel()` 中插入提前返回分支,将 Anthropic 格式请求转为 OpenAI 格式,调用 OpenAI SDK再将 SSE 流转换回 `BetaRawMessageStreamEvent` 格式。下游代码流处理循环、query.ts、QueryEngine.ts、REPL**完全不改**。
## 环境变量
| 变量 | 必需 | 说明 |
|---|---|---|
| `CLAUDE_CODE_USE_OPENAI` | 是 | 设为 `1` 启用 OpenAI 后端 |
| `OPENAI_API_KEY` | 是 | API keyOllama 等可设为任意值) |
| `OPENAI_BASE_URL` | 推荐 | 端点 URL`http://localhost:11434/v1` |
| `OPENAI_MODEL` | 可选 | 覆盖所有请求的模型名(跳过映射) |
| `OPENAI_DEFAULT_OPUS_MODEL` | 可选 | 覆盖 opus 家族对应的模型(如 `o3`, `o3-mini`, `o1-pro` |
| `OPENAI_DEFAULT_SONNET_MODEL` | 可选 | 覆盖 sonnet 家族对应的模型(如 `gpt-4o`, `gpt-4.1` |
| `OPENAI_DEFAULT_HAIKU_MODEL` | 可选 | 覆盖 haiku 家族对应的模型(如 `gpt-4o-mini`, `gpt-4.0-mini` |
| `OPENAI_ORG_ID` | 可选 | Organization ID |
| `OPENAI_PROJECT_ID` | 可选 | Project ID |
### 使用示例
```bash
# Ollama
CLAUDE_CODE_USE_OPENAI=1 \
OPENAI_API_KEY=ollama \
OPENAI_BASE_URL=http://localhost:11434/v1 \
OPENAI_MODEL=qwen2.5-coder-32b \
bun run dev
# DeepSeek自动支持 Thinking
CLAUDE_CODE_USE_OPENAI=1 \
OPENAI_API_KEY=sk-xxx \
OPENAI_BASE_URL=https://api.deepseek.com/v1 \
OPENAI_MODEL=deepseek-chat \
bun run dev
# vLLM
CLAUDE_CODE_USE_OPENAI=1 \
OPENAI_API_KEY=token-abc123 \
OPENAI_BASE_URL=http://localhost:8000/v1 \
OPENAI_MODEL=Qwen/Qwen2.5-Coder-32B-Instruct \
bun run dev
# One API / LiteLLM
CLAUDE_CODE_USE_OPENAI=1 \
OPENAI_API_KEY=sk-your-key \
OPENAI_BASE_URL=https://your-one-api.example.com/v1 \
OPENAI_MODEL=gpt-4o \
bun run dev
# 自定义模型映射(使用家族变量)
CLAUDE_CODE_USE_OPENAI=1 \
OPENAI_API_KEY=sk-xxx \
OPENAI_BASE_URL=https://my-gateway.example.com/v1 \
OPENAI_DEFAULT_SONNET_MODEL="gpt-4o-2024-11-20" \
OPENAI_DEFAULT_HAIKU_MODEL="gpt-4o-mini" \
bun run dev
```
## 架构
### 请求流程
```
queryModel() [claude.ts]
├── 共享预处理(消息归一化、工具过滤、媒体裁剪)
└── if (getAPIProvider() === 'openai')
└── queryModelOpenAI() [openai/index.ts]
├── resolveOpenAIModel() → 解析模型名
├── normalizeMessagesForAPI() → 共享消息预处理
├── toolToAPISchema() → 构建工具 schema
├── anthropicMessagesToOpenAI() → 消息格式转换
├── anthropicToolsToOpenAI() → 工具格式转换
├── openai.chat.completions.create({ stream: true })
└── adaptOpenAIStreamToAnthropic() → 流格式转换
├── delta.reasoning_content → thinking 块
├── delta.content → text 块
├── delta.tool_calls → tool_use 块
├── usage.cached_tokens → cache_read_input_tokens
└── yield BetaRawMessageStreamEvent
```
### 模型名解析优先级
`resolveOpenAIModel()` 的解析顺序:
1. `OPENAI_MODEL` 环境变量 → 直接使用,覆盖所有
2. `OPENAI_DEFAULT_{FAMILY}_MODEL` 变量(如 `OPENAI_DEFAULT_SONNET_MODEL`)→ 按模型家族覆盖
3. `ANTHROPIC_DEFAULT_{FAMILY}_MODEL` 变量(向后兼容)
4. 内置默认映射(见下表)
5. 以上都不匹配 → 原名透传
### 内置模型映射
| Anthropic 模型 | OpenAI 映射 |
|---|---|
| `claude-sonnet-4-6` | `gpt-4o` |
| `claude-sonnet-4-5-20250929` | `gpt-4o` |
| `claude-sonnet-4-20250514` | `gpt-4o` |
| `claude-3-7-sonnet-20250219` | `gpt-4o` |
| `claude-3-5-sonnet-20241022` | `gpt-4o` |
| `claude-opus-4-6` | `o3` |
| `claude-opus-4-5-20251101` | `o3` |
| `claude-opus-4-1-20250805` | `o3` |
| `claude-opus-4-20250514` | `o3` |
| `claude-haiku-4-5-20251001` | `gpt-4o-mini` |
| `claude-3-5-haiku-20241022` | `gpt-4o-mini` |
同时会自动剥离 `[1m]` 后缀Claude 特有的 modifier
## 文件结构
### 新增文件
```
src/services/api/openai/
├── client.ts # OpenAI SDK 客户端工厂(~50 行)
├── convertMessages.ts # Anthropic → OpenAI 消息格式转换(~190 行)
├── convertTools.ts # Anthropic → OpenAI 工具格式转换(~70 行)
├── streamAdapter.ts # SSE 流转换核心,含 thinking + caching~270 行)
├── modelMapping.ts # 模型名解析(~60 行)
├── index.ts # 公共入口 queryModelOpenAI()~110 行)
└── __tests__/
├── convertMessages.test.ts # 10 个测试
├── convertTools.test.ts # 7 个测试
├── modelMapping.test.ts # 6 个测试
└── streamAdapter.test.ts # 14 个测试(含 thinking + caching
```
### 修改文件
| 文件 | 改动 |
|---|---|
| `src/utils/model/providers.ts` | 添加 `'openai'` provider 类型 + `CLAUDE_CODE_USE_OPENAI` 检查(最高优先级) |
| `src/utils/model/configs.ts` | 每个 ModelConfig 添加 `openai` 键 |
| `src/services/api/claude.ts` | 在 `stripExcessMediaItems()` 后插入 OpenAI 提前返回分支(~8 行) |
| `package.json` | 添加 `"openai": "^4.73.0"` 依赖 |
## 消息转换规则
### Anthropic → OpenAI
| Anthropic | OpenAI |
|---|---|
| `system` prompt`string[]` | `role: "system"` 消息(`\n\n` 拼接) |
| `user` + `text` 块 | `role: "user"` 消息 |
| `assistant` + `text` 块 | `role: "assistant"` + `content` |
| `assistant` + `tool_use` 块 | `role: "assistant"` + `tool_calls[]` |
| `user` + `tool_result` 块 | `role: "tool"` + `tool_call_id` |
| `thinking` 块 | 静默丢弃(请求侧) |
### 工具转换
| Anthropic | OpenAI |
|---|---|
| `{ name, description, input_schema }` | `{ type: "function", function: { name, description, parameters } }` |
| `cache_control`, `defer_loading` 等字段 | 剥离 |
| `tool_choice: { type: "auto" }` | `"auto"` |
| `tool_choice: { type: "any" }` | `"required"` |
| `tool_choice: { type: "tool", name }` | `{ type: "function", function: { name } }` |
### 消息转换示例
```
Anthropic: OpenAI:
[
system: ["You are helpful."], [
{ role: "system",
{ role: "user", content: "You are helpful." },
content: [ { role: "user",
{ type: "text", text: "Run ls" } content: "Run ls"
] },
}, { role: "assistant",
{ role: "assistant", content: "I'll check.",
content: [ tool_calls: [{
{ type: "text", text: "I'll check."}, id: "tu_123",
{ type: "tool_use", type: "function",
id: "tu_123", name: "bash", function: {
input: { command: "ls" } } name: "bash",
] arguments: '{"command":"ls"}'
}, }] }
{ role: "user", { role: "tool",
content: [ tool_call_id: "tu_123",
{ type: "tool_result", content: "file1\nfile2"
tool_use_id: "tu_123", }
content: "file1\nfile2" ]
]
}
]
```
## 流转换规则
### SSE Chunk → Anthropic Event 映射
| OpenAI Chunk | Anthropic Event |
|---|---|
| 首个 chunk | `message_start`(含 usage |
| `delta.reasoning_content` | `content_block_start(thinking)` + `thinking_delta` |
| `delta.content` | `content_block_start(text)` + `text_delta` |
| `delta.tool_calls` | `content_block_start(tool_use)` + `input_json_delta` |
| `finish_reason: "stop"` | `message_delta(stop_reason: "end_turn")` |
| `finish_reason: "tool_calls"` | `message_delta(stop_reason: "tool_use")` |
| `finish_reason: "length"` | `message_delta(stop_reason: "max_tokens")` |
### 块顺序
当模型返回 `reasoning_content` 时(如 DeepSeek块顺序与 Anthropic 一致:
```
thinking block (index 0) ← delta.reasoning_content
text block (index 1) ← delta.content
```
或:
```
thinking block (index 0) ← delta.reasoning_content
tool_use block (index 1) ← delta.tool_calls
```
`reasoning_content` 时:
```
text block (index 0) ← delta.content
tool_use block (index 1) ← delta.tool_calls如果有
```
### finish_reason 映射
| OpenAI | Anthropic |
|---|---|
| `stop` | `end_turn` |
| `tool_calls` | `tool_use` |
| `length` | `max_tokens` |
| `content_filter` | `end_turn` |
### 事件序列示例
**纯文本响应**
```
OpenAI chunks:
delta.content = "Hello"
delta.content = " world"
finish_reason = "stop"
→ Anthropic events:
message_start { message: { id, role: 'assistant', usage: {...} } }
content_block_start { index: 0, content_block: { type: 'text' } }
content_block_delta { index: 0, delta: { type: 'text_delta', text: 'Hello' } }
content_block_delta { index: 0, delta: { type: 'text_delta', text: ' world' } }
content_block_stop { index: 0 }
message_delta { delta: { stop_reason: 'end_turn' } }
message_stop
```
**Thinking + 文本DeepSeek 风格)**
```
OpenAI chunks:
delta.reasoning_content = "Let me think..."
delta.reasoning_content = " step by step."
delta.content = "The answer is 42."
finish_reason = "stop"
→ Anthropic events:
message_start { ... }
content_block_start { index: 0, content_block: { type: 'thinking', signature: '' } }
content_block_delta { index: 0, delta: { type: 'thinking_delta', thinking: 'Let me think...' } }
content_block_delta { index: 0, delta: { type: 'thinking_delta', thinking: ' step by step.' } }
content_block_stop { index: 0 }
content_block_start { index: 1, content_block: { type: 'text' } }
content_block_delta { index: 1, delta: { type: 'text_delta', text: 'The answer is 42.' } }
content_block_stop { index: 1 }
message_delta { delta: { stop_reason: 'end_turn' } }
message_stop
```
**工具调用**
```
OpenAI chunks:
delta.tool_calls[0] = { id: 'call_xxx', function: { name: 'bash', arguments: '' } }
delta.tool_calls[0].function.arguments = '{"comm'
delta.tool_calls[0].function.arguments = 'and":"ls"}'
finish_reason = "tool_calls"
→ Anthropic events:
message_start { ... }
content_block_start { index: 0, content_block: { type: 'tool_use', id: 'call_xxx', name: 'bash' } }
content_block_delta { index: 0, delta: { type: 'input_json_delta', partial_json: '{"comm' } }
content_block_delta { index: 0, delta: { type: 'input_json_delta', partial_json: 'and":"ls"}' } }
content_block_stop { index: 0 }
message_delta { delta: { stop_reason: 'tool_use' } }
message_stop
```
## 功能支持
### Thinking思维链
**请求侧**不需要显式配置。支持思维链的模型DeepSeek 等)会自动返回 `delta.reasoning_content`
**响应侧**`delta.reasoning_content` 被转换为 Anthropic `thinking` content block
```ts
// content_block_start
{ type: 'content_block_start', index: 0,
content_block: { type: 'thinking', thinking: '', signature: '' } }
// content_block_delta
{ type: 'content_block_delta', index: 0,
delta: { type: 'thinking_delta', thinking: 'Let me analyze...' } }
```
thinking block 在 text/tool_use block 之前自动关闭,保持 Anthropic 的块顺序。
### Prompt Caching
**请求侧**OpenAI 端点使用自动缓存,无需显式设置 `cache_control`
**响应侧**OpenAI 的 `usage.prompt_tokens_details.cached_tokens` 被映射到 Anthropic 的 `cache_read_input_tokens`
```
OpenAI: usage.prompt_tokens_details.cached_tokens = 800
Anthropic: message_start.message.usage.cache_read_input_tokens = 800
```
`message_start` 的 usage 中报告缓存命中量。
### 工具调用Tool Use
完整支持 OpenAI function calling 格式。所有本地工具Bash、FileEdit、Grep、Glob、Agent 等)透明工作——它们通过 JSON 输入输出通信,格式无关。
工具参数以 `input_json_delta` 形式流式传输,由下游代码拼接解析。
### 不支持的功能
| 功能 | 策略 |
|---|---|
| Beta Headers | 不发送 |
| Server Tools (advisor) | 不发送 |
| Structured Output | 不发送 |
| Fast Mode / Effort | 不发送 |
| Tool Search / defer_loading | 不启用,所有工具直接发送 |
| Anthropic Signature | thinking block 的 `signature` 字段为空字符串 |
| cache_creation_input_tokens | 始终为 0OpenAI 不区分创建/读取) |
## 测试
```bash
# 运行所有 OpenAI 适配层测试
bun test src/services/api/openai/__tests__/
# 单独运行
bun test src/services/api/openai/__tests__/streamAdapter.test.ts # 14 tests含 thinking + caching
bun test src/services/api/openai/__tests__/convertMessages.test.ts # 10 tests
bun test src/services/api/openai/__tests__/convertTools.test.ts # 7 tests
bun test src/services/api/openai/__tests__/modelMapping.test.ts # 6 tests
```
当前测试覆盖:**39 tests / 73 assertions / 0 fail**。
### 测试覆盖矩阵
| 功能 | convertMessages | convertTools | streamAdapter | modelMapping |
|---|---|---|---|---|
| 文本消息转换 | ✅ | | | |
| tool_use 转换 | ✅ | | | |
| tool_result 转换 | ✅ | | | |
| thinking 剥离 | ✅ | | | |
| 完整对话流程 | ✅ | | | |
| 工具 schema 转换 | | ✅ | | |
| tool_choice 映射 | | ✅ | | |
| 纯文本流 | | | ✅ | |
| 工具调用流 | | | ✅ | |
| 混合文本+工具 | | | ✅ | |
| finish_reason 映射 | | | ✅ | |
| thinking 流 | | | ✅ | |
| thinking+text 切换 | | | ✅ | |
| thinking+tool_use 切换 | | | ✅ | |
| 块索引正确性 | | | ✅ | |
| cached_tokens 映射 | | | ✅ | |
| OPENAI_MODEL 覆盖 | | | | ✅ |
| 默认模型映射 | | | | ✅ |
| 未知模型透传 | | | | ✅ |
| [1m] 后缀剥离 | | | | ✅ |
## 端到端验证
```bash
# 1. 安装依赖
bun install
# 2. 运行单元测试
bun test src/services/api/openai/__tests__/
# 3. 连接实际端点(以 Ollama 为例)
CLAUDE_CODE_USE_OPENAI=1 \
OPENAI_API_KEY=ollama \
OPENAI_BASE_URL=http://localhost:11434/v1 \
OPENAI_MODEL=qwen2.5-coder-32b \
bun run dev
# 4. 连接 DeepSeek测试 thinking 支持)
CLAUDE_CODE_USE_OPENAI=1 \
OPENAI_API_KEY=sk-xxx \
OPENAI_BASE_URL=https://api.deepseek.com/v1 \
OPENAI_MODEL=deepseek-reasoner \
bun run dev
# 5. 确认现有测试不受影响
bun test # 无 CLAUDE_CODE_USE_OPENAI 时走原有路径
```
## 代码统计
| 类别 | 行数 |
|---|---|
| 新增源码 | ~620 行 |
| 新增测试 | ~450 行 |
| 改动现有代码 | ~25 行 |
| **总计** | **~1100 行** |

View File

@@ -1,35 +0,0 @@
# 社区项目 & Blog 合集
> 每日更新,欢迎自荐!
## 工具 & 应用
| 项目 | 描述 | 作者 |
|------|------|------|
| [4qtask.vercel.app](https://4qtask.vercel.app/) | 免费四象限时间管理工具 | @kevinhuky |
| [kaying.studio](https://kaying.studio/) | 个人 AI 工具箱 | @kayingai |
| [supsub.ai](https://supsub.ai/) | 高效阅读工具 | @hidumou |
| [x-video-download.net](https://x-video-download.net/) | 视频下载工具 | @syakadou |
| [1openapi.com](https://1openapi.com/) | API 中转站 | @thinker007 |
| [claw-z.com](https://claw-z.com/) | 一键部署 OpenClaw AI Agent场景驱动、全面管理 | @uhhc |
| [gemini-watermark-remover.net](https://gemini-watermark-remover.net/) | Gemini 水印移除工具 | @syakadou |
## GitHub 开源项目
| 项目 | 描述 | 作者 |
|------|------|------|
| [VersperClaw](https://github.com/versperai/VersperClaw) | 全自动科研流 | @versperai |
| [claude-reviews-claude](https://github.com/openedclaude/claude-reviews-claude) | 原汤化原食——Claude 如何看待眼中的老己 | @openedclaude |
| [agentica](https://github.com/shibing624/agentica) | 自研 Agent 框架,借鉴 claude-code 多 Agent 处理 | @shibing624 |
| [macman](https://github.com/tonngw/macman) | Mac 从 0 到 1 保姆级配置教程 | @tonngw |
| [SuperSpec](https://github.com/asasugar/SuperSpec) | SDD / Spec-Driven Development | @asasugar |
| [adnify](https://github.com/adnaan-worker/adnify) | 高颜值高定制化 AI 编辑器 | @adnaan-worker |
| [another-rule-engine](https://github.com/eatmoreduck/another-rule-engine) | 基于 Groovy 的开源多功能决策引擎 | @eatmoreduck |
| [creative_master](https://github.com/chatabc/creative_master) | AI 驱动的创意灵感管理工具 | @chatabc |
| [RapidDoc](https://github.com/RapidAI/RapidDoc) | Office 文件解析工具转 Markdown支持 PDF/Image/Word/PPT/Excel | @hzkitt |
## Blog
| 链接 | 作者 |
|------|------|
| [blog.xiaohuangyu.space](https://blog.xiaohuangyu.space/) | @eatmoreduck |

View File

@@ -137,7 +137,7 @@ Auto mode 可通过以下方式激活:
### 进入时Full Instructions
注入到对话中的指令(`messages.ts:3464`
注入到对话中的指令(`messages.ts:3481`
> Auto mode is active. The user chose continuous, autonomous execution. You should:
>

View File

@@ -18,17 +18,19 @@ keywords: ["权限模型", "Allow Ask Deny", "PermissionRule", "checkPermissions
这些行为由 `PermissionResult` 类型定义(`src/utils/permissions/PermissionResult.ts`)。
## 权限规则的五层来源
## 权限规则的来源
规则从 5 个来源汇聚(`PERMISSION_RULE_SOURCES``permissions.ts:109`),优先级从高到低:
规则从 8 个来源汇聚(`PERMISSION_RULE_SOURCES``permissions.ts:109`),优先级从低到高(后者覆盖前者)
```
1. session — 用户在当前对话中手动授权("Always allow"
2. cliArg — 命令行 --allow/--deny 参数
3. command — Skill 工具的 allowedTools 白名单
4. projectSettings — .claude/settings.json团队共享
5. userSettings — ~/.claude/settings.json跨项目
6. policySettings — 企业管理员下发的策略(用户不可覆盖)
1. userSettings — ~/.claude/settings.json跨项目
2. projectSettings — .claude/settings.json团队共享
3. localSettings — .claude/settings.local.jsongitignored个人覆盖
4. flagSettings — --settings 命令行参数
5. policySettings — 企业管理员下发的策略(用户不可覆盖
6. cliArg — 命令行 --allow/--deny 参数
7. command — Skill 工具的 allowedTools 白名单
8. session — 用户在当前对话中手动授权("Always allow"
```
每个来源维护三个数组:`alwaysAllowRules[source]`、`alwaysAskRules[source]`、`alwaysDenyRules[source]`。
@@ -65,7 +67,7 @@ MCP 工具使用 `getToolNameForPermissionCheck()` 获取匹配名称,支持
**2. 命令模式匹配**BashTool 的 `checkPermissions()`
BashTool 通过 `preparePermissionMatcher()``Tool.ts:514`)解析命令模式:
BashTool 通过 `preparePermissionMatcher()``Tool.ts:520`)解析命令模式:
```json
{"tool": "Bash", "ruleContent": "git *"} → 匹配 "git commit -m 'fix'"
```
@@ -120,7 +122,9 @@ Read/Edit/Write 工具通过 `getPath()` 提取文件路径,与 `ruleContent`
|------|---------------------|---------|------|
| **Default** | `'default'` | 日常使用 | 敏感操作逐一确认 |
| **Plan Mode** | `'plan'` | 探索阶段 | 只能读不能写(`isReadOnly()` 检查) |
| **Auto** | `'auto'` | 信任 AI | 通过 transcript classifier 自动决策 |
| **Accept Edits** | `'acceptEdits'` | 快速迭代 | 工作区内文件编辑自动放行,其他操作仍需确认 |
| **Don't Ask** | `'dontAsk'` | 减少打断 | 尽量自动决策,减少确认弹窗 |
| **Auto** | `'auto'` | 信任 AI | 通过 transcript classifier 自动决策(需 `TRANSCRIPT_CLASSIFIER` feature flag |
| **Bypass** | `'bypassPermissions'` | 完全信任 | 所有操作自动放行(需显式 `--dangerously-skip-permissions` |
Plan Mode 切换由 `EnterPlanModeTool.call()` 触发:
@@ -143,8 +147,8 @@ context.setAppState(prev => ({
```typescript
const DENIAL_LIMITS = {
maxDenialsPerTool: 3, // 同一工具连续拒绝上限
cooldownPeriodMs: 30_000, // 冷却期 30 秒
maxConsecutive: 3, // 同一工具连续拒绝上限
maxTotal: 20, // 总拒绝上限
}
```
@@ -162,9 +166,12 @@ const DENIAL_LIMITS = {
```typescript
type PermissionUpdate =
| { type: 'addRule', behavior, rule, destination }
| { type: 'removeRule', behavior, rule, destination }
| { type: 'setMode', mode, destination }
| { type: 'addRules', destination, rules, behavior }
| { type: 'replaceRules', destination, rules, behavior }
| { type: 'removeRules', destination, rules, behavior }
| { type: 'setMode', destination, mode }
| { type: 'addDirectories', destination, directories }
| { type: 'removeDirectories', destination, directories }
```
当用户在 Ask 对话框中选择 "Always allow",系统调用 `persistPermissionUpdates()` 将规则写入对应层级的 settings 文件project/user/managed同时更新内存中的 `toolPermissionContext`。

View File

@@ -16,13 +16,13 @@ keywords: ["Plan Mode", "计划模式", "EnterPlanMode", "ExitPlanMode", "prepar
<Steps>
<Step title="EnterPlanMode — 进入计划模式">
AI 自主判断(或用户触发)任务需要规划,调用 `EnterPlanModeTool``src/tools/EnterPlanModeTool/EnterPlanModeTool.ts:36`)。该工具需要**用户审批**`checkPermissions` 返回 `ask`)。
AI 自主判断(或用户触发)任务需要规划,调用 `EnterPlanModeTool``packages/builtin-tools/src/tools/EnterPlanModeTool/EnterPlanModeTool.ts:36`)。该工具需要**用户审批**`checkPermissions` 返回 `ask`)。
</Step>
<Step title="探索阶段 — 只读工具集">
权限模式切换为 `'plan'`AI 只能使用 `isReadOnly()` 为 true 的工具Read、Grep、Glob、Agent 等)。写操作被自动拒绝。
</Step>
<Step title="ExitPlanMode — 提交方案审批">
AI 完成探索后,调用 `ExitPlanModeV2Tool``src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts:147`),将计划文件提交给用户审阅。这是第二个**需要用户审批**的节点。
AI 完成探索后,调用 `ExitPlanModeV2Tool``packages/builtin-tools/src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts:147`),将计划文件提交给用户审阅。这是第二个**需要用户审批**的节点。
</Step>
<Step title="恢复执行 — 全部工具权限">
用户批准后权限模式恢复为进入前的状态AI 按计划执行。
@@ -107,7 +107,7 @@ if (isTeammate()) {
## 什么时候该用计划模式
`EnterPlanModeTool` 的 Prompt`src/tools/EnterPlanModeTool/prompt.ts`)定义了两套触发标准——外部版本更积极(鼓励规划),内部版本更克制(仅在真正模糊时使用):
`EnterPlanModeTool` 的 Prompt`packages/builtin-tools/src/tools/EnterPlanModeTool/prompt.ts`)定义了两套触发标准——外部版本更积极(鼓励规划),内部版本更克制(仅在真正模糊时使用):
| 场景 | 外部版本 | 内部版本 |
|------|---------|---------|

View File

@@ -166,7 +166,7 @@ keywords: ["沙箱", "sandbox", "权限", "Bash", "PowerShell", "bubblewrap", "s
5. 这条命令没有被显式排除
6. 这次调用没有被允许以 `dangerouslyDisableSandbox` 绕过
对应入口在 `src/tools/BashTool/shouldUseSandbox.ts` 和 `src/utils/sandbox/sandbox-adapter.ts`。
对应入口在 `packages/builtin-tools/src/tools/BashTool/shouldUseSandbox.ts` 和 `src/utils/sandbox/sandbox-adapter.ts`。
### 3. PowerShell 只在支持平台上走
@@ -518,11 +518,11 @@ REPL / CLI 启动
如果你想继续顺着源码深入,推荐按下面顺序看:
1. `src/tools/BashTool/shouldUseSandbox.ts`
1. `packages/builtin-tools/src/tools/BashTool/shouldUseSandbox.ts`
2. `src/utils/Shell.ts`
3. `src/utils/sandbox/sandbox-adapter.ts`
4. `src/utils/permissions/permissions.ts`
5. `src/tools/BashTool/bashPermissions.ts`
5. `packages/builtin-tools/src/tools/BashTool/bashPermissions.ts`
6. `src/utils/permissions/pathValidation.ts`
7. `src/utils/permissions/filesystem.ts`

View File

@@ -61,7 +61,7 @@ Claude 的 System Prompt 中包含安全指令——这是"软性"约束,依
| `deny` | 直接拒绝 | 匹配 deny 规则 |
| `ask` | 弹窗确认 | 未匹配任何规则 或 匹配 ask 规则 |
以 BashTool 为例(`src/tools/BashTool/bashPermissions.ts``bashToolHasPermission()` 执行了极其细致的检查链:
以 BashTool 为例(`packages/builtin-tools/src/tools/BashTool/bashPermissions.ts``bashToolHasPermission()` 执行了极其细致的检查链:
1. **AST 安全解析**:用 tree-sitter 解析 bash AST检测命令注入`$()`、反引号等)
2. **语义检查**:识别危险命令(`eval`、`exec`、`source` 等)
@@ -169,7 +169,7 @@ Bash("rm -rf node_modules") → ⚠️ 需确认(不可逆)
攻击cd /malicious/dir && git status
/malicious/dir 包含 bare repo + 恶意钩子
防御bashToolHasPermission() 检测 cd + git 组合
强制 require approvalsrc/tools/BashTool/bashPermissions.ts:2209
强制 require approvalpackages/builtin-tools/src/tools/BashTool/bashPermissions.ts:2209
```
### 场景3管道注入
@@ -178,5 +178,5 @@ Bash("rm -rf node_modules") → ⚠️ 需确认(不可逆)
攻击echo 'x' | xargs printf '%s' >> /etc/passwd
splitCommand 会剥离重定向,导致路径检查遗漏
防御:即使管道段独立检查通过,仍对原始命令重新验证路径约束
检查重定向目标中的危险模式(反引号、$()bashPermissions.ts:1992-2056
检查重定向目标中的危险模式(反引号、$()packages/builtin-tools/src/tools/BashTool/bashPermissions.ts:1992-2056
```

View File

@@ -0,0 +1,77 @@
# Task 001: daemon status / stop
> 来源: [stub-recovery-design-1-4.md](../features/stub-recovery-design-1-4.md) 第 1 项
> 优先级: P0 (首选实现项)
> 工作量: 小
> 状态: DONE
## 目标
`claude daemon status``claude daemon stop` 在任意 CLI 进程中都能正确工作,不依赖 TUI 内存态。
## 背景
- `start` 路径已有完整 supervisor + worker 生命周期 (`src/daemon/main.ts`, `src/daemon/workerRegistry.ts`)
- `status` / `stop` 目前只是占位输出 (`src/daemon/main.ts:49`)
- `/remote-control-server` 有自己的命令内 UI 状态,但只维护当前进程内的 `daemonProcess`,不适合跨进程管理
## 实现方案
### 新增文件
| 文件 | 说明 |
|------|------|
| `src/daemon/state.ts` | daemon 状态文件读写模块 |
### 修改文件
| 文件 | 改动 |
|------|------|
| `src/daemon/main.ts` | `start` 写入状态文件;`status`/`stop` 调用 state 模块 |
| `src/commands/remoteControlServer/remoteControlServer.tsx` | 读取同一份状态文件(轻量改动) |
### 状态文件
路径: `~/.claude/daemon/remote-control.json`
```json
{
"pid": 12345,
"cwd": "/path/to/project",
"startedAt": "2026-04-12T10:00:00Z",
"workerKinds": ["bridge", "rcs"],
"lastStatus": "running"
}
```
### status 逻辑
1. 读取状态文件
2. 用进程探测验证 pid 是否存活
3. 输出 `running` / `stopped` / `stale`
4. stale 时自动清理状态文件
### stop 逻辑
1. 读取 pid
2. 发送 `SIGTERM`
3. 等待退出(超时兜底)
4. 超时后 `SIGKILL`
5. 清理状态文件
## 验证步骤
- [ ] `claude daemon start` 正常启动并写入状态文件
- [ ] 新开终端执行 `claude daemon status`,显示 `running`
- [ ] 执行 `claude daemon stop`daemon 正常退出
- [ ] 再次执行 `claude daemon status`,返回 `stopped``stale cleaned`
- [ ] Windows 下 stop 超时兜底正常工作
## 风险
- Windows 信号模型和 Unix 不同,`stop` 需要超时兜底
- 当前设计默认单 supervisor不处理多实例并发
## 依赖
无外部依赖,可独立实施。

View File

@@ -0,0 +1,80 @@
# Task 002: BG_SESSIONS — ps / logs / kill
> 来源: [stub-recovery-design-1-4.md](../features/stub-recovery-design-1-4.md) 第 2 项
> 优先级: P1
> 工作量: 中等
> 状态: DONE
> 阶段: Phase 2A (MVP)
## 目标
`ps` / `logs` / `kill` 做成真正有用的 session 管理命令。不在第一阶段补完 `attach` / `--bg`
## 背景
- fast-path 已接好 (`src/entrypoints/cli.tsx:218`)
- session registry 已有真实实现 (`src/utils/concurrentSessions.ts`)
- `exit` 在 bg session 内已会 `tmux detach-client` (`src/commands/exit/exit.tsx:20`)
- CLI handler 仍全空 (`src/cli/bg.ts`)
- task summary 仍然是 stub (`src/utils/taskSummary.ts`)
## 实现方案
### 修改文件
| 文件 | 改动 |
|------|------|
| `src/cli/bg.ts` | 实现 `ps` / `logs` / `kill` handler |
| `src/utils/concurrentSessions.ts` | 扩展以便后续 attach/--bg 使用 |
| `src/utils/taskSummary.ts` | 补充基础实现 |
### 复用模块
- `src/utils/sessionStorage.ts` — session 存储
- `src/utils/udsClient.ts` — UDS 通信
### ps 命令
- 从 registry 读取 live sessions
- 展示: pid, kind, sessionId, cwd, name, startedAt, bridgeSessionId
- 如果有 activity/status一并展示
### logs 命令
- 支持按 `sessionId` / `pid` / `name` 查找
- 优先复用本地 transcript/log 读取能力
- 如果 registry 里存在 `logPath`,支持 tail 文件
### kill 命令
- 解析目标 session
- 发退出信号
- 清理 stale registry
## 验证步骤
- [ ] `ps` 能列出当前 live sessions
- [ ] `logs <sessionId|pid|name>` 能输出对应日志
- [ ] `kill <sessionId|pid|name>` 能结束目标 session 并清理 registry
- [ ] 无 live session 时各命令有明确提示
## Phase 2B (后续)
- [ ] 实现 `attach`
- [ ] 实现 `--bg`
- [ ] 实现 `taskSummary` 的中途状态更新
### 为什么拆分
- 现有 registry 记录了 `pid / sessionId / name / logPath`
- 但没有可靠的 tmux attach target
- `attach``--bg` 需要补启动/附着元数据设计,不是简单补 handler
## 风险
- `attach` / `--bg` 第二阶段需要 tmux 元数据设计
- Windows 下 tmux 路径需要明确降级策略
## 依赖
- Task 001 (daemon 状态管理可复用模式,但非硬性依赖)

View File

@@ -0,0 +1,87 @@
# Task 003: TEMPLATES — job 文件系统 MVP
> 来源: [stub-recovery-design-1-4.md](../features/stub-recovery-design-1-4.md) 第 3 项
> 优先级: P2
> 工作量: 中等
> 状态: DONE
> 阶段: MVP
## 目标
`new` / `list` / `reply` 做成可用的模板任务系统。第一阶段不碰复杂的自动分类与自动执行。
## 背景
- 命令入口只有 fast-path (`src/entrypoints/cli.tsx:272`)
- handler 是空的 (`src/cli/handlers/templateJobs.ts`)
- `markdownConfigLoader` 已把 `templates` 纳入配置目录 (`src/utils/markdownConfigLoader.ts:35`)
- `query/stopHooks` 已预留 job classifier 链路 (`src/query/stopHooks.ts:103`)
- `jobs/classifier.ts` 仍是 stub (`src/jobs/classifier.ts`)
## 实现方案
### 新增文件
| 文件 | 说明 |
|------|------|
| `src/jobs/state.ts` | job 状态管理 |
| `src/jobs/templates.ts` | 模板解析与列表 |
### 修改文件
| 文件 | 改动 |
|------|------|
| `src/cli/handlers/templateJobs.ts` | 实现 `new` / `list` / `reply` handler |
### 模板来源
`.claude/templates/*.md`
### 模板格式
复用现有 markdown + frontmatter 解析,不另外设计 DSL。
### list 命令
- 列出所有模板
- 显示: 模板名, description, 路径
### new 命令
- 解析模板
-`~/.claude/jobs/<job-id>/` 下创建 job 目录
- 写入 `template.md`, `input.txt`, `state.json`
- 返回 job id 与目录路径
### reply 命令
- 将回复写入 `replies.jsonl``input.txt`
- 更新 `state.json`
## 验证步骤
- [ ] `list` 能列出 `.claude/templates` 下的所有模板
- [ ] `new <template> [args...]` 能创建 job 目录和状态文件
- [ ] `reply <job-id> <text>` 能更新 job 内容和状态
- [ ] frontmatter schema 最小字段集已定义
## Phase 2 (后续)
- [ ] 恢复 `src/jobs/classifier.ts`
- [ ] 让带 `CLAUDE_JOB_DIR` 的 job session 在 turn 完成后自动更新 `state.json`
- [ ] 再决定是否补自动 job runner
### 为什么拆分
- 当前是 "template job commands",不是单纯模板列表
- 自动 job 运行链路没有足够现成实现
- 先做文件系统 job lifecycle 更稳
## 风险
- frontmatter schema 需要先定义最小字段集
- 一旦扩展到"自动运行 job",范围会明显膨胀
## 依赖
无硬性依赖,可独立实施。

View File

@@ -0,0 +1,103 @@
# Task 004: assistant [sessionId] — 分阶段恢复
> 来源: [stub-recovery-design-1-4.md](../features/stub-recovery-design-1-4.md) 第 4 项
> 优先级: P3
> 工作量: Phase 4A 中等4A-4D 全做完很大
> 状态: Phase 4A DONE, 4B-4D TODO
## 目标
不一次性恢复整个 KAIROS 助手系统。先做"明确 sessionId 的 viewer attach 可用",再逐步补 discovery / chooser / install。
## 背景
- attach 主流程已存在 (`src/main.tsx:4708`)
- 远端 viewer 所需基础模块已存在:
- `src/remote/RemoteSessionManager.ts`
- `src/hooks/useAssistantHistory.ts`
- `src/assistant/sessionHistory.ts`
- 真正 stub 的主要是:
- `src/assistant/sessionDiscovery.ts`
- `src/assistant/AssistantSessionChooser.tsx`
- `src/commands/assistant/assistant.tsx:7`
- `src/assistant/index.ts`
## 分阶段实现
### Phase 4A: MVP — 显式 sessionId attach
**修改文件:**
| 文件 | 改动 |
|------|------|
| `src/main.tsx` | 确保 attach 分支可用 |
| `src/commands/assistant/index.ts` | 实现显式 sessionId 参数入口 |
**行为:**
- `claude assistant <sessionId>` — 进入 remote viewer
- `claude assistant` (无参数) — 返回明确提示: 当前版本需要显式 sessionIddiscovery 尚未启用
**验证:**
- [ ] `claude assistant <sessionId>` 能进入 remote viewer
- [ ] 历史懒加载工作正常
- [ ] 无参数模式给出明确提示
### Phase 4B: session discovery
**修改文件:**
| 文件 | 改动 |
|------|------|
| `src/assistant/sessionDiscovery.ts` | 恢复 `discoverAssistantSessions()` |
**行为:**
- 数据来源优先复用现有 sessions / bridge / teleport API不新增协议
- `claude assistant` 无参数时能拿到候选 session 列表
**验证:**
- [ ] 无参数调用能列出可用 sessions
- [ ] 数据来源复用现有通道
### Phase 4C: session chooser
**修改文件:**
| 文件 | 改动 |
|------|------|
| `src/assistant/AssistantSessionChooser.ts` | 恢复交互式选择器 |
**行为:**
- 多 session 时可交互选择
**验证:**
- [ ] 多个 session 时弹出选择器
- [ ] 选择后正确 attach
### Phase 4D: install wizard
**修改文件:**
| 文件 | 改动 |
|------|------|
| `src/commands/assistant/assistant.ts` | 恢复 install wizard 辅助函数 |
**行为:**
- 没有 session 时如何引导用户
**验证:**
- [ ] 无可用 session 时引导用户创建/连接
## 为什么拆分
- attach 渲染层与远端消息通道大部分已在
- 真正缺的是"如何发现目标 session"和"如何交互选择"
- 如果把 `src/assistant/index.ts` 的整套 KAIROS 正常模式也一起拉进来,范围会失控
## 风险
- 这是四项里范围最大的
- 一旦把 KAIROS 正常模式整体拉入,会从"viewer attach"膨胀成"完整 assistant mode 恢复"
## 依赖
- Task 002 的 session registry 模式可复用

View File

@@ -0,0 +1,196 @@
# Task 013: BgEngine 跨平台后台引擎抽象
> 设计文档: [daemon-restructure-design.md](../features/daemon-restructure-design.md) § 四
> 依赖: 无
> 分支: `feat/integrate-5-branches`
## 目标
`src/cli/bg.ts` 中硬编码的 tmux 逻辑提取为引擎抽象层,实现 TmuxEngine + DetachedEngine使后台会话功能在 Windows / macOS / Linux 上都能工作。
## 背景
当前 `bg.ts``handleBgFlag()``attachHandler()` 直接调用 tmux 命令。Windows 上 `--bg` 直接报错退出。需要一个引擎抽象层,根据平台和可用工具自动选择最佳方案。
## 文件清单
### 新增
| 文件 | 说明 |
|------|------|
| `src/cli/bg/engine.ts` | BgEngine 接口 + BgStartOptions/BgStartResult 类型 |
| `src/cli/bg/engines/tmux.ts` | TmuxEngine: 从 `bg.ts` 提取 tmux 相关逻辑 |
| `src/cli/bg/engines/detached.ts` | DetachedEngine: spawn({ detached }) + logFile 重定向 |
| `src/cli/bg/engines/index.ts` | selectEngine() 自动选择 + re-export |
| `src/cli/bg/tail.ts` | 跨平台日志 tail: fs.watch + 轮询 fallback |
### 修改
| 文件 | 变更 |
|------|------|
| `src/cli/bg.ts` | `handleBgFlag()` 改为调用 `selectEngine().start()``attachHandler()` 改为调用 `engine.attach()` |
## 实现方案
### 1. BgEngine 接口 (`src/cli/bg/engine.ts`)
```typescript
export interface BgEngine {
readonly name: string
available(): Promise<boolean>
start(opts: BgStartOptions): Promise<BgStartResult>
attach(session: SessionEntry): Promise<void>
}
export interface BgStartOptions {
sessionName: string
args: string[] // CLI args (去除 --bg)
env: Record<string, string | undefined>
logPath: string
cwd: string
}
export interface BgStartResult {
pid: number
sessionName: string
logPath: string
engineUsed: 'tmux' | 'detached'
}
```
### 2. TmuxEngine (`src/cli/bg/engines/tmux.ts`)
`bg.ts:handleBgFlag()``bg.ts:attachHandler()` 提取:
- `available()`: `execFileNoThrow('tmux', ['-V'])` 返回 code === 0
- `start()`: `tmux new-session -d -s <name> <cmd>`
- `attach()`: `tmux attach-session -t <session.tmuxSessionName>`
### 3. DetachedEngine (`src/cli/bg/engines/detached.ts`)
```typescript
export class DetachedEngine implements BgEngine {
readonly name = 'detached'
async available(): Promise<boolean> {
return true // 总是可用
}
async start(opts: BgStartOptions): Promise<BgStartResult> {
const logFd = openSync(opts.logPath, 'a')
const child = spawn(process.execPath, [process.argv[1]!, ...opts.args], {
detached: true,
stdio: ['ignore', logFd, logFd],
env: opts.env,
cwd: opts.cwd,
})
child.unref()
closeSync(logFd)
return {
pid: child.pid!,
sessionName: opts.sessionName,
logPath: opts.logPath,
engineUsed: 'detached',
}
}
async attach(session: SessionEntry): Promise<void> {
// 委托给 tail.ts
await tailLog(session.logPath!)
}
}
```
### 4. 日志 Tail (`src/cli/bg/tail.ts`)
```typescript
/**
* 跨平台实时日志输出。Ctrl+C 退出,不杀后台进程。
*
* 策略:
* 1. 读取已有内容输出
* 2. fs.watch() 监听文件变化 (主方案)
* 3. 如果 fs.watch 不可靠 (某些 Windows 网络驱动器)fallback 到 500ms 轮询
*/
export async function tailLog(logPath: string): Promise<void>
```
### 5. 引擎选择 (`src/cli/bg/engines/index.ts`)
```typescript
export async function selectEngine(): Promise<BgEngine> {
if (process.platform === 'win32') {
return new DetachedEngine()
}
const tmux = new TmuxEngine()
if (await tmux.available()) {
return tmux
}
return new DetachedEngine()
}
```
### 6. bg.ts 重构
`handleBgFlag()` 改名为 `handleBgStart()`,内部逻辑:
```typescript
export async function handleBgStart(args: string[]): Promise<void> {
const engine = await selectEngine()
const sessionName = `claude-bg-${randomUUID().slice(0, 8)}`
const logPath = join(getClaudeConfigHomeDir(), 'sessions', 'logs', `${sessionName}.log`)
const result = await engine.start({
sessionName,
args: filteredArgs,
env: { ...process.env, CLAUDE_CODE_SESSION_KIND: 'bg', ... },
logPath,
cwd: process.cwd(),
})
console.log(`Background session started: ${result.sessionName}`)
console.log(` Engine: ${result.engineUsed}`)
console.log(` Log: ${result.logPath}`)
console.log(` Use \`claude daemon attach ${result.sessionName}\` to reconnect.`)
}
```
`attachHandler()` 根据 `session.engine` 字段选择引擎:
```typescript
export async function attachHandler(target: string | undefined): Promise<void> {
// ... 找到 session
if (session.engine === 'tmux' && session.tmuxSessionName) {
const tmux = new TmuxEngine()
await tmux.attach(session)
} else {
const detached = new DetachedEngine()
await detached.attach(session)
}
}
```
## SessionEntry 扩展
`sessions/<PID>.json` 新增 `engine` 字段:
```json
{
"pid": 12345,
"engine": "detached",
"logPath": "~/.claude/sessions/logs/claude-bg-a1b2c3d4.log",
"sessionId": "...",
"cwd": "..."
}
```
兼容旧格式: 如果 `engine` 字段缺失,检查 `tmuxSessionName` 存在则为 `tmux`,否则为 `detached`
## 验证清单
- [ ] Windows: `claude daemon bg` 启动后台会话,无 tmux 依赖
- [ ] Windows: `claude daemon attach <name>` 以 tail 模式附着Ctrl+C 退出不杀进程
- [ ] macOS/Linux (有 tmux): 行为与当前一致
- [ ] macOS/Linux (无 tmux): 自动 fallback 到 detached 引擎
- [ ] `claude daemon status` 正确显示 engine 类型
- [ ] 旧格式 session JSON (无 engine 字段) 兼容
- [ ] tsc --noEmit 零错误
- [ ] bun test 通过

View File

@@ -0,0 +1,275 @@
# Task 014: /daemon 命令层级化
> 设计文档: [daemon-restructure-design.md](../features/daemon-restructure-design.md) § 三.1
> 依赖: Task 013 (BgEngine 抽象)
> 分支: `feat/integrate-5-branches`
## 目标
将散落的 `daemon start/stop/status` + `ps/logs/attach/kill` + `--bg` 统一收归 `/daemon` 命名空间,实现 CLI + REPL 双注册。
## 背景
当前这些命令注册在两个互不关联的位置:
- `cli.tsx:203-212`: `daemon [start|status|stop]``daemon/main.ts`
- `cli.tsx:217-246`: `ps|logs|attach|kill|--bg``cli/bg.ts`
需要合并为统一的 `claude daemon <subcommand>` 入口,并新增 REPL `/daemon` 斜杠命令。
## 文件清单
### 新增
| 文件 | 说明 |
|------|------|
| `src/commands/daemon/index.ts` | `/daemon` REPL 斜杠命令注册 (type: local-jsx) |
| `src/commands/daemon/daemon.tsx` | `/daemon` 子命令路由 + status UI 组件 |
### 修改
| 文件 | 变更 |
|------|------|
| `src/entrypoints/cli.tsx` | 统一 daemon 快速路径: `daemon <sub>` 路由到对应 handler。旧命令 `ps/logs/attach/kill` 保留但输出 deprecation 警告后代理 |
| `src/commands.ts` | 注册 `/daemon` 斜杠命令 (feature-gated: DAEMON \|\| BG_SESSIONS) |
| `src/daemon/main.ts` | `daemonMain()` 扩展: 支持 `bg/attach/logs/kill/ps` 子命令 (委托给 bg.ts handlers) |
## 实现方案
### 1. CLI 快速路径统一 (`cli.tsx`)
**改前** (两段独立路由):
```typescript
// 段 1: daemon
if (feature('DAEMON') && args[0] === 'daemon') {
await daemonMain(args.slice(1))
}
// 段 2: bg sessions
if (feature('BG_SESSIONS') && ['ps','logs','attach','kill'].includes(args[0])) {
// ...switch/case
}
```
**改后** (统一入口):
```typescript
// 统一 daemon 入口 — 合并 daemon supervisor + bg sessions
if (
(feature('DAEMON') || feature('BG_SESSIONS')) &&
args[0] === 'daemon'
) {
profileCheckpoint('cli_daemon_path')
const { enableConfigs } = await import('../utils/config.js')
enableConfigs()
const { initSinks } = await import('../utils/sinks.js')
initSinks()
const { daemonMain } = await import('../daemon/main.js')
await daemonMain(args.slice(1))
return
}
// --bg 快捷方式 → daemon bg
if (
feature('BG_SESSIONS') &&
(args.includes('--bg') || args.includes('--background'))
) {
profileCheckpoint('cli_daemon_path')
const { enableConfigs } = await import('../utils/config.js')
enableConfigs()
const bg = await import('../cli/bg.js')
await bg.handleBgStart(args.filter(a => a !== '--bg' && a !== '--background'))
return
}
// 向后兼容: ps/logs/attach/kill → daemon <sub> (deprecated)
if (
feature('BG_SESSIONS') &&
['ps', 'logs', 'attach', 'kill'].includes(args[0] ?? '')
) {
const mapped = args[0] === 'ps' ? 'status' : args[0]
console.error(`[deprecated] Use: claude daemon ${mapped} ${args.slice(1).join(' ')}`.trim())
const { enableConfigs } = await import('../utils/config.js')
enableConfigs()
const { daemonMain } = await import('../daemon/main.js')
await daemonMain([args[0]!, ...args.slice(1)])
return
}
```
### 2. daemonMain 扩展 (`daemon/main.ts`)
```typescript
export async function daemonMain(args: string[]): Promise<void> {
const subcommand = args[0] || 'status'
switch (subcommand) {
// --- Supervisor 管理 ---
case 'start':
await runSupervisor(args.slice(1))
break
case 'stop':
await handleDaemonStop()
break
// --- 会话管理 (委托给 bg.ts) ---
case 'status':
case 'ps':
await showUnifiedStatus() // 新: daemon 状态 + 会话列表
break
case 'bg':
const bg = await import('../cli/bg.js')
await bg.handleBgStart(args.slice(1))
break
case 'attach':
const bg2 = await import('../cli/bg.js')
await bg2.attachHandler(args[1])
break
case 'logs':
const bg3 = await import('../cli/bg.js')
await bg3.logsHandler(args[1])
break
case 'kill':
const bg4 = await import('../cli/bg.js')
await bg4.killHandler(args[1])
break
case '--help': case '-h': case 'help':
printHelp()
break
default:
console.error(`Unknown daemon subcommand: ${subcommand}`)
printHelp()
process.exitCode = 1
}
}
```
### 3. 统一状态面板 (`showUnifiedStatus`)
```typescript
async function showUnifiedStatus(): Promise<void> {
// 1. Daemon supervisor 状态
const daemonResult = queryDaemonStatus()
console.log('=== Daemon Supervisor ===')
switch (daemonResult.status) {
case 'running':
console.log(` Status: running (PID: ${daemonResult.state!.pid})`)
console.log(` Workers: ${daemonResult.state!.workerKinds.join(', ')}`)
break
case 'stopped':
console.log(' Status: stopped')
break
case 'stale':
console.log(' Status: stale (cleaned up)')
break
}
// 2. 后台会话列表
console.log('\n=== Background Sessions ===')
const bg = await import('../cli/bg.js')
await bg.psHandler([])
}
```
### 4. REPL 斜杠命令注册
**`src/commands/daemon/index.ts`**:
```typescript
import type { Command } from '../../commands.js'
import { feature } from 'bun:bundle'
const daemon = {
type: 'local-jsx',
name: 'daemon',
description: 'Manage background sessions and daemon',
argumentHint: '[status|start|stop|bg|attach|logs|kill]',
isEnabled: () => {
if (feature('DAEMON')) return true
if (feature('BG_SESSIONS')) return true
return false
},
load: () => import('./daemon.js'),
} satisfies Command
export default daemon
```
**`src/commands/daemon/daemon.tsx`**:
```typescript
export async function call(
onDone: LocalJSXCommandOnDone,
context: LocalJSXCommandContext,
args: string,
): Promise<React.ReactNode> {
const parts = args.trim().split(/\s+/)
const sub = parts[0] || 'status'
switch (sub) {
case 'status':
case 'ps':
// 调用 showUnifiedStatus捕获输出
// 返回文本结果
break
case 'bg':
// REPL 中启动后台会话
break
case 'start':
case 'stop':
case 'attach':
case 'logs':
case 'kill':
// 委托给对应 handler
break
default:
onDone(`Unknown: ${sub}. Use: status|start|stop|bg|attach|logs|kill`)
return null
}
}
```
**`src/commands.ts`** 添加:
```typescript
// 条件导入
const daemonCmd =
feature('DAEMON') || feature('BG_SESSIONS')
? require('./commands/daemon/index.js').default
: null
// COMMANDS 数组中添加
...(daemonCmd ? [daemonCmd] : []),
```
### 5. 更新 help 文本 (`daemon/main.ts`)
```
Claude Code Daemon — background process management
USAGE
claude daemon [subcommand]
SUBCOMMANDS
status Show daemon and session status (default)
start Start the daemon supervisor
stop Stop the daemon
bg Start a background session
attach Attach to a background session
logs Show session logs
kill Kill a session
help Show this help
REPL
/daemon [subcommand] Same commands available in interactive mode
```
## 验证清单
- [ ] `claude daemon` (无参数) 显示统一状态面板
- [ ] `claude daemon status` 显示 supervisor + 会话列表
- [ ] `claude daemon start/stop` 与当前行为一致
- [ ] `claude daemon bg` 启动后台会话 (调用 BgEngine)
- [ ] `claude daemon attach/logs/kill <target>` 功能正常
- [ ] `claude ps` 输出 deprecation 警告 + 正常工作
- [ ] `claude logs/attach/kill` 同上
- [ ] `claude --bg` 快捷方式正常
- [ ] REPL 中 `/daemon` 可用tab 补全显示
- [ ] REPL 中 `/daemon status` 显示状态信息
- [ ] tsc --noEmit 零错误
- [ ] bun test 通过

View File

@@ -0,0 +1,177 @@
# Task 015: /job 命令层级化
> 设计文档: [daemon-restructure-design.md](../features/daemon-restructure-design.md) § 三.2
> 依赖: 无 (可与 Task 013 并行)
> 分支: `feat/integrate-5-branches`
## 目标
`claude new/list/reply` 收归 `/job` 命名空间,实现 CLI + REPL 双注册。
## 背景
当前 `new`, `list`, `reply` 是顶级 CLI 命令 (`cli.tsx:250-261`),容易与其他命令冲突(特别是 `list` 这种通用词)。需要收归 `claude job <subcommand>` 并新增 REPL `/job` 入口。
## 文件清单
### 新增
| 文件 | 说明 |
|------|------|
| `src/commands/job/index.ts` | `/job` REPL 斜杠命令注册 |
| `src/commands/job/job.tsx` | `/job` 子命令路由 |
### 修改
| 文件 | 变更 |
|------|------|
| `src/entrypoints/cli.tsx` | 新增 `job` 快速路径 + 旧 `new/list/reply` deprecation 代理 |
| `src/commands.ts` | 注册 `/job` 斜杠命令 |
### 不动
| 文件 | 说明 |
|------|------|
| `src/cli/handlers/templateJobs.ts` | 内部 handler 不变,只是被调用方式变了 |
| `src/jobs/state.ts` | job 状态管理不变 |
| `src/jobs/templates.ts` | 模板发现不变 |
| `src/jobs/classifier.ts` | 任务分类器不变 |
## 实现方案
### 1. CLI 快速路径 (`cli.tsx`)
**改后**:
```typescript
// 新: claude job <subcommand>
if (
feature('TEMPLATES') &&
args[0] === 'job'
) {
profileCheckpoint('cli_templates_path')
const { templatesMain } = await import('../cli/handlers/templateJobs.js')
await templatesMain(args.slice(1))
process.exit(0)
}
// 向后兼容 (deprecated)
if (
feature('TEMPLATES') &&
(args[0] === 'new' || args[0] === 'list' || args[0] === 'reply')
) {
console.error(`[deprecated] Use: claude job ${args[0]} ${args.slice(1).join(' ')}`.trim())
profileCheckpoint('cli_templates_path')
const { templatesMain } = await import('../cli/handlers/templateJobs.js')
await templatesMain(args)
process.exit(0)
}
```
### 2. templateJobs.ts 新增 status 子命令
在现有 `switch` 中增加:
```typescript
case 'status':
handleStatus(args.slice(1))
break
```
```typescript
function handleStatus(args: string[]): void {
const jobId = args[0]
if (!jobId) {
console.error('Usage: claude job status <job-id>')
process.exitCode = 1
return
}
const state = readJobState(jobId)
if (!state) {
console.error(`Job not found: ${jobId}`)
process.exitCode = 1
return
}
console.log(`Job: ${state.jobId}`)
console.log(` Template: ${state.templateName}`)
console.log(` Status: ${state.status}`)
console.log(` Created: ${state.createdAt}`)
console.log(` Updated: ${state.updatedAt}`)
}
```
### 3. REPL 斜杠命令
**`src/commands/job/index.ts`**:
```typescript
import type { Command } from '../../commands.js'
import { feature } from 'bun:bundle'
const job = {
type: 'local-jsx',
name: 'job',
description: 'Manage template jobs',
argumentHint: '[list|new|reply|status]',
isEnabled: () => {
if (feature('TEMPLATES')) return true
return false
},
load: () => import('./job.js'),
} satisfies Command
export default job
```
**`src/commands/job/job.tsx`**:
```typescript
export async function call(
onDone: LocalJSXCommandOnDone,
_context: LocalJSXCommandContext,
args: string,
): Promise<React.ReactNode> {
const parts = args.trim().split(/\s+/)
const sub = parts[0] || 'list'
// 委托给 templatesMain
const { templatesMain } = await import('../../cli/handlers/templateJobs.js')
// 捕获 console.log 输出作为结果返回给 REPL
const lines: string[] = []
const origLog = console.log
const origError = console.error
console.log = (...a: unknown[]) => lines.push(a.join(' '))
console.error = (...a: unknown[]) => lines.push(a.join(' '))
try {
await templatesMain([sub, ...parts.slice(1)])
} finally {
console.log = origLog
console.error = origError
}
onDone(lines.join('\n') || 'Done.', { display: 'system' })
return null
}
```
### 4. commands.ts 注册
```typescript
const jobCmd = feature('TEMPLATES')
? require('./commands/job/index.js').default
: null
// COMMANDS 数组:
...(jobCmd ? [jobCmd] : []),
```
## 验证清单
- [ ] `claude job list` 列出模板
- [ ] `claude job new <template>` 创建任务
- [ ] `claude job reply <id> <text>` 回复任务
- [ ] `claude job status <id>` 显示任务状态
- [ ] `claude job` (无参数) 等同于 `claude job list`
- [ ] `claude new/list/reply` 输出 deprecation 警告 + 正常工作
- [ ] REPL 中 `/job` 可用
- [ ] REPL 中 `/job list` 显示模板列表
- [ ] tsc --noEmit 零错误
- [ ] bun test 通过

View File

@@ -0,0 +1,123 @@
# Task 016: 向后兼容 + 测试
> 设计文档: [daemon-restructure-design.md](../features/daemon-restructure-design.md) § 五
> 依赖: Task 014, Task 015
> 分支: `feat/integrate-5-branches`
## 目标
确保旧命令向后兼容 (deprecation 警告 + 正常代理),并为重构后的命令结构编写测试。
## 文件清单
### 新增
| 文件 | 说明 |
|------|------|
| `src/daemon/__tests__/daemonMain.test.ts` | daemonMain 子命令路由测试 |
| `src/cli/bg/__tests__/engine.test.ts` | BgEngine 选择逻辑测试 |
| `src/cli/bg/__tests__/detached.test.ts` | DetachedEngine 启动/停止测试 |
| `src/cli/bg/__tests__/tail.test.ts` | 日志 tail 功能测试 |
### 修改
| 文件 | 变更 |
|------|------|
| `src/entrypoints/cli.tsx` | 确认 deprecation 路径正确代理 |
## 实现方案
### 1. 向后兼容矩阵
| 旧命令 | 新命令 | 处理方式 |
|--------|--------|---------|
| `claude ps` | `claude daemon status` | stderr 输出 `[deprecated] Use: claude daemon status`,然后执行 |
| `claude logs <x>` | `claude daemon logs <x>` | 同上 |
| `claude attach <x>` | `claude daemon attach <x>` | 同上 |
| `claude kill <x>` | `claude daemon kill <x>` | 同上 |
| `claude --bg` | `claude daemon bg` | 保留为快捷方式,**不** deprecate (太常用) |
| `claude new <t>` | `claude job new <t>` | stderr deprecation + 执行 |
| `claude list` | `claude job list` | stderr deprecation + 执行 |
| `claude reply <id>` | `claude job reply <id>` | stderr deprecation + 执行 |
**关键**: deprecation 输出到 stderr 而非 stdout不影响脚本管道。
### 2. 测试计划
#### 2.1 daemonMain 路由测试
```typescript
describe('daemonMain', () => {
test('无参数默认 status', async () => { ... })
test('start 调用 runSupervisor', async () => { ... })
test('stop 调用 handleDaemonStop', async () => { ... })
test('bg 委托给 bg.handleBgStart', async () => { ... })
test('attach 委托给 bg.attachHandler', async () => { ... })
test('logs 委托给 bg.logsHandler', async () => { ... })
test('kill 委托给 bg.killHandler', async () => { ... })
test('未知子命令设置 exitCode=1', async () => { ... })
})
```
#### 2.2 引擎选择测试
```typescript
describe('selectEngine', () => {
test('win32 返回 DetachedEngine', async () => { ... })
test('darwin + tmux 可用返回 TmuxEngine', async () => { ... })
test('darwin + tmux 不可用返回 DetachedEngine', async () => { ... })
test('linux + tmux 可用返回 TmuxEngine', async () => { ... })
})
```
#### 2.3 DetachedEngine 测试
```typescript
describe('DetachedEngine', () => {
test('available 始终返回 true', async () => { ... })
test('start 创建 detached 子进程并写入日志', async () => { ... })
test('start 返回的 PID 文件存在', async () => { ... })
})
```
#### 2.4 Tail 测试
```typescript
describe('tailLog', () => {
test('输出已有日志内容', async () => { ... })
test('追加内容时实时输出', async () => { ... })
test('SIGINT 退出 tail', async () => { ... })
})
```
### 3. 集成验证脚本
可选: 在 `scripts/` 下添加一个手动验证脚本:
```bash
#!/bin/bash
# scripts/verify-daemon-restructure.sh
echo "=== 1. claude daemon status ==="
bun run dev -- daemon status
echo "=== 2. claude daemon bg (should start) ==="
bun run dev -- daemon bg --help
echo "=== 3. claude ps (deprecated) ==="
bun run dev -- ps 2>&1 | head -1
echo "=== 4. claude job list ==="
bun run dev -- job list
echo "=== 5. claude list (deprecated) ==="
bun run dev -- list 2>&1 | head -1
```
## 验证清单
- [ ] 旧命令全部正常工作 (仅多一行 stderr 警告)
- [ ] `--bg` 保持无警告
- [ ] 所有新增测试通过
- [ ] 现有 2695 个测试无回归
- [ ] tsc --noEmit 零错误
- [ ] 手动在 Windows + macOS/Linux 上验证关键路径

View File

@@ -1,147 +0,0 @@
# Tool 系统测试计划
## 概述
Tool 系统是 Claude Code 的核心,负责工具的定义、注册、发现和过滤。本计划覆盖 `src/Tool.ts` 中的工具接口与工具函数、`src/tools.ts` 中的注册/过滤逻辑,以及各工具目录下可独立测试的纯函数。
## 被测文件
| 文件 | 关键导出 |
|------|----------|
| `src/Tool.ts` | `buildTool`, `toolMatchesName`, `findToolByName`, `getEmptyToolPermissionContext`, `filterToolProgressMessages` |
| `src/tools.ts` | `parseToolPreset`, `filterToolsByDenyRules`, `getAllBaseTools`, `getTools`, `assembleToolPool` |
| `src/tools/shared/gitOperationTracking.ts` | `parseGitCommitId`, `detectGitOperation` |
| `src/tools/shared/spawnMultiAgent.ts` | `resolveTeammateModel`, `generateUniqueTeammateName` |
| `src/tools/GrepTool/GrepTool.ts` | `applyHeadLimit`, `formatLimitInfo`(内部辅助函数) |
| `src/tools/FileEditTool/utils.ts` | 字符串匹配/补丁相关纯函数 |
---
## 测试用例
### src/Tool.ts
#### describe('buildTool')
- test('fills in default isEnabled as true') — 不传 isEnabled 时,构建的 tool.isEnabled() 应返回 true
- test('fills in default isConcurrencySafe as false') — 默认值应为 falsefail-closed
- test('fills in default isReadOnly as false') — 默认假设有写操作
- test('fills in default isDestructive as false') — 默认非破坏性
- test('fills in default checkPermissions as allow') — 默认 checkPermissions 应返回 `{ behavior: 'allow', updatedInput }`
- test('fills in default userFacingName from tool name') — userFacingName 默认应返回 tool.name
- test('preserves explicitly provided methods') — 传入自定义 isEnabled 等方法时应覆盖默认值
- test('preserves all non-defaultable properties') — name, inputSchema, call, description 等属性原样保留
#### describe('toolMatchesName')
- test('returns true for exact name match') — `{ name: 'Bash' }` 匹配 'Bash'
- test('returns false for non-matching name') — `{ name: 'Bash' }` 不匹配 'Read'
- test('returns true when name matches an alias') — `{ name: 'Bash', aliases: ['BashTool'] }` 匹配 'BashTool'
- test('returns false when aliases is undefined') — `{ name: 'Bash' }` 不匹配 'BashTool'
- test('returns false when aliases is empty') — `{ name: 'Bash', aliases: [] }` 不匹配 'BashTool'
#### describe('findToolByName')
- test('finds tool by primary name') — 从 tools 列表中按 name 找到工具
- test('finds tool by alias') — 从 tools 列表中按 alias 找到工具
- test('returns undefined when no match') — 找不到时返回 undefined
- test('returns first match when duplicates exist') — 多个同名工具时返回第一个
#### describe('getEmptyToolPermissionContext')
- test('returns default permission mode') — mode 应为 'default'
- test('returns empty maps and arrays') — additionalWorkingDirectories 为空 Maprules 为空对象
- test('returns isBypassPermissionsModeAvailable as false')
#### describe('filterToolProgressMessages')
- test('filters out hook_progress messages') — 移除 type 为 hook_progress 的消息
- test('keeps tool progress messages') — 保留非 hook_progress 的消息
- test('returns empty array for empty input')
- test('handles messages without type field') — data 不含 type 时应保留
---
### src/tools.ts
#### describe('parseToolPreset')
- test('returns "default" for "default" input') — 精确匹配
- test('returns "default" for "Default" input') — 大小写不敏感
- test('returns null for unknown preset') — 未知字符串返回 null
- test('returns null for empty string')
#### describe('filterToolsByDenyRules')
- test('returns all tools when no deny rules') — 空 deny 规则不过滤任何工具
- test('filters out tools matching blanket deny rule') — deny rule `{ toolName: 'Bash' }` 应移除 Bash
- test('does not filter tools with content-specific deny rules') — deny rule `{ toolName: 'Bash', ruleContent: 'rm -rf' }` 不移除 Bash只在运行时阻止特定命令
- test('filters MCP tools by server name prefix') — deny rule `mcp__server` 应移除该 server 下所有工具
- test('preserves tools not matching any deny rule')
#### describe('getAllBaseTools')
- test('returns a non-empty array of tools') — 至少包含核心工具
- test('each tool has required properties') — 每个工具应有 name, inputSchema, call 等属性
- test('includes BashTool, FileReadTool, FileEditTool') — 核心工具始终存在
- test('includes TestingPermissionTool when NODE_ENV is test') — 需设置 env
#### describe('getTools')
- test('returns filtered tools based on permission context') — 根据 deny rules 过滤
- test('returns simple tools in CLAUDE_CODE_SIMPLE mode') — 仅返回 Bash/Read/Edit
- test('filters disabled tools via isEnabled') — isEnabled 返回 false 的工具被排除
---
### src/tools/shared/gitOperationTracking.ts
#### describe('parseGitCommitId')
- test('extracts commit hash from git commit output') — 从 `[main abc1234] message` 中提取 `abc1234`
- test('returns null for non-commit output') — 无法解析时返回 null
- test('handles various branch name formats') — `[feature/foo abc1234]`
#### describe('detectGitOperation')
- test('detects git commit operation') — 命令含 `git commit` 时识别为 commit
- test('detects git push operation') — 命令含 `git push` 时识别
- test('returns null for non-git commands') — 非 git 命令返回 null
- test('detects git merge operation')
- test('detects git rebase operation')
---
### src/tools/shared/spawnMultiAgent.ts
#### describe('resolveTeammateModel')
- test('returns specified model when provided')
- test('falls back to default model when not specified')
#### describe('generateUniqueTeammateName')
- test('generates a name when no existing names') — 无冲突时返回基础名
- test('appends suffix when name conflicts') — 与已有名称冲突时添加后缀
- test('handles multiple conflicts') — 多次冲突时递增后缀
---
## Mock 需求
| 依赖 | Mock 方式 | 说明 |
|------|-----------|------|
| `bun:bundle` (feature) | 已 polyfill 为 `() => false` | 不需额外 mock |
| `process.env` | `bun:test` mock | 测试 `USER_TYPE``NODE_ENV``CLAUDE_CODE_SIMPLE` |
| `getDenyRuleForTool` | mock module | `filterToolsByDenyRules` 测试中需控制返回值 |
| `isToolSearchEnabledOptimistic` | mock module | `getAllBaseTools` 中条件加载 |
## 集成测试场景
放在 `tests/integration/tool-chain.test.ts`
### describe('Tool registration and discovery')
- test('getAllBaseTools returns tools that can be found by findToolByName') — 注册 → 查找完整链路
- test('filterToolsByDenyRules + getTools produces consistent results') — 过滤管线一致性
- test('assembleToolPool deduplicates built-in and MCP tools') — 合并去重逻辑

Some files were not shown because too many files have changed in this diff Show More