前言
OpenCode Go 有滚动 / 每周 / 每月三档配额,但 TUI 里默认看不到。我做了一个侧边栏插件 opencode-usage-widget,把用量画进 Files 区块下面,并支持自动刷新。本文记录实现思路、几个真正踩过的坑,以及怎么装、怎么用。
仓库:github.com/crayonxiaoxin/opencode-go-usage · npm:opencode-usage-widget
它长什么样
侧边栏会出现可折叠的 Go Usage。默认展开;点击标题折叠。折叠状态写在 OpenCode KV(opencode.usage.open),下次启动会恢复。
展开时,Rolling / Weekly / Monthly 各自一条进度条、百分比,以及该窗口自己的重置倒计时(精确到剩余分钟,例如 in 3h 15m、in 2d 4h 15m)。折叠时标题旁显示三档里最高的百分比,例如 ▶ Go Usage 90%。

实现思路
这是一个 TUI 插件,不是 server 插件。入口导出 { id, tui },在 tui(api, options) 里做三件事:注册侧边栏插槽、注册手动刷新命令、在 dispose 时清掉定时器和进行中的请求。
api.slots.register({
order: 600,
slots: {
sidebar_content() {
return <UsageWidget api={api} store={store} />
},
},
})
sidebar_content 和内置的 Context / LSP / Files 并列渲染,order 默认 600,排在 files(500)后面。
模块大致分成:
usage-api.ts:请求GET {base}/zen/go/v1/usage,解析 rolling / weekly / monthly。credential.ts:按优先级找 API key。use-usage.ts:Solid signal 状态机(loading / ready / error),被动刷新。format.ts+widget.tsx:颜色阈值、倒计时文案、可折叠 UI。
刷新是被动的:启动拉一次;订阅 session.idle(每次回复结束);默认 300 秒定时;命令面板里的 usage.refresh。失败会退避,dispose 时 AbortController 取消进行中的请求。
几个关键坑
1. 密钥不在 path.state 里
api.state.path.state 是 XDG state 目录(常见 ~/.local/state/opencode),不是密钥所在处。API key 在 data 目录:~/.local/share/opencode/auth.json(先 opencode-go 再 opencode,且必须是 type: "api")。OAuth token 过不了用量接口的 KeyTable 校验,需要在 opencode.ai/auth 生成 API key,或设 OPENCODE_API_KEY。
2. TUI 里的 fetch 会被包到本地 server
TUI 的 globalThis.fetch 可能被转到本机 OpenCode server,用量请求会 404。插件默认走 node:https 的 nativeFetch,绕过包装。
3. 本地开发不要加载 dist
OpenCode 能直接编译源码里的 JSX。本地把 tui.json 指到 file://…/src/index.tsx。如果指到打包后的 dist/tui.js,很容易打进第二份 solid-js / @opentui/solid,侧边栏渲染异常。
4. bun build 打出来的包:插件 active,侧边栏却是空的
这是发 npm 时踩到的。命令面板里 Refresh usage 在,说明 tui() 已经执行、slots.register 也成功了。但 bun 默认 JSX 会生成:
import { jsxDEV } from "@opentui/solid/jsx-dev-runtime"
插槽返回的节点和宿主 TUI 对不上,区块就是空白。正确做法是用 esbuild-plugin-solid(generate: "universal",moduleName: "@opentui/solid"),让产物 import 宿主的 createElement,并把 solid-js / @opentui/* 全部 external。另外:不要设 main,否则会被当成 server 插件;opencode plug 安装带 --ignore-scripts,tarball 里必须已经有 dist/tui.js。
怎么用
需要 OpenCode >= 1.18.0,以及带套餐的账号和 API key。
从 npm 安装(推荐):
opencode plug opencode-usage-widget -g
去掉 -g 则只装当前项目。也可以在 TUI 的 Plugins 对话框用 shift+i。装完后完全退出再打开 OpenCode。钉死版本:opencode plug opencode-usage-widget@0.1.1 -g;覆盖已有条目加 --force。
从源码安装(开发时): 在 ~/.config/opencode/tui.json 写入:
{
"$schema": "https://opencode.ai/tui.json",
"plugin": [
["file:///绝对路径/opencode-go-usage/src/index.tsx", { "order": 600 }]
]
}
必须用 file://,不要用裸路径。改源码后同样要完全重启 TUI。
常用选项:apiKey、baseUrl(自托管)、order、refreshInterval(秒,0 关定时器)、showWhenUnavailable(无凭证时是否隐藏整块)。手动刷新走命令面板 usage.refresh。
总结
- TUI 插件走
sidebar_content插槽 + Solid 状态,不要和 server 插件混在一个入口。 - 密钥在 data 目录的
auth.json,用量请求必须绕过 TUI 包装过的fetch。 - 本地用源文件;npm 产物必须用 Solid 的 universal 编译,而不是 bun 默认 JSX。
如果你也在给 OpenCode 写侧边栏插件,这三件事基本能避开我们走过的弯路。
/ DISCUSS
讨论
还没有留言,来留下第一条评论吧!