# dsh-ollama-cloud-usage

[English](README.md) | 中文

DeepSeek Harness 插件：在设置页显示 **Ollama Cloud** 剩余额度，并支持在页面内直接填写或更换 Ollama Cloud API Key。它注册为 `settings.section`，id 为 `ollama-quota`，`order: -9`，因此导航位置紧跟内置的 **账号与余额** 页面。（“账号与余额”页面本身没有向插件开放的子插槽，无法在其中追加卡片，因此采用相邻的独立设置项。）

## 显示内容

| 项目 | 数据来源 |
| --- | --- |
| 会话窗口剩余额度 | `limits.session.usage`（`[0, 1]` 区间的小数） |
| 每周窗口剩余额度 | `limits.weekly.usage` |
| 各模型请求数 | `limits.<window>.models[].request_count` |
| 近 4 周费用与统计区间 | `activity.cost`、`activity.period` |
| 密钥来源 | 实际解析到的凭据引用名 |
| API 密钥编辑 | 通过 DSH Remote 调用 `credentials.describe` / `credentials.set` / `credentials.unset` |

数据来自 `GET https://ollama.com/api/usage`，请求头为 `Authorization: Bearer <key>`。这正是 `ollama.com/settings` 中 “Cloud usage” 面板使用的接口；本机守护进程 `127.0.0.1:11434` 没有额度路由。响应中不含套餐名称，也不含重置时间。

## 安装

从 npm 安装：

```sh
dsh plugin --profile <profile> add dsh-ollama-cloud-usage
```

从本地目录安装：

```sh
npm pack --pack-destination dist
dsh plugin --profile <profile> add "$(pwd)/dist/dsh-ollama-cloud-usage-0.2.0.tgz"
```

安装会同步 `dsh.profile.bundles`，profile 会应用新的 bundle 层。若 Host 行没有出现，重启应用即可；更新后的 Client 半需要刷新页面才能加载（桌面版不会监听 client bundle 变化）。

## 自定义 API 密钥

页面中的 **API 密钥** 卡片通过 DSH 内置的 `credentials` Remote 写入 `keyEnvs` 的第一个凭据引用——与“模型设置”里保存密钥的是同一条写入路径。保存后密钥存入 `$DSH_HOME/.credentials.yaml`，并立即重新读取额度；**清除** 会删除该条目。

- 卡片显示引用名、是否已配置，以及来源层（`env`、`file` 等）。
- 若该引用被只读来源（如进程环境变量）覆盖，页面会提示无法在界面修改，而不会悄悄写到下一个引用。
- 密钥不会被回显：输入框始终为空，快照路由也不返回任何密钥。
- 客户端没有 `credentials` Remote 时，会退化为手动配置提示。

## 配置

插件行支持以下字段，均为可选：

| 字段 | 默认值 | 含义 |
| --- | --- | --- |
| `keyEnvs` | `[OLLAMA_CLOUD_API_KEY, OLLAMA_API_KEY]` | 依次尝试的凭据引用；页面编辑的是第一个 |
| `usageUrl` | `https://ollama.com/api/usage` | 用量接口地址 |
| `refreshMs` | `60000` | 快照刷新间隔，最小 `5000` |
| `timeoutMs` | `15000` | 单次请求超时 |

profile patch 示例：

```yaml
- id: ollama-cloud-usage
  config:
    refreshMs: 120000
```

## 凭据

密钥通过 `ctx.credentials` 解析，可来自进程环境变量、`$DSH_HOME/.env`，或 `$DSH_HOME/.credentials.yaml` 的 `refs` 段：

```yaml
version: 1
refs:
  OLLAMA_CLOUD_API_KEY: <在 https://ollama.com/settings/keys 创建的密钥>
```

缺少密钥不会报错：页面会显示编辑框与配置提示。密钥不会进入浏览器——快照路由只返回额度小数、请求数、费用、引用顺序和错误标签。

## 文件结构

| 文件 | 作用 |
| --- | --- |
| `index.js` | Host 半：凭据解析、轮询 `/api/usage`、JSON 快照路由 |
| `client.js` | Client 半：`settings.section` 注册、额度界面与密钥编辑 |
| `cordis.patch.yml` | 插入插件行的 bundle patch |

## 验证

```sh
node --check index.js && node --check client.js
node scripts/verify.mjs
```

`scripts/verify.mjs` 离线驱动两半：Host 路由的正常/缺密钥/401/网络失败/`credentials/updated` 即时刷新路径，以及用贴近真实 Hook 语义的 React 桩渲染 Client 组件，覆盖密钥编辑的 describe/save/clear、只读分支和语言切换。

## Known Limitations and Deferred Work

- `ollama.com/api/usage` 非官方但稳定；响应不含套餐名与重置时间，页面只展示窗口用量。
- 用量为轮询并响应 `credentials/updated`，没有推送通道。
- 只有 `keyEnvs` 的第一个引用可在页面编辑，其余仅能通过配置提供。
