Skip to content

dsh-bot-board

Verified

dsh-bot-board · v0.7.3 · MIT · Web UI

A DeepSeek Harness plugin: a floating board for DS Bot that shows who is running, who is stuck, and who needs you.

Install

dsh plugin add dsh-bot-board

Confirm the layer applied with dsh --profile default --dump-config — see the install guide.

Source

Tags

Creators

Readme

Bot 看板(dsh-bot-board)

English · 中文

npm

给 DS Bot 加一块浮动看板:谁在跑、跑了多久、卡在哪、谁在等谁交活。不用逐个点开他们的会话。

560×480,三件需要你、五个在动、一个闲着

这是一个 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 的实时状态、当前工具、已跑时长、审批与提问、新建 Bot 待选模型 DS Bot 的 POST api/bot(endpoint: "state"),有活在跑时 1.5 秒一次,全队闲着 90 秒后 6 秒一次
派活记录(from/to/open/results)、房间名 宿主侧读 ~/.dsh/bot/state.json,内存缓存,按 mtime+size 失效,5 秒一次
报错 宿主侧订阅 DSH 的 agent/error,按会话映射回 Bot,保留 15 分钟

只读取 DS Bot 的数据,不写它的任何文件。面板自己的位置、尺寸和折叠状态存在浏览器 localStorage,与 DS Bot 无关。

轮询会降频:面板收起或窗口隐藏时,两个轮询都降到 30 秒;连续失败时指数退避(最多 8 倍、上限 30 秒)。全队闲着(没有任何 Bot 在跑、没有审批、没有等交活)超过 90 秒后,实时轮询从 1.5 秒降到 6 秒——一旦有人动起来,下一次 tick 就回到 1.5 秒。间隔还带 ±10% 抖动,免得和 DS Bot 自己的前端锁相。

这不是省电,是因为 api/bot 的 state 端点在上游每次都会跑 refresh + bootstrap + catalog + loadSecrets,unchanged 只省了响应体积,没省这些。所以一个挂着不看、全员闲着的看板,每分钟仍然会让上游跑 40 次这几件事——降频降的是这个。

轮询循环是单飞的(src/client/pollLoop.js):请求在途时收到 wake 会被忽略,由请求自己在落地后排下一个 tick。早期版本会去清一个已经触发过的 timer 然后再 fire,结果是每折叠/展开一次就多挂一条永久轮询链。

看板不会给 DS Bot 传 locale:那个字段在上游是全局 uiLocale,会改掉新建 Bot 的招呼语言和记忆语言。只读插件不该有这个副作用。

安装

插件目录就是本仓库。装 DS Bot 之前它没有东西可画——看板的数据全部来自 DS Bot。

只是要用,在 profile 目录里装它,再把包名加进 bundles,然后完全退出 DSH 重开:

cd ~/.dsh/profiles/desktop
npm install dsh-bot-board      # profile 里有 pnpm-lock.yaml 就用 pnpm add dsh-bot-board
{ "dsh": { "profile": { "bundles": ["...", "dsh-bot-board"] } } }

要改代码,按下面四步从源码装。

  1. 拿代码并构建浏览器侧产物(源码在 src/,client.js 是生成的;仓库里已带一份与源码同步的产物,改了 src/ 才需要重新构建):
git clone https://github.com/coii08o0o/dsh-bot-board.git
cd dsh-bot-board
npm install     # 只装一个开发依赖 esbuild
npm run build
  1. 登记进 profile 的 package.json(位置在 ~/.dsh/profiles/desktop/package.json),把路径换成你的实际路径:
{
  "dependencies": {
    "dsh-bot-board": "file:/你的/路径/dsh-bot-board"
  },
  "dsh": {
    "profile": {
      "bundles": ["...", "dsh-bot-board"]
    }
  }
}
  1. 建立依赖链接(DSH 用 pnpm 管理 profile,file: 依赖也要链进 node_modules 才找得到):
ln -sfn /你的/路径/dsh-bot-board ~/.dsh/profiles/desktop/node_modules/dsh-bot-board
  1. 完全退出 DeepSeek Harness 再打开(直接 killall -9 "DeepSeek Harness" 最干净;osascript quit 会弹系统自动化权限窗),右下角出现「Bot 看板」面板。

客户端半边有 HMR:改完 src/client/** 后 npm run build 即生效,不用重启;改 src/host/** 才需要重启 DSH。

长相在 DS Bot 里设,不在看板里设:打开 Bot 的设置,给它选一个角色(七个轮廓之一)和颜色。看板下一次轮询就会跟着变——它只读,不写你的数据。没选过的 Bot 会按 id 哈希出稳定的脸,也完全能用。详见上面「Bot 的脸从哪来」。

开发

src/host/index.js      宿主侧:快照路由 + 失败存储
src/client/index.js    apply / slot 注册
src/client/rows.js     行构造(纯函数,可单测)
src/client/scene.js    状态优先级(纯函数,可单测)
src/client/layers.js   三层归属 + 交接边表 + 闲着降级(纯函数,可单测)
src/client/station.js  工位 SVG + 灯组件 Lamp + 元信息行
src/client/attention.js 「需要你」列表 + 「闲着」一行
src/client/elapsed.js  每秒跳一次的时长节点(工位和抽屉共用)
src/client/drawer.js   详情抽屉
src/client/legend.js   六态图例(复用抽屉)
src/client/handoffs.js 交接分组边表
src/client/panel.js    外壳、拖动、缩放、折叠、三层主体
src/client/poll.js     两个轮询器(钩子)
src/client/pollLoop.js 轮询循环(纯对象,可用假时钟测试)
src/client/cadence.js  轮询节奏(纯函数:全队闲着就放慢)
src/client/clock.js    共享的一秒心跳
src/client/bridge.js   打开会话的桥
src/client/const.js    可调参数 + 六态 + 工位名册
src/client/format.js   elapsed / ago / clip
src/client/style.js    CSS
src/client/locale.js   中/英文案
tools/build.mjs        esbuild 打包成 __ModuleLoader__ 格式
tools/smoke.mjs        宿主快照 + 纯逻辑 + 产物契约 + CSS
tools/render-check.mjs 用 React 垫片真渲染一遍组件树
npm run build    # 改完 src/ 必须重新构建
npm run smoke
npm run render
npm run check    # 上面三步一起(build + smoke + render)
npm run verify   # 只查一件事:client.js 是不是当前 src/client/*.js 构建出来的
npm run ci       # 发布前跑这个:verify + smoke + render,不前置 build
npm run freeze   # 构建 + 打印 src/产物 两个指纹 + 跑两套检查(复核用)

verify 和 ci 存在的意义是它们不 build。check 永远先跑 build,所以「产物过期」这个状态在 check 里根本无法表达——把旧 client.js 放回 HEAD 再跑 check,531 条断言照样全绿。verify 拿 client.js banner 里的 src 指纹和现算的指纹比对(不比对字节,因为 esbuild 是 ^0.25.0,版本一变输出字节就变;package-lock.json 锁了当前版本,但锁文件本身也会更新);ci 在此基础上再跑两套检查,所以忘记 build 的产物会被 ci 拦在发布之前。改了 src/ 而没重新构建时,npm run ci 会直接失败在第一步。

531 条里有 9 条是恒真 tripwire(输出里带 (invariant) 标记):CSS 由常量插值生成,它们按构造成立,存在是为了抓住「有人把插值手抄成字面量」的那一天。它们不构成行为覆盖,读数时请把它们排除在外。

复核时注意指纹要说是算哪一批文件:src/ 单独算、src+tools+产物 一起算,得到的值完全不同。之前两个人对着报「哈希不一致」,其实是算法不同。

react / react-dom 在构建时保持 external,由 __ModuleLoader__ 注入——打进 bundle 会产生第二份 React,hooks 直接报错。

已踩过的坑(给下次写插件的人)

  • connection.fetch.register 的 path 必须带前导斜杠(/api/bot-board),不带斜杠会 404;路由是精确路径名匹配,不是前缀。
  • connection 服务可能在 apply() 之后才就绪,必须用 ctx.inject(['connection'], cb) 等它,一次性 if (!ctx.connection) return 会让路由永不注册且毫无报错。
  • 客户端 bundle 的 __ModuleLoader__.load({id}) 里 id 必须等于包名,改名后不重打包会静默不加载。
  • 面板挂在 shell.overlay 插槽,order 取 500 以上,避开 ds-bot 的 50/55/60。
  • rooms[].log[] 没有时间字段(只有 seq),想显示「几分钟前」得自己记。
  • works[].room 是房间 id,不是 Bot id;用 Bot 表去查永远查不到名字。
  • bots[].sessionId 是当前分段,segments[] 里只有已结束的分段——做会话→Bot 映射时两个都要收,否则 Bot 切过段之后新会话的报错会丢。
  • api/bot 的 state 不是纯读接口,每次都跑 refresh/bootstrap/catalog/loadSecrets,别拿它做高频轮询。
  • 桌面端改完插件必须整个退出重开;osascript quit 会触发系统自动化权限弹窗,直接 killall -9 "DeepSeek Harness" 最干净。

已知边界

  • 面板常驻所有会话,不只在 DS Bot 里。
  • 派活只显示 state.json 里还留着的记录;DS Bot 在子任务完成时会删掉子记录,历史链路会断,所以这里不做链路图,只做「正在交接」列表。
  • 群聊面板没有做:rooms[].log[] 无时间字段,且本机实测群聊 0 使用率。
  • 报错只能抓到 DSH agent/error 能覆盖的(模型/工具步骤失败);网络层中断另说。
  • 教室是刻意的浅色岛,文字固定深色。暗色主题下房间仍是奶油色——这是设计选择,不是漏改。
  • DS Bot 的 avatar.image 不渲染:上游支持用户上传的图片(最大 160KB 的 data URL),看板只用 shape 和 color。图片要缩进 138px 的工位、而大多数 Bot 根本没有上传图,收益不抵成本——真需要的话从抽屉里显示原图开始。
  • DS Bot 升级后如果改了 api/bot 的字段,看板需要跟着调整。color 的取值域来自 ds-bot 的 src/client/inks.js,上游加新色时这里要同步(加不上的未知名会安全地回落到哈希)。
  • 快照对任何已认证的 DSH 会话可见:/api 有 HttpOnly cookie 和 owner 校验、默认只绑回环,但同源的插件脚本、远程 trustedHosts 和 API operator token 都能读到它。
  • state.json 按半可信输入处理:字段漂移或类型不对时会降级显示(空字符串 / null),不会崩,但可能读到的值是错的——dataVersion 不匹配时面板会明说。
  • 报错原文会进系统通知:通知可能出现在锁屏、录屏或投屏上;敏感环境请在系统设置里关掉这个插件的通知。

卸载

从 profile 的 bundles 和 dependencies 里删掉 dsh-bot-board,删掉软链,重启。

反馈与贡献

提 Issue 请带上三个信息:DSH 版本、ds-bot 版本、面板头部显示的内容(或截图)。DS Bot 升级后改字段是这类插件最常见的问题,版本号能省掉一轮问答。提 PR 前跑一遍 npm run ci——它会先校验 client.js 与 src/ 是否同步,忘 build 的产物到不了主分支。

许可与致谢

MIT。

看板里的七个角色轮廓取自 DS Bot(Apache-2.0)的 CHARACTERS,19 个颜色 ink 的色值取自它的 inks.js;看板把它们按自己的画法重绘成团子(脸盘、眼睛、手、桌面道具都是本项目的)。上游是 Apache-2.0,这里保留出处与许可说明。

版本

  • 0.7.0 — 「闲着」在退化态升级成名册。触发条件是「没人在跑、没有未结交接、上面那层留下的空间够放两行」:这时每个闲着的 Bot 各占一行 44px(和层 1 同一个节奏),头像 + 名字 + 角色(没角色用模型)+ 右侧「闲着」。列数由剩余高度算出而不是断点:560×480 单列九行刚好不滚(475 ≤ 480),420×320 自动分两列、带通知时三列,一个 Bot 都不会藏在滚动里;只有每格窄到 160px 以下才先丢角色列,名字不丢。名册不是层 1 的灰色版——没有白卡(白卡在奶油底上是 1.07:1,不编码任何信息)、没有左侧状态条、没有灯(九个灰圆是墙纸不是通道)、名字 500 字重,所以「需要你」仍然是第一眼。混合态(有人在跑)保持一行 24px。断言 465 → 514(smoke 264 + render 250),新增 P2-1…P2-4 与 C4d 预算。
  • 0.6.0 — 身份改成 DS Bot 自己的两轴:avatar.shape(七个角色轮廓,按 DS Bot 的形状重绘)× color(19 ink 或 #hex),桌面道具仍由 id 哈希。按名字的名册整个删掉——名字不再参与身份,公开版的默认值里不再有作者自己的团队。哈希兜底覆盖没设过长相的 Bot,撞车自动重排(12×7×10 = 840)。灯、尺寸、三层轴不变。上线前全检后断言 465(原 0.5.0 变更日志里的 437 是手抄数字,实测 435)。
  • 0.5.0 — Bot 的身份改成三级解析:上游 color(用户在 DS Bot 界面里选的颜色,19 个命名 ink 或 #rrggbb)压过本地名册,名册压不过就按 id 哈希;名册名字被认领后不再发出(防冒充),哈希层新增 (色, 头饰, 道具) 三重去重(原来两个陌生人有约 1/960 概率画成同一张脸)。INKS 表逐字取自 ds-bot 的 src/client/inks.js,看板与 DS Bot 同色。DS Bot 的 avatar 不渲染(见已知边界)。新增预览场景「身份来源」。断言 424 → 437。
  • 0.4.3 — 审计修复 + 文档对齐。代码:格宽 139 → 138(480 − 39 − 148 − 24 = 269 漏了 PANEL_BORDER 2px,层 2 实际只有 267px,139 宽会让第二行工位溢出 0.9px;改 138 后 C4c = 479.31 ≤ 480,余 0.694px,浏览器实测 0.72px);SCENE_VB 成为 viewBox 与 cellHeight() 的唯一来源,RUNNING_CELL_H 改由 Math.ceil(cellHeight()) 推导;IDLE_BUDGET 从裸的 380 改成 SIZE_MIN.w − PANEL_BORDER − 20 − IDLE_SLOP 并补上界断言;nameWidth 补 CJK 扩展B;waitSince 改用审批到达时刻(approval.at),attentionOf 在名额 ≥2 时保留最老的 error;层 1 展开态的 − 移到第一行(420×320 下原本被裁掉、无法撤销);交接表的「还有 N 项」变成可点击展开的控件;灯加浅色底座(轮廓 1.45:1 → 7.20:1);同名 Bot 不再能冒用同一个座位;宿主侧 works 上限修好、bots/rooms/works/segments 四类脏数据不再让快照永久失效、readAt 驱动 stale、控制字符与 RLO 被剔除;新增 npm run verify(client.js banner 带 src 指纹,防止产物落后源码而检查全绿)。断言 378 → 424。文档:设计规范与需求文档的数字全部按 const.js 重算,交接表位置、§8.3 跨层错误、420 与 560 的定位一并改正。
  • 0.4.0 – 0.4.2 — 三层注意力轴:条件渲染的「需要你」短列表(0–3 行 + +N)、按发送方分组的交接边表、闲着压成一行名字;常驻图例降级成抽屉;格宽从 176 收到 139/128。两轮审计补上的:C4c 原先漏算 grid gap 8 与 .bb-run 下内边距 4;attentionOf 在名额 ≥2 时保留最老的 error;waitSince 改用审批到达时刻;idleLine 的预算从裸的 380 改成从 SIZE_MIN.w 推导并加上界;nameWidth 补上 CJK 扩展B;灯底座圆盘盖住灯的外径。新增 npm run verify:client.js banner 带 src 指纹。
  • 0.3.0 — 拆分源码 + 构建;修 8 个 P0(报错压制、暗色可读、工位跳动、waiting 语义、灯色、room 查错表、切段丢报错、群聊死代码);新增已跑时长、审批详情、详情抽屉、交接列表;六态形状通道;轮询单飞 + 降频;i18n。
  • 0.3.4 — 键盘可用:抽屉加 aria-modal、打开时移入焦点、Tab 在抽屉内循环、Esc 关闭、关闭后焦点回到原工位;交接行补 role/tabIndex 和 Enter/Space;所有控件补 :focus-visible 焦点环。报错红灯改为只表示「现在」:安静超过 3 分钟降级成「闲着」+ ! 徽标,消息留在抽屉里。删掉 sinceKnown 死字段;失败表按 at 淘汰而不是插入序;字典里没有的 activity 兜底成「干活中」而不是打印原始 token。
  • 0.3.3 — 把上游已经给了但被丢掉的数据接上:新建 Bot 等你选模型时亮黄灯(bot.waiting)、问题的说明行与「可多选/可自己说」、这一轮是否在群里跑、交活结果按 Bot 名归属;「正在交接」先按 open > 0 排再截断,老但没交完的活不再被新的已结束记录挤掉。轮询改为自适应:全队闲着 90 秒后从 1.5 秒降到 6 秒,带 ±10% 抖动。
  • 0.3.2 — 修 3 处看得见的错:干完不再盖掉干活(交接落地同一秒接了下一轮的 Bot 会被画成干完 7 秒)、抽屉的已跑时长改为跟心跳走(此前打开后就冻住)、面板位置恢复和缩放后夹回视口(此前窗口变小可能拖不回来)。补 4 条回归断言。
  • 0.3.1 — 修 0.3.0 引入的轮询双链;去掉会改写上游 uiLocale 的 locale 字段;头部计数不再硬编码颜色;抽屉标签按真实契约改为「具体内容」;ago() 走 i18n;交接记录按 owners 表解析归属(切段后不再显示 session id);失败徽标随恢复自动消失;默认高度 480。
  • 0.2.0 — 教室场景、六种表情动作、拖动缩放。