Files
claude-code/docs/features/uds-inbox.md
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

4.1 KiB
Raw Permalink Blame History

UDS_INBOX / pipes

概述

UDS_INBOX 现在不是一个“空壳 flag”而是一套已经落地的本机 IPC 能力。但它同时承载了两层不同目标,必须拆开理解:

  1. UDS peer messaging
    • 面向任意 Claude Code 进程。
    • 使用 src/utils/udsMessaging.tssrc/utils/udsClient.ts
    • 对外入口是 /peersSendMessageTooluds:<socket-path> 地址。
  2. pipes control plane
    • 面向交互式 REPL 会话之间的主从协作。
    • 使用 src/utils/pipeTransport.tssrc/utils/pipeRegistry.tssrc/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.tsxsrc/utils/pipeTransport.tssrc/utils/pipeRegistry.ts 为事实来源