# dsh-save-money

> 在用户自定义时间窗口内自动暂停长任务与模型请求，让 DeepSeek 等分时计价 API 高峰时段零扣费；支持余额显示与 10 分钟粒度消费柱状图。

## Metadata

- Author: [@zhu168](https://github.com/zhu168)
- Repo: <https://github.com/zhu168/dsh-save-money.git>
- GitHub: [zhu168/dsh-save-money](https://github.com/zhu168/dsh-save-money)
- Stars: 33
- Language: JavaScript
- License: [MIT](https://spdx.org/licenses/MIT.html)
- Topics: `dsh`, `dsh-plugin`, `dsh-plugins`
- Forks: 2
- Open Issues: 1
- Last push: 2026-08-18T11:05:22.000Z
- Added: 2026-08-19T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add github:zhu168/dsh-save-money/plugin
```

## Wiki

## 一句话定位
在用户自定义的时间窗口内自动暂停正在运行的 DSH 长任务与所有向模型的请求，窗口结束后自动恢复，让 DeepSeek 等分时计价 API 在高峰时段不产生任何费用；并附带可选的官方账户余额显示与近 8 小时消费柱状图。

## 核心能力
- 自定义多组暂停 / 继续窗口，支持跨午夜（如 23:00–08:00）与按星期过滤
- 到点自动暂停：正在运行的任务被安全"冻住"（进度原样保留），窗口结束自动恢复，没有任务在跑就不暂停
- 请求层闸门：暂停期间 AI 不向模型服务发出任何新请求，零扣费，手动交互始终放行
- 按模型档位决定是否省钱：官方 flash / pro、opencode flash / pro 共 4 个独立开关；无法识别的模型（旧名 `chat`/`reasoner`、第三方等）一律豁免
- 一次性"结束本次省钱模式"按钮：只跳过当前暂停窗口，"启用"总开关不受影响，下个窗口照常生效
- 顶部浮动横幅（即将暂停浅黄 / 已暂停浅红）+ 会话头部常驻彩色状态文字（颜色随状态实时变化），10 种语言 UI（zh / zh-TW / en / de / fr / es / it / pt / ja / ko，自动跟随浏览器）
- 可选 DeepSeek 官方账户余额显示 + 近 8 小时每 10 分钟粒度的消费柱状图（外部消费以警示色区分）
- 配置持久化到工作区 `save-money.config.json`，卸载 / 重装 / 重启不丢失；首次安装自动写到仓库目录而非污染 DSH 安装目录

## 技术实现
- **语言**: TypeScript（源），构建产物为 ESM JavaScript（`scripts/build.js` 把 `src/*.ts` 内联成单文件 `plugin/index.js` 与 `plugin/client.js`）
- **关键依赖**: `@deepseek-ai/dsh-client-ui-primitives`（运行时探测，缺失时回退自绘按钮）；DSH 内置服务（`timer` / `slots` / `agents` / `goals` / `fs` / `sandboxPolicy` / `webServer` / `tools` / `credentials` / `settings` / `subprocess`）；无第三方运行时依赖
- **架构模式**: dual-half 宿主插件（Host + Client），源码 → 官方 bundle 三种安装形态同源（`--patch` overlay / tgz bundle / link+HMR）
  - **Host 半边** (`src/host.ts`)：通过 `ctx.on('llm/stream', ...)` 在请求层拦截所有模型调用（闸门），通过 `ctx.get('goals')` + `ctx.get('agents')` 冻结/恢复长任务，`ctx.timer.interval` 每 30 秒驱动状态机（NORMAL → WARN → PAUSED），动态子模块 `src/config.ts` / `src/state.ts` / `src/host-goals.ts` / `src/balance-host.ts` / `src/gate.ts` / `src/host-tools.ts` / `src/host-http.ts` 在构建时内联
  - **Client 半边** (`src/client.ts`)：注入 `conversation.session.header.utilities` 槽（唯一常驻入口：彩色状态文字）+ `settings.section` 槽（系统设置"省钱插件"分节）+ `shell.overlay`（浮动横幅）；i18n 来自 `src/i18n/*.ts`（10 个语言字典在构建时内联）
  - **挂载声明**：`plugin/package.json#dsh.bundle.patch`（cordis overlay）+ `plugin/cordis.patch.yml`（插入插件行 `id: save-money`）
- **入口文件**: Host 入口 `src/host.ts`（导出 `{ inject: ['timer'], apply(ctx) {...} }`，构建产物 `plugin/index.js`）；Client 入口 `src/client.ts`（构建产物 `plugin/client.js`）；构建脚本 `scripts/build.js`（TS → JS）+ `scripts/make-plugin.js`（生成官方 bundle）；快速试用 overlay `cordis.patch.yml`

## 适用场景
当用户在 DSH 中使用 DeepSeek 等有峰谷分时计价的模型服务，且希望高峰时段（北京时间 09:00–12:00、14:00–18:00）零扣费时：本插件到点把任务冻住、闸门合上、请求彻底不发；窗口结束自动恢复，对话与任务进度原样保留。也可推广到任何"某个时间段不想让机器干活"的场景（自定义电价、自定义带宽错峰）。同时希望看到最近 8 小时每 10 分钟的官方账户消费粒度，用于核对账单与其他设备的消费归因。

## 前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DeepSeek Harness (DSH) | 未声明 | 插件未在 manifest 中显式声明 DSH 最低版本；采用标准 `ctx.on('llm/stream')` + `ctx.timer` + `ctx.get(...)` 注入模式，需 DSH 官方插件形态支持（典型为 0.1.0-rc.6 及以上） |
| Node.js | 未声明 | 仓库内 `package.json` / `plugin/package.json` 均未声明 `engines.node`；`package-lock.json` 中唯一的 `engines` 字段来自 `typescript` 开发依赖（>=14.17） |
| 平台 | 跨平台 | 不引入原生模块；配置落盘走 DSH `fs` 服务（兼容 Node `node:fs`），余额历史走 `~/.dsh/` |
| 原生模块 | 无 | 不依赖 `node-pty` / `node:sqlite` 等原生绑定 |

## 安装方式
```bash
dsh plugin --profile web add github:zhu168/dsh-save-money/plugin
```

## 配置项
所有配置均可在 DSH 设置 → 省钱插件 或会话头部"省钱 · 🟢"状态文字展开的浮层里可视化编辑；以下字段同时可通过 AI 工具 `save_money_configure` 编程式修改（节选自 `src/config.ts:26-58`、`src/host-tools.ts:31-66`，变更后即时校验、自动落盘）：

| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| `enabled` | boolean | 总开关：勾选后到点自动暂停、取消勾选立即恢复所有窗口 | `false` |
| `timezone` | string（IANA 时区名） | 时间窗口使用的时区；浏览器首次启动自动探测，失败回退北京时间 | `Asia/Shanghai` |
| `warnMinutes` | number | 距下个窗口还有多少分钟时进入"即将暂停"WARN 状态、显示浅黄横幅 | `5` |
| `windows` | array | 暂停 / 继续窗口列表，每项为 `{ pauseAt, resumeAt, days?, timezone? }`（HH:mm 字符串，days 为 1-7 数组表示周一到周日） | `[]` |
| `reconcileOnStart` | boolean | 启动时若发现仍在暂停中的目标，是否自动恢复（避免重启后永远冻住） | `true` |
| `lang` | enum | 界面语言：`auto`（跟随浏览器） / `zh` / `zh-TW` / `en` / `de` / `fr` / `es` / `it` / `pt` / `ja` / `ko` | `auto` |
| `showBalance` | boolean | 在会话头部状态文字旁显示 DeepSeek 官方账户余额（仅官方 API 调用后才会显示） | `false` |
| `modelApply.official-flash` | boolean | 暂停窗口内是否暂停官方 DeepSeek flash 模型（勾选 = 暂停省钱） | `true` |
| `modelApply.official-pro` | boolean | 暂停窗口内是否暂停官方 DeepSeek pro 模型 | `true` |
| `modelApply.opencode-flash` | boolean | 暂停窗口内是否暂停 OpenCode Go / Zen 的 flash 模型 | `false` |
| `modelApply.opencode-pro` | boolean | 暂停窗口内是否暂停 OpenCode Go / Zen 的 pro 模型 | `false` |

## 常见问题

**Q: 这个插件和 DSH 自带的"预算 / 费用"功能有什么区别？**

A: 官方费用工具是被动记账、给"超支提醒"；本插件是主动把闸门合上——到点不向模型发请求、不产生任何费用，并把正在运行的任务"冻住"等窗口结束再继续。

**Q: 安装之后页面上看不到"省钱"状态文字怎么办？**

A: 必须完全重启 DSH（Ctrl+C 停掉再启动）并强制刷新浏览器（Ctrl+Shift+R）——界面在启动时挂载。v1.2.5 之前的构建存在"启用勾不上 / 设置点不动"问题，请升级到最新版本。

**Q: 暂停期间 AI 不回复是 bug 吗？**

A: 不是 bug，是预期行为。暂停窗口内的设计就是"不发请求、不产生费用"，运行中的任务被冻结、对话上下文保留；窗口结束自动全部恢复，或点「结束本次省钱模式」立即恢复。

**Q: 配置文件存在哪里？卸载后会不会丢失？**

A: 配置自动落到工作区的 `save-money.config.json`（已 .gitignore）。位置按 6 级候选自动解析：指针文件 `~/.dsh/save-money-config-path.json` > 当前会话工作区 > 名为 dsh-save-money 的会话工作区 > DSH 启动目录 > 启动目录的同级 dsh-save-money 目录 > sandboxPolicy.workspaceRoot。卸载 / 重装不会动它，删除该文件即恢复默认。

**Q: 「结束本次省钱模式」会把总开关关掉吗？**

A: 不会。这个按钮是一次性的内存态操作，只结束**当前触发的这一个**暂停窗口；下一次窗口（今天或以后）照样生效，持久化的"启用"开关不会被改。想关掉所有窗口的省钱模式，手动取消勾选「启用」即可。

**Q: 余额显示只支持 DeepSeek 官方吗？**

A: 是的。余额与消费统计仅在最近一次模型请求跑在官方 DeepSeek 上时显示；其他厂商（硅基流动、中转等）的 Key 不会出现余额。余额历史按 API Key 指纹保存到 `~/.dsh/dsh-save-money-balance.json`，换 Key 自动作废旧历史。

**Q: 「一键 DeepSeek 分时计价策略」会自动启用吗？**

A: 不会。一键策略只会把高峰窗口去重追加进配置（北京时 08:58–12:02、13:58–18:02，提前 2 分钟 / 延后 2 分钟留余量），「启用」开关需用户自己勾选——由你决定。

**Q: 如何卸载？**

A: `dsh plugin --profile web remove dsh-save-money`，然后重启 DSH。配置文件 `save-money.config.json` 与余额历史 `~/.dsh/dsh-save-money-balance.json` 不会被删除，需要彻底清除可手动删除。

## 上手难度
入门 — 一行命令安装 + 重启 DSH + 在会话头部点开状态文字展开浮层勾选「启用」即可使用；进阶处是按需调整时间窗口、模型档位开关与时区。

## 已知问题与限制
- 安装 / 升级后必须完全重启 `dsh web`（Ctrl+C 停掉再启动）并强制刷新浏览器（Ctrl+Shift+R）才能看到界面，只刷新页面不会重新装载服务端插件（README.zh.md:298-306）
- 余额与消费统计仅支持 DeepSeek 官方 API：其他厂商（硅基流动、中转等）的 Key 不会出现余额与柱状图（src/balance-host.ts:88-130）
- 暂停窗口期间 AI 不回复是预期行为，但可能让用户误判为"AI 卡住了"；需配合横幅与状态文字的颜色变化判断当前是 NORMAL / WARN / PAUSED 中哪一种
- 任何无法识别的模型（旧名 `chat` / `reasoner`、其他第三方等）一律豁免暂停：如果你故意用旧名调用，会跳过闸门放行（src/host-tools.ts:33 / README.zh.md:28）
- 配置文件自动落到工作区，但首次安装若当前目录是 DSH 安装目录，插件会优先写到仓库目录并通过 `~/.dsh/save-money-config-path.json` 指针记录，避免污染 DSH 安装目录（src/config.ts:118-185）
- v1.2.2 之前的构建存在 `harness is not defined` 报错、v1.2.4 之前存在界面加载不全、v1.2.5 之前存在"启用勾不上"问题——务必升级到最新版本（README.zh.md:298-306）
- 插件未在 manifest 中显式声明 DSH 与 Node.js 最低版本要求；升级 DSH 大版本后建议先验证兼容

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [dsh-save-money](https://deepseek-plugin.org/plugins/zhu168/dsh-save-money/plugin)
Wiki generated by AI (model: `MiniMax-M3`)
