# dsh-plugin-compact-button [English](README.md) | 中文 DeepSeek Harness Web 输入框的压缩控件:一个按钮,就坐在模型选择器左边,点一下执行当前部署自己的 `/compact` 命令。 ## 它做什么 点它就压缩当前会话。按钮通过 Session 的命令通道提交裸 `/compact` 行,也就是说:持久化的尝试记录、压缩锁、摘要路由,以及 Chat 视图本来就渲染的那个流程节点,全都保持 `/compact` 自己那套。这个插件只贡献手势和它的本地化拒绝提示 —— 绝不另开一条压缩路径。 - **空会话** —— 不渲染;没有历史可压。 - **智能体运行中** —— 变灰、不可点击,但保持普通标签。手动压缩要求智能体空闲,可不是本控件发起的回合不该声称自己在压缩。 - **压缩中** —— 从手势起读作 `压缩中…`,直到压缩那个回合结束才回到普通标签。这段窗口是一个三步闩锁:手势置位 → 观察到回合启动 → 回合结束释放。只看运行状态是不够的 —— 在智能体本来就在运行时被准入的压缩,控件永远看不到「回合启动」这一步,这正是曾经导致压缩结束后标签卡在「压缩中」的情形。 - **被拒绝** —— 在输入框上方显示一行内联原因。传输失败显示宿主自己的消息;没有 `/compact` 命令的部署会被明确报为「能力缺失」,而不是看起来成功了。 ## 安装 ```sh dsh plugin --profile web add dsh-plugin-compact-button ``` 如果你用的 profile 不叫 `web`,换成你自己的名字。这个包声明了 `dsh.bundle`,所以 `dsh plugin` 会自动把它的 patch 层注册进 profile。重启 `dsh web` 并刷新页面;构建载荷是在启动时组合的,所以第一次光刷新不够。 ### 从 GitHub 检出安装 ```sh dsh plugin --profile web add github:liutian11451-png/dsh-plugin-compact-button ``` Git 安装拉的是源码而不是构建产物,所以这个包带了一个 `prepare` 脚本,用普通 tsdown 从 `src/` 构建 `lib/` —— 不需要同级仓库,也不做类型检查。pnpm ≥10 会拒绝执行 Git 依赖的 `prepare`,直到你显式允许,所以第一次 `add` 会以 `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED` 失败,并打印出该加的确切 key。Git 安装的 key 指向解析出来的 tarball,而不是光秃秃的包名: ```yaml allowBuilds: dsh-plugin-compact-button@https://codeload.github.com/liutian11451-png/dsh-plugin-compact-button/tar.gz/: true ``` 把 pnpm 打印出的那一行原样抄进去(它带着本次安装解析到的提交号),然后重新 `add`。注意:这条允许等于「准许在安装时于你机器上执行这个包的代码」,要把它当成这个意思看待。请固定到具体提交(`github:liutian11451-png/dsh-plugin-compact-button#`),免得以后一次 push 就悄悄换掉实际运行的代码。 一个换装时的坑:如果这个插件之前是**从本地目录**装的,请先移除。profile 的 `node_modules` 里残留的链接会和随后进来的 Git 安装冲突,pnpm 会在导入阶段以 `EPERM` 软链错误失败。 如果不想让使用者做这个允许,就发 npm,或者用 `pnpm pack` 出 tarball —— 这两种都不需要任何构建权限。 ### 本地目录 ```sh dsh plugin --profile web add /absolute/path/to/dsh-plugin-compact-button ``` ### 前提 部署必须挂载压缩能力 —— `dsh-command-compact` 加一个压缩后端。两者都在标准 preset 里。没有该命令时按钮仍会渲染,点击会返回明确的「能力不可用」原因;客户端事先无法知道宿主的命令目录。 ## 目录结构 ``` package.json # dsh.bundle + dsh.client 清单 cordis.patch.yml # 插入本包的加载器行 src/index.ts # 根半(空实现) src/client/index.ts # 浏览器半:注册座位 src/client/CompactButton.tsx # 控件本体 src/client/locales.ts # 中英字典 src/client/CompactButton.module.css # 芯片外观与拒绝提示条 tsdown.config.ts # 消费侧构建 smoke.mjs # 加载器契约冒烟测试 ``` 根半是刻意留空的。harness 的客户端模块注册表是**遍历宿主 Loader 的行**来发现 `dsh.client` 包的,所以这个包需要一行已挂载的行作为载体 —— 那行的全部作用就是这个。 ## 开发 ```sh pnpm install pnpm build # 产出 lib/index.js 和 lib/client.js pnpm typecheck node smoke.mjs # 用桩 shell 求值构建出的浏览器半 ``` `smoke.mjs` 检查两条容易写坏、且要到启动才暴露的契约:产物必须接受 `window.__ModuleLoader__.load({ id, factory })` 交接并返回 `module.exports`;`apply()` 必须注册恰好一个 `conversation.input.right` 条目,其注入的动词提交 `/compact` 并把三种准入结果都折叠成文案。 ### 两条构建契约 浏览器包不是普通的 ESM 构建。shell 会抓取 `lib/client.js` 并求值它,所以这个文件必须是 CommonJS 闭包工厂 —— 这就是 `tsdown.config.ts` 里 `banner`、`intro`、`footer` 的由来。ESM 或没有这层包装的产物会在启动时抛错。 shell 模块表能回答的标识符(`react`、`react/jsx-runtime`、`cordis`、共享的 UI primitives 与 store)保持 `require(...)` 调用;其余全部内联。模块表回答不了的 `require` 是必然的运行时抛错,所以构建配置里的 external 列表是显式写死的,而不是从包的依赖里推导。 ## 已知限制 - **手势的可用性取决于命令** —— 没有 `dsh-command-compact` 的部署会渲染按钮,点击后给出「能力不可用」的原因。 - **准入不等于完成** —— 命令 RPC 在宿主准入该行时就返回,所以 `压缩中…` 覆盖的是「从手势到压缩回合结束」这段窗口。由自动策略发起的压缩、或任何别的回合,都不会改这个标签;控件在该回合运行期间只是变灰。 - **忙碌标签是有界的,不是精确的** —— 被准入、却始终没有可观察回合的尝试,会在 8 秒宽限期后释放,因为客户端拿不到可以等待的压缩生命周期。若压缩比这更晚才开始,控件会提前显示为空闲。 - **不能选区** —— 控件总是提交无参数形式,压的是后端自己认定的范围,永远不是手挑的片段。 - **仅空闲智能体** —— 智能体运行时变灰不可点,与 `compactNow` 的要求一致;它不是回合中途强制压缩的手段。 - **仅 Web profile** —— 声明了 `platform: web`;没有终端界面上的等价物。 ## 许可证 MIT