🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

进度提醒条 Kiru-Sama/dsh-progress-bar

DeepSeek Harnessv2.0.0
Kiru-Sama6 天前有提交已提供中文文档扫描:未发现敏感能力

DeepSeek Harness 进度汇报提醒插件:累计每 N 步或每 N 秒提醒 Agent…

36.2/100
综合分
3
GitHub 星标
45
npm 周下载
—/5
用户评分

数据截至 2026/10/29 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-progress-bar
npm 源 · dsh-progress-bar 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · other
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 6 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-progress-bar @ 2.0.0
✓Node 引擎要求 ^22.19.0 || >=24.0.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/29 11:40:56

安全扫描自动 · 静态分析源码
v2.7.0
🟢 扫描:未发现敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。

扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
展开完整介绍(104 字)↓

DeepSeek Harness 进度汇报提醒插件:累计每 N 步或每 N 秒提醒 Agent 汇报一次进度,侧栏实时显示计数,聊天区横幅显示上次提醒时刻。附带余额低额提醒与 DeepSeek 峰谷时段指示。

v2.0.22026-10-28
桌面版一键安装版。 安装:DSH → 设置 → 插件 → 添加插件,粘贴 或下载本页的 tgz 后在「添加插件」里选择它。装完 文件 → 退出 再启动。 详见 INSTALL.md。 Full Changelog:
v2.0.12026-10-28
桌面版一键安装版。 安装:DSH → 设置 → 插件 → 添加插件,粘贴 或下载本页的 tgz 后在「添加插件」里选择它。装完 文件 → 退出 再启动。 详见 INSTALL.md。
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
dsh-progress-bar 让智能体在长回合里主动、简短地汇报进度的 DeepSeek Harness 插件。 安装 / 卸载 / 已知限制 → INSTALL.md。零依赖,不用装任何 npm 包。 除了进度提醒,它顺带做三件小事: - 余额监控 —— 读宿主自己的账户余额(不碰你的 API key),低于阈值就让智能体提醒你充值;充值余额与赠送余额分开显示,判定按两者之和(平台扣款先从赠金扣)。 - 峰谷时段 —— 侧栏常驻显示 DeepSeek 官方的高峰/低谷时段,「梁文峰」= 高峰(红色发光)、「梁文谷」= 低谷(绿色,半价)。 - 可见性 —— 每次提醒会在聊天区弹横幅,告诉你「上次提醒是什么时候」;越过阈值却还在等步骤边界时,也会明确写出来,而不是让你干等。 两个触发器,阈值都可调: | 触发器 | 默认 | 含义 | | 步数 | 10 步 | 自上次汇报起累计 N 次工具调用 | | 时间 | 120 秒 | 自上次汇报起累计经过的真实时间 | 任一命中就提醒一次,然后两个计量一起归零(共用量表,避免「第 10 步刚提醒完、 2 秒后时间阈值又到」的连击刷屏)。 提醒不是弹窗,而是通过 tools/post-execute 决策的 additionalContexts 注入一条合成 user 消息——唯一能让模型真正看见并照做的通道。
展开完整文档(README 剩余 1 节)
dsh-progress-bar

让智能体在长回合里主动、简短地汇报进度的 DeepSeek Harness 插件。

安装 / 卸载 / 已知限制 → INSTALL.md。零依赖,不用装任何 npm 包。

除了进度提醒,它顺带做三件小事:

- 余额监控 —— 读宿主自己的账户余额(不碰你的 API key),低于阈值就让智能体提醒你充值;充值余额与赠送余额分开显示,判定按两者之和(平台扣款先从赠金扣)。
- 峰谷时段 —— 侧栏常驻显示 DeepSeek 官方的高峰/低谷时段,「梁文峰」= 高峰(红色发光)、「梁文谷」= 低谷(绿色,半价)。
- 可见性 —— 每次提醒会在聊天区弹横幅,告诉你「上次提醒是什么时候」;越过阈值却还在等步骤边界时,也会明确写出来,而不是让你干等。

两个触发器,阈值都可调:

| 触发器 | 默认 | 含义 |
| 步数 | 10 步 | 自上次汇报起累计 N 次工具调用 |
| 时间 | 120 秒 | 自上次汇报起累计经过的真实时间 |

任一命中就提醒一次,然后两个计量一起归零(共用量表,避免「第 10 步刚提醒完、 2 秒后时间阈值又到」的连击刷屏)。

提醒不是弹窗,而是通过 tools/post-execute 决策的 additionalContexts 注入一条合成 user 消息——唯一能让模型真正看见并照做的通道。
消息带 source.kind = 'progress-nudge',所以不会被当成用户提示词污染历史。

计量规则

时钟按墙钟推进,running 决定它在不在走。停表只由两件事触发:暂停、回合结束。

| 情况 | 行为 |
| 暂停(面板上的暂停按钮) | 立刻冻结,秒数纹丝不动;干等多久都不涨。恢复后从冻结值继续,不补算暂停期间的时间 |
| 回合结束(agent/turn-stopping) | 归零并停表,面板回到 0 步 / 0 秒 |
| 新回合 / 新用户消息(agent/pre-step 的 turn 编号变化) | 归零并起表——用户刚发消息,接下来的思考时间要计 |
| 智能体主动对你输出文本(agent/assistant-stream 的 text-delta) | 归零并继续走表——「它刚跟人说过话了」,计量从这句话开始重算 |

只有真正对人说话才触发最后一条:思考是 reasoning-delta、执行是 tool-call-delta、空白文本,都不会重置(有测试钉住这三条)。
不需要的话把 resetOnSpeech 设成 false。

为什么要"继续走表"而不是"停表"

最初的实现是「只统计两次工具调用之间」,并且说话后直接 anchorAt = null 停表。
后果是:智能体说完一句话 → 停表 → 接着深度思考 3 分钟、期间一次工具都没调 → 界面上一直显示 0/10 · 0秒,看起来像坏了,这段时间的时间触发也永远打不到。

现在:说话只清零计量、时钟立刻从那一刻重新起表;思考时间照常累计,并在下一次工具调用时参与时间阈值判断。另外 /status 的 live 是读取时现算 的(不是缓存的快照),否则两次工具调用之间接口只会吐旧值——这是同一个 bug 的另一半。

界面

两处界面。

| 元素 | 内容 |
| 侧栏按钮 | 实时显示「第 N/阈值 步 · 已过秒数」;暂停时变色显示「已暂停」。时钟停摆时秒数不做本地插值 |
| 侧栏展开面板 | 两条进度条 + 步数/时间阈值输入框 + 暂停恢复 + 恢复默认 + 已提醒与已汇报次数 |
| 聊天区横幅(常驻) | 只要提醒过至少一次,输入框上方一直显示「● 上次提醒 10月12日 12:27」 |
| 聊天区横幅(高亮) | 新的提醒到达时,换成「● 已提醒智能体汇报进度 · step 10 · #1」并高亮 12 秒,之后回落常驻样式 |

横幅上的时间是宿主返回的 nudge.at(服务器时钟),不是浏览器本地时间——这样它和会话日志、接口里的时间完全对得上。横幅右侧有个 ×,手动关掉后会一直藏到下一次提醒为止(不是永久关闭)。

两个阈值输入即生效(防抖 350ms 后打 /progress-nudge/api/config),没有保存键。
改的是运行时覆盖:立即生效、不写配置档配置、重启后回落到默认值。
输入框只在第一次拿到快照时同步一次,之后不会被轮询覆盖(否则会打断你正在输入的数字);点「恢复默认」会重新同步。

设置页那张卡片已移除——侧栏面板就够了,没必要两处入口。

为什么必须有聊天区横幅

提醒是通过 additionalContexts 注入的合成 user 消息,只有模型看得见;用户那一侧悄无声息——你能看到智能体之后有没有汇报,却看不到「提醒到底发出去没有」。
横幅把这件事补成可见的:Host 在每次提醒时把 nudge 快照(seq/时间戳/触发原因/步数/文案)放进 /status,客户端靠 seq 递增判断「有新提醒」并高亮一次。
首次拿到快照只记基线,不会把历史提醒当新事件弹出来。

投递时机(硬约束,改不了)

提醒只能在步骤边界投递——additionalContexts 只能挂在 tools/post-execute 决策上。所以一个跑 4 分钟的命令,计量早在 120 秒就越界,但提醒必须等命令返回。

为什么不能"不等进程结束就提醒模型":工具执行期间 agent 循环是阻塞的,模型根本没在运行,读不到任何东西。宿主提供了 agent.inject() / agent.steer() 这类"随时可调用"的注入通道,但看运行时源码就知道它们不会打断正在执行的工具:

inject(input) { this.send(input, 'next-step', false); } // 塞进 next-step,不唤醒
steer(input) { this.send(input, 'next-step', true); } // 塞进 next-step + 唤醒
wakeDriver(wakeAfterAbort) {
if (this.phase.kind !== 'idle') { // ← 工具正在跑js
if (… || wakeAfterAbort) this.phase.wakeRequested = true;
return; // 只记一个标记就返回 } …起一个新的运行阶段…
}

唤醒只在智能体空闲时才真的启动新步骤。唯一能强制打断的是 cancel(),那等于杀掉用户正在跑的命令,不可接受。

所以能做的是把「它在等」这件事显示出来:越过时间阈值却还没到步骤边界时, /status 的 pending(due / overSeconds / blocked)让界面显示

● 已到期 224 秒 · 等当前步骤结束后提醒(上次提醒 10月12日 12:35)

而不是让你对着一根越过阈值的进度条和「已提醒 0」猜它是不是坏了。

配置

cordis.patch.yml 里的行配置(默认值见该文件):

| 字段 | 默认 | 说明 |
| enabled | true | 总开关(暂停) |
| stepThreshold | 10 | 累计多少步提醒一次 |
| timeThresholdSeconds | 120 | 距上次汇报累计多少秒提醒一次 |
| minGapSeconds | 45 | 两次提醒的最小间隔,兜底的连击保护 |
| maxPerTurn | 20 | 单回合提醒上限,超过后静默 |
| exclude | ["todo_write","ask_user_question"] | 不计步、也不重置计数的工具 |
| includeSubagents | false | 是否也为子代理计数提醒 |
| resetOnSpeech | true | 智能体主动输出文本时是否归零计量 |
| locale | zh | 提醒文案语言(zh \| en) |
| balance.enabled | true | 是否开启余额监控 |
| balance.thresholdCny | 1.5 | 低于这个金额就提醒 |
| balance.scope | total | 判定口径:total = 充值 + 赠送;recharge = 只看充值 |
| balance.checkSeconds | 300 | 多久查一次余额(最小 30) |
| balance.repeatSeconds | 1800 | 仍在阈值以下时隔多久再提醒;0 = 只提醒一次 |
| balance.includeInReport | true | 低额时在进度汇报末尾顺带提一句 |
| tariff.enabled | true | 是否在侧栏常驻显示「梁文峰 / 梁文谷」 |
| tariff.holidays | [] | 中国法定节假日(北京时间 YYYY-MM-DD),全天按低谷算 |

非法配置在插件激活时直接抛错,不会静默回退。

峰谷时段

DeepSeek 官方口径(Models & Pricing):

Off-peak rates are half of the peak rates. Peak hours are 01:00 - 04:00 and
06:00 - 10:00 UTC, Monday through Friday, excluding Chinese public holidays.
All other hours are off-peak, including weekends and Chinese public holidays in full.

换算成北京时间正好是工作日 09:00–12:00 与 14:00–18:00,低谷一律半价。

| 高峰 | 工作日 09:00–12:00、14:00–18:00 → 梁文峰(橙) |
| 低谷 | 其余全部:午休 12–14、夜间、周末、法定节假日 → 梁文谷(绿) |

侧栏按钮常驻显示当前标签,悬停给出高峰窗口、下次切换时刻与倒计时;面板里另有一行写明官方窗口与「下一次切换:12:00 → 梁文谷(还有 58 分钟)」。

实现要点:

- 时间一律按北京时间算,再用 getUTC 读(加 8 小时后按 UTC 取值),换机器、换 TZ 环境变量结果都不变。
- 下一次切换用「枚举未来 8 天每个高峰窗口的起止,取第一个状态翻转的点」,跨周末、跨节假日都不会漏。
- ⚠️ 中国法定节假日无法离线判断,只能靠 tariff.holidays 手工列。
列表为空时只排除周末——这是唯一诚实的做法,不能假装知道;面板上会提示「未配置节假日,仅按周末与时段判断」。

这是 DeepSeek 官方 API 的计费口径。如果你走第三方中转站,是否适用、折率多少以对方说明为准;不需要的话把 tariff.enabled 关掉即可。

余额监控

余额不自己去打任何 API,而是读宿主自己的 deepseekAccount 服务(设置页「账号与余额」显示的就是它): js const account = ctx.get('deepseekAccount') const outcome = await account.getBalance({ version, locale, timezoneOffsetSeconds }) // → { status:'ready', // value: [{ currency:'CNY', balance:'2.85033112' }], // 充值钱包 // bonusWallets: [{ currency:'CNY', balance:'91.7637864' }] } // 赠送钱包 // | { status:'failed' } | null(未登录)

这样做的好处:插件不碰任何 API key,也不关心中转站——你用哪个服务商、 key 存在哪、走不走中转,都和它无关。

为什么默认按「可用总额」判定

平台扣款先从赠金账户扣。所以「会不会用不了」看的是 充值 + 赠送,只看充值余额会在「赠金还有一大笔」时误报:

| 充值 | 赠送 | 可用总额 | 阈值 1.5 下 |
| ¥2.85 | ¥91.76 | ¥94.61 | total → 不提醒 ✅(recharge → 会误报) |
| ¥1.00 | ¥0.00 | ¥1.00 | 两个口径都提醒 ✅ |

想只在充值余额低时提醒(比如担心赠金过期),把 scope 设成 recharge。
提醒文案的主语会跟着口径变——recharge 口径下说「充值余额只剩 ¥1.00(另有赠送 ¥92.52,可用合计 ¥93.52)」,不会写出「可用余额只剩 ¥93.52」这种误导话术。

| 行为 | 说明 |
| 轮询 | 每 checkSeconds 查一次,读数超过两个周期就算过期,宁可不报也不报旧数 |
| 打开面板 | 侧栏面板一打开就顺手刷一次余额(不然显示的是几分钟前的旧数),另有 ↻ 手动刷新 |
| 低额提醒 | 按 scope 判定命中时,在下一次工具边界投递一条「【余额不足】…」,带真实余额、来源明细、阈值与官方充值链接 |
| 去重 | 按 repeatSeconds 去重;0 表示只提醒一次 |
| 恢复通知 | 余额从「不足」回到「正常」时也投递一条「【余额已恢复】…」,让模型知道用户已经充值、不要再催 |
| 顺带提及 | includeInReport 开着时,低额期间的进度汇报末尾会附一句 |
| 未登录/服务缺失 | 记为 failed / unavailable,不提醒也不崩——不知道就不说 |
| 显示 | 面板两行:可用余额 ¥94.61 + 小字 充值 ¥2.85 · 赠送 ¥91.76;低额时横幅常驻警示;充值恢复后横幅闪一下绿色确认 |

金额显示统一收成两位小数(宿主给的是 2.85033112 这种高精度字符串)。

为什么「恢复」也要通知模型

只报「余额不足」会留下一个坑:用户充值之后模型并不知情,会继续按「余额不足」的记忆行事,反复催充值。所以插件记录低额 ↔ 正常的翻转,恢复时也投递一条通知:

【余额已恢复】现在是 2026-10-24 19:52:03(周六)|可用余额已回到 ¥11.45(充值 ¥11.45),高于阈值 ¥1.5。
用户已经充值了。之前那条「余额不足」作废,不要再提、也不要再催充值;若刚才因此中断了什么,可以继续。

两个细节:

- 恢复的同时会清掉 repeatSeconds 冷却——否则下一次真掉下去时会被 30 分钟去重吞掉,提醒不及时。
- 横幅上的数字跟判定口径一致:scope=total 显示可用总额、scope=recharge 显示充值余额。早期版本一律显示充值余额,有赠金时横幅上的数字是错的。

⚠️ 轮询用的 setInterval 必须 unref(),否则它会一直吊着事件循环,插件卸载后进程也退不掉——测试直接挂死就是这个原因。

自适应退避(增强提醒)

侧栏面板上有「增强提醒」开关,默认开。它解决一个真机发现的问题:

模型跑进「只调工具不说话」的模式后,提高提醒频率只会变成噪音。

这是从会话日志里数出来的,不是猜的。某一 716 轮 / 9445 步的超长会话里:

| 日期 | 提醒次数 | 之后真的汇报了 | 当天助手消息里含文字的比例 |
| 10-09~10-17 | 120 | 120(100%) | 38%~76% |
| 10-22 | 28 | 28(100%) | 24% |
| 10-24 | 82 | 30(37%) | 8% |
| 10-25 | 29 | 9(31%) | 6% |

基线(含文字比例)同步崩塌——说明不是提醒没送到(那 487 条提醒全都在日志里),而是模型那几天本来就不说话,连提醒也只能换来 1/3 的回应。

机制

silentStreak = 自上次「模型对用户说话」以来,已投递的提醒次数
↑ 投递时 +1 ↓ 模型说话时立刻归 0
level = min(floor(silentStreak / afterNudges), maxLevel)

等级越高做两件事:

| 等级 | 步数阈值 | 时间阈值 | 文案 |
| 0 | 10 | 120s | 普通(首次 / 后续 / 耗时) |
| 1 | 20 | 240s | 「未响应」——要求先输出 1-2 行文字再调工具 |
| 2 | 40 | 480s | 「强制」——写明「只调工具不说话 = 没完成」 |
| 3 | 80 | 960s | 同 2 级(上限) |

关键在措辞:普通文案结尾是「汇报完继续执行」,这句话等于给了模型一个跳过汇报的许可——真机日志里它就是这么跳过的。升级档把许可拿掉,改成硬要求。

模型一汇报,立刻复位:silentStreak 归零、等级回 0、阈值回基线。

⚠️ 复位必须放在「还有没有东西可清」的守卫之前。因为提醒刚投递完 steps/ms 就被清成 0,模型紧接着汇报时正好会被那个守卫挡掉——那就成了「明明汇报了,退避却降不下来」。

配置

| 字段 | 默认 | 说明 |
| escalation.enabled | true | 总开关(面板按钮控制的就是它) |
| escalation.afterNudges | 2 | 连续多少次没换来文字开始升级。设 1 = 第一条就升级 |
| escalation.stepFactor | 2 | 每级步数阈值倍数 |
| escalation.timeFactor | 2 | 每级时间阈值倍数 |
| escalation.maxLevel | 3 | 最高等级(0 = 不升级) |

面板上会显示当前状态:正常:按设定阈值提醒 / 已升级 2 · 4 连续未汇报 → 40步 / 480秒。
关闭后显示「关着:始终按固定阈值提醒」,且立即回到基线阈值。

版本检测

侧栏面板底部有一行版本号,带 ↻ 手动查更新:

版本 1.4.0 ↻ 可更新 → 1.5.0 ← 远端更新时(橙色)已是最新 ← 同版本时查询失败(timeout) ← 失败时如实说,不假装最新未开启 ← 关掉后默认 6 小时查一次(intervalSeconds: 21600),启动后缓 10 秒才第一次查,避免和宿主自己的启动请求抢带宽。

只提示,不打扰模型

版本信息只进界面,不进对话——不给模型发任何消息。理由:模型没法更新插件,让它知道版本落后没有任何用,只会诱导它去多管闲事。

三条底线

1. 零外部依赖:用 node 内建的 http/https/fs,不引任何包。
2. 任何异常都吞掉:断网、被墙、限流、返回体不对——全部记 status: 'failed',插件本体照常工作。这是锦上添花的功能,不能成为崩溃源。
3. 失败不猜:查不到就把 latest 置 null、available 置 false,不会留着上一次的旧值假装成功。

版本号比较

按 semver 核心规则自己实现(compareVersions):

| 比较 | 结果 | 说明 |
| 1.10.0 vs 1.9.0 | 1 | 数字比,不是字符串比 |
| 1.2 vs 1.2.0 | 0 | 缺段补 0 |
| v1.3.0 vs 1.3.0 | 0 | v 前缀忽略 |
| 1.3.0 vs 1.3.0-beta | 1 | 预发布版低于同号正式版 |

最后一条第一版写错了:早期用「按 ./- 切开逐段补 0」的办法,把 1.3.0 判成小于 1.3.0-beta。测试第 30 项把它抓出来了。

代理 / hosts 加速的影响

如果挂了改写 hosts 的加速工具(Steam++ / Watt Toolkit 之类),api.github.com 会被指到 127.0.0.1 做 TLS 中间人——Node 不认识它的证书,校验失败,面板显示「查询失败(UNABLE_TO_VERIFY_LEAF_SIGNATURE)」。

这属预期行为,不是 bug:不绕过证书校验是有意的(绕过等于让任何中间人都能冒充)。
想正常查更新就关掉加速,或换能直连的网络。

配置

| 字段 | 默认 | 说明 |
| updateCheck.enabled | true | 关掉后插件完全不出网 |
| updateCheck.intervalSeconds | 21600 | 查询间隔(秒),最小 60 |
| updateCheck.url | GitHub contents API | 任何返回 {version} 或 {content:<base64>} 的地址都行 |

提醒文案

三条,分语气:首次(轻)、后续(详细,带最近工具名与回合合计)、时间型(步数少但耗时长)。
三条都强制写死「汇报完继续执行」与字数上限——否则模型可能停下来等回复,或者把汇报本身变成新的 token 黑洞。文案见 index.js 的 TEXT 常量。

三条都带真实系统时间,例如: text 【进度汇报】现在是 2026-10-12 12:30:09(周一)|距上次汇报已累计 10 步 / 8 秒;本回合起于 2026-10-12 12:30:01,已跑 8 秒。

为什么必须塞时间进去:模型估不准自己的耗时(预估值几乎总是偏低)。把钟直接递到它手上,它才能判断"这一步是不是卡太久了",也才能向用户报出可信的耗时。
回合开始时间是用「当前时间 − 回合已跑毫秒」反推出来的,不需要额外记录。

安装

两种方式,任选一种:

A. 本地目录:设置 → 插件 → 添加插件 → 从本地目录,选这个仓库的根目录(里面有 package.json 的那层),装完 文件 → 退出 再启动。

B. Release tgz:在“添加插件”输入框里粘贴固定地址: text https://github.com/Kiru-Sama/dsh-progress-bar/releases/latest/download/dsh-progress-bar.tgz

不需要手改 profile,也不需要手工建链接。旧版“手工 link”步骤保留在 INSTALL.md 里,只给开发调试/旧版 DSH 回退用。

新增 bundle 不会热加载,必须完全退出重启才会激活。

想改代码 / 发版?先看 RELEASE.md——里面写了版本号怎么定、什么时候打 tag、以及为什么忘了改版本号不会报错。

验证

测试零依赖,不需要装任何东西,只用 Node 自带的能力: bash
node test/run.mjs

它会跑三套:

- smoke.mjs —— Host 半边逻辑(步数/时间触发、冻结、归零、路由、余额、峰谷)
- client.mjs —— Client 半边结构(加载、槽位注册、面板/横幅渲染、样式规则)
- package.mjs —— 发布包结构(bundle patch、main、必须文件、非 private)

index.js 只 import 'node:crypto',client.js 只从宿主模块表取 react——没有 npm 依赖,所以也不存在"装依赖失败"这种问题。用 DSH 自带的 Node 跑即可,或任意 Node 18+。

界面上确认:刷新页面后侧栏底部应出现进度按钮;聊天区输入框上方应在提醒发出时弹横幅。
(设置页那张卡片已经在 v0.1 之后移除。)

日志复盘

会话日志是 ~/.dsh/sessions/<workspace>/<session>/session.v4.jsonl.zstd,多帧 zstd 拼接,Node 的 zstd 解码器不跨帧(整段解压只得到第一帧)。
tools/scan-nudges.cjs 照抄 DSH 自己的 scanZstdFrames 切帧后逐帧解压: powershell
node tools\scan-nudges.cjs count 3 # 每个会话的提醒次数 + 相邻间隔
node tools\scan-nudges.cjs detail 3 # 每次提醒的文案与触发原因

统计口径有个坑:一次提醒会写两条记录(agent/inbox/spliced + user/message),只按字符串匹配会把次数翻倍。正确判据是 type === 'user/message' 且 data.source.kind === 'progress-nudge'。

回滚 powershell powershell -File tools\rollback-profile.ps1

会还原 profile 的 package.json、移除 junction。还原后重启 App 即彻底卸载。
(也可以只把 dsh.profile.bundles 里的 dsh-progress-bar 删掉再重启。)

开发备注

- Host 半边只用到两个公开扩展点:tools/post-execute / agent/pre-step 事件,以及(可选的)webServer.register 前缀路由。
- 刻意零外部依赖:index.js 只 import 'node:crypto'。原因见「坑一」。
- Client 半边是手写的 __ModuleLoader__ 闭包,无构建步骤;
require() 只取平台种子(react),样式只用 --dsw-alias- 主题 token。
- tools/ 与 test/ 是开发用的,不随包发布(见 package.json 的 files)。
- 设计文档见 DESIGN.md,参考实现见 dsh-src/ 与 refs/。

坑一:profile 插件不要 import @deepseek-ai/

实测:插件里 import z from '@deepseek-ai/schemastery' 会让整个插件挂掉,宿主只在 stderr 报一行
progress-nudge (dsh-progress-bar): failed to import。

原因两层:

1. 宿主对 profile 插件的裸依赖不保证解析;
2. 更隐蔽的一层:Node 按「真实路径」解析依赖。本插件用 junction 挂在 <profile>\node_modules\ 下,真实路径是 F:\...,于是 Node 从 F:\ 往上找 node_modules,永远走不到 %USERPROFILE%\.dsh\profiles\node_modules (那里其实躺着 react、express、@deepseek-ai/ 一大票包)。pnpm 装的包因为 realpath 落在 profile 内部,所以没这个问题。

结论:要么零依赖,要么用 pnpm 正常安装。本插件选前者,所以 Config 换成自带的 DEFAULTS + 手工 fail-loud 校验,消息构造也不再借 @deepseek-ai/dsh-llm 的 createUserMessage(DSH 内部实现里 brandString 是恒等函数,普通 uuid 完全等价)。

坑二:本地验证挂载时别点亮浏览器

想在不碰用户正在用的 App 的前提下验证,复制一份 profile 来挂载:

复制 desktop -> probe:改掉 package.json 里的 profile 名,且绝对不要写 BOM & $exe $bin --profile probe --no-open # --no-open 必须加,否则会开浏览器标签

stderr 里出现 dsh: warning: N entry did not activate 就是有插件没加载成功——这是判断插件是否被宿主接受的唯一可靠信号。
带认证探测插件路由用 tools\probe-local.cjs(先拿 token 换 cookie,再打接口)。
验证完记得删掉 %USERPROFILE%\.dsh\profiles\probe。

坑三:说话重置计量时,别把防连击冷却一起清了

resetOnSpeech 一开始顺手写了 state.lastNudgeAt = 0,看起来"把一切都归零"很干净,实际上把 minGapSeconds 一起废掉了:日志里出现了 36 秒、42 秒的相邻提醒,而阈值配的是 45 秒。

正确语义是分开的两件事:

- ms/steps/anchorAt —— 「距上次汇报」的计量,说话时归零;
- lastNudgeAt —— 「距上次提醒」的冷却,只由提醒本身推进。

测试 16 专门钉住这条:说话之后紧接着再凑满阈值,仍然必须被 minGap 挡住。
预览分享卡片长什么样 ↓Kiru-Sama/dsh-progress-bar
分享 · DeepSeek Harness Hub
Kiru-Sama/dsh-progress-bar

DeepSeek Harness 进度汇报提醒插件:累计每 N 步或每 N 秒提醒 Agent…

回到顶部