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 热刷新。