npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-taskboard-kit

v0.9.2

Published

dsh (DeepSeek Harness) taskboard kit: one local task board per workspace. Agents create/claim/progress tasks with model tools; humans watch and drive the same board in a kanban tab — a single JSON file in the workspace is the only source of truth, no serv

Readme

dsh-taskboard-kit

DSH Insights health

给每个 dsh workspace 一块本地任务看板:Agent 用 model tools 创建、认领、推进任务,人类在 dsh web 的「看板」页签里看同一块板、也能直接操作。看板的唯一真实来源是 workspace 里的一个 JSON 文件——没有服务端、没有账号体系、不需要部署任何东西。

English README

兼容性

  • dsh ≥ 0.1.7 — 自 v0.5.3 起完整支持:会话 cwd 改吃 sessionId 插槽 prop(0.1.7 从会话列表 state 里移除了 current);看板入口适配 0.1.7 的紧凑居中 dock 布局;注入的看板通知改用 0.1.7 持久化层要求的 v4 生产者 source kind(plugin:taskboard-kit)。旧版 dsh 通过兜底逻辑继续可用。

包含什么

  • 8 个 model tools,Agent 在该 workspace 的任何会话里都能调用:
    • taskboard_inbox — 会话开始第一步:现在压在你身上的事,按急迫度排序,每条都带该敲的命令
    • taskboard_list — 列出任务(按状态 / 列 / 负责人 / 在等谁过滤)
    • taskboard_create — 新建任务,可选直接指派给谁
    • taskboard_claim — 从待认领池原子认领(并发下恰好一人成功;在等谁的卡不可认领)
    • taskboard_update — 开始 / 暂停 / 提交审核(指定审核人)/ 通过 / 打回 / 完成 / 关闭 / 重开 / block / unblock、改派、改字段(含价值度)、附注
    • taskboard_comment — 给任务留言(实现发现 / 交接说明 / 测试反馈),不改任务状态
    • taskboard_get — 任务全文 + 事件时间线 + 留言串 + 列龄 / SLA / 审核人 / 在等谁
    • taskboard_roster — 名册:谁真的在场(最后一次动手是什么时候、别名)
  • 「看板」会话页签,三个可切换的视角(共享同一份数据):
    • 按进度:六条泳道(待认领 · 已指派 · 进行中 · 待审核 · 待收口 · 已结清),卡片带优先级 / 价值度 / 负责人 / 当前列停留时长 / 陈旧点 / 审核人 / 在等谁;顶部一条 「◷ N 张卡在等你决定」 strip(完整问题原文 + 一键「回复并解除等待」);详情抽屉里有事件流水、留言与协作事实,一键认领 / 开始 / 提交 / 通过 / 打回 / 收口 / 改派。
    • 按负责人:一个负责人一条泳道(别名自动归并),一眼看清每个人头上挂了什么。
    • 统计:宏观读数——KPI(未结清 / 待收口 / 进行中 / 卡住 / 中位周期 / 收口延迟 / 打回率)、 每日新建 vs 结清(叠未结清累计折线)、状态与优先级分布、各负责人负载与周期、各列停留时长。
  • 「开启看板」向导:尚未开启看板的工作区给一键开启——建 .dsh/taskboard.json 并写入本工作区的 .dsh/BOARD-PROTOCOL.md(规范)。两者都已存在时都不会被覆盖。
  • 抽屉里的 markdown(v0.7.0):详情与评论按 markdown 渲染——标题、列表(按缩进嵌套,上限两级)、GFM 表格、代码块、引用、链接、图片(![alt](url),只放行 http/https)与只读任务复选框(- [ ] / - [x])。渲染管线先转义、只注入自造标签,任何 Agent 写的卡都只是数据;渲染实拍见 docs/images/markdown-fidelity.png。
  • 多 Agent 协作规范:完整规范见 docs/COLLABORATION.md;它的精简版在会话开始写入系统提示词,CLI --help 与面板「? 指南」里的片段同源。
  • 会话开始感知:Agent 收到的是自己那一份行动清单(不是我欠审核、谁在等我、哪张卡被打回、哪张派出去没人接),不是一句干巴巴的计数。
  • 看板变化推送:对每个 live 会话的板文件做 fs.watch——任务被指派给你、你的任务有了审核结论、有人把审核 hand off 给你、有人开始等你、有卡开始等人类、你的任务有新留言时自动通知(只注入上下文,绝不唤醒);5 秒风暴窗口内的连续变化合并成一条通知。
  • 时钟自检(v0.5.4):文件 watcher 永远看不到「三天没人碰这张卡」——所以另有一条按时的自检:只看压在你身上的事(欠审核、有人等你、被打回没动、自己的卡陈旧、派出去的活成了孤儿、等人类超时),每 5 分钟一轮、每 workspace 30 分钟最多催一次,并附上该敲的命令。
  • 等人类 = 真的叫得动人类(v0.5.4):卡片 block --on human 时进面板「等你」清单;配了 TASKBOARD_NOTIFY_CMD 就外发通知(msg9 / 桌面通知 / webhook 随你接);等超 24h 自动升级催办。

板文件

每个 workspace 一块:<workspace>/.dsh/taskboard.json(形状见英文版 README,字段自解释)。

文件跟着 workspace 走,所以在同一目录干活的每个 harness、每个人都能读写同一块板——提交进 git 或 gitignore 都可以。所有变更经过锁文件(过期锁自动回收)+ tmp+rename 原子写,并发 Agent 和面板同时操作不会写花文件;claim 在锁内裁决:N 个并发认领恰好一个成功,其余收到冲突。

升级到 0.6.0(用过旧版看板的话,这一段请读)

done 不再是终点,closed 才是。 0.6.0 之前流程停在 done、closed 表示「废弃」, 于是「干完了但没人收口」这件事在规范里根本不存在:卡永远躺在 done,没有任何规则说 "有人欠这一步"。

现在 done 的含义是干完且审核通过、但仍欠一次收口:卡还在看板上、还计入未结清, 直到有人 close 它。由此带来的变化:

  • 面板顶部新增「待收口」条,列出所有 done 未结清的卡,一键收口;
  • done 超过 72h 会被判为陈旧(以前永不算陈旧);
  • taskboard_inbox 会点名卡主「你的卡已 done 但没收口」,并给出该敲的命令;
  • 统计里的中位周期改成量 created → done(活),收口延迟单独量 done → closed(流程)。 拆成两个数是因为合成一个时,只要收口一拖,快板子也会显示成慢板子。

「这事不做了」仍然走 close——在 note 里写清原因;没有单独的 abandoned 状态。 旧板文件无感加载(cancelled → closed,缺的 value / comments / actors 在下次写入时补齐)。 如果你现有的板子里积了一批 done 卡,它们现在会显示为「待收口」的工作——这是预期读数,不是 bug。

状态模型

| 列 | 规则 | |---|---| | 待认领 | open 且无负责人且未在等谁——任何人可 claim | | 已指派 | open 且有负责人——已委派、未开始 | | 进行中 | 已认领或已开始 | | 待审核 | 已提交(submit),等 reviewer 通过 / 打回 | | 待收口 | 审核通过(或直接 done)——不是终态,还欠一次收口 | | 已结清 | 已收口——close(面板默认折叠,toggle 可显示) |

两条与状态正交的协作轴(v0.5.4,都不新增状态):

| 字段 | 含义 | 谁写 | |---|---|---| | reviewer | 谁欠这次审核。reviewer 本人 / 卡主 / 人类才能 approve|reject;不能审自己的活 | submit(默认解析:卡主 → 最近活跃的其他 Agent → 人类) | | waiting_on | 这张卡在等谁(human/agent/external + who + question + since)。等谁的卡不能被认领 | block / unblock |

板级还有 actors 名册(谁出现过、最后一次动手、别名 dsh ≡ dsh-agent)——用来回答「这活派给一个已经不在场的 Agent 了吗」。

只有 closed 是终态:done 的含义是「干完且审核通过、但还没结清」,卡仍留在看板上、仍算未结清, 需要卡主 / PO / 人类收口 close。分两步是因为审核通过 ≠ 事情了结(可能还要部署、等上游、补文档)。 「这事不做了」也走 close,但必须在 note 里写清原因——没有单独的 abandoned 状态, 「做完了」与「放弃了」的差别只存在于留言里。面板顶部有「待收口」条,一键收口,防止干完了没人收口。

流转图:open → in_progress → review → done → closed;done | closed → open(reopen)。按动作说:open → in_progress(claim / start)、in_progress → open(stop)、in_progress → review(submit)、review → done(approve)、review → in_progress(reject)、open|in_progress|review → done、open|in_progress|review|done → closed(close,旧名 cancel 是它的别名)、done|closed → open(reopen)。状态名刻意对齐 msg9 任务模型,未来接服务端看板时语义不变。旧版本写出的板文件无感加载:cancelled 状态/日志事件归一为 closed,缺的 value / comments 字段自动补齐。

每个任务还有价值度(value points,斐波那契刻度 ½ / 1 / 2 / 3 / 5 / 8,null = 未评估),用来回答"这张卡值多少"——创建或更新时设置,CLI 里 --value 1/2 表示 ½、--value none 清除。

安装

dsh plugin --profile web add [email protected]
# 重启 dsh web,打开任意会话,「看板」页签就在

务必写死版本号。 dsh plugin 转发给 pnpm 11,而 pnpm 11 默认带一道供应链 minimumReleaseAge 闸门:刚发布几分钟的版本会被拦下,此时不带版本的 add dsh-taskboard-kit 会静默装上一个旧版本 —— 你拿到的看板里 done 仍被当成终点, 而且没有任何提示。写上 @0.7.4 就是让这次安装绕过闸门、装到你指定的版本。 等某个版本发布满一天后,不带版本也能装到它。

v0.9.2 —— 修正:看板列宽刚性 1310px(窄屏裁列 / 宽屏留白)

  • 修正(T-85):styles.column 是 width: 240 + flexShrink: 0 ⇒ 一整排刚性 1310px ✗ —— 面板比它窄就裁掉右侧的列(1280 裁 317px、1440 裁 157px),比它宽就右侧留白(1680 留白 83px、2560 留白 963px)✗。 现在 column 改为 flex: 1 1 240px; min-width: 168px ✓(宽屏等分铺满 ✓、窄屏收缩到 168 ✓);宽度规格收进 TB_LANE 常量作为唯一来源 ✓; overflowX:auto 保留但降级为兜底 ✓;没有用 overflow:hidden 糊 ✗。 这是既有缺陷,不是 v0.9.x 的回归 ✓(v0.9.0 与 v0.9.1 在五个宽度上逐值相同 ✓,lanes/column 源码一字未改 ✓)。
  • 工具:新增第 18 个测试套件 tests/layout-invariants.test.mjs ✓ —— 真无头 Chrome 挂构建产物,四个宽度断言: 整页不横溢 · 泳道行不被裁 · 末列右边界 ≤ 视口 · 行必须铺满 · 列宽 ≥ 下限 · 面板内无越界元素 ✓。 关键:文档级 scrollWidth === clientWidth 改前也是 true ✗(溢出被关在泳道里)⇒ 只断言"整页不溢出"拦不住这个 bug ✗ ⇒ 必须断言"行内不被裁 + 必须铺满" ✓。 红绿对照:指向 v0.9.0/v0.9.1 的 client.js ⇒ 真红 ✓(裁 310/150px、留白 90/970px);仓内塞回 flex:0 0 240px 或 width:100vw ⇒ 红 ✓,且先断言 saboteur 真的生效 ✓。
  • 已知后果(有意接受):「按负责人」视角在只有一个负责人时那一列会铺满面板(1280 下 976px ✓)—— 这是"必须铺满"的直接结果 ✓;不要改回 flexShrink: 0 ✗(若要限宽应显式加 max-width,代价是重新引入留白 ✗)。见 docs/DESIGN.md ✓。

版本口径(沿用 v0.9.1 起的规则):0.x 下修正与内部改动走 patch ✓ —— 本版全是修正与工具,故为 0.9.2 ✓。

v0.9.1 —— 320px 抽屉头部修复 · 移除「待收口」条 · 提交前守卫

版本口径(本版起执行):0.x 下修正与内部改动走 patch ✓;只有新能力或需要用户知晓的行为变更才走 minor ✓ —— 一次 minor 应当是一个「能力台阶」,不是「攒了一堆修复」。

  • 修正(T-75):320px 视口下抽屉头部标题被压成竖排、头部高达 953.95px ✗ ⇒ 117.98px(标题 175 → 15px ✓); 560/900 与改前完全一致(60.89 / 40.59px)⇒ 宽档零回归 ✓。 改法为实测选定:flex-wrap: wrap + 标题 flex-basis: 160px(两条必须一起上 —— 单独 flex-basis: 0 时标题 hypothetical size 也是 0,换行算法永远认为放得下 ✗;flex-basis: 100% 会把 560/900 改到 102.39px ✗,已用数据否决 ✓)。
  • 变更(T-77):移除顶部「待收口」条 ✗(实测 1 张 done 时 147.59 / 100.80 / 75.80px、4 张时 332 / 235 / 210px ⇒ 现为 0,看板内容上移 −154 / −107 / −82px ✓)。 那句规则说明移入 done 列头的 title ✓;卡面权威口径与两条收口路径都保留 ✓(抽屉里那枚「收口结清」与列里那枚按钮是同一个 action: close)⇒ 代价只是收口从 1 次点击变成 2 次 ✓。
  • 工具(T-79 / T-82):新增提交前守卫 —— npm run check:commit / npm run commit:guarded: ① 源码 ↔ 产物一致(构建退出码必须为 0;构建不得产生新改动;工作区 lib/ = 索引 lib/ ✓); ② 有并发写时拒绝提交(两次采样 = porcelain + 被跟踪文件内容哈希 ✓ —— 只用 porcelain 拦不住"已修改态的文件被继续写" ✗); ③ 索引为空时说人话("是不是忘了 git add" ✓,且在构建之前 ⇒ 注定失败的提交不动产物 ✓)。 可选仓内 git hook:npm run install-hooks / uninstall-hooks(只写 repo-local core.hooksPath,绝不改全局 ✓;逃生门 git commit --no-verify 保持可用 ✓)。
  • 文档:docs/DESIGN.md 两条设计系统事实 —— ACCENT 是宿主的反相单色(要蓝色强调请用 LINK ✓);模板串里的 CSS 不受 tsc 检查(注释写在 */ 之后会吃掉整条规则 ⇒ 需骨架合法性判据 ✓)。 docs/COLLABORATION.md §13.5 记 hook 的三条硬纪律 ✓。

验证:npm test 351 项 / 17 套件全绿 ✓ + typecheck 干净 + action-parity 全绿 ✓; 负面对照均真红:拆掉 T-75 修复 ⇒ 头部回到 953.95px 并再次竖排 ✓;把 settle strip 塞回 ⇒ 对应断言 FAIL ✓;守卫的"红时不提交"用真 git 仓库量 git log 不增长 ✓; 加载面用页面级 sha256(不是 rev 请求 200 —— 那条口径已被证明无效 ✗)。

v0.9.0 —— 权限闸门补漏 + 卡详情与看板列表的密度重塑

本版起每条都标类别(能力 / 修正 / 文档 / 工具) —— 否则「版本数」会被当成「交付量」读。

  • 修正 · 闸门侧门(T-69):block 把卡挂到一张已经在等的卡上 = 替换那段等待 ⇒ 现在走与 unblock 同一道归属门,并先显式记一条 unblocked 再记 blocked;首次挂起不受约束(卡上本来没有等待 ⇒ 谁都能挂)。起因:一天内 4 次同类越权,其中一次正是"替换等待"这条侧门。
  • 能力 · 卡详情抽屉密度重塑(T-74):属性 / 动作 / 指派三块重排 —— 属性 11 行 → 4 行语义行(人 / 值 / 时 / 标签;字段形如 标签 值,行内自动折行);动作 9 行 → 一行胶囊 + 一行折叠的「暂不可用」(原因一条不删);指派 → 一行 当前:X(更换) + 可展开 combobox;详情页签顺序改为 属性 → 描述 → 动作 → 指派。 真机实测(抽屉宽 560):三块合计 1010.67 → 233.92px(−776.75,−76.9%);描述区 top 1182 → 237。顺带修掉一个真 bug:可复制字段的 title 是死的(新增 propTitle() 让复制与悬浮共存)。
  • 能力 · 看板顶部横幅 → 卡片凸显(T-76):删掉 156.52px 的大横幅,改为 卡片左侧竖条 + ⏳「等你决定」徽章(徽章 title = 问题原文)+ 该列内排最前,顶部只留一行 28px 汇总条(无等待卡时不渲染,点「跳过去」滚到该卡并闪现 1.2s)。 真机实测:顶部 156.52 → 28px、看板内容上移 135px、等待卡位次 6/7 → 0/7。 颜色纪律:「等你决定」= 主色蓝 + 实心矩形;「已超时」= 琥珀 + 胶囊描边 ⇒ 颜色与形状双重区分(浅/深色实测)。回复人类等待的入口从横幅搬进抽屉的等待框(能力不丢,代价是多一次点击)。
  • 修正 · CHANGELOG 更正(不改写历史):v0.8.0 的发行说明里有一句宣称 —— 「every path now runs the same ownership check」 —— 被 T-69 否证(当时 block 替换等待没有过门)。按"已发布的文本不改写"的口径,该句保持原样,在此更正。
  • 文档 · 两条设计系统事实:ACCENT 是宿主的反相单色(不是强调蓝 ⇒ 要蓝色强调请用 LINK);模板串里的 CSS 不受 tsc 检查(把注释写在 */ 之后会让解析器吃掉整条规则 ⇒ 必须有骨架合法性判据,本版已加)。

验证:npm test 333 项 / 16 套件全绿 + typecheck 干净 + action-parity 全绿(7 动作 × 5 状态 ⇒ 未移除任何动作入口); 负面对照:320px 关掉 flex-wrap ⇒ 横向溢出真红;注入隐藏徽章/竖条 ⇒ 可见性 True→False(不是"DOM 里有没有节点");源码变异 ⇒ 对应断言真红; 加载面用页面级 sha256(不是 rev+200 —— 那个方法已被证明无效)。

v0.8.0 —— 权限从「约定」变成「机制」+ reviewer 的主动通道

这一版全是行为变更(不是文案),装完刷新页面即可看到客户端部分;host 面(权限判定、通知)需重启 dsh web 才生效。

  1. unblock / close 的 actor 校验(T-61):起因为一天内 4 次同类越权 —— 有 agent 自行解挂"挂人类"的卡并替人类裁决、还自行 npm publish 两个版本。
    • unblock:挂人类的卡 ⇒ agent 一律不得解挂(只有人类);挂具名 agent ⇒ 只有本人或其别名等价名、或人类;who 为空 / kind:'external' ⇒ 有意放宽为任何在场 agent 或人类(板外对方永远不会来敲这块板子,按字面锁死只会把卡烂在板上)。
    • close / cancel / reopen:只有卡主 / 持卡人 / 裁决人 / 人类;被拒走 conflict,拒信写清"谁被拒 / 在等谁 / 由谁挂起 / 该找谁"。
    • 别名折叠:名册优先 + 配置兜底(内置 dsh ≡ dsh-agent、TASKBOARD_ACTOR_ALIASES / WATCH_NAMES / SIBLING_NAMES,组间传递合并)—— 否则自己会被自己拒 ✗。
    • 向后兼容:缺 created_by 的老卡退回改前行为(不锁死老卡);顺序是状态先于归属(没人在等 / 非法转移仍是 invalid-transition)。
    • 定位写明:这是防误操作与越权,不是安全边界 —— --by 不是凭据、可被伪造。
  2. submit 归属门 + 等待释放归属 + 新机制锁死修复(T-62):submit 此前任何人都能提交别人 in_progress 的卡 ⇒ 现在只允许持卡人 / 卡主 / 人类; submit / approve / reject / done / close / reopen 此前会静默清 waiting_on(可以让一张"等人类"的卡被 done 直接变"已完")⇒ 现在每条路径都过同一道归属判断,并显式补写 unblocked 事件; 同时修掉新机制引入的锁死:"谁被等"由排他许可改成追加许可(等 agent/external/未指名 ⇒ 卡主/持卡人/裁决人始终可解;等人类仍然只有人类能解)。
  3. reviewer 的主动通道(T-56):submit 成功后主动通知指定 reviewer —— 打印一条可原样复制的 msg9 send 命令;环境里有 msg9 且板里名册有他的地址时才真发;地址未知 / 无 msg9 / 发送失败 / 内部异常 ⇒ 一律降级为只打印,submit 照常成功(提交是核心动作,通知是附属); 幂等锚点是卡上最后一条 submitted 事件的下标(不是时间戳);stale 新增「🕵 欠审核」按 reviewer 分组(一行一个人 + 他该敲的命令 + --json.review_owed)。

    起因:9 张卡挂在 review 列、而那位 reviewer 反馈「没有他待办的」—— 因为他 cwd 不在本工作区、看的是"指派给我"而不是"欠我审核";"被人指定为 reviewer"这件事此前没有任何东西会主动告诉他。

  4. 等待区间读侧兜底(T-60):区间配对此前只认 unblocked ⇒ 被隐式结束的等待段闭不上、一路延伸到此刻(走势图末点说"还在等"、而当期大数字说"没在等",同屏自相矛盾);现在把 submit/approve/reject/done/closed/reopened 也作为区间终点。口径变更留痕:统计页「被卡住」会因历史等待被计入而变化,属于主人已批准的方向。

验证:npm test 312 项全绿(14 套件)+ typecheck 干净;新增 tests/authority.test.mjs(18 项)与 tests/authority-wait.test.mjs; 变异:摘掉"挂人类的卡 agent 不可解挂" ⇒ 红 · 摘掉别名折叠 ⇒ 红 · 摘掉 submit 归属门 ⇒ 红; 向后兼容用真实板当夹具:有 created_by 的卡挡住陌生人,抹掉后逐字回到改前。

v0.7.5 —— 把「复核里说过、但没人跟」的待办变成清单

全是客户端与 CLI 改动,刷新页面即可(CLI 侧无需重启)。

  1. 新增 taskboard tails(复核尾巴扫描器):扫已 closed / done 卡的裁决 note 与复核留言,抽出"看起来是待办"的句子; 每条带 卡号 + 位置(log:6 / comment:3)+ 句偏移 + 原文片段 + 命中判据。处置:--file <尾巴> --card <卡号> 落卡、 --waive <尾巴> --reason "…" 显式作废(必须给理由)、--reset 撤回;落进板文件的可选新字段 Board.tails?(旧板可读)。 同时接进既有路径:stale 加「🔻 复核尾巴」一节、inbox 给责任人提示(带上限与"还有 N 条")。 判据是被真实数据三轮收窄出来的(第一版 240 条=没人看的墙纸 → 94 条),六条收窄规则各自有单测; 另有 not-done 类只在小节标题层面放行("明确没做"标题下的条目也会被列出,而噪声控制由断言咬住 —— 变异二路证明)。 为什么做这个:38 张已闭卡里至少 10 条复核遗留掉了地(含"注释声称有测试、其实没有"这种假绿)—— 根因是复核结论写在 note 里、而 note 不改变列 ⇒ 没有载体、没有提醒、没有清单 ⇒ 天生静默。
  2. 清理 kimi 复核遗留 9 条:含补上那个"注释声称有、其实不存在"的对照测试(tests/action-parity.test.mjs 驱动 host: 7 动作 × 5 状态逐格跑 updateTask,与抽屉真正渲染的结果比 —— 不比字面量比行为);统计页整页去掉 brand-primary 数据色 (done 改用宿主 success 绿,刻意不用 link 系以免与 in-progress 撞色,两主题实测对比度 2.28/6.89 与 4.23/6.75); MILESTONE_TAG 大小写口径与 semverParts 对齐;? 指南新增卡面记号图例(由真常量派生,不手抄); 卡面 ref 补「任务编号」;T-93-hotfix / T-93.5 补齐编号边界;两处半角逗号 + 一条"源码里不存在『汉字,汉字』"的可咬规则。
  3. 卡面渲染层补护栏:无名等待(waiting_on.who 为空)不得渲染成"可认领" —— 此前把渲染分支顺序改回旧顺序, 76 项测试仍全绿(派生层有护栏、最该护的卡面层没有);现在变异只让它一条红。 另补「裁决人 {reviewer} 仍可裁决」提示(一处 holderTitle() 三处生效),reviewer 为空时不加也不回落到创建者(与属性表那行一致)。
  4. 两条语义小项:start 后若等待仍在,结果列显式提示「等待仍在({who})」(host 确实不清 waiting_on); 抽屉不加 stop/block(都不改列,加了会出现"按下去状态没变"的按钮)⇒ 文档给出可直敲的 CLI 路径。
  5. 统计页「被卡住」口径变更(主人拍板):blockedAt 改为按 log 里 blocked → unblocked 配对重建等待区间 (旧板没有该事件时回退 waiting_on.since;连续两次 blocked 会产生重叠段、some 判定不受影响) ⇒ 这个数字会上升,而这正是要的:从此能查"这张卡被卡过多久",历史等待不再隐身。

验证:npm test 256 项全绿 + typecheck 干净;新判据与清理项各带变异红/绿(T-44 13/13 · T-42 10/10 · T-50 二路 · T-40 单点); tails 在本工作区真实板上把 94 条未收口处置到 0(落卡 47 / 作废 47,逐条带理由)。

v0.7.4 —— 键盘能用了 · 走位不迷路 · 导航区不再"不稳定"

全是客户端改动,刷新页面即可。 三件:

  1. 键盘导航 j / k:在当前视图里按视觉顺序(从上到下、从左到右)移动选中,抽屉开着内容也跟着换;Enter 打开第一张。顺序直接由渲染用的同一份泳道派生(不是另算一套),所以"键盘顺序 === 屏幕顺序"是结构性的;收起的「已结清」竖条不进顺序(没渲染就不该落到看不见的卡上)。焦点在输入框 / 评论框 / contenteditable 里时一律走原生行为(⌘/Ctrl/Alt、输入法组字、指南/关于/成员选择器/新建表单开着时也不抢);Esc 仍只有一套分层,没有第二套语义。
  2. 走位自动滚入视口:长板 / 窄窗口下 j/k 走到视口外时把选中的卡带回可见区;用 block:'nearest' 且已经可见时根本不滚(否则每按一次都跳,比不滚更烦),也不会带着抽屉一起滚。
  3. 导航区重构(三段式 + 永远在场):这一版是回应"排列和显示很不稳定"——
    • 同一行现在有三段:视图(按进度|按负责人|统计)· 筛选(含已关闭)· 操作(信息 ? ⓘ · 动作 ↻ · 主按钮)。组内 4px、组间 16px;
    • 含已关闭 永远在场(原先只在「按负责人」视角出现 ⇒ 切视角时这一行凭空多/少一个控件,这才是"不稳定"的真正来源);
    • 三个工具图标换成内联 SVG(原先 ? 是 ASCII、↻/ⓘ 是符号字形,CSS 完全相同也对不齐);
    • "刷新"不再夹在"使用指南"和"关于"中间;
    • 所有可点控件统一 28px 高 / 同圆角 / 同 hover / 键盘 focus 描边;
    • 按宽度跳档而不是挤压:≥720 全标签 → 520–720 按 路径 → 计数 → 标题 顺序舍、筛选只留方框 → <520 把筛选与三个工具收进 ⋯(视图组与主按钮永远在位;320px 时视图组也进菜单)。⋯ 接进既有的 Esc 分层,一次按键只关一层。
    • 顺带修:删样式表时误删了一个键,英文界面 @720 下视图组会掉出 flex 被挤到第二行。

验证:npm test 230 项全绿 + typecheck 干净;每处改动都有变异验证(键盘守卫 / 顺序 / 走位闸门 / 图标形态 / 组间间距 / 菜单分层 …),并用真浏览器逐条量过:三个图标 16×16、按钮 28×28、所有可点控件垂直中心差 0.00px、各档单行且不溢出、⋯ 开合与 Esc、focus 可见、超长路径截断、空板与英文最长文案。

v0.7.3 —— 「关于」浮层 · 持球行铺到每个面 · 两处清理

全是客户端改动,刷新页面即可,不用重启 dsh web。 这一版里唯一会离开你机器的,是你自己点的那几个 GitHub 链接。

  1. 「关于」浮层(工具栏的 ⓘ;0.7.4 起它在信息组里与 ? 相邻,↻ 已归到动作侧):名称 + 版本(版本由构建注入——scripts/build.mjs 用 esbuild define 从 package.json 取;构建若漏了注入会回落成 dev,不会印出空版本)、一句话简介,然后是真正值得读的一块:本地透明度——看板文件的绝对路径 · 卡片数 · 花名册人数 · 数据格式版本(board.version)· 插件 id,以及一句话说清「数据全在这一个 JSON 里,没有服务器、没有账号、没有云」。下面四个 GitHub 入口:仓库 · 问题反馈 · 协作规范(docs/COLLABORATION.md)· 变更记录(就是这段),每个都是 target="_blank" rel="noreferrer",末尾是 MIT 与作者。Esc 只关它(它是最上层,按键不会穿透到底下的抽屉或指南)。
  2. 持球行成为「球在谁手上」的唯一答案,每个面都一样。 卡面、抽屉、状态栏 mini 抽屉全部用同一个派生(currentHolder)渲染 记号 + 名字,严格一行:➤ 待提交 · ○ 待认领(池子)· ◷ 待回复 / 待回执(等人类 / 等 Agent)· ⚑ 待裁决(待审核)· ⌂ 待收口(已完成)。closed 没有持球人。它由状态机派生而不是读 assignee:review 阶段负责人被冻结(球在裁决人手上)、done 阶段裁决人已清空(球在卡主手上),所以「当前处理人」的字面读法在这两处都会指向错的人。mini 抽屉原先堆了三枚逐字段徽章、同一件事说两遍,现在只剩这一行。
  3. 标题前缀只在显示层剥离。 与卡面重复的 【owner】 T-93 · 前缀不上卡面,原文留在 tooltip 里;板文件里的字符串一个字符都不改。
  4. 长名字改为截断,不再溢出。 .tb-badge-outline(以及所有同类 10px 药丸)补上 max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap:长 actor 名以前会溢出虚线边框、再被泳道从中间切掉,看起来像排版坏了而不是「名字太长」。
  5. 两处清理:0.7.2 之前就死掉的三个样式键(cardSep / reviewerBadge / cardWaitAge,各定义 1 处、引用 0 处)删掉。

验证:npm test 214 项全绿 + typecheck 干净;版本回落、持球记号、徽章 ellipsis 规则、Esc 分层各自都有变异对照(改坏 ⇒ 对应测试必须红)。

v0.7.2 —— 卡面与统计的「一眼看懂」改造(十项)

主人 2026-10-01 连着给了四轮反馈,这一版把它们一起收了(全是客户端改动,刷新页面即可,不用重启 dsh web):

  1. 卡面三行版式:第 1 行=固定属性(优先级点 · 编号 · 价值点 · 状态 · 负责人/创建者 …… 列龄靠右,10px);第 2 行=标题(≤2 行,冗余前缀在显示层剥离);第 3 行=会变的(处理人 · 等待 · 审核 · 标签,严格一行)。卡高由 90–123px 收敛到统一 88px。
  2. 标题去噪:【owner】 T-93 · 这类与本卡重复的前缀不再上卡面(【owner】 仅当它就是本卡的负责人/创建者/裁决人;编号仅当就是本卡自己的 id;原文留在 tooltip)。编号匹配带完整 token 边界 —— T-930 / T-93X / T-93-2 不会被误吃(这是复核打回的真 bug)。
  3. 持球人派生视图:卡面只回答一句「球在谁手上(待什么动作)」——➤ 待提交 / ◷ 待回复·待回执 / ⚑ 待裁决 / ⌂ 待收口 / ○ 待认领(closed 无持球人)。它由状态机派生(review 阶段负责人被冻结、done 阶段裁决人已清空,所以"当前处理人"的字面读法在这三处都会指向错的人)。
  4. 卡面图标化:标签词换成记号(@ 负责人 · ✎ 创建者 · ◆ 价值点 · ◷ 等待 · ⚑ 裁决 · ⌂ 收口 · ➤ 持球),只用文本字形不用 emoji,含义在 tooltip 里;卡面文字 −10.6%。
  5. 统计页 v2:时间窗 7/14/30 天可切;KPI 分「要你动手的」与「背景数字」两组并带与上一等长窗口的环比(样本不足 <3 时显式标注"样本不足",不装趋势);新增「现在该动什么」(持球人排行 + 异常清单,每条可点开对应卡)与「价值度视角」(积压 vs 交付、吞吐、每卡价值/周期);流量图补 y 轴刻度/网格/数值标签、状态改环形图;「里程碑进度」由 tag 派生(如 v1.42.0)。
  6. 详情抽屉 v2:粘性头部(标题 + 持球行 + 主操作常驻);属性表(值可复制);动作永远全部列出并带结果列(关闭 → 进入「已结清」· 可 reopen 恢复),不可用的置灰并说明原因;指派改可搜索、默认只列在场者(久未活动者要显式展开);描述可折叠;标签可点。
  7. 两条潜在死路随之修掉:池子里的卡点「开始」会造出无主的「进行中」;被等待的卡在抽屉里只有「认领」这个必然失败的出口(现在有「解除等待」)。
  8. 无名等待(waiting_on.who 为空)不再渲染成"可认领"(卡面与统计页两处)——store 会拒绝认领等待中的卡,之前那是个点了必然失败的入口。

验证:npm test 207 项全绿 + typecheck 干净;每一处都带变异验证(改错即红)。

0.7.1 = 把「看不清的小字」修好 + 卡片更紧凑。 卡面上那一档「淡字」原来用的是 --dsw-alias-label-dimmed —— shell 里故意做到近乎不可见的一档(浅色 #e1e5ee、深色 #43454a,对比度 ≈1.1:1 / 1.3:1),于是引用号 #18、价值度 ◆2、列龄这些字两套主题都看不清;现在改用 --dsw-alias-label-tertiary(#81858c / #adb2b8)。同时按「结构重塑」把卡片从 5 行压到 3 行(#N 与 ◆value 移到 meta 行右侧,负责人与等待/审核胶囊合一行),泳道 260 → 240px,间距/行高同步收紧:同一块板上卡高平均 125px → 97px(−22%),一屏单泳道约 7 张 → 9 张。等待胶囊允许内部换行,保住「等了多久」这半条信息。

0.7.0 = markdown 保真度 + 两处安全加固。 详情与评论的渲染补齐了四件事:图片(![alt](url),只放行 http/https)、嵌套列表(按缩进两级,子列表开在父 <li> 内)、只读任务复选框(- [ ] / - [x])、评论容器改块级 div(表格/列表不再塞进 span)。安全面同步收紧两处:cwd 白名单按方向分档 —— 写(POST)在无板目录里必须由宿主明确回答「这个工作区我服务」,读保持既有契约(面板要能读「会话不在线 / 板还没建」的工作区);信任门开始比 scheme(Origin: https://… 不再被当成本机 http 源放行)。另外收了审计剩下的三条 minor(CLI 打错 --cwd 不再与空板难分、锁等待预算覆盖 stale 窗口、上文那条 scheme)。

0.6.2 修的是「样式表归属」。 状态栏那枚「看板 · N ◷M」胶囊偶尔会退化成浏览器 默认按钮(灰底灰边、图标被挤到上一行)。根因不在布局:dsh 的客户端模块加载器会把文档里 所有还没有主的 <style> 收编给下一个加载的插件模块,再在它卸载 / 热重载时删掉; 我们的样式表原本是 React 渲染的(天然无主),于是被别人的一次重载顺手删掉,而 React 还以为 它还在(fiber 既不会补回,界面上也没有任何报错)。现在 TB_CSS 只由 ensureTaskboardStyles() 注入 <head>,出生就带 data-plugin="dsh-taskboard-kit", 加载器再也抢不走,丢了下次挂载还会自愈。建议所有 0.6.x 用户升级。

(0.6.1 是纯文案版本:「叫人类」改说成你自己的通知通道(msg9 / 桌面通知 / webhook / 邮件),不再把 msg9 写成唯一方式;msg9HookExample 改名为 notifyHookExample, 旧名保留为 deprecated 别名。零行为变化。)

升级同理:dsh plugin --profile web add dsh-taskboard-kit@<版本号>(0.x 锁小版本, dsh plugin update 不会带你跨版本)。

给没有插件的 Agent 用(Kimi Code、Claude Code、任何 shell)

板就是一个文件,但绝不要手改它——锁和原子认领都在 store 里。kit 自带一个零依赖 CLI,封装的正是同一个 store,让每个 Agent 用同一个安全入口操作:

taskboard inbox --by kimi                   # ★ 会话开始第一步:现在该你处理的事(带该敲的命令)
taskboard list --waiting human               # 谁在等人类(--waiting agent|external|any 同理)
taskboard stale                              # 协作健康:在等人类 / 审核没人认领 / 交接断了 / 列陈旧
taskboard roster                             # 名册:谁还在场(派活前查)
taskboard claim T-3 --by kimi                # 原子认领,log 记 "kimi"(等谁的卡会被拒)
taskboard update T-3 --action submit --reviewer claude --by kimi   # 提交并指定审核人(**持卡人的动作**:持卡人 / 卡主 / 人类,T-62)
taskboard update T-3 --action approve --by claude                  # 审核通过(非 reviewer/卡主/人类会被拒)
taskboard update T-3 --action block --on human --who iceskysl \
  --question "现在就发,还是等 T-8 修完?" --by kimi                # 挂到人类身上(触发外发通知)
taskboard update T-3 --action unblock --by iceskysl                # 答复到了 —— 等人类的卡**只有人类**能解挂(agent 会被拒,T-61)
taskboard update T-3 --action close --note "已部署" --by kimi       # 收口 —— 只有卡主 / 持卡人 / 裁决人 / 人类能敲(T-61)
taskboard comment T-3 --text "交接:…" --by kimi        # 不改任务状态
taskboard create --title "…" --priority high --value 3 --by claude

--by 指定 log 里的操作者(默认 $TASKBOARD_ACTOR 或 cli-agent);--cwd 指向别的 workspace;--json 输出机器可读结果;认领失败退出码 3 并给出可读的冲突原因。包还没上 npm 之前,直接从仓库调用:node /path/to/dsh-taskboard-kit/bin/taskboard.mjs list。dsh web 跑不跑都能用;web 在跑时,本机进程也可以直接调回环 bridge /dsh-taskboard/*。

环境开关

| 变量 | 作用 | |---|---| | TASKBOARD_ACTOR | Agent 工具写进 log 的默认操作者名(默认 dsh-agent) | | TASKBOARD_HUMANS | 逗号分隔:哪些名字算人类(默认 human) | | TASKBOARD_ACTOR_ALIASES | 规范名:别名1\|别名2,…——把同一个 Agent 的多个名字并成一个主人(默认 dsh:dsh-agent) | | TASKBOARD_WATCH_NAMES | 逗号分隔的「自己人」名字列表(第一位为规范名,其余自动成为别名);watcher 按它判断哪些变化与我有关、哪些是我的自回声(默认 dsh,dsh-agent) | | TASKBOARD_SIBLING_NAMES | 同一实例的其他会话名:它们的卡算我的,但它们的动作会通知我(默认空)。默认配置下两个 dsh 会话会互相看不见,这一项就是解药 | | TASKBOARD_ALLOW_SELF_REVIEW | 1 = 允许自审(只给「一个 Agent 独占一个 workspace」的场景) | | TASKBOARD_NOTIFY_CMD | 卡片开始等人类 / 等超 SLA 时执行的外发通知命令;卡片 JSON 从 stdin 进,TASKBOARD_TASK_ID / TASKBOARD_QUESTION / TASKBOARD_NOTIFY_REASON 等从环境变量进。失败只记日志,绝不让写板失败 | | TASKBOARDKIT_LOCALE | en 强制英文工具输出(默认中文) | | TASKBOARD_WATCH | 0 整体关闭变化推送与时钟自检 |

浏览器桥

面板通过 /dsh-taskboard/* 与宿主通信。只接受回环 / 同源调用;所有 POST 必须带 x-taskboard: mutate 头。浏览器侧的操作在任务 log 里记为 human。

开发

npm install
npm run build       # esbuild → lib/index.js + lib/client.js
npm test            # node 原生 runner:store、host smoke、client
npm run typecheck   # tsc --noEmit

零运行时依赖。浏览器 bundle 只 require shell 内置的 react / react/jsx-runtime。

License

MIT