diff --git a/docs/features/all-features-guide.md b/docs/features/all-features-guide.md new file mode 100644 index 000000000..3323ee97b --- /dev/null +++ b/docs/features/all-features-guide.md @@ -0,0 +1,562 @@ +# 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 — 删除指定任务 +``` + +--- + +## 4. Voice Mode 语音模式 + +**PR**: #92 `feat: enable /voice mode with native audio binaries` +**Feature Flag**: `VOICE_MODE` + +### 说明 +Push-to-Talk 语音输入,音频通过 WebSocket 流式传输到 Anthropic STT(Nova 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 + Windows,Linux 后端待完成。 + +### 使用 +```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 实例通过 UDS(Unix 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 — 选中实例 +/pipes all — 全选 +/pipes none — 取消全选 +/attach — 手动 attach 某实例 +/detach — 断开连接 +/send — 向指定实例发送消息 +/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 ` 自动转为 PowerShell 循环: +```powershell +while($true){ ; Start-Sleep -Seconds } +``` + +**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/build | 伴侣系统 | +| `BRIDGE_MODE` | ✅ dev/build | 远程控制 | +| `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/build | Pipe IPC | +| `LAN_PIPES` | ✅ dev/build | 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 | 上下文折叠 | + +手动启用任意 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 | diff --git a/docs/features/lan-pipes-implementation.md b/docs/features/lan-pipes-implementation.md index c25b3391a..36240fc18 100644 --- a/docs/features/lan-pipes-implementation.md +++ b/docs/features/lan-pipes-implementation.md @@ -1,545 +1,321 @@ -# LAN Pipes 实现文档 +# LAN Pipes — 技术实现文档 -## 1. 概述 +面向开发者的实现细节。用户指南见 [lan-pipes.md](./lan-pipes.md)。 -### 1.1 目标 - -在现有 UDS (Unix Domain Socket) 本地 Pipe 通讯系统基础上,增加 **TCP 传输层** 和 **UDP Multicast 发现机制**,使同一局域网内不同机器上的 Claude Code CLI 实例可以: - -1. **自动发现** — 通过 UDP multicast 零配置发现 LAN 内的其他实例 -2. **TCP 连接** — 通过 TCP 建立跨机器的双向 NDJSON 管道 -3. **复用现有协议** — attach/detach/prompt/stream 等消息类型无需修改 - -### 1.2 设计原则 - -- **向后兼容**:所有 LAN 功能通过 `feature('LAN_PIPES')` 门控,不影响现有 UDS 功能 -- **双模式共存**:PipeServer 同时监听 UDS 和 TCP,PipeClient 根据参数自动选择连接模式 -- **本地优先**:本地 registry 条目优先于 LAN beacon 发现的条目 -- **安全保守**:TCP 连接需用户显式同意,multicast TTL=1 不跨路由器 +--- -### 1.3 架构总览 +## 架构 ``` -Machine A (192.168.1.10) Machine B (192.168.1.20) +Machine A (192.168.50.22) Machine B (192.168.50.27) ┌───────────────────────────┐ ┌───────────────────────────┐ │ PipeServer │ │ PipeServer │ -│ UDS: cli-abc.sock │ │ UDS: cli-def.sock │ -│ TCP: 0.0.0.0: │◄──TCP───►│ TCP: 0.0.0.0: │ +│ UDS: ~/.claude/pipes/ │ │ UDS: ~/.claude/pipes/ │ +│ cli-abc.sock │ │ cli-def.sock │ +│ TCP: 0.0.0.0: │◄──TCP───►│ TCP: 0.0.0.0: │ ├───────────────────────────┤ ├───────────────────────────┤ │ LanBeacon │ │ LanBeacon │ -│ UDP multicast │◄──UDP───►│ UDP multicast │ -│ 224.0.71.67:7101 │ mcast │ 224.0.71.67:7101 │ +│ UDP 224.0.71.67:7101 │◄──UDP───►│ UDP 224.0.71.67:7101 │ ├───────────────────────────┤ ├───────────────────────────┤ -│ PipeRegistry │ │ PipeRegistry │ -│ registry.json (local) │ │ registry.json (local) │ -│ + mergeWithLanPeers() │ │ + mergeWithLanPeers() │ +│ usePipeIpc (hook) │ │ usePipeIpc (hook) │ +│ initPipeServer │ │ initPipeServer │ +│ registerMessageHandlers │ │ registerMessageHandlers │ +│ runMainHeartbeat │ │ runSubHeartbeat │ +│ cleanupPipeIpc │ │ cleanupPipeIpc │ └───────────────────────────┘ └───────────────────────────┘ ``` ---- - -## 2. Feature Flag +## Feature Flag -### 2.1 注册 +`LAN_PIPES` — 在 `scripts/dev.ts` 和 `build.ts` 的 `DEFAULT_FEATURES` 中启用。 -**文件**: `scripts/dev.ts` (L49), `build.ts` (L43) +所有 LAN 代码路径通过 `feature('LAN_PIPES')` 编译时门控。`feature()` 只能在 `if` 或三元中使用(Bun 编译时常量约束)。 -`LAN_PIPES` 添加到 `DEFAULT_FEATURES` / `DEFAULT_BUILD_FEATURES` 数组中,dev 和 build 默认启用。 - -也可通过环境变量 `FEATURE_LAN_PIPES=1` 单独启用。 - -### 2.2 使用约束 +--- -Bun 的 `feature()` 只能在 `if` 语句或三元条件中直接使用(编译时常量),不能赋值给变量。所有使用点均遵循此约束。 +## 核心文件 + +| 文件 | 说明 | +|------|------| +| `src/utils/pipeTransport.ts` | PipeServer/PipeClient(UDS + 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 注册表 + 消息订阅 | --- -## 3. 核心变更详情 +## PipeServer TCP 扩展 -### 3.1 PipeServer TCP 扩展 +`src/utils/pipeTransport.ts` -**文件**: `src/utils/pipeTransport.ts` - -#### 新增类型 +### 类型 ```typescript export type PipeTransportMode = 'uds' | 'tcp' export type TcpEndpoint = { host: string; port: number } -export type PipeServerOptions = { - enableTcp?: boolean - tcpPort?: number // 0 = 随机端口 -} +export type PipeServerOptions = { enableTcp?: boolean; tcpPort?: number } ``` -#### PipeServer 类变更 +### PipeServer 变更 -| 成员 | 变更类型 | 说明 | -|------|----------|------| -| `tcpServer: Server \| null` | 新增字段 | TCP net.Server 实例 | -| `_tcpAddress: TcpEndpoint \| null` | 新增字段 | TCP 监听地址 | -| `tcpAddress` getter | 新增 | 公开 TCP 端口信息 | -| `setupSocket(socket)` | 重构提取 | 从 `start()` 中提取,UDS 和 TCP 共用 | -| `start(options?)` | 修改签名 | 新增可选 `PipeServerOptions` 参数 | -| `startTcpServer(port)` | 新增私有方法 | 启动 TCP 监听 | -| `close()` | 修改 | 增加 TCP server 关闭逻辑 | +- `setupSocket(socket)` — 从 start() 提取的共享方法,UDS 和 TCP 共用 +- `start(options?)` — 可选启用 TCP,port=0 让 OS 分配 +- 内部维护两个 `net.Server`,共享同一组 `clients: Set` 和 `handlers` +- `tcpAddress` getter 暴露 TCP 端口 +- `close()` 同时关闭两个 server -**关键设计决策**:`setupSocket()` 方法被提取为共享逻辑,使 UDS 和 TCP 的 socket 处理完全一致。两种传输模式共享同一组 `clients: Set` 和 `handlers`,对上层代码完全透明。 +socket 帧解析使用 `attachNdjsonFramer()` from `ndjsonFramer.ts`(替代原先 3 份重复代码)。 -#### 代码路径 +### PipeClient 变更 -``` -start(options?) - ├── ensurePipesDir() - ├── 清理 stale socket (Unix) - ├── createServer() → UDS 监听 (现有逻辑) - │ └── setupSocket() ← 提取的共享逻辑 - └── if options.enableTcp - └── startTcpServer(port) - ├── createServer() → TCP 监听 0.0.0.0 - │ └── setupSocket() ← 同一个方法 - └── 记录 _tcpAddress -``` - -### 3.2 PipeClient TCP 扩展 - -**文件**: `src/utils/pipeTransport.ts` - -#### PipeClient 类变更 - -| 成员 | 变更类型 | 说明 | -|------|----------|------| -| `tcpEndpoint: TcpEndpoint \| null` | 新增字段 | TCP 连接目标 | -| `constructor(target, sender?, tcpEndpoint?)` | 修改签名 | 新增可选 TCP endpoint | -| `connect(timeout)` | 修改 | 根据 tcpEndpoint 分派 | -| `connectTcp(timeout)` | 新增私有方法 | TCP 连接实现 | -| `connectUds(timeout)` | 重构提取 | 原 `connect()` 的 UDS 逻辑 | - -**关键设计决策**:TCP 连接不需要等待文件存在(UDS 的 `access()` 轮询),直接建立 TCP 连接。超时机制相同。 - -### 3.3 工厂函数更新 - -```typescript -// 新签名 -export async function createPipeServer( - name: string, - options?: PipeServerOptions, // 新增 -): Promise - -export async function connectToPipe( - targetName: string, - senderName?: string, - timeoutMs?: number, - tcpEndpoint?: TcpEndpoint, // 新增 -): Promise -``` +- 构造函数新增可选 `TcpEndpoint` 参数 +- `connect()` 根据 tcpEndpoint 分派到 `connectTcp()` 或 `connectUds()` +- TCP 不需要文件存在轮询,直接建连 --- -### 3.4 LAN Beacon — UDP Multicast 发现 +## LAN Beacon -**文件**: `src/utils/lanBeacon.ts` (新文件,~170 行) +`src/utils/lanBeacon.ts` -#### 协议参数 +### 协议参数 -| 参数 | 值 | 说明 | -|------|-----|------| -| Multicast 组 | `224.0.71.67` | "CC" = Claude Code 的 ASCII 对应 | -| 端口 | `7101` | 固定 UDP 端口 | -| 广播间隔 | `3000ms` | 3 秒一次 announce | -| Peer 超时 | `15000ms` | 15 秒无 announce 视为 lost | -| TTL | `1` | 仅链路本地,不跨路由器 | +| 参数 | 值 | +|------|-----| +| Multicast 组 | `224.0.71.67` | +| 端口 | `7101` | +| 广播间隔 | `3000ms` | +| Peer 超时 | `15000ms` | +| TTL | `1` | -#### Announce 包格式 +### Announce 包 ```typescript type LanAnnounce = { - proto: 'claude-pipe-v1' // 协议标识符(用于过滤非本协议 UDP 包) - pipeName: string // e.g. "cli-abc12345" - machineId: string // OS-level 稳定指纹 - hostname: string // 主机名 - ip: string // 发送端本地 IPv4 - tcpPort: number // TCP PipeServer 端口 - role: 'main' | 'sub' // 当前角色 - ts: number // unix ms 时间戳 + proto: 'claude-pipe-v1' + pipeName: string + machineId: string + hostname: string + ip: string + tcpPort: number + role: 'main' | 'sub' + ts: number } ``` -#### LanBeacon 类 API +### API ```typescript class LanBeacon extends EventEmitter { constructor(announce: Omit) - start(): void // 开始广播 + 监听 - stop(): void // 停止并释放资源 - getPeers(): Map // 当前已知 peers - updateAnnounce(partial): void // 更新自身 announce 数据 + start(): void + stop(): void + getPeers(): Map // 防御性拷贝 + updateAnnounce(partial): void // 使用 spread(不可变更新) - // Events on('peer-discovered', (peer: LanAnnounce) => void) on('peer-lost', (pipeName: string) => void) } ``` -#### 内部行为 +### 存储 -1. **启动**:`createSocket({ type: 'udp4', reuseAddr: true })` → `bind(7101)` → `addMembership('224.0.71.67')` → `setMulticastTTL(1)` -2. **广播**:`setInterval(sendAnnounce, 3000)` + 启动时立即发一次 -3. **接收**:`socket.on('message')` → JSON.parse → 过滤 `proto !== 'claude-pipe-v1'` 和自身 → 更新 peers Map → 触发 `peer-discovered` 事件 -4. **清理**:`setInterval(cleanupStalePeers, 7500)` — 超过 15 秒未收到 announce 的 peer 从 Map 移除,触发 `peer-lost` 事件 -5. **停止**:清除所有 timer → `dropMembership` → `socket.close()` → 清空 peers +module-level singleton:`getLanBeacon()` / `setLanBeacon()`。不挂在 Zustand state 上(避免 `setState` 展开时丢失引用)。 -#### 错误处理 +### 网卡绑定 -所有 socket/网络错误均为 **non-fatal**(logError 但不 throw)。multicast 在某些网络环境可能不支持,这不应阻止 CLI 正常运行。 +`addMembership(group, localIp)` + `setMulticastInterface(localIp)` 指定 LAN 网卡。解决 Windows 上 WSL/Docker 虚拟网卡劫持 multicast 的问题。 --- -### 3.5 Registry 扩展 +## Hook 架构 -**文件**: `src/utils/pipeRegistry.ts` +从 REPL.tsx 提取的 ~830 行 Pipe IPC 代码: -#### 类型变更 +### usePipeIpc(生命周期) -```typescript -export interface PipeRegistryEntry { - // ... 现有字段 ... - tcpPort?: number // 新增:TCP 监听端口 - lanVisible?: boolean // 新增:是否参与 LAN 广播 -} -``` +`src/hooks/usePipeIpc.ts`(623 行) -#### 新增函数 +在 REPL.tsx 顶层通过 feature-gated require 加载: ```typescript -export type MergedPipeEntry = { - id: string - pipeName: string - role: string - machineId: string - ip: string - hostname: string - alive: boolean - source: 'local' | 'lan' // 来源标识 - tcpEndpoint?: TcpEndpoint // LAN peer 的 TCP 端点 -} +const usePipeIpc = feature('UDS_INBOX') + ? require('../hooks/usePipeIpc.js').usePipeIpc + : () => undefined; -export function mergeWithLanPeers( - registry: PipeRegistry, - lanPeers: Map, -): MergedPipeEntry[] +// 组件内 +usePipeIpc({ store, handleIncomingPrompt }); ``` -**合并逻辑**: -1. 先添加本地 registry 的 main 和所有 subs(`source: 'local'`) -2. 遍历 LAN peers,跳过已在本地 registry 中存在的 pipeName -3. 剩余的 LAN peers 作为 `source: 'lan'` 条目添加 - ---- - -### 3.6 Peer Address 扩展 - -**文件**: `src/utils/peerAddress.ts` - -#### parseAddress 变更 +内部使用 **lazy getter** 函数加载依赖(避免循环依赖导致 Bun 运行时崩溃): ```typescript -// 之前 -export function parseAddress(to: string): { - scheme: 'uds' | 'bridge' | 'other' - target: string -} - -// 之后 -export function parseAddress(to: string): { - scheme: 'uds' | 'bridge' | 'tcp' | 'other' // 新增 'tcp' - target: string -} +const pt = () => require('../utils/pipeTransport.js') +const pr = () => require('../utils/pipeRegistry.js') +const mm = () => require('./useMasterMonitor.js') +// ... ``` -新增 `tcp:` 前缀解析:`tcp:192.168.1.20:7100` → `{ scheme: 'tcp', target: '192.168.1.20:7100' }` +`import type` 用于静态类型(不会触发模块加载)。 -#### 新增 parseTcpTarget +### 四个阶段函数 -```typescript -export function parseTcpTarget( - target: string, -): { host: string; port: number } | null -``` +| 函数 | 职责 | +|------|------| +| `initPipeServer` | 角色判定 + server 创建 + beacon 启动 | +| `registerMessageHandlers` | ping、attach、prompt、permission、detach 五个 handler | +| `runMainHeartbeat` | cleanup + 发现 + auto-attach + 清理死连接 | +| `runSubHeartbeat` | 检测 main 是否存活,死亡则接管或独立 | -解析 `host:port` 字符串,正则 `^([^:]+):(\d+)$`。 +### usePipeRelay(消息回传) ---- +`src/hooks/usePipeRelay.ts`(38 行) -### 3.7 REPL Bootstrap 集成 +提供 `relayPipeMessage()` 和 `pipeReturnHadErrorRef`。relay 函数通过 `getPipeRelay()` module singleton 读取(替代 `globalThis.__pipeSendToMaster`)。 -**文件**: `src/screens/REPL.tsx` +### usePipePermissionForward(权限转发) -#### 启动阶段 (L5165-5200) +`src/hooks/usePipePermissionForward.ts`(159 行) -在现有 `createPipeServer(pipeName)` 调用处: +订阅 `subscribePipeEntries()`,处理: +- `permission_request` → 解析 payload → 查找 tool → 加入确认队列 +- `permission_cancel` → 从队列移除 +- `stream/error/done` → 转为系统消息显示(含 role + IP 标签) -```typescript -// 根据 LAN_PIPES flag 决定是否启用 TCP -const server = await createPipeServer( - pipeName, - feature('LAN_PIPES') ? { enableTcp: true, tcpPort: 0 } : undefined -); - -// 启动 LAN beacon -if (feature('LAN_PIPES') && server.tcpAddress) { - const { LanBeacon } = require('../utils/lanBeacon.js'); - lanBeaconInstance = new LanBeacon({ - pipeName, machineId, hostname, ip, tcpPort: server.tcpAddress.port, role - }); - lanBeaconInstance.start(); - - // Store beacon in module-level singleton (not on Zustand state) - const { setLanBeacon } = require('../utils/lanBeacon.js'); - setLanBeacon(lanBeaconInstance); - - // 注册 entry 时附带 tcpPort - await registerAsMain({ ...entry, tcpPort: server.tcpAddress.port, lanVisible: true }); -} -``` +### usePipeRouter(输入路由) -#### Heartbeat ��段 +`src/hooks/usePipeRouter.ts`(130 行) -在 main heartbeat 循环中: - -1. `refreshDiscoveredPipes(aliveSubs)` 同时包含本地 subs 和 LAN beacon peers -2. auto-attach 循环同时遍历本地 subs 和 LAN peers(LAN peers 通过 TCP endpoint 连接) -3. cleanup 时检查 LAN beacon peers 列表,避免误删 LAN 连接 - -```typescript -// auto-attach 统一目标列表:本地 subs + LAN peers -const attachTargets = [...aliveSubs.map(s => ({ pipeName: s.pipeName }))]; -if (feature('LAN_PIPES')) { - const beacon = getLanBeacon(); - for (const [name, peer] of beacon.getPeers()) { - attachTargets.push({ pipeName: name, tcpEndpoint: { host: peer.ip, port: peer.tcpPort } }); - } -} -``` - -#### Cleanup 阶段 - -```typescript -// 停止 LAN beacon -const { getLanBeacon, setLanBeacon } = require('../utils/lanBeacon.js'); -const beacon = getLanBeacon(); -if (beacon) { - try { beacon.stop(); } catch {} - setLanBeacon(null); -} -``` - -**Beacon 存储方案**:使用 `lanBeacon.ts` 中的 module-level singleton(`getLanBeacon()`/`setLanBeacon()`),不挂在 Zustand store state 上,避免 `setState` 展开时丢失引用。 - ---- - -### 3.8 /pipes 命令 LAN 显示 - -**文件**: `src/commands/pipes/pipes.ts` - -在现有 registry 显示之后,如果 `feature('LAN_PIPES')` 启用: - -1. 通过 `getLanBeacon()` 获取 LAN peers -2. 调用 `mergeWithLanPeers()` 合并 -3. 过滤 `source === 'lan'` 的条目 -4. 显示格式:`☐ [role] pipeName hostname/ip tcp:host:port [LAN]` - ---- - -### 3.9 /attach 命令 TCP 支持 - -**文件**: `src/commands/attach/attach.ts` - -在连接之前,如果 `feature('LAN_PIPES')` 启用: - -1. 在 `discoveredPipes` 中查找目标 pipe -2. 通过 `_lanBeacon.getPeers()` 检查是否为 LAN peer -3. 如果是,构造 `TcpEndpoint` 传给 `connectToPipe()` -4. 错误消息中包含 TCP 端点信息便于诊断 +提供 `routeToSelectedPipes(input): boolean`。读取 `selectedPipes` + `routeMode`,逐个发送到已连接目标。通知显示 `[role] hostname/ip`(LAN peer)或 `[role]`(本机)。 --- -### 3.10 SendMessageTool TCP 支持 - -**文件**: `src/tools/SendMessageTool/SendMessageTool.ts` +## Registry 并行探测 -#### inputSchema 描述更新 +`src/utils/pipeRegistry.ts` -当 `LAN_PIPES` 启用时,`to` 字段描述追加 `, or "tcp::" for a LAN peer`。 - -#### checkPermissions +### getAliveSubs() ```typescript -if (feature('LAN_PIPES') && parseAddress(input.to).scheme === 'tcp') { - return { - behavior: 'ask', - message: `Send a message to LAN peer ${input.to}?...`, - decisionReason: { - type: 'safetyCheck', - reason: 'Cross-machine LAN message requires explicit user consent', - classifierApprovable: false, - }, - } +export async function getAliveSubs(): Promise { + 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) } ``` -**安全设计**:`classifierApprovable: false` 确保自动模式不会跳过用户确认。 +### cleanupStaleEntries() -#### validateInput +两阶段: +1. **无锁并行探测**:`Promise.all` 探测 main + 所有 subs +2. **短暂持锁写入**:`acquireLock()` → 重新读取 → 应用变更 → 写入 → `releaseLock()` -新增 `tcp:` scheme 验证分支(与 `uds:` 类似,仅允许 plain text 消息)。 +持锁时间从 N 秒降至 ~10ms。 -#### call() +### getMachineId() -```typescript -if (addr.scheme === 'tcp' && feature('LAN_PIPES')) { - const ep = parseTcpTarget(addr.target); - const client = new PipeClient(input.to, `send-${process.pid}`, ep); - await client.connect(5000); - client.send({ type: 'chat', data: input.message }); - client.disconnect(); - return { data: { success: true, message: `... → TCP ${ep.host}:${ep.port}` } }; -} -``` +Windows/macOS 使用 `execFile`(异步),不阻塞主线程。结果缓存,仅首次调用执行。 --- -## 4. 数据流 - -### 4.1 LAN 发现流程 - -``` -CLI-A 启动 - → PipeServer.start({ enableTcp: true, tcpPort: 0 }) - → TCP server 监听 0.0.0.0:随机端口 - → LanBeacon.start() - → 每 3s 广播 UDP announce (pipeName, ip, tcpPort, role, machineId) - -CLI-B 启动 (另一台机器) - → 同上 - → LanBeacon 收到 CLI-A 的 announce - → peer-discovered 事件 - → Heartbeat 循环合并 LAN peers 到 discoveredPipes - -用户在 CLI-B 执行 /pipes - → 显示 CLI-A 条目,标记 [LAN] -``` +## NDJSON 协议 -### 4.2 跨机器 Attach 流程 +### 消息类型 -``` -CLI-B 执行 /attach cli-abc12345 - → feature('LAN_PIPES') → 查找 discoveredPipes → 找到 LAN peer - → _lanBeacon.getPeers() → 获取 { ip: '192.168.1.10', tcpPort: 7100 } - → connectToPipe(name, myName, undefined, { host: '192.168.1.10', port: 7100 }) - → PipeClient.connectTcp() → net.createConnection({ host, port }) - → client.send({ type: 'attach_request' }) - → 等待 attach_accept / attach_reject - → 成功:注册 slave client,切换 master 角色 -``` +| 类型 | 方向 | 数据 | +|------|------|------| +| `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 })` | -### 4.3 跨机器消息发送 +### 帧格式 +每行一个 JSON 对象,`\n` 分隔: ``` -用户或 AI 使用 SendMessageTool - → to: "tcp:192.168.1.20:7102" - → checkPermissions → behavior: 'ask' → 用户确认 - → parseTcpTarget('192.168.1.20:7102') → { host, port } - → new PipeClient(to, sender, { host, port }) - → client.connect(5000) - → client.send({ type: 'chat', data: message }) - → client.disconnect() +{"type":"ping","from":"cli-abc","ts":"2026-04-11T00:00:00.000Z"}\n +{"type":"prompt","data":"检查 git status","from":"cli-abc"}\n ``` --- -## 5. 测试 - -### 5.1 新增测试文件 - -| 文件 | 测试数 | 覆盖内容 | -|------|--------|----------| -| `src/utils/__tests__/lanBeacon.test.ts` | 7 | socket 初始化、announce 发送、peer 发现、自身过滤、协议过滤、role 更新 | -| `src/utils/__tests__/peerAddress.test.ts` | 8 | uds/bridge/tcp/other scheme 解析、parseTcpTarget 正确/异常 | - -### 5.2 测试策略 - -- **lanBeacon.test.ts**:mock dgram 模块,验证 beacon 的发送/接收/清理逻辑 -- **peerAddress.test.ts**:纯函数测试,无外部依赖 -- **现有 pipeTransport.test.ts**:2 个现有测试继续通过(TCP 扩展不改变 UDS 行为) - -### 5.3 测试结果 +## 跨机器 Attach 流程 ``` -全量测试:2190 pass / 0 fail / 130 files / 4.27s +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' } ``` ---- - -## 6. 变更文件清单 - -| 文件 | 操作 | 变更行数(约) | -|------|------|-------------| -| `scripts/dev.ts` | 修改 | +1 (feature flag) | -| `build.ts` | 修改 | +1 (feature flag) | -| `src/utils/pipeTransport.ts` | 修改 | +120 (TCP 扩展) | -| `src/utils/lanBeacon.ts` | **新增** | ~170 (UDP beacon) | -| `src/utils/pipeRegistry.ts` | 修改 | +80 (类型 + merge 函数) | -| `src/utils/peerAddress.ts` | 修改 | +12 (tcp scheme + parseTcpTarget) | -| `src/screens/REPL.tsx` | 修改 | +45 (bootstrap + heartbeat + cleanup) | -| `src/commands/pipes/pipes.ts` | 修改 | +25 (LAN peers 显示) | -| `src/commands/attach/attach.ts` | 修改 | +25 (TCP endpoint 解析) | -| `src/tools/SendMessageTool/SendMessageTool.ts` | 修改 | +45 (tcp scheme 全链路) | -| `src/utils/__tests__/lanBeacon.test.ts` | **新增** | ~140 (7 tests) | -| `src/utils/__tests__/peerAddress.test.ts` | **新增** | ~60 (8 tests) | -| `docs/features/lan-pipes.md` | **新增** | ~90 (用户文档) | +关键:跨机器 attach 不要求对方是 sub 角色。通过 `machineId` 区分 LAN peer。 --- -## 7. 已知限制和后续改进 - -### 7.1 当前限制 - -1. **无 TCP 认证**:TCP 连接无握手认证,同一局域网内任何知道端口号的进程都能连接 -2. **beacon ref 通过 `(state as any)._lanBeacon` 传递**:这是一个 pragmatic hack,因为 AppState 类型由 decompiled 代码定义,修改类型的成本过高 -3. **multicast 依赖网络环境**:部分企业网络、AP 隔离的 WiFi 可能不支持 multicast -4. **TCP 端口随机**:每次启动分配不同端口,需依赖 beacon 发现 +## SendMessageTool TCP 支持 -### 7.2 后续改进方向 +`src/tools/SendMessageTool/SendMessageTool.ts` -1. **HMAC-SHA256 认证**:首次 TCP 握手交换 machineId + challenge token -2. **heartbeat 中 TCP auto-attach LAN peers**:目前 heartbeat 只 auto-attach 本地 registry 的 subs,LAN peers 需手动 /attach -3. **固定端口范围配置**:允许用户配置 TCP 端口范围,便于防火墙规则 -4. **mDNS/DNS-SD 作为 beacon 替代**:在 multicast 受限的环境提供更可靠的发现 -5. **加密传输**:TLS over TCP,确保消息不被中间人窃听 +- `to` 字段支持 `tcp:host:port` 格式 +- `checkPermissions`:`tcp:` scheme 返回 `behavior: 'ask'`,`classifierApprovable: false` +- `call()`:创建临时 `PipeClient` → connect → send → disconnect --- -## 8. 防火墙要求 +## 测试 -| 协议 | 端口 | 方向 | 用途 | -|------|------|------|------| -| UDP | 7101 | IN + OUT | Multicast beacon 发现 | -| TCP | 动态 (0) | IN | PipeServer TCP 监听 | +| 文件 | 测试数 | 覆盖 | +|------|--------|------| +| `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 注册/移除、事件发射 | -### Windows +全量:2190 pass / 0 fail -```powershell -netsh advfirewall firewall add rule name="Claude LAN Beacon" dir=in action=allow protocol=UDP localport=7101 -netsh advfirewall firewall add rule name="Claude LAN Pipes" dir=in action=allow program="" enable=yes -``` +--- -### macOS +## 已知限制 -首次运行时系统弹窗允许即可。 +1. **TCP 无认证** — 同 LAN 内知道端口号即可连接 +2. **Beacon 明文广播** — IP/hostname/machineId 未 hash +3. **单网卡选择** — `getLocalIp()` 返回首个非内部 IPv4,可能选到 VPN +4. **端口随机** — 每次启动不同端口,依赖 beacon 发现 +5. **SendMessageTool 每次创建新连接** — 未复用已有 slave client -### Linux +## 后续改进方向 -```bash -sudo firewall-cmd --add-port=7101/udp -# TCP 端口随机,建议放行 bun 进程 -``` +1. HMAC-SHA256 TCP 握手认证 +2. machineId hash 后再广播 +3. 多网卡选择(优先 RFC 1918 地址) +4. 固定端口范围配置 +5. TLS 加密传输 +6. SendMessageTool 复用已连接的 slave client diff --git a/docs/features/lan-pipes.md b/docs/features/lan-pipes.md index 62cac518b..94af42f83 100644 --- a/docs/features/lan-pipes.md +++ b/docs/features/lan-pipes.md @@ -1,86 +1,193 @@ -# LAN Pipes — 局域网跨机器通讯 +# LAN Pipes — 局域网多机器群控指南 -## 概述 +## 什么是 LAN Pipes -在现有 UDS (Unix Domain Socket) 本地 Pipe 通讯基础上,增加 TCP 传输层和 UDP Multicast 发现机制,使同一局域网内不同机器上的 Claude Code 实例可以互相发现、连接和双向通讯。 +LAN Pipes 让多台机器上的 Claude Code 实例通过局域网自动发现并协作。你可以在一台机器(main)上操控其他机器(sub)上的 Claude Code,发送 prompt、查看执行结果、审批权限请求——全程零配置。 -## Feature Flag +基于本机 Pipe IPC(`UDS_INBOX`)扩展,新增 TCP 传输层 + UDP Multicast 发现。 -`LAN_PIPES` — dev/build 默认启用。也可通过 `FEATURE_LAN_PIPES=1` 环境变量启用。 +## 前置条件 -## 架构 +- 两台或以上机器在同一局域网 +- 每台机器安装了 CCB 并能 `bun run dev` +- Feature flag `LAN_PIPES`(dev/build 默认开启) +- 防火墙允许 UDP 7101 + TCP 动态端口(见下方配置) -``` -Machine A (192.168.1.10) Machine B (192.168.1.20) -┌─────────────────────────┐ ┌─────────────────────────┐ -│ PipeServer │ │ PipeServer │ -│ UDS: cli-abc.sock │ │ UDS: cli-def.sock │ -│ TCP: 0.0.0.0:7100 │◄─TCP────►│ TCP: 0.0.0.0:7102 │ -├─────────────────────────┤ ├─────────────────────────┤ -│ LanBeacon │◄─UDP─────│ LanBeacon │ -│ multicast 224.0.71.67 │ mcast ►│ multicast 224.0.71.67 │ -└─────────────────────────┘ └─────────────────────────┘ -``` +## 快速开始 -## 组件 +### 第一步:配置防火墙 -### 1. PipeServer TCP 扩展 (`pipeTransport.ts`) +**每台机器都需要执行。** -- `PipeServer.start()` 接受 `PipeServerOptions`,可选启用 TCP 监听 -- 内部维护两个 `net.Server` — UDS + TCP,共享同一组 clients 和 handlers -- `PipeServer.tcpAddress` getter 返回 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 +``` -### 2. PipeClient TCP 扩展 (`pipeTransport.ts`) +验证网络为"专用"(非公共):`Get-NetConnectionProfile` -- 构造函数新增可选 `TcpEndpoint` 参数 -- `connect()` 根据是否有 TCP endpoint 选择连接模式 -- 对下游调用者完全透明 +**macOS**: +首次运行时系统弹出"允许接受传入连接"对话框,点击"允许"。 -### 3. LAN Beacon (`lanBeacon.ts`) +如果使用 pf 防火墙: +```bash +echo "pass in proto udp from any to any port 7101" | sudo pfctl -ef - +``` -- UDP multicast 组: `224.0.71.67:7101` -- 每 3 秒广播 announce 包,包含 pipeName、machineId、hostname、ip、tcpPort、role -- 15 秒无 announce 视为 peer lost -- TTL=1,仅 link-local,不跨路由器 +**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 +``` -### 4. Registry 扩展 (`pipeRegistry.ts`) +**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 +``` -- `PipeRegistryEntry` 新增 `tcpPort?` 和 `lanVisible?` 字段 -- `mergeWithLanPeers()` 合并本地 registry 和 LAN beacon 发现的远端 peers +### 第二步:启动 -### 5. Peer Address (`peerAddress.ts`) +```bash +# 机器 A(例如 192.168.50.22) +bun run dev -- `parseAddress()` 新增 `tcp` scheme: `tcp:192.168.1.20:7100` -- `parseTcpTarget()` 解析 `host:port` 字符串 +# 机器 B(例如 192.168.50.27) +bun run dev +``` -## 使用方式 +启动后等待 3-5 秒(beacon 广播间隔),两边自动发现并连接。 -### 查看 LAN Peers +### 第三步:查看和操作 +在任一台机器上: ``` /pipes ``` -输出中会显示 `[LAN]` 标记的远端实例。 +输出示例: +``` +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] -``` -/attach +LAN Peers: + ☐ [main] cli-04d67950 vmwin11/192.168.50.27 tcp:192.168.50.27:58853 [LAN] ``` -自动检测 LAN peer 并通过 TCP 连接。 +### 第四步:选中目标并发送任务 -### 发送消息到 LAN Peer +1. 按 `Shift+↓` 展开选择面板 +2. `↑↓` 移动到 LAN peer +3. `Space` 选中 +4. `Enter` 确认 +5. 输入 prompt,自动路由到远端执行 +远端执行结果会流式回传到你的消息列表: ``` -/send tcp:192.168.1.20:7100 +[main vmwin11/192.168.50.27 / cli-04d67950] 正在检查 git status... +[main vmwin11/192.168.50.27 / cli-04d67950] Completed ``` -或通过 SendMessage tool 使用 `tcp:` scheme。 +## 完整命令参考 + +| 命令 | 说明 | +|------|------| +| `/pipes` | 显示所有实例(本机 + LAN),Shift+↓ 展开选择面板 | +| `/pipes select ` | 选中某实例 | +| `/pipes all` | 全选 | +| `/pipes none` | 取消全选 | +| `/attach ` | 手动 attach(自动识别 LAN peer 并通过 TCP 连接) | +| `/detach ` | 断开连接 | +| `/send ` | 向指定 pipe 发送消息 | +| `/send tcp:host:port ` | 直接通过 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 丢失 + +### 通信机制 + +- 本机实例:UDS(Unix 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 连接需用户显式同意(checkPermissions 返回 `ask`) -- Multicast TTL=1,仅限链路本地 -- 后续可增加 HMAC-SHA256 challenge 认证 +- TCP 连接当前**无认证**——同 LAN 内知道端口号即可连接 +- Multicast TTL=1,不跨路由器 +- AI 通过 `SendMessageTool` 发送 `tcp:` 消息时需**用户显式确认** +- 建议仅在信任的局域网中使用