
Security News
Deno Goes the Way of the Dinosaur
Cloudflare is acquiring Deno’s team, which will provide another year of bug fixes and security updates before ending support for the runtime.
dsh-agent-board
Advanced tools
DeepSeek Harness 智能看板:任务卡片 + 一次性 Worker/Verifier 派发 + 依赖调度 + 管线分档 + Team 模式(歧义上报主窗口裁决)
智能看板插件 — agent 团队的持久台账与治理层:把「派发 → 执行 → 验收 → 度量 → 复盘」跑成全链路闭环,每一张卡都是可审计、可度量的长期资产。
dsh-agent-board 是 agent 团队的持久台账与治理层——看板只是界面,内核是「派发 → 执行 → 验收 → 度量 → 复盘」的全链路闭环。 它与「一次性组队、跑完即散」的冲锋型编排器、「人建卡、agent 认领、人逐张验收」的手工看板不是一个代际:
acceptance 硬性脚本命令由 Worker 实跑、Verifier 独立复跑;结论分通过 / 驳回并逐条给证据。人只看该看的——风险队列「待你过目」把该亲自确认的卡推到眼前,其余交给机器闭环。流水线归机器,审计台归人。 我们不造「跑完就散」的冲锋队,也不做「人逐张盯着验收」的手工看板;我们的信念只有三条:验收独立复跑、人只看该看的、数据沉淀成资产。别人负责冲锋,agent-board 负责记账与验收——互补,不对抗。
dsh --profile web| 宿主 DSH 版本 | 应装插件版本 | 原因 |
|---|---|---|
| ≥ 0.2.0(含 rc) | ≥ 1.3.0(必须) | 0.2.0 起宿主在启动/安装时强制校验 peerDependencies,区间不含 0.2.0 的包直接拒绝激活(路由不挂载、面板不出现)。1.3.0 声明 ^0.1.7 || 0.2.0-rc.2 || ^0.2.0——注意 semver 预发布不命中宽区间,0.2.0-rc.2 必须显式枚举。运行时 API(subagents/systemPrompt/agents/uiWorkspace.openSession/sessions/v4 日志格式)在 0.2.0 全部兼容,已过 0.2.0-rc.2 实测(E2E 23+8 断言全绿) |
| 0.1.7 ~ 0.1.7-x(含 rc) | ≥ 1.2.2(必须) | 0.1.7 会话日志升级为 format v4:插件消息 source.kind 必须是生产者自有 kind。1.2.1 及更早会在任务完成/阻塞回执落盘时抛 SessionFormatError: format v4 message requires a producer-owned source kind,并连带使主窗口当前轮次失败(表现为「本轮运行失败」);同时「跳转会话」因宿主移除 sessions.open 而失效(控制台 sessionsSvc.open is not a function),卡片活动心跳读不到 v4 日志(session.v4.jsonl.zstd) |
| 0.1.5-rc.1 ~ 0.1.6 | ≤ 1.2.1 | 1.2.2 起按 0.1.7 协议编写(v4 source kind、uiWorkspace.openSession 跳转),旧宿主未做回归验证,建议停留 1.2.1 |
dsh plugin --profile web add dsh-agent-board@latest # 0.1.7+/0.2.x 宿主(推荐)
dsh plugin --profile web add dsh-agent-board@1.2.1 # 0.1.5/0.1.6 宿主
从 ≤1.2.1 升到 ≥1.2.2 必须重启 DSH(host 端代码在启动时加载;1.2.2 之前的老版本还有一个路由残留 bug:禁用/启用热重载会撞
duplicate exact route,只能重启恢复,1.2.2 已修复)。
已发布至 npm 官方 registry(dsh-agent-board):
dsh plugin --profile web add dsh-agent-board
# 重启 dsh 生效
dsh --profile web
git clone https://github.com/PPawnsir/task-board-plugin.git
dsh plugin --profile web add <本仓库绝对路径>/packages/dsh-agent-board
# 重启 dsh
plugin tree failed to loadcurl -X POST http://127.0.0.1:3080/dsh-agent-board \
-H "Content-Type: application/json" \
-d '{"method":"get-tasks","args":{"sessionId":"<sessionId>"}}'
返回 JSON 即正常;405 空 body 说明路由未挂载。
# 市场版
dsh plugin --profile web add dsh-agent-board@latest
# 源码版
git pull
# 两者都需重启 dsh
dsh plugin --profile web remove dsh-agent-board
# 重启 dsh
看板数据存在
~/.dsh/tasks-<sessionId>.json,卸载不删数据。
- 归属:看板文件按会话分文件,同时在文件里记
ownerCwd(创建该看板的会话工作区路径,取不到则省略该字段)——~/.dsh/tasks-*.json每个文件是一块看板,list-boards全局视图可看到本机所有板。- 重启继承:DSH 重启后同一会话的根 id 可能漂移,此时新 id 没有对应文件——若同工作区(
ownerCwd严格相等)存在唯一「原主已不在agents.roots()」的看板,则自动继承:文件重命名为新 id、文件内ownerSession改写为新 id、console.error留一行[task-board] 继承看板 <旧sid> → <新sid>;多个候选一律不自动接管(记一行日志后按空板处理,防误合并,旧板仍可在list-boards全局视图里看到)。- 写盘保护:落盘走 临时文件+rename 原子写(EPERM/EBUSY 退避重试);瞬时读失败/坏文件隔离后返回的空板禁止回写(防一个"读不到"的瞬间把看板覆成空板),坏文件隔离为
.corrupt-<时间戳>留档不丢数据。
看板数据(~/.dsh/tasks-<sessionId>.json)是本插件唯一的持久化状态,按三层防线保证数据不丢、事故可见:
fsync → rename 覆盖目标」——rename 在同分区是原子的,进程在写盘中途被强杀时磁盘上最多残留一个 .tmp 残件,看板本体永远不会是截断的半个 JSON。Windows 上 rename 覆盖已存在目标原生支持(实测直接覆盖成功),仅当目标被并发读句柄/Defender/索引器瞬时占用(EPERM/EBUSY/EACCES/ENOTEMPTY)时做有限退避重试;重试耗尽仍失败则降级「先 unlink 目标再 rename」并留日志——绝不丢整板。.corrupt-<时间戳> 留档隔离(防反复 poison),同时在「架构健康」区亮一条 err 级红条(healthHints)提示「看板数据文件腐坏已隔离,历史在 .corrupt-<ts>,可联系恢复」,并向 owner 会话推送通知——数据不丢,也不再静默从空板重启。JSON.parse 报错 position 截断法,与人工恢复同款手法),成功则以抢救出的完整板为底自动写回继续(healthHints 红条记「已抢救保留 N 张卡,丢弃撕裂残片」),失败才回退空板。两种情况下原始文件都留档 .corrupt-<ts>,可随时人工恢复。核心能力一页速览(★ 为 v1.7.5–1.8.1 新栈):
★:硬性验收脚本独立复跑、驳回全量带回重派、Verifier 自测指南(userTest)、风险队列「待你过目」、验收时序防护(Verifier 在场时主窗口抢批需显式 force:true;有活跃 run 的卡禁止归档;Verifier 迟到结论落 lateVerdict 留痕+迟到驳回直投告警,不再静默吞掉)★:Token 消耗(总量 / 有效 / 缓存读,按模型·按任务·按日)+ 记分卡(模型表现 / 质量趋势 / 驳回聚类)★:运行时健康自检(派发冻结 / 结算停滞告警)、异常驱动审视(风险队列 / 质量异动告警 / 批次摘要)、起草 lint、数据安全(原子写盘 / 腐坏隔离 / 自动 salvage)、僵尸 run 留档清扫(host 重启后「落定卡上的 running 无 endedAt 留档」在派发周期自动关账 stale-closed + 清认领位,归档门禁不再被幻影 run 永久拦截)、子会话生命周期收口(一次性 run 落定/迟到 verdict 落账后主动 interrupt 子会话——「结算≠停止」空转根治;continuable 收紧为「续跑位真在本 child 手上」才豁免,残影 Worker 无处藏身)、terminate 三保险(no-rec 也按认领位盲杀补刀 + interrupt 失败 err 级可见化 + hold:true 原子「终止+转手动」)、配置审计(set-board-config 成功写入落板级 configLog {key,from,to,actor,at} 截尾 50 条;模型下拉两段式选中≠保存)以下各节是完整规格。
delegationDepth(fork/seed 会话 depth=0 认根;真子代理 depth≥1 才隐藏看板入口),不再误把带 parentSession 的 fork 当子代理currentColor 跟随主题,浅深色自适应)zoom 等比缩放(字体/图标/间距一并放大,只影响本面板、不碰宿主页面),选中即时生效并 localStorage 本地记忆(键 dsh-agent-board-ui-zoom)⛁ 数字);区底固定口径 caption:累计 / Top 8 仅看板派发的 run 消耗,主窗口行并列不混入task-muxnqunk,用户 2026-10-07 裁决「算总的吧」,推翻 task-muwq9u04 的有效主显):Token 区主数字均为总量口径(含缓存读)——今日大数字 / 近 7 天柱 / 按模型分布 / Top 8 / 主窗口行一律显总量,有效消耗退居悬浮 title 或次要小字;旧口径日(e=null)的「今日显 — / 矮灰柱」防护顺势退役(总量恒有值,正常画柱,悬浮注明有效不可知)。不动的:「模型表现」「质量趋势」区保持有效口径(效率指标语义),报告导出分列口径不动。实证背景:本板累计 10.3M 里缓存读占 9.7M(94%)——总量与有效的差额一眼可在累计三分量与悬浮里对照task-muxnqunk 翻转版,替代 task-muwq9u04):按模型分布行与任务消耗 Top 8 行的主数字一律为总量(含缓存读;模型取 host 的 byModel,任务取 topTasks[].total),有效消耗(byModelEff 模型有效分摊 / topTasks[].effective)进悬浮 title——与「今日」「近 7 天」同口径;老 host 缺 byModelEff 或老卡无五分量留账时 title 标「有效不可知」(口径不伪造)task-muwc7hjd):仪表盘顶部的「统计范围」(快捷:今天 / 近 7 天 / 近 30 天 / 全部 + 自定义起止)现在同时作用于 Token 区的按模型分布 / 任务消耗 Top 8 / 累计三分量——范围变化即用新范围重拉 get-tasks,由 host 按每个 run 的本地日落点(t.runs[i].at → YYYY-MM-DD,两端闭区间)过滤:范围外 run 不计入 total/byModel/top,byDay 同步裁到范围内;范围激活时 Token 区标题带「范围内: …」标记。今日大数字与「近 7 天」柱子是自身固定口径,不随范围变化(区底第二行 caption 与范围筛选浮层均写明)。无范围(两端皆空)时聚合结果与旧版逐字一致(parity);无 run 级留账(老卡 / runs 条目未落 usage)退化为按 updatedAt 本地日判定,无 at 的老 run 只在无范围时计入(宁可漏不错),run 未记模型名时按入选 run 占比摊任务级模型小计(合计与有效同法摊派,ΣbyModel 与入选总量、ΣbyModelEff 与入选有效各自对齐)。数据源口径修正(task-muwq9u04):run 记录数组在任务级 t.runs[](t.usage.runs 只是结算次数计数)——此前误把计数当数组读,范围过滤静默退化成 updatedAt 单日近似、Top 8 与无范围逐字相同;现已逐 run 精确裁切,且范围切换后客户端按 usageSummary 的 JSON 串比对补一次 notify(选范围即渲染,不等下一次任意刷新)。Token 口径三连修(task-muwsnyqv):① 范围内 byDay 按入选 run 的本地日落点逐日重建(to 端闭区间,from=to=今天 时今天不丢——修「范围含今天时 total 含今天、byDay 却吞今天」);② usageSummary 同时返回未过滤全量 byDayFull 与范围内 byDay,「今日」「近 7 天」改读 byDayFull 兑现固定口径承诺(老 host 缺字段退化读 byDay);③ task-muxnqunk):总量主显后 e=null 的旧口径日就是正常柱(t 恒有值,柱高按总量归一),不再画矮灰柱 / 今日显「—」,有效不可知只在悬浮 title 注明~/.dsh/sessions/*/<runId>/session.v4.jsonl.zstd),把 assistant/message 事件的 usage(inputTokens / outputTokens / cacheReadTokens / cacheWriteTokens / totalTokens,字段形状以真实日志为准)按 zstd 帧逐帧累加到任务 usage(含按模型小计、runs 计数与 byDay 日账——本地日 YYYY-MM-DD,一次 run 整笔记在结算日;多轮重跑/驳回重做自动累加);run 级留账:本次用量同时原样写回 t.runs 对应条目的 usage(五分量俱全),因此按天 / 按模型 / 按阶段任何维度都能从 runs 精确重建,口径若要再调整不必回头猜byDay 为双指标形态 { t, e }(t = 总量含缓存读,e = 有效消耗不含缓存读;一次 run 不跨日拆分)。聚合端兼容老数据:值是裸 number 的历史日账按 { t: n, e: null } 处理——总量照常保留(「近 7 天」不会整段消失),有效值不可知就置 null;口径翻转后(task-muxnqunk)旧口径日按总量正常展示(今日大数字显总量、近 7 天按总量画柱),有效不可知只在悬浮 title 注明——task-muwsnyqv 的「显 — / 矮灰柱」防护已随总量主显退役get-tasks 再现算 board 级 usageSummary(总量 / 有效合计 / 按模型(合计 byModel + 有效分摊 byModelEff,两者同源累加)/ Top8(带有效与缓存读拆分)/ 日账双份(范围内 byDay + 未过滤全量 byDayFull,后者供「今日」「近 7 天」固定口径读取),不落盘额外表;老任务无 byDay 时整笔近似归到 updatedAt 的本地日,无 updatedAt 则不计入任何日)——只做展示、不做计费断言,日志读不到或没有 usage 时一律显示「暂无数据」;第二参 range(可选 { from, to } 本地日)给定即只聚合该范围内的 run(口径见上条)task-muwsol23):累计行下方新增一行「主窗口(本会话):今日 X · 累计 Y」(总量口径含缓存读——task-muxnqunk 翻转后缓存读不再单列、已含在 total 里,有效值见悬浮 title),按模型分布尾部追加一条「主窗口(对话)」(琥珀色与 run 模型区分,总量为 0 不渲染,固定尾部不参与排序);数据源是该看板所属主会话自己的 v4 日志,host 侧增量尾读聚合(缓存键=会话 id:文件不变零读、变大只读新增字节段、变小/轮换全量重读一次,尾部半帧不结算下轮补读——3s 轮询稳态零全量重读),五分量与有效口径(e=输入+输出+缓存写)同 Worker 完全一致;隔离红线:不进 Top 8、不进「本看板累计」、不进架构健康/学习飞轮基数,只并列展示;随统计范围裁剪(按 assistant/message 事件的本地日落点);日志不存在/读取失败/无 usage 一律静默降级(不渲染该行,不炸轮询)task-muxhtgi2):Token 区下方新增模型 × 场景八指标对比表——每行一个 模型 × 角色(worker/verifier)× 规模段(小 <1M / 中 1~10M / 大 >10M,按任务有效 token 分桶)桶;八列口径一句话版:有效均值 = 桶内 run 有效消耗(输入+输出+缓存写,不含缓存读)的均值、耗时中位 = run 耗时(endedAt−at)中位数(P90 在行 title)、驳回率 = 归因到本桶的验收驳回 / 桶内 runs、一次通过率 = 桶内 resolved 任务中零驳回占比、超时率 = 超时落定 run / 桶内 runs、失败率 = 跑崩落定(incomplete/error/failed)run / 桶内 runs(terminated 人工终止不计入,task-mv73ym6i)、续跑率 = resume 续跑记录 / 桶内 runs、缓存命中率 = cacheRead/(input+cacheRead)(⚠️ 跨 provider 对比先核 input 是否含缓存读);表头列名均带 title 口径说明;表头下两个本地筛选器(角色 全部/worker/verifier + 规模段 全部/小/中/大)只在已返回的 scoreboard 上过滤、不重拉;桶内 runs<5 整行灰显 + title「样本 <5,仅供参考」(不参与任何「最优」强调);无数据显「暂无足够 run 数据」;Token 区 caption 新增「→ 模型表现」锚链接一键滚动到位。数据源 = get-tasks 响应里的 usageSummary.scoreboard(卡2 host 聚合底座 buildScoreboard,与 Token 区同一统计范围口径裁剪)task-muxhtgil):模型表现区下方新增全局趋势四块(P1 质量 KPI 并入)——一次通过率(近 14 天柱形:当日落定 resolved 任务中零驳回占比,今日柱高亮 + 块头标今日值,无落定日画灰基线不假装 0%)、卡时长分布(四桶横条 <10m / 10-30m / 30-60m / >60m,创建→落定墙钟含排队/验收全程)、超时率走势(近 14 天迷你柱行:当日超时落定 run / 当日 runs)、续跑成功率(resume 续跑记录中 completed 占比,范围总量口径、host 出参无逐日故不伪造 byDay);全部读 usageSummary.scoreboard.trends(卡2 已按统计范围裁剪,client 只渲染不重拉),范围激活时区头带「范围内: …」徽章;近 14 天为固定窗口(范围落在窗口外时对应日柱为空,caption 写明);整区/单块空态均灰显不炸task-muxhu1zv):质量趋势区下方新增驳回原因 Top3——host 对验收驳回文本做规则法关键词聚类(不上 embedding:驳回文本结构模板化;首命中归类,占比分母=驳回总数,未匹配进「其他」兜底桶;按驳回消息自身本地日落点随统计范围裁剪),每行 TopN 类目 + 占比 + 代表原文(行 title 悬浮,各截 80 字)+ 「建议沉淀为约定」结构化文本(形如「驳回 Top1『验收脚本未实跑』占 42%——建议在派发约定/Worker prompt 补一条:…」,一键复制按钮,沉淀动作人工);挂 usageSummary.scoreboard.rejectionClusters,老 host 缺字段整块不渲染,无驳回显空态。同一通道的**「按表现荐模型」hint**(卡5③):某模型在中小卡 worker 桶合并后 runs≥10 且一次通过率≥90% 且有效均值较其他每个合格模型严格低 >30% → 「架构健康」区亮黄条「模型 X 在中小卡表现最优(通过率 92% · 有效均值 0.8M,较其他合格模型低 35%),建议设为默认 workerModel」;无足够数据/无对比对象不亮get-tasks 顺带对近 50 张卡现算四信号(纯函数零存储:touches 声明热度 ≥8 次且占比 ≥40% / 带 touches 任务滞留中位数 >2 倍 / 任务执行时长 p90 >45min(claimedAt→resolvedAt 纯干活口径,不含排队)/ 同路径驳回 ≥2 次),命中才在仪表盘渲染提示条(⚠️/ℹ️ 两级,最多 3 条)——让运行数据主动提示"该优化架构了"(如某文件反复成为锁热点=该拆),信号只建议不裁判;运行时健康自检(task-muxhrkbg)复用同一 hint 通道——host 侧在 poolCycle 成功轮 / settle 结算 / 幽灵回收三处记内存心跳(state.poolHealth,不落盘):有可派卡+有空位却 >5min 无成功派发轮 → 亮「🔴 派发循环疑似冻结」,有在跑卡却 >30min 无任何结算 → 黄级「结算通道长时间无活动」,幽灵表项回收 >0 时留一条一次性 info 记录(90s 保鲜、读到即灭)——运行事故不再只靠 e2e 翻车与肉眼发现;质量异动告警(异常驱动审视②):usageSummary.scoreboard.trends 环比——近 7 天一次通过率较再前 7 天跌 >10 个百分点(两侧样本各 ≥5 防小样本误报)→ 黄条「质量异动:一次通过率本周 X%(上周 Y%),建议抽查近期验收」,超时率 / 驳回率突变各加一条同构规则(阈值常量置顶,恰好 10pp 不亮、10.1pp 亮)buildReport 顶部一页纸——完成 N 张 / 驳回 M 次 / Token 总量(约 X,附有效 Y)/ 异常事件计数(超时 + 幽灵回收,读现有字段与 healthHints)/ 一句话质量趋势;纯聚合现有字段、不新建状态,无数据时优雅空态(一句话「近 24 小时无活动记录」)task-muzikj1y):get-tasks 对每张卡现算 reviewHint={score,reasons[]}(纯函数 core.computeReviewHints,现算零落库)——四条硬信号恒计入:被驳回过(rejectCount>0 或 verification.verdict=rejected 或 messages 有 rejection 包)/ 上报过歧义(messages 有 arbitration 裁决包)/ touches 碰核心文件(dispatch.mjs|rpc.mjs|core.mjs)/ full 无 acceptance;两条软信号仅质量异动告警激活期间计入(联动加严):diff>300 行(deliverable.diff 的 git diff --stat 解析)/ 续跑≥2 次(runs 中 resume:true 计数)。已完成/归档的命中卡带「👁 建议过目」徽章(悬浮全部理由行),FilterBar 加 chip「待你过目」一键只看未阅命中卡;打开详情页即幂等落 reviewedAt(唯一新落库字段,mark-reviewed RPC 只写一次),已阅卡徽章消失、chip 不计;详情顶部新增「审视摘要区」(仅命中时显示)四问动线——①为什么在这(理由行)/ ②改了什么(deliverable.summary+diffStat,标「Worker 汇报」来源徽标)/ ③机器怎么验的(verification 结论+验收脚本+驳回/仲裁史,标「Verifier 实证」/「系统记录」徽标)/ ④怎么亲自确认(复用 verification.userTest 自测指南,缺省显示 tier=internal 提示);报告「批次摘要」段加一行「未过目 N 张」task-mv2131cz,用户指令「这个清理可以做到看板上」):DSH 宿主无会话删除 API(归档=执行门禁不删数据),看板是唯一知道「哪些会话账已结清」的组件——清理只能长在看板上。仪表盘新增「存储清理」区:「预览可清理会话」按钮 → 展示可删会话数 + 预估释放空间 + 按卡分组明细 + 跳过项与理由(只读不删;体积估算优先读宿主 SessionPersistenceSnapshot.sizeBytes,快照缺省时回退目录遍历);「清理」按钮二次确认后真删(删除不可恢复,token 账早已记入卡片、删除不影响任何统计),完成后报告「已释放 N / 跳过 M 及理由」lib/cleanup.mjs 纯函数):只删本板 runs[] 关联的会话 id,且 主闸 = 卡龄——所属卡 status=archived 且 archivedAt 距今 ≥ cleanupRetentionDays(板级设置项,默认 7 天、可配 1-90,回收与归档生命周期对齐);三底闸永留——① outcome 已落定(非 running)② 会话当前不活跃(不在 ctx.agents 活跃树 / 非本会话血统)③ 路径安全(id 白名单 + rm 前 isWithin 再验)——任一解析不确定即跳过并计入理由(宁漏勿错删)。continuable/usageRecorded 两道旧闸已撤:归档满保留天数即视为账本封存、续跑意愿过期(恢复待办时旧会话已被删走,既有「冷复活失败→回落新 spawn」路径承接,零新逻辑)~/.dsh/sessions/<bucket>/<id>/(fs.rm recursive)+ projcache 缓存 ~/.dsh/storages/session_projcache/sessions/<id>.json;路径逃逸双闸防护:① 会话 id 白名单 [A-Za-z0-9_-](含 ../、/、\ 一律拒)② rm 前再验目标绝对路径仍在 sessions/projcache 桶内(path.relative 判定)。注册表索引残留:~/.dsh/storages/session_projcache.json(宿主托管的 version/seq 结构)不清理——只是元数据索引,残留条目不占会话日志体积,宿主自会 GC;每次清理写 board.cleanupLog 留痕(时间/操作者/删除数/释放字节/会话 id 清单,上限 50 条)note_search / note_manage)完全由主窗口 agent 自己决定lesson-candidate 消息(场景 / 错误做法 / 来源);② 主窗口裁决 Worker 歧义 → 一条 lesson-candidate 消息(场景 / 疑问 / 裁决结论)。同一事件按「同时间戳 / 同内容前缀」轻量判重只落一条,且不写 history 流转记录(不刷屏)push-lesson RPC followup 给主窗口 agent(提示语写明「请用你可用的笔记/记忆工具沉淀,或评估后忽略」),推送成功后按钮变「✅ 已推送」置灰contextNotes)feedbackEnabled(⚙️ 设置区「学习反馈」,默认开):关掉后不生成候选、prompt 不提软召回、详情页候选卡片与「沉淀」按钮整个不渲染;老看板文件没有该字段 → 读路径自动补 true(与升级前行为一致)dsh-agent-board 与笔记类插件(如 dsh-notes-plugin)之间没有任何依赖、服务调用或文件直写——看板只发一条 followup 文本,怎么用由主窗口 agent 决定draft → pending → in-progress → verifying → resolved → archived
↓ ↑
blocked ←────── reject
dependsOn 声明依赖(DFS 环检测),依赖全部完成后才会被派发,串行链路自动编排full(执行+验证)/ work(只做不验)/ direct(不进池,主窗口直接处理),创建时按规则自动分类、可手动覆盖acceptance 字段写验收脚本命令,Worker 必须实际运行、Verifier 必须独立复跑git checkout / git restore / git reset --hard / git clean 等——会冲掉并行 Worker 与你自己的未提交在途编辑);只改自己写的文件、别人改了别的文件与你无关,确实需要干净基线时走歧义上报(board_report kind=escalate)由主窗口裁决;提交只允许精确路径 git add(本卡 touches 声明的文件,或逐一列出明确改过的文件路径),禁止 git add -A / git add . / git add 目录——并行 Worker 共享暂存区,宽泛 add 会把别卡在途编辑卷进 commit(实证 n-mv6xntg1p6i5:三起暂存吞并)write 写入全量(单次超长输出会撞模型输出上限、上下文耗尽零产出),先 write 落主体骨架、再用 edit 追加续块(每块 ≤4KB)逐块落地git status 看工作区有无未提交半成品,能续作就续作,别盲目从零」——重发/重派场景的旧产物先盘点再决定touches 声明本任务要改的文件/glob(如 ["src/**", "README.md"]);持有文件锁的任务(in-progress/verifying)与候选 touches 重叠就跳过本轮(卡片显示 🔒 等文件释放,详情页列出在等谁),锁随工作态:状态流转到已完成(resolved)即放锁,cancelled/归档同样不再持锁(归档回归纯收纳动作、不再是释放点)——锁只护「正在写」的阶段,「验收后-提交前」的窗口期由主窗口「回执到即提交」纪律 + 史诗 post-hook 承接,不用长持锁把整批串行化。避免并行 Worker 改同一批文件互踩;手动「派发」遇到冲突会列出冲突任务,确认后才以 force 越权派发board_report(kind: "progress",question 写一行进展摘要 ≤200 字符)上报——进行中的卡片显示「📈 最近进展 · 相对时间」(覆盖式只留最新一条),详情页消息流保留全部 progress 条目history 流转记录,避免刷屏archive-task 对「无活跃 run 的 in-progress」——典型如被 parentKick 推进后子任务已全部归档的史诗——直接放行,有活跃 run 的仍拒);归档子任务仍计入史诗进度并在详情留档可见——进度分子口径 settled = resolved | cancelled | archived、分母也含归档,归档一张子卡不会再让史诗进度从 0/10 退化成 0/9(进度只增不减),全归档的父卡也照常显示徽章;详情子任务清单不排归档行(灰化 + 行尾「已归档」徽章 + 沉底排序,点击仍可进子卡看留档)create-task 拒绝不完整 sessionId(防裸短 id 建出幻影板)get-tasks 响应附 tasksHash;客户端轮询带上轮 hash 作 ifHash,host 比对一致时返回 {unchanged:true} 轻量响应(不含 tasks 全量——轮询载荷从 1.34MB 级降到 KB 级,usage/healthHints/池状态等轻量聚合照常返回),前端保留 state.tasks 不动并跳过重渲染;hash 不一致 / 不带 ifHash / includeArchived 一律全量返回(老客户端零回归)isRoot 判定改读持久 parentSession(根会话=无父)——休眠根会话(有板有卡但无活 agent)也算 root,入口不再分钟级消失;子代理会话(parentSession 指向父)恒不显示入口。客户端防抖仍保留兜底:已确认 root 的会话需连续 3 次(≈9s)false 才收起抽屉(会话生命周期内「曾确认 true」粘滞),看板不再在生成状态切换时突然消失;从未确认 root 的子代理会话仍即时隐藏入口,保护语义不变
settled = resolved | cancelled | archived,total 同口径含归档;有在跑子任务时附「▸ 在跑:标题」行);子卡标题下显示「↳ 父任务标题」;依赖未满足的待办卡底部灰字「⛓ 等待「依赖标题」」(childStats 由 host 现算,缺字段一律不渲染)epic.hooks = { pre: { enabled, prompt, state, runId }, post: 同构 }——前置让子任务具备开跑条件(串行闸门:未完成前该史诗的子任务一张都不派),后置把这批活收口(全部子任务了结后跑一遍,完成后史诗才转验证中);prompt 只给薄框架契约,具体动作由 hook agent 自行决策,吃不准就走歧义上报(失败即转阻塞等人裁决:重试/跳过/放弃,不自动重跑)。hook run 记在 epic.runs[](role hook-pre/hook-post),卡片带相位徽章(⏳ 前置准备中 / 🧪 收尾中 / ⚠️ hook 失败待裁决,无 hooks 的老卡零渲染),详情页 hooks 区可编辑 enabled+prompt、查看 state/耗时并跳转 run 会话、失败一键跳裁决区;hooks 仅主窗口可设(工具与 RPC 双通道门禁),commit/push 不入任何默认形态delete-task RPC(卡片 hover 垃圾桶按钮 / 详情页「删除」按钮,均先 confirm('删除不可恢复,确认删除「标题」?'))+ batch-op op='delete'(多选模式底部「批量删除」,同样 confirm)。状态门禁:草稿/待办/阻塞可删;进行中/验证中拒绝并提示先用 terminate-agent 终止(避免在跑的 run 变孤儿);已完成/取消引导改用归档(archive-task,留档可检索);有未归档子任务时拒删(防 parentId 悬空破坏父任务自动流转);已归档任务幂等返回 ok。是真删(从 tasks 数组移除),因此不产生 batch-undo 撤销快照(批量条对 delete 不显示「↩️ 撤销」),删除操作在 host 端 console.error 留一行日志便于溯源pipeline: direct,不进池派发),再挂若干 10~30 分钟的子任务(task_create 传 parentId=父卡 id,有先后顺序用 dependsOn 串联),子任务全部完成后父卡自动流转(checkParentAuto)——task_create 工具描述与 Team 模式提示词都写了这条契约;容器卡结构性不派发:凡有子任务的卡(epic)永不进派发候选(与 pipeline 字段无关,不再只靠 direct 口头约定——手滑建 full 档 epic 也不会被派出占 worker 槽),子任务全了结转 verifying 后派 Verifier 验收不受影响task_create / create-task 发现描述超 500 字符、或标题/描述命中「全量 / 整体 / 系统级 / 全面 / 重构 / 所有模块 / 整个」等史诗特征词时,返回体附带一行 suggestSplit 建议文案(只提示,不阻断创建与派发;未命中则不出现该字段,老调用方无感)epicSplit(史诗拆分总开关)(⚙️ 入池配置弹层「功能」小节,默认开):关掉只停引导——Team 提示词第 6 条拆分条款整条不注入、create-task/task_create 响应不再附 suggestSplit 软提示;机制不禁(显式传 parentId 建子卡、史诗自动收口与 hooks 状态机照常工作,明确要拆时不受阻);老看板文件没有该字段 → 读路径自动补 true(与升级前行为一致)。工具描述里的粒度契约是静态工具定义(随 request header 快照),不在开关范围set-board-config 对 workerModel/verifierModel 的非空值校验当前网关可用清单(list-models 同款枚举)——手写非法 id(如把熔断通知里的显示名抄成 id)直接拒写并返回合法清单前 8 个,验收 spawn 不再 UNKNOWN_MODEL 秒死;空串=清除放行;宿主无 llm 服务时降级跳过校验不炸。配套熔断通知分态:UNKNOWN_MODEL 类失败报「配置非法(不在可用清单)」,与「验收连续失败」区分——mistake 归 mistake,quality 归 quality路径:L起-L止 — 一句用途」);文件内容本体不进 prompt,由子代理用 read 工具按行号范围按需自取(执行时盘面更新鲜;旧形态「host 读盘取正文注入」既受单文件 8KB/总包 40KB 截断,又随 runtime 快照每轮刷新重发——自治 run 实测 6×48.8K 字符≈白烧 75–100K token);UI 侧调研门禁——full/work 且声明了 touches 却未附调研的卡片亮「⚠️ 无调研」徽章,详情页「调研注入」区列 files 清单 + notes 字数(无则明示)
contextFiles 条目写法「path:L2350-L2420 / path:L2350」+ 可选「 — 一句用途」(em dash 两侧空格分隔;缺省只给路径行号)——锚点只认尾部 :L<行号>(兼容 Windows 盘符),清单里原样带上行号供子代理直接按行段 read;锚点写错(:L0 / :L5-L2)自动剥掉,不误导子代理去读空段read(path, offset, limit) 取需要的那段,清单里给出的行号就是起点;task_preview_context / preview-context 返回的也是这份瘦身清单(不是文件正文)task_create/create-task 响应附 warning 字段——①描述为空「Worker 只能凭标题猜需求」②full/work + touches 非空而未附调研上下文 ③touches 含整树 glob 建议精确到文件级(可多条合并);GUI 表单内黄色展示不关窗。epic 发布(publish)时自动轻量预检全部子任务注入情况,缺材料则 pushSysNote 汇总提醒主窗口(全有不打扰);派发时清单组装失败落任务「最近失败」行,不再静默。另存 lintWarnings[] 起草 lint(四规则:touches 整树 glob「粒度过粗,几乎锁整仓」/ 相对路径双仓库歧义「建议加仓库前缀」/ full 无验收「建议带验收命令」/ 标题缺动词或描述空),落卡透出、详情页 ⚠️ 行展示,不阻断创建board_verdict 工具 / Verifier 文本结算 / 手动 task_verify·verify-task)统一往 t.messages 落一条 kind: "rejection" 完整驳回包(summary + checks 逐条核对证据;手动路径补写 t.verification),经 buildMessages 全量注入重派 Worker prompt——新 Worker 据此返工,不再只看到 300 字截断的 history 记录gist(一句人话说改了什么)/ steps[](用户操作步骤,每条一步)/ expect(预期看到什么)/ tier(ui=界面可操作 | metric=看指标变化 | internal=纯内部无用户可感知面;internal 时 steps 可空、expect 写「验证靠测试套件」);诚实护栏写死在 prompt:只给亲自验过/从 diff 可推导的步骤,不许编没验过的操作,UI 特性给具体路径(哪个区哪个按钮),host-only 改动如实标 internal。双模落账 t.verification.userTest(工具通道 board_verdict 的 userTest 参数 / 文本通道收「## 自测指南」段;tier 非法/缺省一律归 internal 保守档,缺段/字段全空不挂字段);详情页验证记录区渲染「📋 自测指南」块(gist + 编号步骤 + 预期 + tier 徽章:ui 绿 / metric 蓝 / internal 灰),报告导出聚合「## 本版自测清单」段(按验收通过时间倒序近 10 张已验收卡,internal 收末尾并标注「无用户可感知面」)verifyUserGuide(⚙️ 设置区「验收」小节——「通知」旁,默认开):关掉后 Verifier prompt 不拼指南段(省 token)、验收落账不挂 userTest、详情页自测指南块与报告清单段整块不渲染;老看板文件没有该字段 → 读路径自动补 true(与升级前行为一致)persona(宿主 scoped persona-prefix 影子段)——独立判断不轻信 Worker 汇报、以验收脚本实证为准、诚实分级、结论写给主窗口与用户双读者;prompt 内写死文件纪律(可写临时/测试文件,工程代码与文档只读,验收结束清理,事后 touches 审计兜底);toolFilter 保守收窄只砍联网检索(web_fetch/web_search),spawn 失败自动剥外挂参数裸请求重试(Worker spawn 路径不受影响)一句话:Worker 从「一次性 run」变成持久子会话——超时不再丢现场,重派时原会话冷复活接着干;Verifier 与 hook run 仍是一次性。
subagents.startContinuable(rec 持 childId),turn 结束改由 host 事件 agent/status 的 running→idle 观测(一次性路径本就用 run.result 结算,未受影响);claimedBy / t.runs[].id / 详情页会话跳转的 id 语义不变(仍是子会话 id)interrupt 失败(会话已死/无权限)绝不阻断结算:任务照常回待办,只给该 run 落 noResume 标记(重派直接起新 Worker,不空唤醒)subagents.sendMessage(活父 Agent, childId, 断点续跑指令)——子会话带着上一轮全部上下文复活,先盘点工作树再从断点继续;t.runs[] 追加一条 resume: true 记录(详情页历史会话按钮带 ↻ 标记),续跑同样计入三连败计数;续跑不可用(NOT_RESUMABLE 等)→ 回落全新 Worker,并把原因写进任务消息随首条 prompt 注入listChildren(root):仍在列 → 重建 rec 观测(监听器本就在)并重挂两级超时臂、基线取当前日志字节数;不在列 → 视为会话已死,走硬超时等价物(回待办重排 + 留一行流转记录),不占 Worker 并发位seq 记水位线(落在 t.runs[].usageSeq):每次结算只累加水位线之后的 assistant/message 增量,本轮没新增量就一行都不记;one-shot 路径(每 run 独立日志)行为逐字不变workerContinuable(默认开):关掉即逐字回退旧的一次性路径(零 startContinuable/零 sendMessage/零 interrupt,结算仍走 run.result+dispose);Verifier 与 hooks(hook-pre/hook-post)保持一次性,不受该开关影响agent/status 的 running→idle,身份取 agent.session.id)与上报通道(board_report 落定即收尾)两条入口,任一到达即关账(结局/usage/超时臂三件套,幂等);派发周期自带幽灵活跃表项 GC(卡面证据核对回收残留 rec,防残留把派发容量顶到 0 拖死全池)+ 整轮 try/catch 与逐卡隔离(单点异常只作废该卡该轮)+ 去抖 latch 时间戳兜底复位task_intervene 对 continuable rec 走宿主投递通道(保留插件 source,下一个 step 边界消费),会话不可用降级 sendMessage 冷复活投递,再不行回退「记录注入随重派送达」并在 history 注明看板上一个选择器切换三档工作模式(RPC 单入口 set-work-mode,mode = list / auto / team):
| 档位 | 内部映射 | 行为 | 适合场景 |
|---|---|---|---|
| 📋 清单模式 | boardMode=manual + teamMode=false | 看板当 TODO 列表:任务建了就是 pending 躺着,主窗口自己 claim 办理,或逐张在详情页点「派发」才起 Worker | 需求还在拆、想自己盯着逐条推进;或只想借看板记账 |
| ⚡ 自动派发 | boardMode=auto + teamMode=false | 即建即派:pending 任务在心跳周期内自动派给一级 Worker,主窗口也可以自己 claim 干活 | 任务描述已经写清楚、依赖也理顺,交给 Worker 跑 |
| 🤖 Team 托管 | boardMode=auto + teamMode=true | 主窗口当调度员:task_create 缺省建草稿(补完 dependsOn/上下文再 publish 统一发布),Worker 歧义上报主窗口裁决 | 多任务编排、长链路、需要人工把关键决策点 |
三档通用(不是某一档专属):
acceptance 硬性验收脚本命令,Worker 必须实际运行、Verifier 必须独立复跑;跨档一致touches 文件级排他锁在活动任务间生效,冲突任务跳过本轮派发,锁随工作态(in-progress/verifying 持有;状态流转到 resolved 即释放,cancelled/归档同样释放——归档不再承担解锁职责);跨档一致task_create/create-task 与更新入口现算四规则软警告(touches 整树 glob「粒度过粗,几乎锁整仓」/ 相对路径双仓库歧义「建议加仓库前缀」/ full 无验收「建议带验收命令」/ 标题缺动词或描述空),存 lintWarnings[] 落卡透出、详情页 ⚠️ 行展示,不阻断;跨档一致Team 托管档独有(调度员体验):
task_create / create-task 缺省建为草稿(草稿不派发),先把所有任务的 dependsOn、contextNotes/contextFiles 补齐,再逐个 task_update publish=true 统一发布;确实要立即派发的单个任务才显式传 draft:falsenotifyDispatch(⚡ 派发回执:任务被 Worker/Verifier 领走时播报)与 notifyDone(✅ 完成回执:完成/阻塞时聚合播报),缺省均开(老看板文件缺字段自动补 true);歧义裁决通知不受开关影响(裁决通道不是回执,任务等人裁决必须提醒)兼容:旧的
set-board-mode/set-team-mode两个 RPC 原样保留(旧客户端与脚本不受影响), 内部仍以boardMode+teamMode两个字段落盘,老看板文件无损;get-tasks额外返回派生字段workMode供 UI 单点读取。
| 类别 | 工具 |
|---|---|
| 任务管理 | task_create / task_list / task_context / task_update / task_claim / task_resolve / task_verify / task_archive / task_cancel |
| 池治理 | task_terminate / task_intervene / task_arbitrate |
| 子代理上报 | board_report / board_verdict |
管理工具仅主窗口可用(子代理调用会被拒绝);
board_report/board_verdict是子代理的专用上报通道。board_report的kind三档:complete(交付完成)/escalate(歧义上报等裁决)/progress(里程碑进展,静默可见、不通知)。
└── packages/dsh-agent-board/ # 插件全部源码
│ ├── index.mjs # host 端薄壳(~70 行):cordis 契约 + 共享 state 构建 + 模块接线
│ ├── lib/core.mjs # 纯逻辑核心:状态机/依赖/分类/prompt/解析(无 IO,可单测)
│ ├── lib/*.mjs # host 端领域模块(按任务边界拆分,见下节)
│ ├── lib/client/ # client 端模块源(按用户感知域拆分,见下节)
│ ├── lib/client.js # client 端产物(⚠️ GENERATED:scripts/build-client.cjs 拼装,勿直接编辑)
│ ├── scripts/build-client.cjs # 零依赖组装器(模块源 → 产物;--check 校验产物新鲜度)
│ ├── test/ # 无头集成套件(node --test;*.test.mjs 为测试本体,
│ │ └── helpers/mock-ctx.mjs # helpers/ 是假宿主基建,不被当测试跑)
│ ├── package.json # dsh.bundle.patch + dsh.client 元数据
│ └── cordis.patch.yml # bundle 挂载行
└── docs/
├── PRD.md # 产品需求文档
├── PACKAGING.md # 打包/安装踩坑记录(link 依赖、单例隔离等)
├── icon-style-guide.md # 图标风格指南(Lucide 线性 SVG + emoji 分界)
└── REGRESSION-v59.md # 端到端回归测试记录
v1.6.0 起 host 端从单体 index.mjs(1487 行)拆为薄壳 + 7 个领域模块,
共享闭包状态收进显式 state 对象逐模块注入——模块边界即任务边界,并行任务不再全员互锁:
| 模块 | 域 | 内容 |
|---|---|---|
policy.mjs | 策略层 | 粒度治理软闸门 + 学习飞轮候选教训(纯函数零状态) |
usage.mjs | 统计 | v4 会话日志定位 / zstd 分帧 / token usage 聚合(纯函数;有效消耗 effectiveTokens + byModelEff 模型有效分摊 + byDay 双指标 {t,e} 聚合,兼容老 number 日账;统计范围按任务级 t.runs[].at 逐 run 裁切;sinceSeq 水位线增量结算——同一持久子会话多次结算不重复计账;readMainWindowUsage 主窗口会话增量尾读聚合——文件偏移水位缓存,追加只读增量、截断全量重读、尾部半帧不结算) |
session.mjs | 会话 | root 解析缓存 / 会话 id 归一 / workMode 派生 / runsFor |
store.mjs | 持久化 | boardPath / rt / wt 原子落盘 / 跨重启继承 / fileLocks 串行化 / mutateLocked |
notify.mjs | 通知 | makeMsg / 歧义 25s 去抖 / 回执聚合 + 空闲门控 / 投递前过滤 |
dispatch.mjs | 派发引擎 | poolCycle / spawnOneShot / settleRun / 两级超时 / 孤儿回收 / 可续跑 Worker(continuable + 重启 reconcile + usage 水位线) |
rpc.mjs | 接口层 | RPC 路由 + 13 个 Agent 工具注册 |
(store→dispatch 的循环依赖由 deps.poolCycle 晚绑定解开;index.mjs 对外 re-export 契约不变。)
dsh web 的 client 运行时不具备模块解析能力(entry 被整体读成字符串经 new Function 求值,
相对 import 是语法错误),所以前端模块化走构建时拼装:模块源在 lib/client/,
npm run build-client(pretest/prepublishOnly 已挂链)拼装成单文件产物 lib/client.js。
四个模块按用户感知域划分——边界即未来任务边界,新功能先想清楚落在哪个域:
| 模块 | 域 | 内容 |
|---|---|---|
kernel.js | 底座(用户不可感知) | 渲染原语(ic/icText/ActorLink)、RPC 封装与轮询族、共享状态(state/listeners/notify)、图标(ICONS)、共享任务工具,以及面板骨架入口(BoardButton/ViewTab/TopPanel/slots.inject) |
board-list.js | 看板列表 | 看板列与卡片(Card)、筛选条、多选批量操作条、建卡表单、归档列表 |
task-detail.js | 任务详情 | 详情抽屉(编辑/流转/冻结/touches/历史会话/高优介入)、歧义裁决对话与候选教训沉淀、依赖区块 |
dashboard.js | 仪表盘与设置 | 统计图表、Token 消耗、模型表现(八指标×场景筛选)、质量趋势(通过率/时长分布/超时/续跑)、全局总览、报告生成、团队池视图、池/模型/超时设置与工作模式开关 |
四个模块拼进同一个 apply(ctx) 函数作用域(var/function 声明提升使跨模块引用与拼接顺序无关;
所有同步执行代码——DOM 监听、轮询注册、布局同步、slots.inject——都在 kernel 域内保持原相对顺序)。
改模块源后必须重新组装(npm run build-client)产物才更新;直接编辑 lib/client.js 会在下次拼装时被覆盖。
v68 起拆除了"动态源码 → 静态包"的转换层(build-pkg.cjs):插件已稳定, 双形态维护的复杂度大于收益,包内文件即唯一源码,改完重启 dsh 即生效。
v74 起去池化(一次性派发)+ 纯逻辑抽到
lib/core.mjs,在包目录跑npm test(node --test,无头集成全套件)即可验证状态机/依赖/派发决策, 不用重启 dsh 人肉回归——跑法与口径详见 docs/DEVTESTING.md。
cd packages/dsh-agent-board && npm test——pretest 自动先拼装前端产物
(build-client),再跑 node --test test/**/*.test.mjs:纯逻辑单测 + 无头宿主集成全套件
(当前 355 例,~6s),无需 dsh 环境。test/helpers/mock-ctx.mjs 是无头基建(假 cordis ctx / 临时 HOME / 虚拟时钟 /
剧本化 subagents),不是测试;靠 *.test.mjs 文件名约定排除,不会被误跑。.github/workflows/test.yml 在 push/PR 时跑语法检查 + npm test,
套件随脚本自动生效;prepublishOnly 门禁同款。index.mjs / lib/*.mjs)不可热重载(宿主模块表按 URL 缓存),
改了必须重启 dsh;管理接口 disable→enable 只能重组组合层(路由/工具卸下再挂上),拉不到新代码。
实测证据与探针脚本(scripts/reload-probe.cjs)见 docs/DEVTESTING.md。tag 驱动,GitHub Actions 自动发布到 npm(.github/workflows/publish.yml)。两种打 tag 方式都支持:
方式 1:命令行
cd packages/dsh-agent-board
npm version patch # 或 minor / major——改 package.json
git add -A && git commit -m 'release: vX.Y.Z' && git tag vX.Y.Z
git push --follow-tags # tag 推送触发流水线
方式 2:GitHub 网页(Releases 页)
packages/dsh-agent-board/package.json 的 version 改成目标版本并合入 main(网页直接编辑即可)vX.Y.Z 选 Create new tag(target 选 main)package.json version(如 tag v1.0.1 但包里是 1.0.0),防止版本错位packages/dsh-agent-board 跑一次 npm run sync-readme 同步进包(npm 页面展示的是包内 README)NPM_TOKEN
(npm granular access token:bypass 2FA + direct publish)test.yml 跑语法检查 + 无头集成全套件(npm test)npm publish --registry=https://registry.npmjs.org(本机默认源是镜像时必须显式指定)MIT
FAQs
DeepSeek Harness 智能看板:任务卡片 + 一次性 Worker/Verifier 派发 + 依赖调度 + 管线分档 + Team 模式(歧义上报主窗口裁决)
We found that dsh-agent-board demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
Cloudflare is acquiring Deno’s team, which will provide another year of bug fixes and security updates before ending support for the runtime.

Security News
Anthropic’s free OSS Scanner uses Mythos and other Claude models to find open source vulnerabilities and send maintainers reports with proposed fixes.

Security News
On Front Lines’ Early Adopters: CISO podcast, Andrew Becherer shares lessons from Datadog, weighs the long-term costs of AI-built tools, and explains how founders can actually gain a CISO’s trust.