在输入框下方显示当前这一轮 DeepSeek Harness 任务的实时进度条、百分比与预计剩余时间;估计随轮次实时重锚,任务失败或中断时进度条变红。
安装
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:778672151/dsh-session-turn-eta
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
该插件的 README 只有英文版本。
Live remaining-time prediction for the current DeepSeek Harness turn, shown as a progress bar with a live percentage under the composer.
- Running — a bar whose width follows elapsed time over the predicted total,
with a percentage and a humanised time left (
~12m 34s left/约剩 12 分 34 秒). The percentage ticks locally while the turn is open. The filled track ends in a leading dot and carries a slow shimmer. - Finishing — once a turn outruns its own estimate the bar fills and pulses with a "finishing" label, instead of a misleading "0s left".
- Completed — 100%, with a short one-shot burst at the tip.
- Failed or interrupted — the bar turns red and reads "progress interrupted".
Install
dsh plugin --profile web add github:778672151/dsh-session-turn-eta
The repository ships a prebuilt lib/, so installing does not run a build step.
Restart dsh web if the profile asks for it, then send any message: the bar
appears under the input box while the turn runs.
Compatibility
| DeepSeek-Harness desktop | 0.2.1-rc.5 (type-checked against its published packages) |
@deepseek-ai/cordis |
>=4.0.5 <5 |
@deepseek-ai/dsh-session |
^0.2.1-rc.1 |
@deepseek-ai/dsh-session-projection |
^0.2.1-rc.1 |
@deepseek-ai/dsh-client-ui-conversation / dsh-client-locale |
^0.2.1-rc.1 (client half, optional peers) |
| Node | >=22 for building; the shipped bundle runs on the DSH host |
How it works
The host half registers one turnEta session projection and nothing else:
it folds the durable turn/start, step/start, step/end and turn/end
events into a prediction. The projection registry already drives every
registered unit once per committed event, so the plugin does not replay
session/event a second time; it only mirrors the registry's change feed
(onChanged, which fires when the published view changed by Object.is) onto
two typed Cordis events: turn-eta/update while a turn is open and
turn-eta/complete once per turn.
- The per-step rate blends the live turn's own observed rate with the session's
90th-percentile historical step duration (read after winsorising the sample
at
8 x median), so the rate tracks the steps that dominate a turn while a single 9-hour idle gap still cannot drag it up. - The expected step count is the conditional median of the finished turns that were at least as long as this one, so a growing turn keeps a live estimate.
- The published total is held against early noise and re-anchored upward once the turn has passed 50% of it, so a turn that keeps working stops being pinned to its first guess and the estimate never sits at 100% while it runs.
- The total always keeps at least one step of runway while the turn is open, so a prediction can never report completion before the turn actually ends.
- A running turn renders at most 99%; only a turn that really ended shows 100%. A turn that outran its estimate fills and pulses under a "finishing" label instead.
- Every finished turn anchors the next one, whatever closed it (a turn that errored or was aborted is still evidence of how long turns run); the first turn bootstraps from a prior until the session has real history.
The client half reads that projection through the standard useProjection seat
and renders it on the conversation.composer.dock slot. The plugin never
mutates the session and registers no model-visible capability.
Skins
The bar ships five skins: auto (harness theme tokens, the default and the only
one that follows light/dark automatically), bilibili, mint, sunset, and
ocean. A skin only owns the fill gradient, the leading-dot glow, the track
tint, and the celebration colour; layout and accessibility never change.
Pick one either per render or document-wide:
// per render (the dock entry accepts an optional `skin` prop)
<TurnProgress skin="bilibili" ... />
<!-- document-wide, e.g. in the host page or a user script -->
<body data-turn-eta-skin="ocean">
The client entry exports TURN_ETA_SKINS, TURN_ETA_DEFAULT_SKIN,
TURN_ETA_SKIN_ATTRIBUTE, isTurnEtaSkin() and resolveTurnEtaSkin(). Unknown
values fall back to auto. All motion (shimmer, pulse, celebration) is disabled
under prefers-reduced-motion: reduce.
Embedding the estimator
The fold is plain data in, plain data out: the same code the bar renders from can be driven without Cordis, a session, or the plugin instance.
import { createTurnEtaFold, etaCore, ETA_TUNING } from '@dsh-external/dsh-session-turn-eta'
// full fold: the projection the client renders
const fold = createTurnEtaFold()
for (const event of durableLog) fold.apply(event)
const { remainingMs, predictedTotalMs, method } = fold.view()
// or just the math, from whatever facts you already have
const core = etaCore({ startTime, stepDurations, completedTurnSteps, stepSamples, asOf })
createTurnEtaFold(seed) accepts a captured state() so a fold can continue
from a projection checkpoint instead of replaying the whole log. ETA_TUNING
exposes every constant (RATE_PERCENTILE, REANCHOR_AT, OUTLIER_CAP, …) so a
consumer can read the calibration instead of copying numbers.
Cost
The projection runs on every committed session event, so the fold is written to cost O(1) amortised per event rather than O(history) per event:
- the sample history is appended as a list and its ascending copy is grown by
insertion (
withSample), so sorting is never repeated for one append; - the rate profile (0.9 / 0.25 / 0.75 quantiles of a winsorised list) is cached per sample-list reference, so it is recomputed once per finished step instead of once per event;
- the expected step count is read off the ascending anchors by binary search instead of filtering and re-sorting them;
- the view of an event reuses the core its anchor advance already computed.
Measured with npm run bench on Node 24 (per-event cost of the fold alone, no
registry, no UI): 12.9k events over 8 turns of 50 steps run at ~245k events/s,
up from ~9.5k events/s before these changes; the cost stays flat as the history
grows (32k events over 80 turns: ~150k events/s).
npm run test:equiv fuzzes the optimised primitives against the reference
formulas (9,300 comparisons) so the speed-ups cannot drift from the maths.
Build
The published bundle is built by tsdown (no monorepo checkout required):
npm install
npm run build # -> lib/index.js (host) + lib/client.js (client)
npm test # host estimator invariants + client render states
npm run typecheck checks both halves against the published 0.2.1-rc.x
contract: the host half (tsconfig.json) against dsh-session /
dsh-session-projection, and the client half (tsconfig.client.json) against
dsh-client-ui-slots / dsh-api-session-controller / @types/react.
scripts/build.sh is an optional development helper that links a contract tree
(DSH_CONTRACT_DIR, defaulting to a local copy of the published packages) and
type-checks both halves, so the build and the desktop app agree on the same
contract instead of on whatever a monorepo checkout happens to contain.
License
MIT
链接
同类插件
zhu1090093659/dsh-web#packages/dsh-task-board★ 9967
侧边栏多列任务看板:卡片交给真实 DSH 智能体会话执行,支持 cron 定时(Host 侧到点执行,关浏览器也生效)。
zhu1090093659/dsh-web#packages/dsh-web-all★ 9967
DSH Web UI 插件与皮肤合集:任务看板、git 图、右侧面板、远程移动端 UI、桌宠、实时 token 统计与皮肤中心。
MeteorNOX/DeepSeek-Balance-Whale-Widget★ 6767
右下角常驻的小鲸鱼挂件:余额、今日已用与每轮对话消耗(含峰谷价),余额预警与今日预算的泡泡内容都可编辑;泡泡点击序列模块化自定义,支持并列加权 A/B、随机台词与随机图片;内置 30+ 厂商模板(OpenAI / OpenRouter / Kimi / 硅基流动 / 方舟 / 智谱 / MiniMax 等),按模型查余额与订阅额度;另有任务结束音效、导入音频、自定义角色与资源管理。数据全在本机,无遥测。
ccch1mneyyy/dsh-TUI★ 6630
Claude Code 风格全屏终端 UI:像素鲸鱼顶栏、实时工作状态行、思考流式展开。
omdsh-dev/DSH-better-sidebar★ 4833
侧边栏完整工作台:内置文件渲染编辑、终端、Git 与子代理,支持三方插件注册新 Tab。
Devin-AXIS/deepseek-design#deepseek-idesign★ 1681
可视化设计工作室,支持网站、App 原型、海报、信息卡、报告和杂志的模板创建、元素编辑、选区级 AI 草稿衔接与导出。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。