dsh-agent-board 1.7.3 → 1.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -102,15 +102,19 @@ dsh plugin --profile web remove dsh-agent-board
102
102
 
103
103
  ### 仪表盘(Token 消耗)
104
104
 
105
- - 仪表盘视图新增「Token 消耗」区:本看板累计**有效 / 缓存读 / 合计**三分量 + 输入 / 输出(缓存写非零时一并展示)拆分、按模型分布条形图、任务消耗 **Top 8**(标题可点击直达该任务详情,title 附「有效 N / 缓存读 M」拆分);大数字为**今日有效消耗**(本地日口径,无日账则显示 0,旁附「含缓存读共 X」小字对照,有效值不可知时以总量近似并标 `~`)、旁附「累计(本看板)」三分量小字,下方「近 7 天」迷你条形按日展示近 7 天**有效消耗**(今天高亮,title 补总量对照,7 天全为 0 时不渲染);进行中的卡片右上角显示本任务已累计消耗(`⛁ 数字`);区底固定一行口径 caption:**仅看板派发的 Worker/Verifier run 消耗,不含主窗口对话**
106
- - 口径要点:**有效消耗 = 输入 + 输出 + 缓存写(不含缓存读)**。实证本板累计 10.3M 里缓存读占 9.7M(94%)、有效消耗仅 605K——总量被缓存读撑高约 17 倍,因此大数字与「近 7 天」一律用有效值,缓存读单列可查(差额一眼可见),避免「仪表盘与真实消耗差太多」
107
- - **主数字口径统一**(`task-muwq9u04`):**按模型分布行与任务消耗 Top 8 行的主数字一律为有效消耗**(含缓存读的合计进悬浮 title),与「今日」「近 7 天」同口径——不再出现「今日有效 3.7M / 单任务 21M」这类同区并排的矛盾数字(模型有效分摊由 host 的 `byModelEff` 给出;老 host 缺该字段或老卡无五分量留账时,主数字退化用合计并在 title 标 `~`)
108
- - **统计范围接通 Token 区**(`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(选范围即渲染,不等下一次任意刷新)
105
+ - 仪表盘视图新增「Token 消耗」区:本看板累计**有效 / 缓存读 / 合计**三分量 + 输入 / 输出(缓存写非零时一并展示)拆分、按模型分布条形图、任务消耗 **Top 8**(标题可点击直达该任务详情,title 附「有效 N / 缓存读 M」拆分);大数字为**今日总量**(含缓存读,本地日口径,无日账则显示 0,旁附「其中有效 X」小字对照,有效消耗详见悬浮 title)、旁附「累计(本看板)」三分量小字,下方「近 7 天」迷你条形按日展示近 7 天**总量**(今天高亮,title 补有效对照,7 天全为 0 时不渲染);进行中的卡片右上角显示本任务已累计消耗(`⛁ 数字`);区底固定口径 caption:累计 / Top 8 仅看板派发的 run 消耗,主窗口行并列不混入
106
+ - 口径要点:**有效消耗 = 输入 + 输出 + 缓存写(不含缓存读)**;总量 = 有效 + 缓存读。**主显口径翻转(`task-muxnqunk`,用户 2026-10-07 裁决「算总的吧」,推翻 `task-muwq9u04` 的有效主显)**:Token 区**主数字均为总量口径(含缓存读)**——今日大数字 / 近 7 天柱 / 按模型分布 / Top 8 / 主窗口行一律显总量,有效消耗退居悬浮 title 或次要小字;旧口径日(`e=null`)的「今日显 — / 矮灰柱」防护顺势退役(总量恒有值,正常画柱,悬浮注明有效不可知)。**不动的**:「模型表现」「质量趋势」区保持有效口径(效率指标语义),报告导出分列口径不动。实证背景:本板累计 10.3M 里缓存读占 9.7M(94%)——总量与有效的差额一眼可在累计三分量与悬浮里对照
107
+ - **主数字口径统一**(`task-muxnqunk` 翻转版,替代 `task-muwq9u04`):**按模型分布行与任务消耗 Top 8 行的主数字一律为总量**(含缓存读;模型取 host 的 `byModel`,任务取 `topTasks[].total`),有效消耗(`byModelEff` 模型有效分摊 / `topTasks[].effective`)进悬浮 title——与「今日」「近 7 天」同口径;老 host 缺 `byModelEff` 或老卡无五分量留账时 title 标「有效不可知」(口径不伪造)
108
+ - **统计范围接通 Token 区**(`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 注明
109
109
  - 数据来源:每次 Worker/Verifier run 结算时读该 run 的 v4 会话日志(`~/.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 精确重建,口径若要再调整不必回头猜
110
- - `byDay` 为**双指标**形态 `{ t, e }`(`t` = 总量含缓存读,`e` = 有效消耗不含缓存读;一次 run 不跨日拆分)。聚合端兼容老数据:值是裸 number 的历史日账按 `{ t: n, e: null }` 处理——总量照常保留(「近 7 天」不会整段消失),有效值不可知就置 `null` 并由 UI 标 `~` 近似,**绝不把总量冒充有效值**
111
- - `get-tasks` 再现算 board 级 `usageSummary`(总量 / 有效合计 / 按模型(合计 `byModel` + 有效分摊 `byModelEff`,两者同源累加)/ Top8(带有效与缓存读拆分)/ 日账 `byDay`,不落盘额外表;老任务无 `byDay` 时整笔近似归到 `updatedAt` 的本地日,无 `updatedAt` 则不计入任何日)——**只做展示、不做计费断言**,日志读不到或没有 usage 时一律显示「暂无数据」;第二参 `range`(可选 `{ from, to }` 本地日)给定即只聚合该范围内的 run(口径见上条)
112
- - 统计口径边界:本区只统计**看板派发的 Worker/Verifier run**,**不含主窗口对话本身**(不越界统计,UI caption 已明示)
113
- - 「架构健康」区(架构自省 L1):`get-tasks` 顺带对**近 50 张卡**现算四信号(纯函数零存储:touches 声明热度 ≥8 次且占比 ≥40% / 带 touches 任务滞留中位数 >2 倍 / 任务**执行**时长 p90 >45min(claimedAt→resolvedAt 纯干活口径,不含排队)/ 同路径驳回 ≥2 次),命中才在仪表盘渲染提示条(⚠️/ℹ️ 两级,最多 3 条)——让运行数据主动提示"该优化架构了"(如某文件反复成为锁热点=该拆),信号只建议不裁判
110
+ - `byDay` 为**双指标**形态 `{ t, e }`(`t` = 总量含缓存读,`e` = 有效消耗不含缓存读;一次 run 不跨日拆分)。聚合端兼容老数据:值是裸 number 的历史日账按 `{ t: n, e: null }` 处理——总量照常保留(「近 7 天」不会整段消失),有效值不可知就置 `null`;**口径翻转后(`task-muxnqunk`)旧口径日按总量正常展示**(今日大数字显总量、近 7 天按总量画柱),有效不可知只在悬浮 title 注明——`task-muwsnyqv` 的「显 — / 矮灰柱」防护已随总量主显退役
111
+ - `get-tasks` 再现算 board 级 `usageSummary`(总量 / 有效合计 / 按模型(合计 `byModel` + 有效分摊 `byModelEff`,两者同源累加)/ Top8(带有效与缓存读拆分)/ 日账双份(范围内 `byDay` + 未过滤全量 `byDayFull`,后者供「今日」「近 7 天」固定口径读取),不落盘额外表;老任务无 `byDay` 时整笔近似归到 `updatedAt` 的本地日,无 `updatedAt` 则不计入任何日)——**只做展示、不做计费断言**,日志读不到或没有 usage 时一律显示「暂无数据」;第二参 `range`(可选 `{ from, to }` 本地日)给定即只聚合该范围内的 run(口径见上条)
112
+ - **主窗口(本会话对话)消耗单列**(`task-muwsol23`):累计行下方新增一行「**主窗口(本会话):今日 X · 累计 Y**」(**总量口径含缓存读**——`task-muxnqunk` 翻转后缓存读不再单列、已含在 total 里,有效值见悬浮 title),按模型分布尾部追加一条「**主窗口(对话)**」(琥珀色与 run 模型区分,总量为 0 不渲染,固定尾部不参与排序);数据源是该看板所属主会话自己的 v4 日志,host 侧**增量尾读**聚合(缓存键=会话 id:文件不变零读、变大只读新增字节段、变小/轮换全量重读一次,尾部半帧不结算下轮补读——3s 轮询稳态零全量重读),五分量与有效口径(e=输入+输出+缓存写)同 Worker 完全一致;**隔离红线:不进 Top 8、不进「本看板累计」、不进架构健康/学习飞轮基数**,只并列展示;随统计范围裁剪(按 `assistant/message` 事件的本地日落点);日志不存在/读取失败/无 usage 一律**静默降级**(不渲染该行,不炸轮询)
113
+ - 统计口径边界:本区累计 / Top 8 / 架构健康与学习飞轮基数只统计**看板派发的 Worker/Verifier run**,**不含主窗口对话**;主窗口对话消耗按上条单列一行 + 模型分布尾部一条并列展示(不越界混入,UI caption 已明示)
114
+ - **「模型表现」区**(记分卡卡3,`task-muxhtgi2`):Token 区下方新增**模型 × 场景七指标对比表**——每行一个 模型 × 角色(worker/verifier)× 规模段(小 <1M / 中 1~10M / 大 >10M,按任务有效 token 分桶)桶;七列口径一句话版:**有效均值** = 桶内 run 有效消耗(输入+输出+缓存写,不含缓存读)的均值、**耗时中位** = run 耗时(endedAt−at)中位数(P90 在行 title)、**驳回率** = 归因到本桶的验收驳回 / 桶内 runs、**一次通过率** = 桶内 resolved 任务中零驳回占比、**超时率** = 超时落定 run / 桶内 runs、**续跑率** = 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 区同一统计范围口径裁剪)
115
+ - **「质量趋势」区**(记分卡卡4,`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 写明);整区/单块空态均灰显不炸
116
+ - **「驳回聚类」区**(记分卡卡5,`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」;无足够数据/无对比对象不亮
117
+ - 「架构健康」区(架构自省 L1):`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 翻车与肉眼发现
114
118
  - 统计区耗时同口径拆分:「平均排队 / 平均执行」双行展示(平均验收单列不变)
115
119
  - 统计区新增「调研 ROI」对比行:resolved/archived 卡按有无调研注入分组现算卡数 / 平均执行时长 / 平均 token(双组总样本 ≥4 才渲染,无调研组明显更慢时数字 warn 色提示)
116
120
 
@@ -162,6 +166,8 @@ draft → pending → in-progress → verifying → resolved → archived
162
166
  - 看门狗:运行超时且事件流停滞 → 标记"疑似卡死"(不自动杀,裁决权交主窗口/用户)
163
167
  - 歧义上报:Worker 遇到歧义不猜测,上报等主窗口裁决(任何模式下都通知);裁决后新 Worker 携带裁决答案接手
164
168
  - 驳回详情全量带回:三条驳回路径(`board_verdict` 工具 / Verifier 文本结算 / 手动 `task_verify`·`verify-task`)统一往 `t.messages` 落一条 `kind: "rejection"` 完整驳回包(summary + checks 逐条核对证据;手动路径补写 `t.verification`),经 `buildMessages` 全量注入重派 Worker prompt——新 Worker 据此返工,不再只看到 300 字截断的 history 记录
169
+ - **Verifier 自测指南(userTest)**:Verifier prompt 末尾追加「## 自测指南」段契约——四字段 `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` 收末尾并标注「无用户可感知面」)
170
+ - **开关 `verifyUserGuide`**(⚙️ 设置区「验收」小节——「通知」旁,默认**开**):关掉后 Verifier prompt 不拼指南段(省 token)、验收落账不挂 `userTest`、详情页自测指南块与报告清单段整块不渲染;老看板文件没有该字段 → 读路径自动补 `true`(与升级前行为一致)
165
171
  - 手动派发:详情页「派发 / 派发验收」按钮可随时手动触发单任务派发(auto 模式补派、manual 模式主通道)
166
172
  - 会话隔离:看板按会话分桶,多会话互不干扰
167
173
 
@@ -227,7 +233,8 @@ Team 托管档独有(调度员体验):
227
233
  │ ├── lib/client/ # client 端模块源(按用户感知域拆分,见下节)
228
234
  │ ├── lib/client.js # client 端产物(⚠️ GENERATED:scripts/build-client.cjs 拼装,勿直接编辑)
229
235
  │ ├── scripts/build-client.cjs # 零依赖组装器(模块源 → 产物;--check 校验产物新鲜度)
230
- │ ├── test/core.test.mjs # 单元测试(node --test,84 例)
236
+ │ ├── test/ # 无头集成套件(node --test;*.test.mjs 为测试本体,
237
+ │ │ └── helpers/mock-ctx.mjs # helpers/ 是假宿主基建,不被当测试跑)
231
238
  │ ├── package.json # dsh.bundle.patch + dsh.client 元数据
232
239
  │ └── cordis.patch.yml # bundle 挂载行
233
240
  └── docs/
@@ -245,7 +252,7 @@ v1.6.0 起 host 端从单体 index.mjs(1487 行)拆为薄壳 + 7 个领域
245
252
  | 模块 | 域 | 内容 |
246
253
  |---|---|---|
247
254
  | `policy.mjs` | 策略层 | 粒度治理软闸门 + 学习飞轮候选教训(纯函数零状态) |
248
- | `usage.mjs` | 统计 | v4 会话日志定位 / zstd 分帧 / token usage 聚合(纯函数;有效消耗 `effectiveTokens` + `byModelEff` 模型有效分摊 + `byDay` 双指标 `{t,e}` 聚合,兼容老 number 日账;统计范围按任务级 `t.runs[].at` 逐 run 裁切;`sinceSeq` 水位线增量结算——同一持久子会话多次结算不重复计账) |
255
+ | `usage.mjs` | 统计 | v4 会话日志定位 / zstd 分帧 / token usage 聚合(纯函数;有效消耗 `effectiveTokens` + `byModelEff` 模型有效分摊 + `byDay` 双指标 `{t,e}` 聚合,兼容老 number 日账;统计范围按任务级 `t.runs[].at` 逐 run 裁切;`sinceSeq` 水位线增量结算——同一持久子会话多次结算不重复计账;`readMainWindowUsage` 主窗口会话**增量尾读**聚合——文件偏移水位缓存,追加只读增量、截断全量重读、尾部半帧不结算) |
249
256
  | `session.mjs` | 会话 | root 解析缓存 / 会话 id 归一 / workMode 派生 / runsFor |
250
257
  | `store.mjs` | 持久化 | boardPath / rt / wt 原子落盘 / 跨重启继承 / fileLocks 串行化 / mutateLocked |
251
258
  | `notify.mjs` | 通知 | makeMsg / 歧义 25s 去抖 / 回执聚合 + 空闲门控 / 投递前过滤 |
@@ -266,7 +273,7 @@ dsh web 的 client 运行时不具备模块解析能力(entry 被整体读成
266
273
  | `kernel.js` | 底座(用户不可感知) | 渲染原语(ic/icText/ActorLink)、RPC 封装与轮询族、共享状态(state/listeners/notify)、图标(ICONS)、共享任务工具,以及面板骨架入口(BoardButton/ViewTab/TopPanel/slots.inject) |
267
274
  | `board-list.js` | 看板列表 | 看板列与卡片(Card)、筛选条、多选批量操作条、建卡表单、归档列表 |
268
275
  | `task-detail.js` | 任务详情 | 详情抽屉(编辑/流转/冻结/touches/历史会话/高优介入)、歧义裁决对话与候选教训沉淀、依赖区块 |
269
- | `dashboard.js` | 仪表盘与设置 | 统计图表、Token 消耗、全局总览、报告生成、团队池视图、池/模型/超时设置与工作模式开关 |
276
+ | `dashboard.js` | 仪表盘与设置 | 统计图表、Token 消耗、模型表现(七指标×场景筛选)、质量趋势(通过率/时长分布/超时/续跑)、全局总览、报告生成、团队池视图、池/模型/超时设置与工作模式开关 |
270
277
 
271
278
  四个模块拼进同一个 `apply(ctx)` 函数作用域(`var`/`function` 声明提升使跨模块引用与拼接顺序无关;
272
279
  所有同步执行代码——DOM 监听、轮询注册、布局同步、slots.inject——都在 kernel 域内保持原相对顺序)。
@@ -275,9 +282,22 @@ dsh web 的 client 运行时不具备模块解析能力(entry 被整体读成
275
282
  > v68 起拆除了"动态源码 → 静态包"的转换层(build-pkg.cjs):插件已稳定,
276
283
  > 双形态维护的复杂度大于收益,包内文件即唯一源码,改完重启 dsh 即生效。
277
284
  >
278
- > v74 起去池化(一次性派发)+ 纯逻辑抽到 `lib/core.mjs`,跑
279
- > `node --test packages/dsh-agent-board/test/` 即可验证状态机/依赖/派发决策,
280
- > 不用重启 dsh 人肉回归。
285
+ > v74 起去池化(一次性派发)+ 纯逻辑抽到 `lib/core.mjs`,在包目录跑
286
+ > `npm test`(node --test,无头集成全套件)即可验证状态机/依赖/派发决策,
287
+ > 不用重启 dsh 人肉回归——跑法与口径详见 [docs/DEVTESTING.md](docs/DEVTESTING.md)。
288
+
289
+ ## 开发与测试
290
+
291
+ - **一条命令**:`cd packages/dsh-agent-board && npm test`——`pretest` 自动先拼装前端产物
292
+ (`build-client`),再跑 `node --test test/**/*.test.mjs`:纯逻辑单测 + 无头宿主集成全套件
293
+ (当前 355 例,~6s),无需 dsh 环境。
294
+ - **helpers 约定**:`test/helpers/mock-ctx.mjs` 是无头基建(假 cordis ctx / 临时 HOME / 虚拟时钟 /
295
+ 剧本化 subagents),不是测试;靠 `*.test.mjs` 文件名约定排除,不会被误跑。
296
+ - **CI 零改动继承**:`.github/workflows/test.yml` 在 push/PR 时跑语法检查 + `npm test`,
297
+ 套件随脚本自动生效;`prepublishOnly` 门禁同款。
298
+ - **插件改动生效口径**:host 端代码(`index.mjs` / `lib/*.mjs`)不可热重载(宿主模块表按 URL 缓存),
299
+ 改了必须重启 dsh;管理接口 disable→enable 只能重组组合层(路由/工具卸下再挂上),拉不到新代码。
300
+ 实测证据与探针脚本(`scripts/reload-probe.cjs`)见 [docs/DEVTESTING.md](docs/DEVTESTING.md)。
281
301
 
282
302
  ## 文档
283
303
 
@@ -285,6 +305,7 @@ dsh web 的 client 运行时不具备模块解析能力(entry 被整体读成
285
305
  - [docs/PACKAGING.md](docs/PACKAGING.md) — 正式安装(Bundle 打包)注意事项
286
306
  - [docs/icon-style-guide.md](docs/icon-style-guide.md) — 图标规范
287
307
  - [docs/REGRESSION-v59.md](docs/REGRESSION-v59.md) — 回归测试说明
308
+ - [docs/DEVTESTING.md](docs/DEVTESTING.md) — 开发与测试:无头套件跑法 / CI 继承 / 热重载口径
288
309
 
289
310
  ## 发布新版本(维护者)
290
311
 
@@ -309,7 +330,7 @@ git push --follow-tags # tag 推送触发流水线
309
330
  - **README 单一来源**:本文件(根 README)即唯一来源;发版前在 `packages/dsh-agent-board` 跑一次 `npm run sync-readme` 同步进包(npm 页面展示的是包内 README)
310
331
  - 需在仓库 **Settings → Secrets and variables → Actions** 配置 `NPM_TOKEN`
311
332
  (npm granular access token:bypass 2FA + direct publish)
312
- - 日常 push / PR 有 `test.yml` 跑语法检查 + 60 例单测
333
+ - 日常 push / PR 有 `test.yml` 跑语法检查 + 无头集成全套件(`npm test`)
313
334
  - 本地手动发布仍然可用:`npm publish --registry=https://registry.npmjs.org`(本机默认源是镜像时必须显式指定)
314
335
 
315
336
  ## License
package/index.mjs CHANGED
@@ -15,7 +15,7 @@
15
15
  //
16
16
  // 兼容 re-export:对外导出契约不变(单测与历史引用直接 import 自本文件)。
17
17
  export { TASK_SIZE_CONTRACT, SUGGEST_SPLIT_TEXT, TEAM_SPLIT_RULE, suggestSplitOf, withSplitHint, splitRuleOf } from './lib/policy.mjs'
18
- export { findRunLog, readRunUsage, aggregateUsageSummary, effectiveTokens, taskEffectiveTokens } from './lib/usage.mjs'
18
+ export { findRunLog, readRunUsage, aggregateUsageSummary, effectiveTokens, taskEffectiveTokens, readMainWindowUsage, sizeBucketOf, runRoleOf, auditRunEntry, auditRunsCompleteness, attributeRejection, buildScoreboard, SCOREBOARD_MIN_SAMPLE, SIZE_BUCKET_SMALL_MAX, SIZE_BUCKET_MEDIUM_MAX, clusterRejections, REJECTION_CLUSTER_RULES, modelPerfHint, MODEL_HINT_MIN_RUNS, MODEL_HINT_MIN_PASS, MODEL_HINT_EFF_GAP } from './lib/usage.mjs'
19
19
  import { createSession } from './lib/session.mjs'
20
20
  import { createStore } from './lib/store.mjs'
21
21
  import { createNotify } from './lib/notify.mjs'
@@ -45,6 +45,16 @@ export function apply(ctx) {
45
45
  receiptBuf: {}, // 回执 45s/满 5 条聚合窗口
46
46
  receiptedKeys: {}, // 回执幂等去重(完成事件指纹,1h TTL)
47
47
  sysNotesBuf: {}, // 系统级异常通知队列(随回执冲刷)
48
+ mainWindowUsageCache: {}, // 主窗口消耗增量尾读缓存(task-muwsol23):sid → { size, mtimeMs, 聚合五分量+byDay },
49
+ // 文件不变零读 / 变大只读增量 / 变小全量重读一次;纯内存不落盘,重启自然全量一次
50
+ scoreboardCache: {}, // 记分卡聚合缓存(task-muxhtgh9 卡2):sid → { taskCount, stamp, recs },
51
+ // runs 只增不改——键=(任务数, 最新落定时刻) 命中则提取层零重算,范围裁剪在装配层现算;
52
+ // 纯内存不落盘,重启自然全量一次(与 mainWindowUsageCache 同生命周期纪律)
53
+ poolHealth: {}, // 运行时健康自检(task-muxhrkbg)内存心跳:sid → { bornAt, poolLastOkAt, dispatchOk,
54
+ // lastDispatchAt, settleLastOkAt, reapNote }——dispatch.mjs 在 poolCycle 成功轮 /
55
+ // settleRunRecord 成功结算 / 幽灵回收 >0 / spawn 成功四处打点,rpc get-tasks 现算
56
+ // 运行时 hint(health.computeRuntimeHealthHints)。纯内存不落盘:重启后 bornAt 起算,
57
+ // 心跳阈值的宽限期随之重置(心跳的意义是「host 活着时在不在转」,跨重启无继承价值)
48
58
  }
49
59
  // ===== 模块接线(依赖顺序:session → store → notify → dispatch → rpc)=====
50
60
  var session = createSession(ctx, state)