2008924 / dsh-progress-viz

Listed

Real-time stage & ETA dashboard for DeepSeek Harness (dsh) from session event stream | dsh 任务进度可视化:会话事件流实时阶段+ETA 看板

mainSession View source

Installation

npx -y @deepseek-ai/dsh plugin --profile web add github:2008924/dsh-progress-viz

This installation command is an unverified starting point generated from the GitHub repository address.

README

Maintainer-authored documentation snapshot.

View on GitHub ↗
Commit 7369098Synced Aug 18, 2026

dsh Progress Viz

CI License Python DSH Market 收录徽章

实时可视化 dsh(headless 模式)任务执行过程的独立看板工具包——读取会话事件流,呈现阶段进度、ETA 与实时动态流,纯本地运行。

English: dsh Progress Viz is a self-contained dashboard that visualizes dsh headless task execution in real time. It parses the local session event stream (session.jsonl.zstd) to show stage progress, ETA and a live activity feed — 100% local, no API calls, no tokens consumed.

dashboard

背景痛点

dsh 在 headless 模式下只输出最终答案,执行过程(读哪些文件、跑了什么命令、任务清单推进到哪一步)完全不可见。任务一跑就是几分钟甚至更久,期间无法判断:

  • 任务是否还活着、卡在哪一步?
  • 当前处于整个任务的哪个阶段、还剩多少阶段?
  • 大概还要等多久?

原理

dsh 会把每次任务的完整事件流实时追加写入本地会话文件:

~/.dsh/sessions/<cwd编码>/<session-id>/session.jsonl.zstd

(zstd 压缩的 JSONL,每行一个事件,type 字段区分类型。)

本工具关心的事件(v1.1 扩展后):

事件类型含义用途
todo/write模型写入任务清单(data.todos,每项有 content + status阶段数据源:取第一个未完成项为当前阶段
step/start步骤边界无 todo 时的兜底计数
tool/call工具调用(data.name + data.arguments最近动作 + 事件流/时间线
session/titledsh 自动生成的任务标题(data.title任务标题(卡片优先显示,无标题回退 cwd basename)
assistant/message模型消息(data.usage 含 token 统计)成本估算:累计 tokens × DeepSeek 定价常量

解压必须用 zstandard 的 stream_reader 全量流式解压(decompressobj 只能解第一个 frame 是已知的坑)。看板每 4 秒轮询一次(重新扫描最近任务列表并逐任务解析),页面每 5 秒自动刷新。

安装与快速开始

# 方式一:只装依赖,直接运行脚本(无需安装本项目)
pip install "zstandard>=0.21"
python dashboard.py 8123

# 方式二:按项目安装(pyproject.toml,自动带上 zstandard 依赖)
pip install .
python dashboard.py 8123        # 或 python -m dashboard 8123

本项目是纯脚本型包(无 console script 入口、不提供 import 模块), pip install . 只是安装依赖并注册元信息;运行方式与直接运行脚本完全一致: 在项目目录执行 python dashboard.py [port](或 python -m dashboard [port])。

启动行为:

  • 自动打开浏览器:服务器启动成功后自动用系统默认浏览器打开 <http://127.0.0.1:<实际端口>>;
  • 端口冲突自动递增:指定端口(或默认 8123)被占用时自动 +1 重试 (最多 5 次),并打印「端口 X 被占用,改用 Y」;连续 5 个端口都被占用才报错退出;
  • --no-open:启动时不自动打开浏览器(如远程/无头环境): python dashboard.py 8123 --no-open
  • --status:不启动服务器,直接打印当前任务状态表 (状态 / 标题 / 阶段 k/N / ETA / 成本)后退出(exit 0),无任务打印「暂无任务」: python dashboard.py --status
  • 飞书完成通知--feishu-webhook <URL>(或环境变量 FEISHU_WEBHOOK)启用—— 任务从 running 变为 completed 时(看板轮询检测到状态翻转)向 webhook POST 一条 文本消息「✅ dsh 任务完成:<标题>()· 耗时 mm:ss · 阶段 <最后阶段>」; 同一会话只通知一次(缓存已通知会话 id),启动时已 completed 的任务不通知, 发送失败静默(不阻塞看板);--no-feishu 强制关闭。

浏览器打开 http://127.0.0.1:8123

  • 多任务分栏:看板扫描 ~/.dsh/sessions全部会话,只保留最近 1 小时内有写入 (文件 mtime 距今 < 3600s)的任务,按 mtime 降序取前 8 个,以网格分栏展示 (≥1400px 三列 / ≥900px 两列 / 其余单列,响应式);
  • 运行中置顶分区(v1.2):任务按状态分为「🟢 运行中」与「✅ 已完成」两个区块 (运行中在上、已完成沉底),各带计数徽章;点击区块标题栏可整体折叠/展开(默认展开), 长列表防信息过载;
  • 运行中卡片(mtime 距今 ≤ 30s):绿色状态点「正在运行」+ 任务标题 + cwd + 会话 id(前 8 位)+ 已运行时长 + 阶段进度条(阶段 k/N + 名称)+ ETA(预计完成时刻 + 剩余时间 + 推算方式)+ 成本估算(有 usage 数据才显示)+ 「详情」展开区(点击展开完整时间线,等宽字体)+ 事件流(默认展开,max-height 滚动);
  • 已完成卡片(mtime 距今 > 30s):灰色「已完成」+ 标题 + cwd + 耗时 + 最后阶段名 (stage 或「步骤N」),事件流默认折叠(点击展开),避免信息过载;
  • 无任务时:显示「等待 dsh 任务开始...」,启动一个 dsh headless 任务后自动出现分栏;
  • 标题区实时显示任务总数与运行中数(如「共 8 个任务 · 运行中 2 · 每 5 秒自动刷新」)。

/api/live 返回最近任务列表 JSON:{"tasks": [ {id, cwd, title, status, stage, stage_idx, stage_total, stage_pct, action, eta_s, eta_mode, eta_at, elapsed_s, tail, cost_est, timeline} ]},无任务时 tasks=[]。每个任务的 ETA 独立计算 (融合算法复用,历史会话排除任务自身);单个会话扫描/解析失败会静默跳过, 不影响其他任务。

v1.1 新功能说明

  • 成本显示(A):解析 assistant/message(或 tool/result)事件的 data.usage(实测本机格式:inputTokens / outputTokens / cacheReadTokens), 按模块级常量 PRICES(DeepSeek 官方定价,元/百万 tokens,注释标明价格与日期、 可改)估算成本,卡片显示「≈¥0.0123」并标注估算。事件流无 usage 数据时 cost_estNone,前端不显示(不硬编假数据)。
  • 任务标题(D):解析 session/title 事件的 data.title(取最后一个非空), 任务卡片优先显示标题;无标题回退 cwd 的 basename;再回退完整 cwd。
  • CLI 状态查询(C)--status 不启动服务器,直接打印当前任务状态表。
  • 飞书完成通知(B)--feishu-webhook / FEISHU_WEBHOOK 启用;任务 running→completed 翻转时通知一次(去重),启动时已 completed 不通知,失败静默。
  • 详情时间线(E)/api/live 任务对象新增 timeline 字段([{t, type, desc}], 最多 50 条,chunk 连续合并、取最近);运行中卡片「详情」点击展开。

v1.2 看板 UI 更新

  • 运行中置顶:任务按状态分为「运行中」「已完成」两个区块,运行中在上、已完成沉底;
  • 区块折叠:两个区块均可点击标题栏折叠/展开(默认展开),长列表防信息过载;
  • 计数徽章:标题与区块同步显示「共 N 个任务 · 运行中 M」实时计数;
  • 跨平台修复:cwd 标题回退在 Linux/macOS 上正确取 basename(反斜杠归一化为正斜杠, 修复 test_v11 在 macos/ubuntu 上的失败)。

插件版(dsh-progress-viz-plugin)

除了「独立版」(看板直接 zstd 解析会话文件),本工具提供 cordis 插件版: 插件挂载到 dsh profile(任务执行的地方,如 headless),实时监听会话事件, 只保留语义事件(todo/writestep/startstep/endtool/calltool/resultassistant/messageturn/startturn/endsession/titlesession),过滤 chunk 等中间态噪音(assistant/chunkreasoning-chunkstool-call-chunkstext-chunksrequest/* 等),原子重写 <DSH_HOME>/progress/<session-id>.json(及 current.json)供看板消费。

与独立版的关系:看板新增数据源,优先读插件输出(实时、已过滤噪音); <DSH_HOME>/progress/ 缺失或没有文件时,自动回退现有 zstd 解析路径 (行为不变,新增优先级不影响回退)。/api/live 字段语义不变(插件任务 eta_*Nonetailtimeline 派生)。

安装(dsh plugin add)

插件源码在 plugin/ 目录(TypeScript、ESM、lib/index.js 产物)。构建并挂载:

cd publish/dsh-progress-viz/plugin
pnpm install --registry https://registry.npmmirror.com   # 国内 registry
pnpm build                                                # tsc → lib/index.js
# 回到任意目录,把插件挂到 headless profile(本地目录绝对路径):
dsh plugin --profile headless add <plugin 目录绝对路径>
dsh --profile headless --dump-config   # 验证输出包含 progress-viz

dsh plugin add 会执行 pnpm add <路径> 并把本包加入 profile 的 dsh.profile.bundles(插件包声明了 dsh.bundle.patch)。若环境不支持 dsh plugin,可手动把插件加入 profile package.jsondependenciesdsh.profile.bundles 数组后执行 pnpm install。插件零配置可挂载。

输出格式

每个会话一个文件:<DSH_HOME>/progress/<session-id>.json(原子写:临时文件 + rename,每次语义事件更新重写);会话结束(session/disposed 或空闲超时)后 标记 finished: true 并保留文件;新会话开始(session/created)时重置状态。

{
  "session_id": "session-xxxxxxxx-...",
  "title": "任务标题", "cwd": "C:\\work",
  "stage": "当前阶段", "stage_idx": 2, "stage_total": 3, "stage_pct": 67,
  "action": "运行 bash 命令: pytest -q",
  "cost_est": 0.0123, "elapsed_s": 42,
  "updated_at": "2026-08-15T12:00:00.000Z", "finished": false,
  "timeline": [{"t": "12:00:01", "type": "todo/write", "desc": "当前第 2 项/共 3 项"}]
}

阶段逻辑与独立版一致(todo 第一个未完成项优先、step/start 计数兜底); 成本按同一 DeepSeek 定价常量估算(无 usage → null)。详见 plugin/README.md

阶段与 ETA 说明

  • 阶段来自模型的 todo/write 任务清单(取第一个未完成项,idx 从 1 开始);模型必须使用 todo 工具维护清单才能显示阶段。建议在任务提示里引导,例如:

    【输出约定】请使用 todo 工具维护你的任务清单:每个主要步骤列一项
    (开始标记 in_progress、完成标记 completed,清单变化时更新)。
    
  • ETA线性外推 + 历史均值融合

    • 线性分量 linear_s:已走过阶段的平均耗时 × 剩余阶段数;
    • 历史分量 hist_s:同 cwd 目录下历史会话(排除当前监控会话)耗时的中位数 (每个历史会话耗时 = 事件流最大 time − 最小 time;无历史/扫描失败时视为不可用);
    • 融合公式eta = α·linear_s + (1−α)·hist_s,α 随阶段进度自适应: k≥3 → α=0.7k==2 → α=0.5k<2 → α=0(纯历史均值);
    • 回退链eta_mode 标记):有阶段信息(k≥2 且 n>k)且历史可用 → blend; 有阶段但无历史 → 纯 linear(α=1);无阶段但有历史 → 纯 history(α=0);都无 → none(不显示 ETA);
    • 历史会话每次全量扫描(会话数少,代价可接受),结果按会话目录 mtime 缓存, 4 秒轮询时 mtime 未变化直接复用 hist_s。

测试

python tests/make_fixtures.py          # 生成合成 fixtures(无真实会话数据)
python tests/test_session_progress.py  # 会话解析单测(无需 pytest),exit 0 全过
python tests/test_eta_blend.py         # ETA 融合算法单测(历史会话 fixture 生成到临时目录)
python tests/test_multi_pane.py        # 多任务分栏单测(1 小时窗口 / mtime 排序 / status 判定)
python tests/test_tail_format.py       # tail 可读性单测(chunk 合并 / 时间戳 / 动作高亮 / 截断)
python tests/test_port.py              # 端口冲突自动递增单测(socket 占用模拟,随机高位端口)
python tests/test_cache.py             # 解析缓存单测(mtime 未变不重新解压 / 修改后重解析 / 缓存清理)
python tests/test_v11.py               # v1.1 五项增强单测(标题 / 成本 / CLI --status / 飞书通知 / 时间线)
python tests/test_plugin_progress.py   # 插件版数据源单测(优先级 / 回退 / status / 去重 / 窗口)

GitHub Actions CI(.github/workflows/ci.yml)在 push 到 main 与 pull_request 时, 以 ubuntu / macos / windows × Python 3.9 / 3.11 六种组合逐套运行上述单测。

常见问题

遇到「zstandard 未安装」「看不到任务」「端口被占用」「路径显示异常」「显示步骤N 而不是任务名」「任务完成后卡片还在」「如何卸载/停止看板」等问题,请查阅 docs/FAQ.md(7 问 7 答)。

文件结构

dsh-progress-viz/
├── .github/workflows/ci.yml # GitHub Actions CI(3 平台 × 2 Python 矩阵)
├── dashboard.py          # 独立看板服务器(全库扫描 + 4s 轮询 + 解析缓存 + 多任务分栏 +
│                         #   ETA + 成本估算 + 任务标题 + 详情时间线 + 飞书完成通知 + CLI --status)
├── session_progress.py   # 会话事件流 → 阶段解析器(纯本地)
├── index.html            # 看板页面(深色主题,多任务网格分栏,标题/成本/详情时间线,5s 自动刷新)
├── pyproject.toml        # 项目元信息 / 依赖声明(pip install . 用)
├── tests/
│   ├── make_fixtures.py              # 合成 fixtures 生成器(含历史会话 fixture)
│   ├── test_session_progress.py      # 单测(无需 pytest)
│   ├── test_eta_blend.py             # ETA 融合算法单测
│   ├── test_multi_pane.py            # 多任务分栏单测
│   ├── test_tail_format.py           # tail 可读性单测
│   ├── test_port.py                  # 端口冲突自动递增单测
│   ├── test_cache.py                 # 解析缓存单测
│   ├── test_v11.py                   # v1.1 五项增强单测(标题/成本/CLI/飞书/时间线)
│   ├── test_plugin_progress.py       # 插件版数据源单测(优先级/回退/status/去重/窗口)
│   └── fixtures/session-synthetic.jsonl.zstd
├── docs/
│   ├── FAQ.md            # 常见问题(7 问 7 答)
│   └── screenshot.png    # 看板效果图
├── README.md
├── LICENSE
└── requirements.txt

License

MIT(Copyright (c) 2026 dsh-progress-viz contributors)

Project files and signals

Shown items are public repository signals detected in the directory snapshot.

TestsDetected
DocumentationDetected

Repository information

Language
Python
License
MIT
Latest release
v0.1.0
Last updated
Aug 16, 2026, 9:50 PM

Install deliberately

Review source code, permissions, lifecycle hooks, dependencies and network access. Test untrusted plugins in an isolated environment.