DeepSeek Harness 的实时"工作状态行"插件:把会话事件折叠成俏皮思考文案、正在运行的工具与已耗时,同时投递给 TUI 提示符与 Web 客户端。
- 语言
- TypeScript
- License
- MIT
- 分支
- main
安装
$ dsh plugin --profile web add github:ccch1mneyyy/working-activity在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程
一句话定位
DeepSeek Harness 的实时"工作状态行"插件,把模型会话里的事件折叠成一条普通用户看得懂的进度文字——思考时是俏皮短句、跑工具时是"动作 + 文件/命令 + 已耗时"、收尾给一句搞定加汇总——同时投递给 TUI 提示符和 Web 客户端的输入区上方。
核心能力
- 把会话事件(
turn/start/assistant/chunk/tool/call/tool/result/turn/end)与agent/status折叠成 idle/waiting/thinking/tool/done 五段状态,按 500ms tick 刷新 - 自动识别工具名映射成俏皮动词(
翻翻文档/改改/跑个命令/搜搜东西/派个小弟等),参数细节从path/command/query/url自动抽取并截断 - 思考文案池约 95 句中文口语化短句 + 面无表情的英文(
lol/hm/ok),每约 4 秒轮换;本地时间 00:00–06:00 混入深夜文案;想久了自动分档(30s / 1min / 5min) - TUI 侧:在
ctx.tuiPrompt注册${activity}模板值,加入theme.leftPrompt即显示 - Web 侧:作为 slot 插件挂到
conversation.input.dock,composer 上方渲染一行带阶段色呼吸点的状态行 + 工具计数徽标 - 可选注入"⏵ 模型自述"约定到 system prompt:让模型在回复首行写"⏵ 你在做什么",状态行实时抽取这一行展示,并在聊天正文里过滤
- 收尾摘要:
搞定 ✓ · N 工具 · 想Xs 干Ys,最后一格短暂钉住最近工具的片段
技术实现
- 语言: TypeScript(ESM,
"type": "module"),Node 端 tsc 编译到lib/,Web 端走 tsdown 出 closure-factory bundle 到lib/client.js - 关键依赖:
@deepseek-ai/cordis@^4.0.1、@deepseek-ai/dsh-session@^0.1.0-rc.6、@deepseek-ai/dsh-agent@^0.1.0-rc.6、@deepseek-ai/schemastery@^3.18.1 - 架构模式: Cordis 宿主插件(
name: 'working-activity')+ Web slot 插件(注册到conversation.input.dock,order 15)+ invariant 伴生插件(./invariant,用dsh-invariants服务校验activity/status形状);自挂载由dsh.bundle.patch → cordis.patch.yml的- insert:实现 - 入口文件:
packages/activity/working-activity/src/index.ts(宿主插件apply(ctx, config))→src/status.ts(纯状态机ActivityTracker,clock-injected)→src/client/index.ts(Web slotapply(ctx),注册WorkingLine)→src/invariant.ts(校验伴生)
适用场景
DSH 用户在长任务里想看到模型当下到底在干什么——是还在想、卡在思考、还是在跑 npm install——而不是只盯着转圈。等长工具执行时一眼看到已耗时和操作的文件/命令;收尾时看到思考与执行时间拆分,心里有数。配 dsh-cc 终端的状态栏或官方 Web 端使用最直接,也支持自定义任何消费端订阅 activity/status 事件。
前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DeepSeek Harness | 0.1.0-rc.6+ | 由 peerDependencies 中多个 @deepseek-ai/dsh-*@^0.1.0-rc.6 锁定 |
| Node.js | ^22.19.0 || >=24.0.0 | engines.node 声明;CI 使用 Node 24 |
| pnpm | 10+(推荐 11+) | dsh plugin add 转发给 pnpm;pnpm 9 传递依赖提升问题会导致模块解析失败 |
| 平台 | macOS / Windows / Linux | 跨平台,纯 JS/TS 实现,无原生模块 |
| 原生模块 | 无 | 不依赖 node-gyp 构建 |
| Web 端额外要求 | 官方 rc.6 源码仓库打上 patches/webui-working-activity.patch | Web 端需要这条 runtime 补丁把 activity/status 接进 ConversationSnapshot;不打卡也装但状态行恒空 |
| 必需凭证 | 无 | 状态行纯本地推导,不读 API key、不发网络请求 |
安装方式
dsh plugin --profile web add github:ccch1mneyyy/working-activity
安装命令本身只在仓库根 npm 包发布时填写 GitHub shortlink。
dsh-working-activity实际包名固定(被 dsh-cc-tui 依赖),发布前请确认 package.json#repository 指向本仓库。
配置项
所有可调参数都集中在 Config Schema(packages/activity/working-activity/src/index.ts:36),在 profile 用户补丁层按 id 覆盖:
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
phrases | 布尔 | 俏皮文案池开关;关闭后渲染朴素功能标签(思考中 · 总1m23s) | true |
publish | 布尔 | 追加 activity/status 会话事件供 Web / dsh-cc 消费。默认关闭:开启后含状态行的会话无法 resume(session.append() 不支持 ignorable) | false |
tickMs | 数字 | 状态行渲染 tick 间隔(ms),范围 100–5000 | 500 |
publishIntervalMs | 数字 | 状态行稳定时两次发布的最小间隔(ms),范围 500–30000;dsh-cc 推荐 500 | 2000 |
detailLimit | 数字 | 工具细节展示最大长度(路径/命令/搜索模式字符数),范围 8–120 | 40 |
customActions | 对象 | 工具名精确映射到动作文案池,如 {"my_deploy":["部署一下","上线中"]}(大小写不敏感) | {} |
narrate | 布尔 | 向 system prompt 注入"⏵ 模型自述"约定;关闭后只由事件推导 | true |
常见问题
Q: 我看 dsh 官方 README 装了 Web 端,但 composer 上方没出现工作状态行。
A: 本包的 slot 插件只贡献注册到 conversation.input.dock,要让 Web 真正渲染还需要一条 runtime 补丁把 activity/status 事件接进 ConversationSnapshot.activity 字段。在你的官方 rc.6 源码仓库根目录 git apply <本仓库>/patches/webui-working-activity.patch(已通过 git apply --check 验证)即可。补丁没合入前 Web 端不会报错,只是 WorkingLine 组件恒返回 null。
Q: TUI 里看不到 ${activity} 显示,怎么办?
A: 模板里没加 ${activity} 槽位值会被模板渲染器省略。需要在 profile 用户补丁层($DSH_HOME/profiles/<profile>/cordis.patch.yml)里给 dsh-tui 的 theme.leftPrompt 加上:'${cwd}${git/worktree}${activity}${model}${token_meter/cache_hit_rate}${context}'。同时确认 profile 装了 dsh-tui 和本插件两个包。
Q: 开启 publish: true 后历史会话 resume 失败,为什么?
A: DSH 当前版本的 session.append() 不能把事件标记为 ignorable,resume 读取路径对未知不可忽略事件类型会拒绝。开启 publish 后凡是渲染过状态行的会话都打了一个 activity/status,整条日志 resume 报错。仅在宿主支持 ignorable append、且你的消费端是基于日志重放的 UI 时再开启;普通 Web UI 用 conversation.input.dock 槽位走实时事件,不需要 publish。
Q: 我有自己的工具(比如内部 deploy 工具),想让状态行显示"部署一下 staging"。
A: 在 customActions 里按工具精确名配动作池:{"my_deploy":["部署一下","上线中"]}。匹配按工具名大小写不敏感精确匹配,没匹配上就走内置的"翻翻文档/改改/跑个命令/派个小弟"等映射,识别不出的工具回退到"干活/调用/整一下"。
Q: 状态行秒数跳动太迟钝,跟手不上长工具。
A: 把 publishIntervalMs 调到 500(默认 2000),让"稳定行"也能 0.5s 重发一次——耗时数字就连续跳动了。改 profile 用户补丁层对应 id 的 config 即可:{ id: working-activity, config: { publishIntervalMs: 500 } },别再 insert 同 id 的行(会双实例)。
Q: 卸载插件会改动 DSH 核心吗?会丢会话吗?
A: 不会。本插件是纯挂载,不修改 DeepSeek Harness 任何源码;卸载即还原。会话日志保留在 profile 的 sessions 目录下原路径。activity/status 事件不影响其他事件类型——只是它本身的存在会让启用 publish 期间的会话 resume 失败(见上条)。
Q: macOS / Windows / Linux 都能用吗?需要装额外系统依赖吗?
A: 跨平台可用,无原生模块、不依赖 node-gyp。在三个系统上 pnpm install && pnpm run build 都能跑通。Windows 上注意 dsh plugin 转发的 pnpm 命令走 cmd,不要用 Git Bash 直接调用。
上手难度
入门 — dsh plugin add 一行命令装上即工作;TUI 端默认配置即可看到状态行,Web 端再补一条 git apply。常用调参只涉及 publishIntervalMs 一项。
已知问题与限制
publish默认关闭:开启后渲染过状态行的会话无法 resume(session.append()不支持 ignorable;src/index.ts:38-46/registration.ts:9-13)。- 单一活跃状态行:插件按会话维护一条状态行;TUI 槽位显示最近活跃会话,多会话并行时只看到最新一条(
README.md:118)。 - 无工具进度百分比:DSH 没有工具进度事件,长工具只显示已耗时,没有像 pi 版那样的"还剩 ~11s"(
README.md:120)。 - 无动画帧:TUI 槽位渲染静态文本片段;pi 版的 moon/comet/braille 动画预设需等 prompt 槽位契约支持帧回调后再做(
README.md:121)。 - Web 端需 runtime 补丁:
ConversationSnapshot.activity字段由patches/webui-working-activity.patch接入官方 rc.6 runtime;官方若把该字段合入发布线,补丁即退役,宿主升级后保持兼容(src/client/activity.ts:8-15)。 - Web 双入口:输入区
WorkingLine与聊天区TurnStatus渲染同一快照;dock 条目覆盖全部阶段,旧补丁的回合级标签不再单独存在(README.md:122/docs/dsh-working-activity.md:205-206)。 - narration 是注入约定不是协议:模型自述的"⏵ 你在做什么"依赖模型遵守
before_agent_start时追加的 system prompt 段;不支持该约定或不输出的模型看不到这一行(src/index.ts:93-94/src/status.ts:472-480)。 - 不区分 DSH 提示词面:插件向 system prompt 注入自述约定会增加少量 token;固定且小(单段文本),对缓存稳定性无影响,但每轮都重发(
README.md:103-105)。
让 agent 的"工作状态行"活过来——实时工具动态与进度、俏皮文案、模型自述、上下文预警。同一套想法,适配两个平台:pi CLI 与 DeepSeek Harness(DSH)。
作者:chimney(@ccch1mneyyy)。社区出品,非官方项目。
本仓库分为 pi和dsh两个版本,两个 npm 包继续独立发布,各自的安装方式不变。
平台一览
| 平台 | npm 包 | 源码位置 | 安装 |
|---|---|---|---|
| pi CLI | pi-working-activity | extensions/ | pi install npm:pi-working-activity |
| DeepSeek Harness | dsh-working-activity | packages/activity/working-activity/ | dsh plugin --profile <profile> add dsh-working-activity |
目录结构
extensions/ pi 版扩展(唯一源码,无构建)
tests/ pi 版测试
package.json pi 版包(发布 pi-working-activity)
packages/activity/working-activity/ DSH 版插件(发布 dsh-working-activity)
patches/webui-working-activity.patch DSH Web UI runtime 补丁
docs/dsh-working-activity.md DSH 版完整文档(原 dsh 仓库 README)
pi 版
让 pi 的 Working 行活过来——实时工具动态与进度 + 俏皮中文文案 + 稀有彩虹彩蛋 + 模型自述 + 上下文预警。
功能一览
🛠 真实工具活动
监听 tool_execution_start / tool_execution_end,Working 行实时显示正在跑什么——不是假转圈。
翻翻 src/index.ts
改改 package.json
跑命令 npm run build
搜搜 NARRATE_MIN_MS
📈 实时工具进度
监听 tool_execution_update,优先读取工具返回的百分比、阶段和状态;对 bash 等流式输出,也会识别常见的下载、构建、测试和部署进度。
拉取模型权重 · 42% · 8s
跑命令 npm test · Testing integration · 12s
部署一下 staging · Deploying assets · 31s
普通输出不会直接塞进 Working 行,只有结构化进度、百分比和可识别阶段会展示。
⏩ 快工具队列重播
执行时间 < 1.5s 的工具一闪而过?不会。快工具排队逐个播 1s,最后一条粘留 3s,让你看得到。
💬 俏皮文案池
思考时 Working 行轮换 95 条口语化短句,约 2.6s 一换,像活人在说话。
嗯…让我捋捋 → 盘一下盘一下 → 大脑转起来了 → 思考.gif → 啾,让我想想 → lol → 别催别催
想太久了自动换档:
- 🕐 30s:转圈圈… 马上马上 嗯,让我细想想
- 🕑 1min:还在努力… 烧脑中… 这题有点东西
- 🕒 5min:还没放弃… 这题真的硬… 我给跪了…
🎰 稀有彩虹彩蛋
约 1/150 概率(每 6–7 分钟一次),Working 行炸出炫彩流光,停留 7.5 秒。
✦ S S R ! ✦ ✧ 金色传说 ✧ ✶ 你发现我了 ✶
四层特效叠加:平滑色相梯度慢滚 + 亮度波浪呼吸 + 一道带下划线的高光从左扫到右 + 两侧金边花饰轮转。比 1.0 的均匀彩虹有质感得多。
⏵ 模型自述
默认开启。扩展通过 context 事件向模型注入一条约定:每个步骤开始时写 ⏵ 你在做什么(≤20 字)。扩展实时解析流式输出,把自述显示在 Working 行。不需要可在配置里设 "narrate": false 或 /activity narrate off。
⏵ 查一下报错原因 → Working 行:查一下报错原因 · 搜搜 error.log
⏵ 给补丁跑个验证 → Working 行:给补丁跑个验证 · 跑命令 node test
📊 实时配速
- 思考中:
嗯… · 总1m23s - 工具中:
改改 file.ts · 3s - 结束后:底部状态区闪现
搞定 ✓ · 4 工具 · 想3s 干2s,同时对话区末尾弹通知⏱ 总用时 1m23s · 4 工具 · 想12s 干11s
⚠ 上下文预警
每 3s 检查一次 context 用量。超过阈值(默认 80%)时 Working 行亮黄:
⚠ 上下文85% · 嗯… · 总1m23s
contextWarnAt: 0 关闭。
🔥 连击检测
连续 5+ 工具触发 火力全开×N(并行工具也算连击)。10+ 工具收尾时显示 十连击。
⏱ 慢工具提示
单工具超 30s 亮 这个有点慢 · 前缀。
⏳ 工具剩余时间
工具回报进度百分比时,按已耗时和完成比例推算剩余时间(支持 percent / percentage / progressPercent / current/total):
拉取模型权重 · 42% · 还剩~11s
没有百分比进度的工具不显示,不影响其他信息。
🌿 git 分支上下文
检测到 git 操作(git/gh 等工具名,或 bash 类命令里带 git )时,Working 行显示当前分支(缓存 20s,异步获取不阻塞):
拉代码 · main · 3s
非 git 仓库自动隐藏。
🌙 时间感知
- 0–6 点:思考池混入
修仙中…夜猫子出没熬夜冠军等深夜专属文案 - 周末:首次会话弹一句
周末也在卷?放假也陪你
🎨 28 个动画预设
/activity 打开交互选择器,或 /activity frames <name> 直接切:
claude braille moon comet spark breathe dots circle star2 flip aesthetic hamburger random …
😐 英文冷幽默
lol hm oh ok um heh uh nah mm wow nice rgrg done again gg ez
混在一堆「嗯…」「盘一下」「啾」中间,冷不丁冒一句面无表情的英语。那种「我也不是真的在笑」的冷感。
❌ 工具失败文案
出错的工具不再只是 ✗,而是随机一句:
翻车了 · 读文件 config.json ✗
权限不对? · 跑命令 npm i ✗
🤖 子代理计数
并行多个子代理时显示 小弟×N:
派个小弟 修测试 · 小弟×3 · 另 2 项
⚡ ~tok/s 流式速率
showTokPerSec: true 后,按 text_delta 的中英文字符粗估流式 token 速率:
~42 tok/s · 嗯… · 总1m23s
Pi 的流式事件不提供逐段 usage,因此这是实时估算值;收尾摘要里的 token 数仍使用模型返回的实际 usage。
🎄 节假日彩蛋
元旦、春节、情人节、愚人节、劳动节、儿童节、万圣节、平安夜、圣诞、跨年——自动检测,思考池混入节日专属文案,同样用七彩流光渲染。
🔄 模型切换梗
/model 切模型时,Working 行闪一句和模型名相关的梗,1.5s 后恢复。
☕ 累计活跃提醒
默认每累计活跃 3 小时弹一次提示,提醒喝水休息。只有 agent 真正运行的时间计入;workRemindAt: 0 关闭,或改成其他间隔(小时数)。
💰 成本与 token 核算
每轮结束时(≥3s)在通知里追加本轮成本和 token 总量,直接读 Pi 官方核算的 usage.cost.total——和你的账单一致,不是估算。
⏱ 总用时 2m12s · 15 工具 · 想 123s 干 6s · 💰 $0.087 · 🔥 34.2k tok
/activity stats 查看更详细的分项:本轮 / 会话累计花费、缓存命中率、思考 token。
| 字段 | 来源 |
|---|---|
| 💰 成本 | Pi 官方 usage.cost.total(含缓存折扣、阶梯价) |
| 🔥 token | input + output + cacheRead + cacheWrite |
| 缓存命中 | cacheRead / (input + cacheRead) |
| 🧠 思考 | reasoning token(output 的子集,不重复计费) |
🗜️ 上下文压缩感知
监听 session_compact 事件,上下文被压缩时闪现一条通知——和上下文预警形成完整闭环:警告 → 压缩 → 恢复。
🗜️ 上下文已压缩 · 45.0k→12.0k tok · 腾出 73%
🗜️ 溢出自动压缩 · 45.0k→12.0k tok · 腾出 73% · 将重试
压缩调用的成本也会自动累计到本轮/会话统计。
🔧 自定义工具映射
customActions 让你为自己的工具/MCP 定义文案映射,按工具名精确匹配(不执行配置中的正则):
{
"customActions": {
"my_deploy": ["部署一下", "上线中"],
"format_code": ["格式化", "整理代码"]
}
}
⚙ 交互设置面板
/activity settings 打开可搜索的设置面板,统一调整模式、动画、自述、速率、上下文阈值、活跃提醒和全部特性开关。
面板顶部会使用当前主题实时播放动画和文案预览;每次切换立即持久化,不需要退出面板。
🩺 内置 Doctor
/activity doctor 一次检查:
- 配置 JSON 是否可解析、阈值关系是否有效
- 当前预设和全部动画结构是否完整
- 特性键是否认识
- 当前主题能否提取 RGB accent
- 配置目录与文件是否真正可读写
🎭 双模式 + 特性开关
花埑功能全部可选。总开关一键切换:
/activity mode minimal → 只显示真实工具 + 计时 + 预警
/activity mode lively → 全套俏皮文案 + 彩蛋(默认)
单特性独立开关(覆盖模式默认):
/activity feature → 列出所有特性状态
/activity feature rareEggs off → 只关彩虹彩蛋
/activity feature shimmer auto → 恢复跟随模式
可开关特性:phrases(俏皮文案)rareEggs(彩虹彩蛋)nightPhrases(深夜文案)weekend(周末问候)holidays(节假日)combo(连击)failPhrases(失败文案)modelQuips(模型梗)shimmer(星辉扫过)continuePhrases(打断接梗)
安装
pi install npm:pi-working-activity
配置
~/.pi/agent/working-activity.json(首次运行自动生成):
| 键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
frames | string | "moon" | 动画预设名,"random" 每轮随机 |
narrate | boolean | true | ⏵ 模型自述开关(默认开,显式 false 关闭) |
contextWarnAt | number | 80 | 上下文预警阈值(百分比),0 关闭 |
contextDangerAt | number | 95 | 上下文危险阈值,超过后变红 |
showTokPerSec | boolean | false | 流式输出时显示 ~tok/s 估算速率 |
workRemindAt | number | 3 | 累计活跃 N 小时提醒喝水,0 关闭 |
customPhrases | string[] | [] | 追加到思考文案池的自定义短句 |
customActions | object | — | 自定义工具→文案映射,如 {"my_tool": ["搞一下","整一个"]} |
debugLog | boolean | false | 调试日志(~/.pi/agent/working-activity-debug.log,>512KB 自动截断) |
mode | string | "lively" | "minimal" 只保留功能性信息 |
features | object | — | 单特性开关,如 {"rareEggs": false},覆盖 mode 默认 |
命令
| 命令 | 说明 |
|---|---|
/activity settings | 打开可搜索设置面板,实时预览动画和文案 |
/activity doctor | 检查配置、主题、预设和持久化权限 |
/activity | 打开动画预设交互选择器 |
/activity frames <name> | 直接切换预设,如 /activity frames claude |
/activity frames random | 每轮随机一个预设 |
/activity narrate on|off | 开关模型自述 |
/activity mode lively|minimal | 总开关:花哨 / 极简 |
/activity feature | 列出所有特性开关状态 |
/activity feature <名> on|off|auto | 单特性开关,auto 恢复跟随模式 |
/activity status | 显示当前所有配置 |
/activity warn <0-100> | 修改上下文预警阈值,0=关闭 |
/activity danger <n> | 修改红色危险阈值,必须不低于 warn 阈值 |
/activity tps on|off | 开关流式 ~tok/s 估算显示 |
/activity remind <0-24> | 设置累计活跃提醒间隔,0=关闭 |
/activity phrase add <文案> | 追加自定义思考短语 |
/activity phrase list | 列出所有自定义短语 |
/activity stats | 本轮+会话统计:工具数、想/干比、💰成本、🔥token、缓存命中、思考 token |
/activity config export | 导出当前配置 JSON 到当前目录 working-activity.export.json |
/activity config import <路径> | 从文件导入配置并立即生效(自动校验) |
模型自述原理
- 扩展通过
before_agent_start把约定追加到该轮 system prompt:「每一步写⏵ 你正在做的事(≤20 字)」 - 模型在流式输出中写下
⏵ 查一下报错原因 - 扩展实时解析
text_delta,提取最新⏵行展示在 Working 行 - 每个 LLM turn 重置等待态;自述最低展示 2s,流式活跃时不消失,安静 5s 后退回普通文案
文案风格
- 中文:短、口语、俏皮,不说教不摆谱
- 英文:面无表情的冷幽默,穿插在中文文案中制造反差
- 游戏梗(SSR、金色传说、gg、ez)只放在稀有彩蛋池(1/150 爆率),不影响日常使用
DSH 版
DeepSeek Harness 的实时"工作状态行"插件:模型的实时活动——俏皮思考文案、真正在跑的工具、已耗时、收尾摘要——在 agent 干活时展示在 Web UI 与 dsh-cc 终端上。
安装
dsh plugin --profile <你的 profile> add dsh-working-activity
装好 dsh-cc-tui 后同装本插件,dsh-cc 状态栏会消费 activity/status 事件流渲染工作状态行。Web 端需要额外的 runtime 补丁,见下方文档。
文档
- DSH 版完整文档(原 dsh-working-activity 仓库 README:特性、挂载机制、配置、已知限制)
- 插件包 README:
packages/activity/working-activity/README.md(英文)与README.zh.md
开发
cd packages/activity/working-activity
pnpm install && pnpm run build # 构建(host tsc + client tsc,产物进 lib/)
pnpm run build:client # 构建浏览器 bundle(tsdown → lib/client.js)
pnpm test # 单测 + 集成测试(状态机/文案/自述/集成)
已知限制
- 单一状态行:每会话一条,Web/终端消费端显示最近活跃会话。
- 无进度百分比:DSH 没有工具进度事件,长工具只显示已耗时。
publish默认关闭:追加activity/status会话事件目前会导致会话日志无法 resume,仅对支持 ignorable append 的宿主开启(详见插件 README)。
隐私与安全
两个版本都不采集、不上传任何数据,无网络请求、无遥测。pi 版配置与文案只存在本地;DSH 版 activity/status 仅写入本地会话日志(log-only 事件,模型不可见,回放忽略)。
License
根仓库文档与 pi 版:MIT。DSH 插件包(packages/activity/working-activity/):BSD-3-Clause(见其 package.json 与 LICENSE)。