dsh-opencode-usage

OpenCode Go 套餐用量显示插件(DSH Web):输入框下方常驻徽章显示滚动 / 每周 / 每月用量百分比与重置倒计时,点击展开进度卡片;Agent 可经 opencode_go_usage 工具随时查询余额。

DSH 官方 bundle 插件,安装一条命令: ``` dsh plugin --profile web add github:vinyumao/dsh-opencode-usage# ``` [English](README.md) | **中文** ## 能力面 | 工具 | 说明 | | --- | --- | | `opencode_go_usage` | 对话中查询 OpenCode Go 套餐余额:三个窗口的已用百分比与重置倒计时(无参数) | | UI 能力 | 说明 | | --- | --- | | 常驻徽章 | 输入框(composer)下方一行:`OpenCode Go:滚动用量 0% · 每周用量 0% · 每月用量 0%`,按配置间隔自动刷新 | | 用量卡片 | 点击徽章展开:三个窗口的进度条 + 已用百分比 + 重置倒计时(每秒走动)+ 立即刷新 + `opencode` 链接(新标签页打开网页端用量面板) | | 配置表单 | 卡片内直接填写 API key / Base URL / 刷新间隔 / 用量网页 URL,保存即生效 | | 双语界面 | 中文 / English——所有文案跟随全局 DSH 语言设置(设置 → 通用 → 语言),卡片底部也内置 中文 / English 切换按钮(切换整个 GUI 语言) | | Key 复用 | API key 默认取环境变量 `OPENCODE_GO_API_KEY`——与 DSH 的 opencode-go 模型提供商配置(`settings.yaml` 中 `apiKeyEnv`)一致,通常**零配置可用** | ## 原理 用量来自 OpenCode Go 订阅套餐的配额接口: ``` GET https://opencode.ai/zen/go/v1/usage Authorization: Bearer # 即普通的 Anthropic 兼容 API Key ``` 响应示例: ```json { "usage": { "rolling": { "status": "ok", "percent": 0, "resetsAt": "2026-…Z" }, "weekly": { "status": "ok", "percent": 0, "resetsAt": "2026-…Z" }, "monthly": { "status": "ok", "percent": 0, "resetsAt": "2026-…Z" } } } ``` > ⚠️ **存疑标注**:该接口**未写入 OpenCode 官方公开文档**,由 [cc-switch 社区](https://github.com/farion1231/cc-switch/issues/6433) 发现(issue 中附有验证脚本)。响应结构可能随 opencode 变动;本插件做了防御性解析(`usage.` 前缀与裸窗口、`resetsAt` 与 `resetsInSeconds` 两种形式均可识别),结构若变更请以实际响应为准。 浏览器不直接访问上游:所有请求经宿主进程的 `/api/dsh-opencode-usage/*` 路由代理(同源 fetch),**API key 不进入浏览器**。 ### 关于 OpenCode Zen 本插件**仅面向 Go 套餐**——它展示的是订阅配额窗口,只有 OpenCode Go 才有。OpenCode Zen 是另一套**按量付费**网关(预充值余额、按 token 计费),**没有等价的 API-key 鉴权余额接口**:官方功能请求([anomalyco/opencode#10448](https://github.com/anomalyco/opencode/issues/10448)「Add Zen balance API endpoint」)至今仍未实现;社区中能显示 Zen 余额的工具都依赖抓取工作区 billing 页面的浏览器 cookie(脆弱方案,如 [CodexBar](https://github.com/steipete/CodexBar/blob/main/docs/opencode.md))。若未来 OpenCode 提供公开的 Zen 余额 API,本插件可增加 `plan` 选项接入。 ## 安装 > **零运行时 SDK 依赖**:host 半部分**不 import 任何 `@deepseek-ai/*` 运行时包**——Agent 工具按 `ctx.tools.register` 直接接受的原始可注册形状编写(`output.schema` 为标准 JSON Schema,含 `render`/`execute`),而不是用 `@deepseek-ai/dsh-tools` 的 `defineTool` 构建。这正是 git vendoring 安装(`dsh plugin add github:...`,会 clone 到工作区 `vendor/` 目录)能开箱即用的原因:Node 永远不需要从插件自己的 `node_modules` 解析 `@deepseek-ai/*`,因为插件根本不 import 它们。(早期版本 import 了 `defineTool`;若遇到 `@deepseek-ai/dsh-tools` 的 `ERR_MODULE_NOT_FOUND`,请更新到最新 ref。) ### 方式一:`dsh plugin` 一条命令(推荐) 从任意目录执行: ```sh dsh plugin --profile web add github:vinyumao/dsh-opencode-usage# ``` `package.json` 声明了 `dsh.bundle.patch`,安装后自动进入 profile 的 `dsh.profile.bundles` 层栈并挂载 `cordis.patch.yml`。然后**重启 `dsh web`**,输入框下方出现余额徽章。 > git 安装拉取的是源码;本插件为纯源码(`index.mjs` / `client.js` 无构建步骤),装完即用,无需 `prepare` 脚本。若 pnpm 提示需要 `allowBuilds` 许可,请把 pnpm 打印的包 key 加入 profile 的 `pnpm-workspace.yaml` 后重试;为可复现安装,建议固定 `` 为 commit SHA(`#`)。 ### 方式二:手动接入 1. 在 profile 的 `package.json` `dependencies` 增加: ```json "@chen-001/dsh-opencode-usage": "github:vinyumao/dsh-opencode-usage#" ``` 2. 在 profile 目录执行 `pnpm install`。 3. 确认 profile 的 `dsh.profile.bundles` 已包含该包(`dsh plugin` 会自动 reconcile);或在其 `cordis.patch.yml` 增加: ```yaml - insert: - id: opencode-usage name: '@chen-001/dsh-opencode-usage' ``` 4. **重启 `dsh web`**,输入框下方出现余额徽章。 ### 给 AI(agent)的安装指引 若由 AI 助手代为安装,请按以下步骤执行: 1. **确认 dsh CLI 可用**:`dsh --version`。若在仓库源码环境运行,用 `pnpm dsh ...` 代替。 2. **安装**(`#` 建议固定为仓库最新 commit SHA): ```sh dsh plugin --profile web add github:vinyumao/dsh-opencode-usage# ``` - 首次会初始化 profile(自动带 `@deepseek-ai/dsh-base`)。 - 若 pnpm 拒绝执行 git 依赖的 prepare 脚本,将 pnpm 打印的包 key 加入 `$DSH_HOME/profiles/web/pnpm-workspace.yaml` 的 `allowBuilds` 后重跑。 3. **验证层栈**:`dsh --profile web --dump-config` 应能看到 `# == @chen-001/dsh-opencode-usage` 层(含 `opencode-usage` 行)。 4. **重启 web**:结束当前 `dsh web` 进程后重新启动。 5. **冒烟**:浏览器打开 DSH Web GUI,输入框下方应出现 `OpenCode Go:…` 徽章;对话中让 Agent 执行 `opencode_go_usage` 工具应返回三个窗口用量。 6. **告警排查**:若徽章显示「查询失败」,检查 `OPENCODE_GO_API_KEY` 环境变量是否已设置,或点击徽章在配置表单中填写 API key。 ## 卸载 与安装同一条 `dsh plugin` 命令即可卸载:它会在 profile 目录执行 `pnpm remove`,并自动把该插件从 `dsh.profile.bundles` 层栈中移除(无需手动改 `cordis.patch.yml` 或 bundles 列表): ```sh dsh plugin --profile web remove @chen-001/dsh-opencode-usage ``` 然后**重启 `dsh web`**:徽章消失,`/api/dsh-opencode-usage/*` 路由、`opencode_go_usage` 工具与 Agent 宣告一并卸载。 ### 可选清理 - **配置文件**:API key 明文存于 `~/.dsh/dsh-opencode-usage.json`(权限 0600)。若不打算重装,删除之:`rm ~/.dsh/dsh-opencode-usage.json`。(key 也可能被 DSH 的 opencode-go 模型提供商经 `OPENCODE_GO_API_KEY` 环境变量引用——那是独立配置,与本插件无关。) - **allowBuilds 条目**:若安装时曾把 pnpm 打印的包 key 加入 profile 的 `pnpm-workspace.yaml` 的 `allowBuilds`,可一并移除。 ### 手动兜底 若 `dsh plugin` 不可用,可在 profile 目录(`~/.dsh/profiles/web`)手动移除依赖与层条目: 1. `pnpm remove @chen-001/dsh-opencode-usage` 2. 删除 `package.json` 中 `dsh.profile.bundles` 里的 `"@chen-001/dsh-opencode-usage"` 行 3. 重启 `dsh web` ### 验证 - `dsh --profile web --dump-config` 不应再列出 `# == @chen-001/dsh-opencode-usage` 层。 - 重启后输入框下方不再出现 `OpenCode Go:…` 徽章。 ## 配置 API key 解析顺序:插件配置文件 → 环境变量 `OPENCODE_GO_API_KEY` → 无。 | 配置 | 默认值 | 说明 | | --- | --- | --- | | `apiKey` | 环境变量 | 在用量卡片「配置」中填写后存 `~/.dsh/dsh-opencode-usage.json`(权限 0600) | | `baseUrl` | `https://opencode.ai/zen/go` | 上游网关地址,末尾自动拼 `/v1/usage` | | `refreshSeconds` | `300` | 徽章自动刷新间隔(秒,最小 10) | | `webUsageUrl` | *(空)* | 卡片上 `opencode` 按钮打开的网页端用量面板,如 `https://opencode.ai/workspace//go`。workspace ID 与账号绑定、因人而异——请配置自己的,不要照抄别人的;留空则隐藏按钮 | | `enabled` / `announceToAgent` | `true` | 总开关 / 是否向 Agent 宣告插件 | 文件方式(可选): ```json // ~/.dsh/dsh-opencode-usage.json { "apiKey": "sk-…", "baseUrl": "https://opencode.ai/zen/go", "refreshSeconds": 300, "webUsageUrl": "https://opencode.ai/workspace//go" } ``` ## Agent 工具 `opencode_go_usage`(无参数)返回: ``` OpenCode Go 用量(https://opencode.ai/zen/go) 滚动用量:0%,重置于 3 小时 20 分钟 每周用量:0%,重置于 2 天 9 小时 每月用量:0%,重置于 30 天 22 小时 抓取时间:… ``` ## 安全 - `/api/dsh-opencode-usage/*` 仅限 loopback(含同源校验),LAN 暴露的部署不会泄漏代理的 key。 - API key 明文存于 `~/.dsh/dsh-opencode-usage.json`(0600),与 dsh-ssh 的凭据存储同一信任模型。 - 配置读取接口只返回 `hasApiKey` / `apiKeySource`,key 本身永不出宿主机。 ## 插件管理 已装插件可用 [plugin-registry](https://github.com/vlln/plugin-registry) 的**薄控制台**管理(浏览器面板):管理 profile 插件安装态(bundle 层栈 + insert 行 + 启停),无需手改配置。安装: ``` dsh plugin --profile web add github:vlln/plugin-registry/packages/plugin/console ``` ## 开发 ```sh node tests/sanity.mjs # 纯逻辑验证(解析/格式化/配置读写),无需 dsh 环境 node tests/routes.mjs # 路由层集成验证(loopback 围栏/方法守卫/JSON body) ``` ## 已知限制 - 徽章挂在 composer dock(会话打开时显示),无会话时不可见。 - 用量接口非官方文档化,结构可能变化(见「原理」)。 - 配置表单的 key 输入为「追加/覆盖」语义:留空保存 = 不改动现有 key;如需回退到环境变量,请手动编辑配置文件删除 `apiKey` 字段。 ## License [MIT](LICENSE)