Files
2026-04-03 13:01:19 +08:00

16 KiB

Swarm 系统

Claude Code 的 Swarm 系统是一个多智能体协作框架,支持团队模式、进程内队友和多种终端后端实现。

1. Swarm 系统概述

1.1 核心目录结构

位置: /src/utils/swarm/

swarm/
├── backends/
│   ├── types.ts              # 后端类型定义
│   ├── registry.ts           # 后端注册表
│   ├── detection.ts          # 环境检测
│   ├── TmuxBackend.ts        # Tmux 后端
│   ├── ITermBackend.ts       # iTerm2 后端
│   ├── InProcessBackend.ts   # 进程内后端
│   ├── PaneBackendExecutor.ts # 面板执行器
│   └── teammateModeSnapshot.ts # 团队模式快照
├── teamHelpers.ts            # 团队辅助函数
├── teammateInit.ts           # 队友初始化
├── teammateLayoutManager.ts  # 布局管理
├── teammateModel.ts          # 队友模型
├── teammatePromptAddendum.ts # 提示补充
├── permissionSync.ts         # 权限同步
├── reconnection.ts           # 重连机制
├── spawnUtils.ts            # 生成工具
├── spawnInProcess.ts         # 进程内生成
├── inProcessRunner.ts       # 进程内运行器
├── constants.ts              # 常量定义
└── leaderPermissionBridge.ts # 权限桥接

2. 团队模式快照 (teammateModeSnapshot.ts)

2.1 快照机制

// 位置:/src/utils/swarm/backends/teammateModeSnapshot.ts

export type TeammateMode = 'auto' | 'tmux' | 'in-process'

// CLI 覆盖
let cliTeammateModeOverride: TeammateMode | null = null

// 捕获启动时的团队模式
export function captureTeammateModeSnapshot(): void {
  if (cliTeammateModeOverride) {
    initialTeammateMode = cliTeammateModeOverride
  } else {
    const config = getGlobalConfig()
    initialTeammateMode = config.teammateMode ?? 'auto'
  }
}

// 获取快照模式
export function getTeammateModeFromSnapshot(): TeammateMode

2.2 模式类型

模式 描述
auto 自动检测可用后端
tmux 强制使用 Tmux 后端
in-process 使用进程内后端

3. 团队辅助函数 (teamHelpers.ts)

3.1 团队文件操作

// 获取团队目录
export function getTeamDir(teamName: string): string

// 获取团队配置文件路径
export function getTeamFilePath(teamName: string): string

// 读取团队文件(同步)
export function readTeamFile(teamName: string): TeamFile | null

// 读取团队文件(异步)
export async function readTeamFileAsync(teamName: string): Promise<TeamFile | null>

// 写入团队文件(同步)
function writeTeamFile(teamName: string, teamFile: TeamFile): void

// 写入团队文件(异步)
export async function writeTeamFileAsync(teamName: string, teamFile: TeamFile): Promise<void>

3.2 团队成员管理

// 从团队文件移除队友
export function removeTeammateFromTeamFile(
  teamName: string,
  identifier: { agentId?: string; name?: string }
): boolean

// 移除成员
export function removeMemberFromTeam(
  teamName: string,
  tmuxPaneId: string
): boolean

// 按 Agent ID 移除成员
export function removeMemberByAgentId(
  teamName: string,
  agentId: string
): boolean

// 设置成员权限模式
export function setMemberMode(
  teamName: string,
  memberName: string,
  mode: PermissionMode
): boolean

// 同步队友模式
export function syncTeammateMode(mode: PermissionMode, teamNameOverride?: string): void

// 设置成员活跃状态
export async function setMemberActive(
  teamName: string,
  memberName: string,
  isActive: boolean
): Promise<void>

3.3 团队清理

// 清理会话团队
export async function cleanupSessionTeams(): Promise<void>

// 清理团队目录
export async function cleanupTeamDirectories(teamName: string): Promise<void>

// 注册团队会话清理
export function registerTeamForSessionCleanup(teamName: string): void

// 注销团队会话清理
export function unregisterTeamForSessionCleanup(teamName: string): void

4. 队友初始化 (teammateInit.ts)

4.1 初始化流程

// 位置:/src/utils/swarm/teammateInit.ts

export function initializeTeammateHooks(
  setAppState: (updater: (prev: AppState) => AppState) => void,
  sessionId: string,
  teamInfo: { teamName: string; agentId: string; agentName: string }
): void

4.2 团队权限应用

// 应用团队范围的允许路径
if (teamFile.teamAllowedPaths && teamFile.teamAllowedPaths.length > 0) {
  for (const allowedPath of teamFile.teamAllowedPaths) {
    setAppState(prev => ({
      ...prev,
      toolPermissionContext: applyPermissionUpdate(
        prev.toolPermissionContext,
        {
          type: 'addRules',
          rules: [{ toolName: allowedPath.toolName, ruleContent }],
          behavior: 'allow',
          destination: 'session'
        }
      )
    }))
  }
}

4.3 停止钩子注册

// 注册停止钩子以通知团队领导
addFunctionHook(
  setAppState,
  sessionId,
  'Stop',
  '',
  async (messages, _signal) => {
    // 标记为空闲
    void setMemberActive(teamName, agentName, false)

    // 发送空闲通知
    const notification = createIdleNotification(agentName, {...})
    await writeToMailbox(leadAgentName, {...})

    return true
  }
)

5. 布局管理 (teammateLayoutManager.ts)

5.1 队友颜色分配

// 分配队友颜色
export function assignTeammateColor(teammateId: string): AgentColorName

// 获取队友颜色
export function getTeammateColor(teammateId: string): AgentColorName | undefined

// 清除所有颜色分配
export function clearTeammateColors(): void

5.2 后端选择

async function getBackend(): Promise<PaneBackend> {
  return (await detectAndGetBackend()).backend
}

5.3 面板操作

// 在 Swarm 视图中创建队友面板
export async function createTeammatePaneInSwarmView(
  teammateName: string,
  teammateColor: AgentColorName
): Promise<{ paneId: string; isFirstTeammate: boolean }>

// 启用面板边框状态
export async function enablePaneBorderStatus(
  windowTarget?: string,
  useSwarmSocket?: boolean
): Promise<void>

// 发送命令到面板
export async function sendCommandToPane(
  paneId: string,
  command: string,
  useSwarmSocket?: boolean
): Promise<void>

6. 后端系统 (backends/)

6.1 后端类型

位置: /src/utils/swarm/backends/types.ts

export type BackendType = 'tmux' | 'iterm2' | 'in-process'

export type PaneBackendType = 'tmux' | 'iterm2'

export type PaneId = string

export type CreatePaneResult = {
  paneId: PaneId
  isFirstTeammate: boolean
}

6.2 PaneBackend 接口

export type PaneBackend = {
  readonly type: BackendType
  readonly displayName: string
  readonly supportsHideShow: boolean

  isAvailable(): Promise<boolean>
  isRunningInside(): Promise<boolean>

  createTeammatePaneInSwarmView(
    name: string,
    color: AgentColorName
  ): Promise<CreatePaneResult>

  sendCommandToPane(
    paneId: PaneId,
    command: string,
    useExternalSession?: boolean
  ): Promise<void>

  setPaneBorderColor(
    paneId: PaneId,
    color: AgentColorName,
    useExternalSession?: boolean
  ): Promise<void>

  setPaneTitle(
    paneId: PaneId,
    name: string,
    color: AgentColorName,
    useExternalSession?: boolean
  ): Promise<void>

  enablePaneBorderStatus(
    windowTarget?: string,
    useExternalSession?: boolean
  ): Promise<void>

  rebalancePanes(windowTarget: string, hasLeader: boolean): Promise<void>

  killPane(paneId: PaneId, useExternalSession?: boolean): Promise<boolean>

  hidePane(paneId: PaneId, useExternalSession?: boolean): Promise<boolean>

  showPane(
    paneId: PaneId,
    targetWindowOrPane: string,
    useExternalSession?: boolean
  ): Promise<boolean>
}

6.3 TmuxBackend

位置: /src/utils/swarm/backends/TmuxBackend.ts

使用 tmux 进行面板管理的后端实现。

功能:

  • 创建 tmux 窗口和面板
  • 发送命令到指定面板
  • 设置面板颜色和标题
  • 管理面板布局

6.4 ITermBackend

位置: /src/utils/swarm/backends/ITermBackend.ts

使用 iTerm2 原生分割面板的后端实现。

功能:

  • 通过 it2 CLI 与 iTerm2 通信
  • 创建垂直/水平分割
  • 设置 profile 和颜色

6.5 InProcessBackend

位置: /src/utils/swarm/backends/InProcessBackend.ts

在当前 Node.js 进程中运行队友的后端。

特性:

  • 共享 API 客户端和 MCP 连接
  • 通过文件邮箱通信
  • 使用 AbortController 终止
  • 始终可用(无外部依赖)
export class InProcessBackend implements TeammateExecutor {
  readonly type = 'in-process' as const

  async spawn(config: TeammateSpawnConfig): Promise<TeammateSpawnResult>
  async sendMessage(agentId: string, message: TeammateMessage): Promise<void>
  async terminate(agentId: string, reason?: string): Promise<boolean>
  async kill(agentId: string): Promise<boolean>
  async isActive(agentId: string): Promise<boolean>
}

6.6 后端注册表

位置: /src/utils/swarm/backends/registry.ts

// 检测并获取合适的后端
export async function detectAndGetBackend(): Promise<BackendDetectionResult>

// 注册所有后端
export async function ensureBackendsRegistered(): Promise<void>

// 按类型获取后端
export async function getBackendByType(type: BackendType): Promise<PaneBackend>

7. 权限同步 (permissionSync.ts)

7.1 权限请求流程

Worker Agent → 权限请求 → Leader Mailbox
Leader Agent ← 轮询 ← 权限队列
     ↓
用户批准/拒绝
     ↓
Leader → 权限响应 → Worker Mailbox
Worker ← 处理响应 ←

7.2 权限请求结构

export type SwarmPermissionRequest = {
  id: string
  workerId: string
  workerName: string
  workerColor?: string
  teamName: string
  toolName: string
  toolUseId: string
  description: string
  input: Record<string, unknown>
  permissionSuggestions: unknown[]
  status: 'pending' | 'approved' | 'rejected'
  resolvedBy?: 'worker' | 'leader'
  resolvedAt?: number
  feedback?: string
  updatedInput?: Record<string, unknown>
  permissionUpdates?: PermissionUpdate[]
  createdAt: number
}

7.3 权限操作

// 创建权限请求
export function createPermissionRequest(params: {...}): SwarmPermissionRequest

// 写入待处理权限请求
export async function writePermissionRequest(
  request: SwarmPermissionRequest
): Promise<SwarmPermissionRequest>

// 读取待处理权限
export async function readPendingPermissions(
  teamName?: string
): Promise<SwarmPermissionRequest[]>

// 解决权限请求
export async function resolvePermission(
  requestId: string,
  resolution: PermissionResolution,
  teamName?: string
): Promise<boolean>

// 通过邮箱发送权限请求
export async function sendPermissionRequestViaMailbox(
  request: SwarmPermissionRequest
): Promise<boolean>

// 通过邮箱发送权限响应
export async function sendPermissionResponseViaMailbox(
  workerName: string,
  resolution: PermissionResolution,
  requestId: string,
  teamName?: string
): Promise<boolean>

7.4 沙箱权限

// 发送沙箱权限请求
export async function sendSandboxPermissionRequestViaMailbox(
  host: string,
  requestId: string,
  teamName?: string
): Promise<boolean>

// 发送沙箱权限响应
export async function sendSandboxPermissionResponseViaMailbox(
  workerName: string,
  requestId: string,
  host: string,
  allow: boolean,
  teamName?: string
): Promise<boolean>

7.5 团队领导检查

// 检查是否为团队领导
export function isTeamLeader(teamName?: string): boolean

// 检查是否为 Swarm Worker
export function isSwarmWorker(): boolean

8. 重连机制 (reconnection.ts)

8.1 初始团队上下文计算

export function computeInitialTeamContext():
  | AppState['teamContext']
  | undefined {
  // 从 CLI 参数获取动态团队上下文
  const context = getDynamicTeamContext()

  if (!context?.teamName || !context?.agentName) {
    return undefined
  }

  // 读取团队文件获取领导 Agent ID
  const teamFile = readTeamFile(teamName)

  return {
    teamName,
    teamFilePath,
    leadAgentId: teamFile.leadAgentId,
    selfAgentId: agentId,
    selfAgentName: agentName,
    isLeader,
    teammates: {}
  }
}

8.2 从会话恢复团队上下文

export function initializeTeammateContextFromSession(
  setAppState: (updater: (prev: AppState) => AppState) => void,
  teamName: string,
  agentName: string
): void {
  // 从团队文件读取成员信息
  const teamFile = readTeamFile(teamName)
  const member = teamFile.members.find(m => m.name === agentName)
  const agentId = member?.agentId

  // 设置 AppState 中的团队上下文
  setAppState(prev => ({
    ...prev,
    teamContext: {
      teamName,
      teamFilePath,
      leadAgentId: teamFile.leadAgentId,
      selfAgentId: agentId,
      selfAgentName: agentName,
      isLeader: false,
      teammates: {}
    }
  }))
}

9. 队友生成 (spawnUtils.ts, spawnInProcess.ts)

9.1 进程内队友生成

// 位置:/src/utils/swarm/spawnInProcess.ts

export async function spawnInProcessTeammate(
  identity: TeammateIdentity,
  context: ToolUseContext
): Promise<{
  success: boolean
  agentId: string
  taskId?: string
  teammateContext?: TeammateContext
  abortController?: AbortController
  error?: string
}>

export function killInProcessTeammate(
  taskId: string,
  setAppState: (updater: (prev: AppState) => AppState) => void
): boolean

9.2 进程内运行器

// 位置:/src/utils/swarm/inProcessRunner.ts

export async function startInProcessTeammate(params: {
  identity: TeammateIdentity
  taskId: string
  prompt: string
  teammateContext: TeammateContext
  toolUseContext: ToolUseContext
  abortController: AbortController
  model?: string
  systemPrompt?: string
  systemPromptMode?: 'default' | 'replace' | 'append'
  allowedTools?: string[]
  allowPermissionPrompts?: boolean
}): Promise<void>

10. TeammateExecutor 接口

10.1 接口定义

export type TeammateExecutor = {
  readonly type: BackendType

  isAvailable(): Promise<boolean>
  spawn(config: TeammateSpawnConfig): Promise<TeammateSpawnResult>
  sendMessage(agentId: string, message: TeammateMessage): Promise<void>
  terminate(agentId: string, reason?: string): Promise<boolean>
  kill(agentId: string): Promise<boolean>
  isActive(agentId: string): Promise<boolean>
}

10.2 TeammateSpawnConfig

export type TeammateSpawnConfig = TeammateIdentity & {
  prompt: string
  cwd: string
  model?: string
  systemPrompt?: string
  systemPromptMode?: 'default' | 'replace' | 'append'
  worktreePath?: string
  parentSessionId: string
  permissions?: string[]
  allowPermissionPrompts?: boolean
}

10.3 TeammateSpawnResult

export type TeammateSpawnResult = {
  success: boolean
  agentId: string  // 格式: agentName@teamName
  error?: string
  abortController?: AbortController  // 进程内队友使用
  taskId?: string   // AppState.tasks 中的任务 ID
  paneId?: PaneId   // 基于面板的后端使用
}

11. 消息类型

11.1 TeammateMessage

export type TeammateMessage = {
  text: string
  from: string
  color?: string
  timestamp?: string
  summary?: string  // 5-10 字预览
}

12. 类型守卫

12.1 面板后端检查

export function isPaneBackend(type: BackendType): type is 'tmux' | 'iterm2' {
  return type === 'tmux' || type === 'iterm2'
}

13. 环境检测

13.1 tmux 检测

// 检测是否在 tmux 会话内运行
export async function isInsideTmux(): Promise<boolean>

13.2 iTerm2 检测

// 检测 iTerm2 是否可用
export async function isITerm2Available(): Promise<boolean>

14. 团队常量

位置: /src/utils/swarm/constants.ts

export const TEAM_LEAD_NAME = 'team-lead'
export const DEFAULT_TEAM_PANE_WIDTH = '30%'
export const DEFAULT_TEAM_PANE_HEIGHT = '50%'