dsh-bot-board
DS Bot 团队的一块浮动看板:谁在跑、在跑什么工具,谁在等别的 Bot 交活,谁在等你批或等你答,谁报错了;带按发送方分组的交接表、显示待批命令或待答问题的单个 Bot 抽屉,收起后是一条状态胶囊。只读,不写 DS Bot 的数据。需要先装 DS Bot(按 0.1.7 与 0.2.0 开发);没有 DS Bot 时面板不显示。
安装
dsh plugin --profile web add dsh-bot-board
沙箱测试结果
| 阶段 | 结果 |
|---|---|
| 1 安装 | ✓ |
| 2 列装 | ✓ |
| 3 挂载 | ✓ |
| 4 启动 | — |
四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。
README
Bot 看板(dsh-bot-board)
[English](README.md) · 中文

给 DS Bot 加一块浮动看板:谁在跑、跑了多久、卡在哪、谁在等谁交活。不用逐个点开他们的会话。
这是一个 DeepSeek Harness(DSH)插件,需要先装 DS Bot(包名 ds-bot)。没有 DS Bot 就没有东西可显示,面板不会出现。
它只读 DS Bot 的数据,不写:不改 state.json,不调会改状态的 api/bot,也不传 locale——那个字段会改掉你新建 Bot 的界面语言。
依赖:DSH(Developer Preview 即可)、DS Bot 0.1.7 或 0.2.0(开发时用的就是这两个)、Node ≥ 20(只有从源码构建需要)。
它显示什么
整体是一间 Bot 教室,从上到下三层,按「要不要你动手」递减:
1. 需要你(0–3 行,44px/行):只有等你批 / 等你答 / 报错的 Bot。每行是团子小像(30px,就是教室里那张脸的裁剪)+ 名字 + 动作原文 + 已跑时长 + 状态灯。三个灯贴右对齐成一条竖轨,菱形和方形可以直接纵向比较。空的时候是一行「没有需要你的事」——不是空白,面板必须告诉你它查过了。超过 3 个时,第 3 行动作列的右端会出现一个 +N chip,点它(或 Tab + Enter)就地展开全部,再点收起:不占一行高度,也不会把第 4 个人变成无名氏。
2. 在动(整幅教室):正在跑、在等别的 Bot 交活、以及刚交完活(7 秒内)的 Bot,按名册序排进网格(窄窗口自动 2 列,可滚动)。交接边表长在这一层里面,位置在工位网格之前。
3. 闲着:默认一行(24px),只剩名字,没有图像、没有表面、没有灯。当没人在跑、也没有未结交接时,它升级成名册——每个闲着的 Bot 一行,44px,和层 1 同一个节奏:头像 + 名字 + 角色(没设角色就用模型)+ 右侧的「闲着」。面板矮了按剩余高度自动分两列或三列,一个 Bot 都不会藏在滚动里;只有每格窄到 160px 以下时才先丢掉角色那一列,名字永远不丢。带「!」徽标的是「报错过但已经安静下来」的 Bot,徽标在任何形态下都不丢。
三层靠图像 / 行高 / 字重 / 表面四个通道递减,不用色块分区:层 1 有 30px 头像和白卡,层 2 是房间地面本身(无底色、无阴影),层 3 默认什么都没有;升级成名册时也只有 30px 头像和 500 字重的名字——没有白卡、没有左侧状态条、没有灯,所以「需要你」仍然是第一眼。状态色只出现在层 1 的左侧 3px 状态条和灯上。
每个工位从左到右是:椅子 + 木桌(桌上显示器、状态灯、桌面道具),桌后坐着一个圆圆的团子 Bot,工位下方是 Bot 名和已跑时长。
六种状态
状态 · 灯色 · 形状 · 含义
干活 · 绿 · 圆 · 正在跑(working / thinking / searching / sending / 转交中)
等你 · 黄 · 方 · 有审批、提问,或新建的 Bot 在等你选模型
等交活 · 蓝 · 圆 · 它在等别的 Bot 把活交回来,不是等你
卡住 · 红 · 菱形 · 报错了,且当前没有在干活。超过 3 分钟仍无动静就降级成「闲着」+ 红色「!」徽标——红灯只表示现在卡住
闲着 · 灰 · 圆 · 什么都没干
干完 · 青 · 圆 · 刚接到一次干净的交接,7 秒后回落
「等你」和「等交活」是两个状态:一个要你动手,一个不用。混在一起会让黄灯天天误报,最后你就开始忽略它。
状态不只靠颜色:卡住是菱形、等你方形、其余圆形,每个灯都有描边(层 1 的 12px 灯描边 1.5px;工位里的小灯从 0.8 提到 1.2,因为在 138px 格宽下 0.8 只渲染成 0.65px,被抗锯齿摊成一层浅灰——闲着 的灰填充对比度只有 1.53:1,几乎看不见)。因为绿(#22C55E)和红(#EF4444)在红绿色盲下几乎是同一个点(ΔE 13.6),而它们在奶油底上的对比度只有 2.28:1 和 3.76:1——只靠颜色,最该分辨的一对反而最难分辨。显示器也分了六种画面:等你是一根竖线加感叹号,等交活是箭头,干活是三道进度条,干完是勾,卡住是红条,闲着是空屏。
格宽 138 / 格高 128 不是随手定的:480 − 2(面板边框) − 39(头) − 148(3 行需要你 + 间距 + 内边距) − 24(闲着) = 267 留给「在动」,两整行 + grid gap 8 + .bb-run 下内边距 4 必须装进 267,所以 2 × (0.7765W + 20) + 12 ≤ 267 → W ≤ 138.4。取 138 后灯轮廓 5.19px,仍远在 4px 下限之上。默认尺寸 560×480、3 件需要你 + 5 个在动 + 1 个闲着(9 个 Bot 满员),浏览器实测零滚动(npm run preview 生成的 docs/preview-0.7.0.html 里每个面板下方的灰字是 clientHeight / scrollHeight 量出来的,不是算出来的;实测余量 0.72px,算术上是 0.694px——差额来自浏览器把格子渲染成 127.14 而不是 127.153。离破很近,改任何 padding 都要重跑)。
工位上的信息
[团子 + 显示器 + 状态灯] Bot2 4m12s
- 已跑时长:这一轮从什么时候开始,秒级刷新(只重绘这一个节点,SVG 不动)
- 当前动作:工位格只有 138px 宽,装不下第三行,所以动作在 hover 的 title 和抽屉里(
等你批 Bash/报错:模型超时/等 Chief、Bot5);层 1 的「需要你」列表里它是常显的一列文字。waiting状态的「等谁」只有 title 这一条常驻线索——交接边表是works派生的欠账,不是waiting派生的实时堵点,两回事 - 超时变色:干活超过 5 分钟,时长变琥珀色并加粗(可能卡住了,但还没报错)
- 失败徽标:报错后又重新干活的 Bot,右上角留一个红色「!」,主状态回到绿色。这个徽标会自己消失:失败时间早于本轮起点,或 Bot 已连续干活超过 1 分钟,就判定为「已经恢复了」
- hover 看完整 title;点击打开详情抽屉
Bot 的脸从哪来(DS Bot 说了算)
看板不发明身份。每个 Bot 的长相由 DS Bot 自己的两个字段决定,看板只是把它们画出来:
轴 · 来源 · 取值
角色(身体轮廓) · state.json 的 bots[].avatar.shape · DS Bot 的七个角色:whale star moon wave squircle zed(Bull)hex(Blossom)
颜色 · bots[].color · 19 个命名 ink(deepseek/blue/violet…)或任意 #rrggbb
桌面道具 · 看板自己 · 10 种,按 Bot id 哈希(上游没有描述它的字段)
七个轮廓是按 DS Bot 的形状重绘的:鲸鱼有尾鳍和圆身、星形有五角、花形有花瓣、牛形有角,脸盘和眼睛按各自轮廓内缩(星形的凹角撑不住一个 18px 的脸盘),有圆边的轮廓才有手。所以「我的 Bot 是蓝色鲸鱼」在两个界面上是同一句话。
DS Bot 只在用户显式选过时才存这两个字段——新建的 Bot 默认两个都没有。没有的部分按 Bot id 哈希补:12 色 × 7 轮廓 × 10 道具 = 840 种组合,同一个 Bot 每次刷新都是同一张脸,两个 Bot 撞到同一套组合时自动换一套。上游给的部分永远优先,哈希只填空白。
名字不参与身份。 一个叫 Chief 的 Bot 不会因此得到任何特殊长相——名字是自由文本,随语言变,而 avatar.shape 是闭集七项。
六态怎么认(图例是抽屉,不是常驻条)
头部那个 ? 按钮打开六态说明:每行一个灯 + 状态名 + 一句人话。它用的是和现场同一个 Lamp 组件(12px 竖轨 / 16px 图例 / 14px 抽屉头部),所以图例不会和现场漂移。
以前这条图例常驻在首屏,占 27px、每 1.5 秒重渲染一次、内容永不变化——最贵的像素给了最不需要看的东西。现在它按需打开,六态靠三层覆盖:层 1 的动作原文直接是词(等你批 / 报错)、工位的 title 带状态名、形状本身(菱形 / 方形 / 圆)。
详情抽屉
点工位打开,不用跳会话就能看到:
- 角色、模型、状态、已跑时长、当前动作
- 这一轮在哪跑:只在这一轮发生在群聊里时才显示(
work.bots[botId].roomId) - 等你审批时:这次调用要动的东西(等宽代码块,可能是命令、文件路径或 URL——DS Bot 的
detail.code取的是command|file_path|url|query里第一个非空值,所以标签写「具体内容」而不是「命令」)+ 审批原因 - 等你回答时:问题原文 + 说明 + 所有可选项。
multiSelect为真时编号换成☐(编号会读成「选一个」),allowCustom为真时末尾加一行「也可以自己说」 - 最近一次报错的完整消息
- 最近一次这个 Bot 交接回来的结果(
work.results[]每条带name,按名字挑,不是取最后一条) - 底部「打开聊天 ↗」跳到那个 Bot 的会话
正在交接(在「在动」里面,工位网格之前)
只列 open > 0 的活。按发送方分组,组头是「共 N 项」——组最大的那个就是瓶颈:
Bot1 · 共 7 项 → Bot2 4 项待交 12 分钟前 → Bot3 3 项待交 未开工 8 分钟前 Bot2 · 共 2 项 ⇄ Bot1 2 项待交 互相等 5 分钟前
→是派活方向(谁派给谁),欠账方向是反的。- 「共 N 项」是这一组的答案,不是全局面板的总数:谁压着最多,谁就是瓶颈。
⇄+互相等表示 A→B 和 B→A 同时开着,也就是死锁。两侧各保留一条边,各自的数量都是真的,没有一边的数字被合并掉。被堵只给真的动不了的接收方(等你/卡住)。接收方在干活时绝不标「被堵」——他正在飞快还账,去催他是错的。接收方闲着但账还开着,标「未开工」:该看一眼,但没人在堵它。
点一行跳到接收方的抽屉。空的时候整块不渲染(连 0 高的空壳都没有)。
位置在工位网格之前,不是之后。 6 个 Bot 在跑时,两行工位已经占满这一层(266.31px 里的 267px,余 0.694px),边表和网格不可能同时完整可见——而那一刻正是它最要紧的时候:刚对 Bot1 说完「八份都过一遍」,8 个在跑、8 条边同时开着。既然滚动不可避免,就先看关系:工位位置固定、靠位置记人,滚下去看格子代价小;哪些账还开着是每次都要重新读的新信息。完全不滚动时,头部的 N 项在交接 仍然回答「有没有在交接」。
提醒
- 只在「等你审批/回答」和「报错」时弹系统通知,其他情况只变色,不打扰。
- 同一件事只弹一次;新的事才会再弹。
- 面板收起来时,胶囊上带「N 忙 · N 待 · N 等 · N 错」。
交互
- 拖动标题栏移动面板,位置记住。
- 拖右下角调整大小(默认 560×480,最小 420×320,最大 980×700),大小记住。
- × 收起成右下角胶囊,再点展开。
- ? 打开六态图例(抽屉),Esc 或 × 关掉。
- 点工位 / 点「需要你」里的一行 / 点「闲着」里的一个名字都打开详情抽屉(抽屉里再点「打开聊天」跳会话)。
- Esc 关闭抽屉;抽屉打开时焦点会移进去、Tab 在抽屉内循环,关掉后回到刚才那一行(不是回到网格)。交接边、列表行、闲着名字都可以 Tab + Enter 打开。
- 名册顺序永不改变,分层只是在渲染期对行做过滤:一个 Bot 只在真的开始/结束一轮时才在「在动 / 闲着」之间换层(还有 1.2 秒的稳定窗,一次轮询的抖动不搬家)。位置是你记人的方式。
- 「需要你」不走这个稳定窗。 它是这块面板唯一不许滞后的答案:审批一来就得进列表,一处理就得离开。给它加防抖会让面板和自己的头部计数互相打脸(头部说「1 等你」,列表说「没有需要你的事」),处理完的那一刻还会让那个 Bot 三层都不在。
数据从哪来
数据 · 来源
每个 Bot 的实时状态、
…(truncated)
以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:4,最后更新 2026-10-23