# 安装教程(dsh-balance-chart) > **English quick start** is at the [bottom of this page](#english-quick-start). > 本页是面向「没写过插件、也不熟命令行」的用户的分步教程。全部照做大约 5 分钟。 --- ## 目录 - [第 0 步:确认前置条件](#第-0-步确认前置条件) - [第 1 步:把仓库下载到本机](#第-1-步把仓库下载到本机) - [第 2 步:把插件装进 web profile](#第-2-步把插件装进-web-profile) - [第 3 步:把插件挂到配置树里](#第-3-步把插件挂到配置树里) - [第 4 步:刷新浏览器](#第-4-步刷新浏览器) - [第 5 步:确认真的装好了](#第-5-步确认真的装好了) - [以后怎么更新](#以后怎么更新) - [怎么卸载](#怎么卸载) - [排错手册](#排错手册) - [English quick start](#english-quick-start) --- ## 第 0 步:确认前置条件 装插件之前,先确认下面三件事。**任何一件没满足,插件都不会出现,而且报错会很难懂**,所以别跳过。 ### ① Node.js ≥ 20 打开终端(Windows 用 PowerShell),执行: ```powershell node --version ``` 看到 `v20.x` / `v22.x` / `v24.x` 之类就对了。如果提示「不是内部或外部命令」,先去 装一个 LTS 版本。 ### ② DSH 已经装好,而且 `dsh web` 能正常打开 ```powershell dsh --version ``` 然后确认你现在能在浏览器里打开 DSH 的界面。本教程按默认地址 `http://127.0.0.1:3080` 讲解; 如果你改过端口,把下文所有 `3080` 换成你自己的端口即可。 > 如果你还没装 DSH:`npm i -g @deepseek-ai/dsh`,然后 `dsh web` 启动。 ### ③ DSH 的凭据里有 `DEEPSEEK_API_KEY` 插件读余额用的就是这个凭据(和 `llm-deepseek` 用的是同一个,不需要你再填一次)。 **没有它也能装、也能用** —— 只是余额那一层会显示「余额不可用」, 而「每轮对话花了多少钱」(价卡换算那一路)照常工作。 ### ④ 搞清楚你的 `DSH_HOME` 在哪 DSH 把 profile 和数据都放在 `DSH_HOME` 下,默认是用户目录里的 `.dsh`: | 系统 | 默认 `DSH_HOME` | profile 的 patch 文件 | |---|---|---| | Windows | `C:\Users\<你的用户名>\.dsh` | `C:\Users\<你的用户名>\.dsh\profiles\web\cordis.patch.yml` | | macOS / Linux | `~/.dsh` | `~/.dsh/profiles/web/cordis.patch.yml` | 在 PowerShell 里可以直接打印出来: ```powershell if ($env:DSH_HOME) { $env:DSH_HOME } else { "$env:USERPROFILE\.dsh" } ``` > 下文凡是出现 `$DSH_HOME` 的地方,都替换成上表或上面命令输出的那个真实路径。 > macOS / Linux 上 `~/.dsh` 一般就是你看到的样子,不用替换。 --- ## 第 1 步:把仓库下载到本机 **⚠️ 关键:这个目录要长期留着。** 插件不是被复制进 DSH 的,而是 DSH 里放了一个**链接指向这个目录**。 你如果把目录删了、挪了,插件会立刻失效。 推荐放在用户目录下(不要放在 `Downloads`、临时文件夹、或会被清理工具扫到的地方): ```powershell # Windows(PowerShell) cd $env:USERPROFILE git clone https://github.com/fqsklm/dsh-balance-chart.git ``` ```bash # macOS / Linux cd ~ git clone https://github.com/fqsklm/dsh-balance-chart.git ``` **没有装 git?** 也可以不用 git:在仓库页面点绿色的 `Code` → `Download ZIP`, 解压到 `C:\Users\<你的用户名>\dsh-balance-chart`(macOS/Linux 是 `~/dsh-balance-chart`)。 缺点是不能用 `git pull` 更新,以后要更新得重新下载解压。 记住这个目录的**绝对路径**,下一步要用: ```powershell # 确认目录里有 package.json 和 lib 文件夹 Get-ChildItem "$env:USERPROFILE\dsh-balance-chart" ``` --- ## 第 2 步:把插件装进 web profile DSH 自带的 `dsh plugin` 命令会把这个包登记为 web profile 的依赖(`link:` 表示「链接到本机目录」,不是从 npm 下载)。 **在仓库目录里**执行(`$PWD` 就是当前目录): ```powershell # Windows(PowerShell) cd $env:USERPROFILE\dsh-balance-chart dsh plugin --profile web add link:$PWD ``` ```bash # macOS / Linux cd ~/dsh-balance-chart dsh plugin --profile web add link:"$PWD" ``` > **想直接写绝对路径也行**,效果完全一样: > ```powershell > dsh plugin --profile web add link:C:\Users\1kg\dsh-balance-chart # Windows,注意别加引号 > dsh plugin --profile web add link:/Users/you/dsh-balance-chart # macOS > dsh plugin --profile web add link:/home/you/dsh-balance-chart # Linux > ``` **怎么知道成功了?** 命令会输出一段安装日志(`+ dsh-balance-chart 1.0.0`),并且 `$DSH_HOME/profiles/web/package.json` 里会出现这么一条: ```json "dependencies": { "dsh-balance-chart": "link:C:/Users/you/dsh-balance-chart" } ``` 顺便还能看到一个关键字段——web profile 的 patch 是**热重载**的,这正是第 4 步不用重启的原因: ```json "dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-balance-chart"], "patchReload": "live" } } ``` > **这一步之后插件还没生效。** `add` 只是让它「可被加载」,真正把它挂进配置树的是下一步。 --- ## 第 3 步:把插件挂到配置树里 打开 `$DSH_HOME/profiles/web/cordis.patch.yml`,在文件末尾加上这三行**结构完全一致**的内容 (YAML 对缩进敏感:`- insert:` 顶格,下一层缩进 4 个空格,再下一层缩进 6 个空格): ```yaml - insert: - id: balance-chart name: dsh-balance-chart ``` **用记事本 / VS Code 打开都行**: ```powershell # Windows:用记事本打开(路径按你的实际 DSH_HOME 调整) notepad "$env:USERPROFILE\.dsh\profiles\web\cordis.patch.yml" ``` ```bash # macOS open -e ~/.dsh/profiles/web/cordis.patch.yml # Linux xdg-open ~/.dsh/profiles/web/cordis.patch.yml # 或者在终端里直接追加 cat >> ~/.dsh/profiles/web/cordis.patch.yml <<'EOF' - insert: - id: balance-chart name: dsh-balance-chart EOF ``` ### ⚠️ 这一格最容易踩的坑 **文件原本长这样**(新 profile 的默认内容,最后一行是一个空的数组字面量): ```yaml # Your patch layer for this dsh profile, applied after every bundle layer: # ... [] - insert: ← ❌ 这样加是错的:`[]` 和 `- insert` 不能共存,整份文件会解析失败 - id: balance-chart name: dsh-balance-chart ``` **正确做法:把那个 `[]` 删掉**,改成下面这样(注释留着无所谓): ```yaml # Your patch layer for this dsh profile... - insert: - id: balance-chart name: dsh-balance-chart ``` 三步自查: 1. 全文**只有一个** `insert:` 段落。(重复插入会产生两行同 id 的 loader 行,两个实例会抢同样的 HTTP 路由并报错。) 2. `id` 是 `balance-chart`,`name` 是 `dsh-balance-chart`(**前面没有 `./`、没有 `link:`、不能带 `/`**)。 3. 缩进是「4 空格 + 6 空格」,**不是 Tab**。 ### 为什么激活行要放在这里,而不是包自带的 `cordis.patch.yml` 里? 这是**故意**的设计:web profile 的 `patchReload: live` 只监听 profile 自己的 patch 文件, 所以写在这里能做到**改完立刻生效、不用重启 `dsh web`**。 插件包自带的 `cordis.patch.yml` 因此是空的(`[]`);如果两边都写 `insert`,就会出现上面说的「重复 loader 行」。 --- ## 第 4 步:刷新浏览器 **回到 DSH 的页面,按 F5**(macOS 用 +R)。 客户端那半(画图表的代码)是浏览器从 DSH 拉的 bundle,必须重新拉一次才会挂上插槽。 **「其实装好了但看不见」十有八九就是漏了这一步。** 刷新后,在**打开任意一个会话**的情况下,标题栏第二行(「对话 / 轨迹」那一行)的正中就会出现卡片。 如果只开了欢迎页 / 没有打开会话,标题栏不存在,自然也就没有卡片——先点进一个会话。 --- ## 第 5 步:确认真的装好了 三个层次,从浅到深: ### ① 肉眼 会话标题栏正中出现图表卡片:上行是峰谷时段条 + 「今日消耗 ¥x」,中间是柱状图 + 折线,下面是余额条。 窗口太窄时卡片会跟着缩(`min(640px, 54vw)`)。 ### ② 接口(不需要登录,仅本机) ```powershell curl.exe -s http://127.0.0.1:3080/dsh-balance/state ``` 应当返回一大段 JSON。想看得清楚点,只取几个关键字段: ```powershell curl.exe -s http://127.0.0.1:3080/dsh-balance/state | ConvertFrom-Json | Select-Object day, @{n='ok';e={$_.balance.ok}}, @{n='total';e={$_.balance.total}}, @{n='spent';e={$_.today.spent}}, @{n='points';e={$_.today.count}}, @{n='isPeak';e={$_.peak.isPeak}} ``` | 字段 | 含义 | 正常值 | |---|---|---| | `balance.ok` | 余额接口是否拿到了数据 | `true`(`false` 时看 `balance.error`) | | `balance.total` | 当前余额 | 你的真实余额 | | `today.spent` | 今日消耗(已结算 + 进行中的合计口径见 README) | `0` 起步,随对话增长 | | `today.count` | 今天已记录的轮次数 | 有对话就 > 0 | | `status.keyMissing` | 是否找不到 `DEEPSEEK_API_KEY` | `false` | ### ③ 日志 `dsh web` 的输出里应当出现: ``` balance-chart: mounted (ledger: C:\Users\<你>\.dsh\.dsh-balance-chart.json) ``` 所有本插件的日志都以 `balance-chart:` 开头。 ### 手动触发一次刷新 ```powershell curl.exe -s -X POST http://127.0.0.1:3080/dsh-balance/refresh ``` 也可以直接在界面里点 `⚙` → 「立即刷新余额」。 --- ## 以后怎么更新 ```powershell cd $env:USERPROFILE\dsh-balance-chart git pull ``` 然后按改动的部分决定要不要重启(**这是实测结论**): | 改了哪半 | 生效方式 | |---|---| | `lib/client.js`(界面) | 按 F5 即可。DSH 每 500ms 检测客户端 bundle,变了会广播新版本号。 | | `lib/index.js`(宿主) | **重启 `dsh web`**,再 F5。 | | `package.json` 的 `dsh.client` 声明 | 重启 `dsh web`。 | > 「宿主侧能不能不重启就热更新」这个问题已经试过五种方案,全部失败,原因写在 README 的常见问题里。 > 结论就一句:**改宿主代码 = 重启 `dsh web`**。 ### 如果 `git clone` / `git pull` / `git push` 连不上或报 TLS 错误 Windows 上遇到过两种,症状和修法都不一样,**先分辨再动手**: **① 连不上:`Failed to connect to github.com port 443`(等 20 秒后超时)** 这是 **DNS 解析出来的 IP 不通**(`github.com` 在不同地区会解析到不同的地址段,被墙或被运营商劫持时就会这样)。 先确认: ```powershell Resolve-DnsName github.com -Type A | Select-Object Name, IPAddress Test-NetConnection (Resolve-DnsName github.com -Type A).IPAddress -Port 443 ``` 如果 `TcpTestSucceeded` 是 `False`,但换成另外几个 GitHub 地址段是通的: ```powershell foreach ($ip in @('140.82.113.3','140.82.114.3','20.27.177.113')) { "{0} -> {1}" -f $ip, (Test-NetConnection $ip -Port 443 -WarningAction SilentlyContinue).TcpTestSucceeded } ``` 那就让 git 直接连那个能通的 IP(**只对当前仓库生效**,会正常校验 TLS 证书,因为 SNI 仍然是 `github.com`): ```powershell git config --local http.curloptResolve "github.com:443:140.82.113.3" ``` > 这个 IP 是 GitHub 的地址之一,随时可能变。它只是「临时绕开坏掉的 DNS」,不是长久之计—— > 换 DNS(比如 `1.1.1.1`)、或者把 `github.com` 的正确 IP 写进系统 hosts 才是根治。 > 换过 DNS 之后记得 `git config --local --unset http.curloptResolve`。 **② TLS 凭证错误:`schannel: AcquireCredentialsHandle failed: SEC_E_NO_CREDENTIALS`** 这是 Windows 的 schannel 拿不到当前用户的凭证(常见于受限权限 / 服务账户 / 特殊安全策略下运行的终端), 和仓库本身无关。换一个正常的 PowerShell 窗口、或者以你自己的账户重新打开终端再试通常就好了。 (注意 `http.sslBackend=openssl` 这条网上常见的偏方对 Git for Windows 的官方构建**无效**—— 那个构建只带 schannel,设了只会报 `Unsupported SSL backend 'openssl'`。) --- ## 怎么卸载 ```powershell # 1) 打开 $DSH_HOME/profiles/web/cordis.patch.yml,删掉你加的那段 insert # (如果删完之后文件空了,写一个 [] 进去) # 2) 移除依赖 dsh plugin --profile web remove dsh-balance-chart # 3) 回浏览器按 F5 ``` 数据文件 `$DSH_HOME/.dsh-balance-chart.json`(余额缓存 + 当日记录 + 你的设置)不会被自动删除: 想彻底清干净就手动删掉它,想留着以后重装就留着。 --- ## 排错手册 ### 卡片完全不出现 按顺序排除,每步都有明确的判据: 1. **打开的是会话页吗?** 卡片挂在会话标题栏的插槽里,欢迎页没有这个插槽。 2. **F5 过了吗?** 99% 的「设置看着都对但没显示」都是这个原因。 3. **`cordis.patch.yml` 改对了吗?** 对照[第 3 步](#第-3-步把插件挂到配置树里)的三条自查。 4. **依赖真的装上了吗?** 看 `$DSH_HOME/profiles/web/package.json` 里有没有 `dsh-balance-chart`。 5. **看 `dsh web` 的日志**有没有 `balance-chart:` 开头的报错。若是「重复路由 / duplicate route」,说明 loader 行插了两遍。 6. **重启 `dsh web`** 再 F5。这一步能把「patch 应用失败」的所有情况排除掉。 ### patch 应用失败会是什么表现? **注意:这类失败经常是「静默」的** —— 接口照常返回 200、旧的数据还在,看起来一切正常,只是新代码没生效。 所以判断「插件是否真的换上去」不能只看接口通不通,要看**新版本独有的东西** (比如 `/dsh-balance/state` 返回里有没有 `pending` / `trimmed` 字段)。 已知会导致整份 patch 回滚、旧树静默保留的写法: - specifier 写成**相对路径**(`./`、`../`)—— 运行期解析不了。 - specifier 带**子路径**(`dsh-balance-chart/host`)—— 包名解析器不接受含 `/` 的 specifier, 该行直接加载失败,**而且客户端半侧会从模块图里消失**。 - YAML 缩进错、Tab 缩进、`[]` 和 `- insert` 混写 —— 文件整体解析失败。 ### 「余额不可用」 说明 `api.deepseek.com/user/balance` 那一路没拿到数据。依次检查: - 凭据里有没有 `DEEPSEEK_API_KEY`(看 `/dsh-balance/state` 里 `status.keyMissing`)。 - `balance.error` 字段写着具体原因(`未配置 DEEPSEEK_API_KEY` / `余额接口 HTTP <码>` / 超时)。 - 网络能不能直连 `api.deepseek.com`;公司网络 / 某些地区需要代理,而 DSH 的 Node 进程未必继承了你的系统代理。 - 点「立即刷新余额」再看一次。 **余额不可用不等于插件坏了**:每轮消耗的换算值仍然照常工作,柱子照样画得出来。 ### 数字和平台对不上 依次对照(这些都是**设计上的已知取舍**,不是 bug): - 正在进行的那一轮还没结算:标题栏「今日消耗」含进行中,但柱子/折线只画已结算的,所以最右那根柱子会小一点。 - 插件加载之前发生的消耗不会补记(余额差值法是向前观测的,没有基准可还原)。 - 跨天那一笔的日期只能按观测时刻近似(昨晚 23:00 后的消耗记到今天那一格)。 - 余额接口只给两位小数,单轮几分钱以下的消耗靠价卡换算补齐。 - DeepSeek 调价了:去 `⚙` 里改价卡。 - 记账方式选的是「仅按价卡换算」而不是「余额差值优先」:后者最接近真实扣费。 ### 柱子底部被滚动条裁掉 / 突然出现一条很粗的原生滚动条 这是 Windows 上修过的一个真实 bug,触发条件很反直觉:**在 Chrome 里,只要给滚动条写了 `scrollbar-width`, `::-webkit-scrollbar` 的自定义样式就会被整块忽略、退回系统原生滚动条**(Windows 上是 10px、还带两枚箭头按钮), 比容器预留的高度多 3px,正好把柱子底部裁掉。 现在的做法是只写 `::-webkit-scrollbar{height:var(--dsh-scrollbar-width,8px)}` 跟着宿主主题走, 绝不写 `scrollbar-width`。如果你自己改样式时踩到同样的坑,量一下真实滚动条高度再决定预留多少,别写死数字。 ### 设置菜单被代码块挡住 / 全屏盖不住卡片 这是 `z-index` 的问题,而且**上限和下限都由宿主决定**: - 下限:宿主的吸顶元素在 `z-index:6`(代码块表头,就是「复制」那一行)、`7`(输入区 / 聊天槽)、`8`(宽度拖柄)。 - 上限:宿主 `shell.overlay` 那一层是 `z-index:20`——卡片必须低于它,否则全屏盖不住卡片。 所以卡片层级要落在 **8 < z < 20**,当前是 10。改之前先确认宿主的这几层有没有变。 ### 想彻底重来 ```powershell # 1) 删掉 cordis.patch.yml 里的 insert # 2) dsh plugin --profile web remove dsh-balance-chart # 3) 删掉数据文件(可选) Remove-Item "$env:USERPROFILE\.dsh\.dsh-balance-chart.json" -ErrorAction SilentlyContinue # 4) 重启 dsh web # 5) 重新走第 2、3、4 步 ``` --- ## English quick start `dsh-balance-chart` is a zero-dependency plugin for the DeepSeek Harness (DSH) web GUI that draws your DeepSeek **account balance**, **today's per-turn spend**, and the current **peak / off-peak pricing window** on the conversation header. Requirements: Node.js ≥ 20, a working DSH install (`dsh web` opens in your browser), and the `DEEPSEEK_API_KEY` credential already configured in DSH (the balance layer degrades gracefully without it). ```bash # 1) Clone somewhere permanent — DSH links to this directory, so don't delete or move it later. cd ~ && git clone https://github.com/fqsklm/dsh-balance-chart.git # 2) Register the package as a dependency of the web profile cd dsh-balance-chart dsh plugin --profile web add link:"$PWD" # 3) Activate it: append this to $DSH_HOME/profiles/web/cordis.patch.yml # (default $DSH_HOME is ~/.dsh; if that file currently contains a bare `[]`, replace it) # # - insert: # - id: balance-chart # name: dsh-balance-chart # 4) Press F5 in the DSH browser tab, then open any conversation. ``` Verify: `curl http://127.0.0.1:3080/dsh-balance/state` should return JSON with `balance.ok: true` and a growing `today.spent`. Update: `git pull` → press F5 for `lib/client.js` changes; restart `dsh web` for `lib/index.js` changes. Uninstall: remove the `insert` block from `cordis.patch.yml`, then `dsh plugin --profile web remove dsh-balance-chart`. MIT licensed. See the [README](../README.md) for the full documentation (Chinese).