Skip to content

代码 Wiki

本页是面向代码阅读者和维护者的架构参考手册,涵盖系统边界、启动链路、模块职责、关键类型与函数,以及依赖方向。如需面向用户的文档,请参阅指南参考章节。

心智模型

xacpx 是一座"消息频道 ↔ 命令路由 ↔ acpx 会话驱动"的桥梁:

  • 入站: 消息来自微信、飞书、CLI 等频道,每个会话由 chatKey 标识。
  • 路由器: 解析斜杠命令(/ss/use/cancel 等)和普通文本。命令分发给对应处理器;普通文本则作为 prompt 发往当前会话。
  • 会话: 维护逻辑会话(别名 / 智能体 / 工作区 / 上下文 / 回复模式)到传输会话(acpx 命名会话)的映射关系。
  • 传输层: 以统一接口抽象 ensureSession / prompt / cancel / setMode。两种具体实现:
    • acpx-cli — 直接以子进程方式启动 acpx(可选 node-pty PTY 分配)。
    • acpx-bridge — 独立桥接子进程 + JSONL 协议;并发控制和事件处理更强。
  • 编排(可选):在协调器会话下管理向多个工作器会话的任务委派——进度上报、人工确认、群组扇出/汇聚。
  • 守护进程: 后台进程生命周期(start / status / stop)。维护 PID、状态、日志元数据并托管编排 IPC 服务器。
  • MCP(可选):将编排能力以 MCP stdio 服务器的形式暴露给外部宿主(Codex、Claude Code 等)。

入口点

入口点文件功能
CLI 入口src/cli.tsrunCli() — 分发所有 xacpx <command> 子命令
应用组装 / 依赖注入src/main.tsbuildApp() — 组装配置、状态、日志、会话、传输、编排、路由、智能体
启动 / 关闭序列src/run-console.tsrunConsole() — 守护进程运行时、消费者锁、频道启动、最终清理
命令路由src/commands/command-router.tsCommandRouter
会话状态src/sessions/session-service.tsSessionService
传输层边界src/transport/types.tsSessionTransport 接口

应用组装与启动生命周期

buildApp() 是依赖注入中心——将配置、状态、日志、会话、传输、编排、路由和智能体组装为一个 AppRuntimesrc/main.ts

runConsole() 负责启动序列、信号驱动的关闭流程以及清理一致性:src/run-console.ts

  1. buildApp(paths) 组装运行时。
  2. 守护进程模式下:写入守护进程运行时元数据,启动编排 IPC 服务器,启动心跳。
  3. 获取消费者锁(防止多个进程同时消费同一微信账号)。
  4. channels.startAll(...) — 并行启动所有频道。
  5. finally:停止 IPC / 释放资源 / stopAll / 释放锁。

命令路由

数据流(从微信到 acpx)

  1. 频道收到消息(chatKey + 文本 + 可选媒体)。
  2. ConsoleAgent.chat() 调用 router.handle(chatKey, input, reply, replyContextToken, accountId, media)
  3. CommandRouter.handle()
    • / 开头的输入:parseCommand() 分发到对应处理器。
    • 普通文本:视为 prompt,解析到当前会话,转发给 transport.prompt()
  4. 传输层执行:
    • acpx-cli:启动 acpx ... prompt 子进程并聚合输出。
    • acpx-bridge:向桥接子进程发送 JSONL 请求;桥接子进程负责调度并回写事件。
  5. 回复流回频道(流式 / 详细 / 最终,取决于配置的回复模式)。

关键组件

  • parseCommand() — 斜杠命令解析器,内置别名解析(/ss/session/ws/workspace/stop/cancel):src/commands/parse-command.ts
  • CommandRouter — 精简路由器 + 上下文组装器;同时处理传输调用观测、自动修复和诊断摘要:src/commands/command-router.ts
  • 处理器 — 按职责边界拆分:会话生命周期、快捷方式创建、恢复、重置、配置命令:src/commands/handlers/
  • router-types.ts — 显式定义 RouterResponseCommandRouterContext 和会话操作接口:src/commands/router-types.ts

完整模块说明请参阅命令模块

会话模型

两种会话概念

逻辑会话(xacpx 管理)— alias / agent / workspace 加上持久化状态(replyModemodeId、上下文等)。由 SessionService 管理,写入 state.json

传输会话(acpx 管理)— transportSession 字符串,用作底层 acpx 命名会话的名称。ResolvedSession 是传递给传输层的完整路由上下文(包含 cwdagentCommandtransportSession 等):src/transport/types.ts

核心数据概念

  • chatKey — 稳定的会话标识符,在所有频道中全局唯一。格式:<channelId>:<channel-internal-id>。频道注册表用它来路由出站消息:src/channels/channel-registry.ts
  • replyMode — xacpx 回复策略(stream / final / verbose),存储在逻辑会话上。
  • modeId — 底层智能体模式(如 codex plan),存储在逻辑会话上。
  • 编排对象coordinatorSessionworkerSessiontaskgroup。组装点在 buildApp() 中:src/main.ts

传输层

统一接口

ts
// src/transport/types.ts
interface SessionTransport {
  ensureSession(session: ResolvedSession, opts?): Promise<void>;
  prompt(session: ResolvedSession, text: string, opts?: PromptOptions): Promise<void>;
  cancel(session: ResolvedSession): Promise<void>;
  setMode(session: ResolvedSession, modeId: string): Promise<void>;
  hasSession(session: ResolvedSession): Promise<boolean>;
}

两种实现:

acpx 解析顺序

  1. 配置中的 transport.command(显式覆盖)。
  2. 主包 node_modules 中内置的 acpx
  3. Shell PATH 中的 acpx

频道

核心仅内置 weixin 频道以及通用的频道/插件基础设施。飞书、元宝及所有其他非微信频道均由插件提供,位于 packages/channel-* 或外部 npm 包——而非 src/channels/

频道接口

  • MessageChannelRuntime — 登录 / 启动 / 发送 / 任务通知:src/channels/types.ts
  • MessageChannelRegistry — 聚合器,并行启动所有频道(允许部分失败;全部失败时抛出异常),并按 chatKey 路由出站消息:src/channels/channel-registry.ts

ConsoleAgent

ConsoleAgent 是频道到路由器的适配器:它规范化媒体内容、拒绝空消息、记录日志,并调用 router.handle(...)。频道只依赖 WechatAgent 的行为,不依赖 CommandRouter 的内部细节:src/console-agent.ts

内置微信频道

src/weixin/ 是内置微信服务提供者(登录、轮询、媒体管线、配额管理),由 WeixinChannel 托管:src/channels/weixin-channel.ts

频道能力:原生会话列表格式

/ssn 原生会话列表的渲染格式由各频道通过 MessageChannelRuntime.nativeSessionListFormat 声明("cards" | "table",默认 "table"weixin 声明为 "cards")。注册表通过 nativeSessionListFormat(chatKey) 暴露该值,由 CommandRouter 注入到 CommandRouterContext.resolveNativeSessionListFormat 中,再由原生会话处理器读取。新频道只需在运行时声明此能力——无需修改处理器。

守护进程子系统

完整说明请参阅守护进程模块

DaemonController — 外部控制接口(CLI 调用):

  • getStatus() — PID 缺失 → 已停止;PID 存在但进程不在 → 清理运行时文件;PID 存在但无状态 → 不确定。
  • start() — 以分离模式启动 → 写入 PID → 轮询 status.json 等待就绪(PID 匹配)。
  • stop() — 终止进程 → 等待退出 → 清理 PID 和状态文件。

源码:src/daemon/daemon-controller.ts

守护进程通过三个信号综合判断存活状态:PID 文件、该 PID 对应进程是否实际存在,以及 status.json 是否已写入。所有运行时文件路径集中管理于:src/daemon/daemon-files.ts

桥接子系统

桥接子系统将 acpx 的驱动逻辑隔离到独立的子进程中,使主进程获得更可控的并发性和事件通道。它是 acpx-bridge 传输实现的后端支撑。

入口与运行时

JSONL 协议

  • 方法:ensureSession / hasSession / prompt / setMode / cancel / removeSession / ...src/transport/acpx-bridge/acpx-bridge-protocol.ts
  • 消息类型:request / response 以及 eventprompt.segmentsession.progresssession.note)。
  • 严格的单行 JSON 协议:主进程可接收 session.progressprompt.segment 作为事件。仅当有媒体内容时 prompt.text 才可为空字符串。

服务器调度

BridgeServer.handleLine() 接收一行 JSON 输入,输出一行 JSON;错误统一包装为 BridgeErrorResponse。会话范围内的请求(SESSION_SCOPED_METHODS)以 [agentIdentity, cwd, name]scheduleKey,在同一 key 内串行执行。cancel 运行在更高优先级的 control 车道,可抢占正在进行的 prompt 请求。源码:src/bridge/bridge-server.ts

配置与状态

默认路径(来自 resolveRuntimePaths()

路径内容写入方
~/.xacpx/config.json智能体、工作区、频道、插件、传输——静态配置ConfigStore、CLI
~/.xacpx/state.json会话、聊天上下文、编排状态DebouncedStateStore(50 ms 合并)→ StateStore
~/.xacpx/runtime/daemon.pid当前守护进程 PIDDaemonRuntime
~/.xacpx/runtime/status.json守护进程心跳 / start_at / 日志路径DaemonRuntime
~/.xacpx/runtime/app.log有界应用日志(滚动)AppLogger
~/.xacpx/runtime/orchestration.sockUnix socket(Windows 上为 \\.\pipe\xacpx-orchestration-<hash>OrchestrationServer
~/.xacpx/plugins/插件 npm 主目录(独立的 package.json + node_modulesxacpx plugin add/update

WEACPX_CONFIGWEACPX_STATE 环境变量分别覆盖配置和状态文件路径。

职责边界

  • config — 用户显式设置(传输、频道、智能体、工作区、日志、编排参数等)。
  • state — 运行时状态(会话、聊天上下文、编排状态机数据等)。

完整字段说明请参阅配置参考/config 命令

日志

AppLogger — 带本地滚动文件的结构化事件日志:

  • 通过 createAppLogger({ filePath, level, maxSizeBytes, maxFiles, retentionDays }) 创建。
  • 达到 maxSizeBytes 时使用 .1/.2/... 后缀滚动;超出 maxFiles 的文件将被清理。
  • retentionDays 保留。

源码:src/logging/app-logger.ts

状态持久化

DebouncedStateStoreStateStorewritePrivateFileAtomicproper-lockfile 实现跨进程互斥 + write-file-atomic 实现原子重命名 + Windows EBUSY 兜底):src/state/

MCP stdio 服务器

xacpx mcp-stdio 启动一个 MCP stdio 服务器并暴露编排工具:

此模式要求守护进程正在运行(编排 IPC 端点必须可用)。暴露给外部宿主的 MCP 服务器名称为 xacpx(工具前缀 mcp__xacpx__*)。

基于 MIT 许可证发布。