# working-activity

> DeepSeek Harness 的实时"工作状态行"插件：把会话事件折叠成俏皮思考文案、正在运行的工具与已耗时，同时投递给 TUI 提示符与 Web 客户端。

## 元数据

- 作者: [@ccch1mneyyy](https://github.com/ccch1mneyyy)
- 仓库: <https://github.com/ccch1mneyyy/working-activity.git>
- GitHub: [ccch1mneyyy/working-activity](https://github.com/ccch1mneyyy/working-activity)
- Star: 649
- 主语言: TypeScript
- License: [MIT](https://spdx.org/licenses/MIT.html)
- Topics: `deepseek-harness`, `dsh-plugin`, `pi-coding-agent`, `pi-plugin`, `statusline`, `working-line`
- Fork: 231
- Open Issues: 1
- 最后推送: 2026-08-16T16:33:10.000Z
- 加入目录: 2026-08-16T00:00:00.000Z

## 安装

```bash
dsh plugin --profile web add github:ccch1mneyyy/working-activity
```

## 百科

## 一句话定位
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 slot `apply(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、不发网络请求 |

## 安装方式
```bash
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`）。

---

本文档由 [deepseek-plugin.org](https://deepseek-plugin.org) 自动生成，对应 HTML 页面: [working-activity](https://deepseek-plugin.org/plugins/ccch1mneyyy/working-activity)
百度百科由 AI 生成 (模型: `MiniMax-M3`)
