乐于分享
好东西不私藏

OpenCode 源码-Control Plane 与 Gateway——多工作区编排核心

OpenCode 源码-Control Plane 与 Gateway——多工作区编排核心

OpenCode 源码解析

第 12 讲:Control Plane 与 Gateway——多工作区编排核心

基于 dev 分支源码 · 2026-07-19

一、Control Plane:OpenCode 的调度中心

前十一讲覆盖了 OpenCode 从 CLI 到配置系统的核心能力。这一讲进入Control Plane(控制平面)——OpenCode 实现多工作区编排、远程会话迁移和事件同步的核心基础设施。Control Plane 横跨 7 个文件、约 1,139 行代码,是整个系统的"调度中心"。

📦 本讲核心文件

packages/opencode/src/control-plane/workspace.ts(964 行)— 工作区服务与同步循环

packages/opencode/src/control-plane/types.ts(59 行)— 工作区类型定义

packages/opencode/src/control-plane/workspace-adapter-runtime.ts(51 行)— 适配器运行时

packages/opencode/src/control-plane/util.ts(39 行)— 事件等待工具

packages/opencode/src/control-plane/adapters/(2 文件)— 工作区适配器注册

二、Workspace Service 架构

workspace.ts(964 行)是 Control Plane 的核心,实现了工作区的 CRUD、会话迁移、远程同步和 SSE 事件推送。

1. Workspace 服务接口

📄 control-plane/workspace.ts (第 131-147 行)

export interface Interface {
  readonly create: (input: CreateInput)
    => Effect.Effect<Info, CreateError>
  readonly sessionWarp: (input: SessionWarpInput)
    => Effect.Effect<void, SessionWarpError>
  readonly list: (project: Project.Info)
    => Effect.Effect<Info[]>
  readonly syncList: (project: Project.Info)
    => Effect.Effect<void>
  readonly get: (id: WorkspaceV2.ID)
    => Effect.Effect<Info | undefined>
  readonly remove: (id: WorkspaceV2.ID)
    => Effect.Effect<Info | undefined>
  readonly status: ()
    => Effect.Effect<ConnectionStatus[]>
  readonly isSyncing: (workspaceID: WorkspaceV2.ID)
    => Effect.Effect<boolean>
  readonly waitForSync: (workspaceID: WorkspaceV2.ID,
    state: Record<string, number>,
    signal?: AbortSignal, timeout?: number)
    => Effect.Effect<void, WaitForSyncError>
  readonly startWorkspaceSyncing:
    (projectID: ProjectV2.ID)
    => Effect.Effect<void>
}

设计亮点:11 个公开方法覆盖了工作区生命周期管理、会话迁移、远程同步和状态查询。所有方法返回 Effect.Effect,支持异步组合和错误处理。

2. 工作区类型定义

📄 control-plane/types.ts (第 7-21 行)

export const WorkspaceInfo = Schema.Struct({
  id: WorkspaceV2.ID,
  type: Schema.String,
  name: Schema.String,
  branch: Schema.optional(
    Schema.NullOr(Schema.String)),
  directory: Schema.optional(
    Schema.NullOr(Schema.String)),
  extra: Schema.optional(
    Schema.NullOr(Schema.Unknown)),
  projectID: ProjectV2.ID,
}).annotate({ identifier: "Workspace" })

export const WorkspaceListedInfo = Schema.Struct(
  Struct.omit(WorkspaceInfo.fields, ["id"])
).annotate({ identifier: "WorkspaceListedInfo" })

类型设计:WorkspaceInfo 包含 ID、类型、名称、分支、目录、额外数据和项目 ID。WorkspaceListedInfo 是列表视图,省略了 ID 字段。

三、工作区适配器系统

工作区适配器定义了本地和远程工作区的行为抽象,支持扩展新的工作区类型。

1. 适配器接口

📄 control-plane/types.ts (第 46-59 行)

export type WorkspaceAdapter = {
  name: string
  description: string
  configure(info: WorkspaceInfo,
    context?: WorkspaceAdapterContext)
    : WorkspaceInfo | Promise<WorkspaceInfo>
  create(info: WorkspaceInfo,
    env: Record<string, string | undefined>,
    from?: WorkspaceInfo,
    context?: WorkspaceAdapterContext)
    : Promise<void>
  list?(context?: WorkspaceAdapterContext)
    : WorkspaceListedInfo[] | Promise<WorkspaceListedInfo[]>
  remove(info: WorkspaceInfo,
    context?: WorkspaceAdapterContext)
    : Promise<void>
  target(info: WorkspaceInfo,
    context?: WorkspaceAdapterContext)
    : Target | Promise<Target>
}

适配器方法:configure 配置工作区、create 创建工作区、list 列出工作区、remove 删除工作区、target 获取目标地址。支持本地和远程两种 Target 类型。

2. 适配器运行时

📄 control-plane/workspace-adapter-runtime.ts (第 14-49 行)

export const target = (info: WorkspaceInfo) =>
  Effect.gen(function* () {
    const adapter = getAdapter(info.projectID, info.type)
    const ctx = yield* context
    return yield* EffectBridge.fromPromise(
      () => adapter.target(info, ctx)
    )
  })

export const configure = (adapter: WorkspaceAdapter,
  info: WorkspaceInfo) =>
  Effect.gen(function* () {
    const ctx = yield* context
    return yield* EffectBridge.fromPromise(
      () => adapter.configure(info, ctx)
    )
  })

export const create = (adapter: WorkspaceAdapter,
  info: WorkspaceInfo,
  env: Record<string, string | undefined>,
  from?: WorkspaceInfo) =>
  Effect.gen(function* () {
    const ctx = yield* context
    return yield* EffectBridge.fromPromise(
      () => adapter.create(info, env, from, ctx)
    )
  })

运行时设计:所有适配器方法通过 EffectBridge.fromPromise 包装,将异步 Promise 转换为 Effect。上下文通过 InstanceRefWorkspaceRef 注入。

四、SSE 同步与事件推送

Control Plane 通过 SSE(Server-Sent Events)实现远程工作区的实时同步。

1. SSE 连接

📄 control-plane/workspace.ts (第 184-199 行)

const connectSSE = Effect.fn("Workspace.connectSSE")(
  function* (url: URL | string,
    headers: HeadersInit | undefined) {
    const response = yield* http.execute(
      HttpClientRequest.get(route(url, "/global/event"), {
        headers: new Headers(headers),
        accept: "text/event-stream",
      })
    )
    if (response.status < 200 || response.status >= 300) {
      return yield* new SyncHttpError({
        message: `Workspace sync HTTP failure: ${response.status}`,
        status: response.status,
      })
    }
  })

SSE 流程:连接到远程工作区的 /global/event 端点,接收实时事件流。支持状态码检查和错误处理。

2. 事件等待工具

📄 control-plane/util.ts (第 4-38 行)

export function waitEvent(input: {
  timeout: number; signal?: AbortSignal;
  fn: (event: GlobalEvent) => boolean
}) {
  if (input.signal?.aborted)
    return Effect.fail(input.signal.reason ??
      new Error("Request aborted"))

  return Effect.callback<void, unknown>((resume) => {
    const handler = (event: GlobalEvent) => {
      try {
        if (!input.fn(event)) return
        cleanup()
        resume(Effect.void)
      } catch (error) {
        cleanup()
        resume(Effect.fail(error))
      }
    }
    const cleanup = () => {
      clearTimeout(timeout)
      GlobalBus.off("event", handler)
      input.signal?.removeEventListener("abort", abort)
    }
    const timeout = setTimeout(() => {
      cleanup()
      resume(Effect.fail(
        new Error("Timed out waiting for global event")
      ))
    }, input.timeout)
    GlobalBus.on("event", handler)
    return Effect.sync(cleanup)
  })
}

工具设计:waitEvent 等待满足条件的全局事件,支持超时和取消信号。使用 Effect.callback 实现异步等待。

五、总结

🔹 11 个公开方法覆盖工作区 CRUD、会话迁移、远程同步

🔹 WorkspaceAdapter 抽象支持本地和远程工作区扩展

🔹 EffectBridge 将异步 Promise 包装为 Effect

🔹 SSE 实现远程工作区实时事件同步

🔹 waitEvent 工具支持超时和取消的全局事件等待

🔹 FiberMap 管理多个工作区的同步 Fiber

← 系列导航 →

← 第 11 讲:Config 配置系统 | 第 13 讲:TUI 终端界面 →

关注公众号获取更多 OpenCode 源码解析干货

源码:https://github.com/opencode-ai/opencode