Dashboard 是 botmux 的 Web 管控面:一个独立 Node 进程(src/dashboard.ts,约 5900 行的单体 HTTP server,非导出模块)+ React 19 单页前端(src/dashboard/web/,react ^19.2.7)。它自己不承载会话状态,而是把所有在线 daemon 的事件聚合成统一视图,并把写操作路由回各自的 owner daemon。

进程与端口

  • 监听 0.0.0.0:7891(BOTMUX_DASHBOARD_HOST/PORT 可覆盖,config.ts);实际绑定端口写入 ~/.botmux/.dashboard-port 供 CLI 发现。
  • 端口段刻意留间隔:dashboard 探测回退区间 [7891, 7911]、daemon IPC 基址 7950、Web 终端代理基址 8800,避免 macOS 上通配绑定与 loopback 占用并存的路由竞态(config.ts 注释)。
  • 通配绑定时用 listenWithProbe + /__selfcheck 随机 nonce 做绑定后回环自检,确认端口真归本进程。
  • botmux dashboard [current|rotate](cli/dashboard-command.ts)经 HMAC 认证的 /__cli/* 端点获取/轮换 token 并打印登录 URL;token 持久化在 ~/.botmux/.dashboard-token。

多 daemon 聚合(后端数据面)

  • DaemonRegistry(registry.ts)watch + 15s 轮询 <dataDir>/dashboard-daemons/*.json 描述符,90s 心跳过期过滤在线 daemon;描述符含 larkAppId、ipcPort、botIndex、workflowIpcProtocol 等。
  • subscribeDaemon(aggregator.ts)对每个在线 daemon 订阅其 IPC SSE 流 http://127.0.0.1:<ipcPort>/api/events,断线 1s 退避重连。
  • Aggregator 是纯状态机:折叠 session.spawned/update/exited、schedule.created/updated/deleted 等事件,启动时先用 GET 快照 hydrate 再让 SSE 追上;ownerOf(sessionId) 记录行归属的 larkAppId 用于写路由,terminalProxyPortOf 给出该会话的终端代理端口。

前后端通信

  • REST:/api/sessions、/api/schedules、/api/settings、/api/skills、/api/plugins、/api/whiteboards、/api/update/*、/api/trigger、/api/v3/runs*、bot onboarding / feishu-login / federation 等几十个端点(dashboard.ts 内巨型 request handler)。
  • SSE:浏览器 EventSource('/events')(dashboard.ts 约 5481 行)中继 aggregator 事件,附 15s heartbeat;roster 签名变化时推 bots.changed。SPA 主通道刻意用 SSE 而非 WebSocket(源码注释),唯一的 WS 是下面两条。
  • 前端自愈(web/store.ts):先建 SSE 再拉快照、缓冲期间事件;每次 open(含重连)都重新 reconcile 全量快照,避免错过 delete 类事件。
  • WebSocket 仅两处:
    • /s/<sessionId> — Web 终端反向代理:dashboard 做原始 socket 桥接,按 sessionId 查 aggregator 拿终端代理端口,直透到 daemon 的 terminal proxy 再到 worker(见 web-terminal);
    • /debug-terminal/<id>/ws — owner-only 调试终端(xterm)。

认证模型

  • 默认 publicReadOnly 开启:GET/HEAD 只读面(sessions、schedules、SSE)无 token 可访问,过期链接降级为只读浏览;写操作(POST/PATCH/DELETE)与原始 PTY 日志必须持当前 token。
  • 浏览器持 cookie;CLI 走 X-Botmux-Cli-* HMAC 头,签名串绑定 method + path + port,防止凭证被转发重放到其他路由/端口(auth.ts)。
  • /api/v3/* 全路由强制认证(goal、节点 id 可能含项目/个人信息)。

功能面(dashboard-routes.ts)

页面路由:overview(总览)、sessions(会话看板/看板视图)、workflows(v3 run 页)、groups(群矩阵)、schedules、roles(+角色画像)、skills、plugins、connectors(含 webhook 日志)、team federation(hub/spoke 团队联邦)、whiteboards、monitoring、monitor-room、office(HD2D 像素办公室,资产按需下载约 74MB)、insights、bot-defaults、settings。后端还提供:版本更新/回滚、bot onboarding、飞书扫码登录、OAuth loopback 回调(127.0.0.1:9768)、资源监控告警、创建群/邀请/转移等群操作。

Workflow run 可视化(v3-runs-api.ts)

  • GET /api/v3/runs / /api/v3/runs/:id — 读 ~/.botmux/v3-runs/<runId>/ 的 journal+dag,经 ops-projection.ts 投影成只读 RunView(DAG 图 + 每节点 live/replay 终端);防御性读取,半写的 run 也能渲染;视图绝不外泄写 token。
  • GET .../nodes/:nodeId/pty-log — 原始终端日志(仅认证),超 4MB 只取尾部。
  • POST .../cancel — dashboard 只做路由:从不可变 run.json 的 chatBinding 解析 owner daemon 并代理过去,自己从不写 journal;无 owner 的 run 提示走 botmux workflow cancel。
  • 旧 /api/workflows(v2)返回 410,指向 v3 接口(见 workflow-engine)。

前端构建(scripts/build-dashboard.mjs)

esbuild 打包:入口 src/dashboard/web/app.tsx → dist/dashboard-web/(dashboard.ts 以 WEB_DIR = join(__dirname, 'dashboard-web') 同目录加载);ESM + code splitting(chunks/[name]-[hash])、target es2022、生产 minify;静态资源(index.html、style.css、skins、game 等)直接拷贝。--watch / BOTMUX_DASHBOARD_WATCH=1 开发模式:不 minify、inline sourcemap、120ms 防抖增量重建,并写 .botmux-dashboard-dev / .botmux-dashboard-reload 标记,服务端据此向前端注入 /__dev/reload SSE 热刷新。

相关页面:dashboard、daemon-worker、architecture-overview。