Bundle
dsh-web-archive
DSH Web 客户端插件:把会话里非正文的工具卡片(read/think/bash/...)合并折叠为输入框上方一个可展开的 "Deep Sleeping..." 小列表,前端不再显示一堆工具卡片。
- Source
- renat3u
- stars
- 8 stars
- License
- MIT
- Updated
- Updated 16 days ago
Readme
# dsh-web-archive
**Deep Sleeping...** — DeepSeek Harness (dsh) Web 模式的客户端插件。
把会话里**正文之外的所有 display**(工具卡片 read / bash / web_search / grep /
edit 等,以及消息内的 **Think 推理块**,含运行中的调用)折叠成内联的小卡片,
**无 emoji、与 Read/Think/Bash 卡片同款样式、放在它们原来的位置**:
- **每条消息的 think 组 + 其后紧跟的工具组合成一块**(落单的 think 组 /
工具组各自成块),工具组区域随块折叠、不留空白;
- 正文消息保持 `文本a - [折叠块] - 文本b - 文本c` 的原始结构。
```
Deep Sleeping... (3) ← 折叠态,点击展开
Deep Sleeping... (3) · 收起 ← 展开态,所有卡片原地显示
```
前端不再出现一长串 Read / Think / Bash 卡片;正文消息完全不受影响。
## 特性
- **零核心改动**:纯浏览器端插件,不修改 dsh 任何源码、不注册 slot key,
不会与内置工具卡片的 `conversation.chat.toolview` 注册冲突。
- **零运行时依赖**:bundle 完全自包含,不 require 任何模块表条目。
- **Think 也折叠**:消息内的推理块(`data-variant="think"`)与工具卡片
一并合并。
- **实时跟随**:MutationObserver + rAF 合并,流式新卡片、卡片结算、切换
会话都自动重放折叠状态。
- **选择联动**:折叠态下若有行被选中(详情联动),自动展开该簇,避免
看不到正在查看的卡片。
- **主题适配**:颜色走 dsh 的 `--dsw-*` CSS 变量(带兜底值),明暗主题
都可用。
## 工作原理
ChatView 渲染时对每个工具调用行写入稳定 data 属性:
| 元素 | 属性 |
|---|---|
| 会话流容器 | `[data-chat-flow]` |
| 工具调用行(含运行中) | `[data-chat-call-id]` / `data-chat-anchor-key="call:…"` |
| Think 推理块行 | `[data-variant="think"]` 且无 `data-tool` |
| run_code 子派发行 | 位于 `[data-subcalls]` 内(不折叠,跟随父卡片) |
| 正文消息 | `data-chat-anchor-key="node:…"`(不折叠,且会断开簇) |
插件只做两件事:
1. 把 `[data-chat-flow]` 里的**非正文行**——顶层 `[data-chat-call-id]`
工具卡片行 + `[data-variant="think"]` 且无 `data-tool` 的推理块行——
`display:none`(React 的 vdom diff 不会覆盖 CSSOM 上的手动样式);
2. 把**每个回合合成一块**:某条消息的 think 组与紧跟其后的工具组(跳过
装饰元素)合并,在 think 消息的**原位**插入一张与工具卡片同款样式的
小卡片(`Deep Sleeping... (N)`,N = think 行数 + 工具卡片数),工具组
元素随块折叠;点击切换展开/收起。落单的 think 组 / 工具组各自成块。
正文消息保持 `文本a - [折叠块] - 文本b - 文本c` 的原始结构。
注入的 chip 在 React 管理的 flow 子树内,但只做前置插入与 display 切换,
MutationObserver + rAF 合并重放,React 重渲染/切换会话/流式新卡片都会自动
跟上(自愈);卸载时全部还原。
## 安装
插件以 **bundle 层** 方式挂载进 dsh web profile(`package.json` 里的
`dsh.bundle.patch` 声明 + 包内 `cordis.patch.yml` 的 `insert` 行),
`dsh.client` 声明(`platform: "web"`)让 client-modules 服务自动注入浏览器 bundle。
> 命令形式:官方约定源码 checkout 场景统一用 `pnpm dsh <args...>` 运行
> TypeScript 入口并透传参数(见下文「运行与构建」);npm 全局安装后可直接
> `dsh <args...>`。下文命令按 `dsh …` 泛称书写。
### 方式一:本地路径
```sh
pnpm dsh plugin --profile web add file:/path/to/dsh-web-archive
```
`dsh plugin add` 会 pnpm 安装依赖,并把声明了 `dsh.bundle` 的包自动加进
profile 的 `dsh.profile.bundles` 层列表。
### 方式二:手动挂载(等价于上面的结果)
1. 把插件放进 profile 的 node_modules(pnpm 风格软链):
```sh
ln -s /path/to/dsh-web-archive $DSH_HOME/profiles/node_modules/dsh-web-archive
```
2. 在 profile manifest(`$DSH_HOME/profiles/web/package.json`)里登记:
```json
"dependencies": { "dsh-web-archive": "file:/path/to/dsh-web-archive" },
"dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-web-archive"] } }
```
3. 重启 web 表面(源码环境 Ctrl+C 后重跑 `pnpm dsh web`),刷新页面。
> 注:profile 的 `cordis.patch.yml` 用户层与 bundle 层走同一个 patch
> 算法,支持 `insert` 行;长驻表面(web profile)通过 watch-only HMR
> 热重放用户层——新插入的行不需要重启即可挂载(新增的 client 行要等一次
> 页面刷新让浏览器拿到新的 `window.__DSH_BOOT__` 图)。bundle 层
> (`dsh.profile.bundles`)的增删则要重启 web 表面才生效。
## 运行与构建
官方源码构建形式(仓库 checkout 内):
```sh
pnpm install # 安装依赖(一次性)
pnpm run build # 准备仓库产物(一次性)
pnpm dsh web # 启动 Web UI,无需重新构建
```
`pnpm dsh <args...>` 是官方约定的源码运行形式(`dsh web` 是
`--profile web` 的别名)。`pnpm install` **不会**把 `dsh` 注册进 shell 的
全局 PATH——`pnpm dsh` 每次都要带前缀。裸 `dsh` 命令需要 npm 全局安装
(`npm install -g @deepseek-ai/dsh`),或走官方安装包示例
`npx @deepseek-ai/dsh web`。开发 client 插件时可另开 `pnpm run dev:web`
(官方 dev 监视器):它重建 client bundle 并触发 client-hmr 热替换;新增
插件行仍需一次页面刷新拿到新的 boot 图。
插件自身 bundle 构建:
```sh
node build.mjs # 产出 lib/client.js(esbuild,自包含 iife)
```
构建走本地 devDependency esbuild(JS API,无 shell 依赖);仓库根执行
`npm install`(或 pnpm install)后即可运行。`lib/client.js` 随包提供,
改 `src/` 后重新构建即可。
## 文件结构
```
dsh-web-archive/
├── package.json # dsh.client + dsh.bundle 声明 + npm 发布元数据 + exports["./client"]
├── cordis.patch.yml # bundle 层:insert 一行挂载本插件
├── build.mjs # 构建脚本(esbuild;prepack 钩子调用)
├── tsconfig.json
├── src/
│ ├── index.ts # host half:空 apply(让插件出现在宿主插件树)
│ ├── client.ts # browser half:cordis 插件入口
│ └── deep-sleep.ts # DeepSleepController:折叠/展开核心
└── lib/
├── index.js # host half 产物
├── client.js # 浏览器 bundle(已构建)
└── types/ # 手写类型声明(index.d.ts / client/index.d.ts)
```
## 兼容性
DOM 契约基于官方 Web 客户端 ChatView 渲染的稳定 data 属性:
`data-chat-flow` / `data-chat-call-id` / `data-chat-anchor-key` /
`data-subcalls` / `data-selected` / `data-state` / `data-variant`。
当前构建的 CSS Modules 类名是短哈希,正文检测不使用类名字面量,而是文本
节点 walker(跳过 think 行 / 工具卡片 / 插件自身的 chip),对类名变化
免疫。官方后续版本若改动这些属性,更新 `src/deep-sleep.ts` 顶部的
选择器即可。
Install
dsh plugin --profile web add github:renat3u/dsh-web-archive#777ae5ec25d391dee8ea2087b6db67cb89e8a378
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-web-archive from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.