Skip to content

Commit dd0df79

Browse files
committed
feat: 更新文档以反映首次 npm 发布和包元数据,添加发布脚本
1 parent d51e0f0 commit dd0df79

5 files changed

Lines changed: 49 additions & 96 deletions

File tree

‎README.md‎

Lines changed: 38 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# opencode-token-usage
22

3-
面向 **OpenCode 2** 的 token 用量插件,当前版本 **0.2.1**。SDK 依赖固定为 2.0.9,宿主已验证 2.0.9、2.0.10 和 2.0.11。在原生 TUI 侧边栏追加用量面板,统计当前会话所在的整棵会话树,包括未打开的子代理,并显示性能指标与当前查看会话的上下文占用。
3+
[![npm version](https://img.shields.io/npm/v/%40chenlongapps%2Fopencode-token-usage?logo=npm)](https://www.npmjs.com/package/@chenlongapps/opencode-token-usage)
4+
[![OpenCode 2](https://img.shields.io/badge/OpenCode-2-5A67D8)](https://opencode.ai/)
5+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6+
7+
面向 **OpenCode 2** 的 token 用量插件。在原生 TUI 中显示整棵会话树(含子代理)的 token、估算费用与性能指标,以及当前会话的上下文占用。
48

59
## 预览
610

@@ -20,109 +24,72 @@ TPS 48.7 tok/s
2024
TTFT 2.7s
2125
```
2226

23-
示例费用使用每百万 token 的 Input / Output / Cache Read / Cache Write 单价 $2 / $8 / $0.2 / $3。实际价格与上下文上限取自当前查看会话的活动模型。
27+
实际价格与上下文上限取自当前会话的活动模型。
2428

2529
## 安装
2630

27-
需要 Node.js 22+ 和 OpenCode **2.0.9、2.0.10 或 2.0.11**。更高版本的 OpenCode 尚未验证;npm SDK 依赖仍锁定为 2.0.9。
28-
29-
将 npm 包加入项目的 `opencode.json` 或 `opencode.jsonc`,保留已有插件:
30-
31-
```json
32-
{
33-
"plugins": ["@chenlongapps/opencode-token-usage"]
34-
}
35-
```
36-
37-
OpenCode 会下载并加载主插件与 TUI 入口。需要固定版本时可写成 `@chenlongapps/opencode-token-usage@0.2.1`。重启 OpenCode 并进入会话后,面板会追加到原生侧边栏;侧边栏的显示与宽度由宿主管理,终端需要足够宽,并且 CLI 设置 `session.sidebar` 为 `auto`。
38-
39-
OpenCode 2.0.9–2.0.11 在子代理视图中强制隐藏侧边栏,因此插件通过 `session.composer.top` 在输入区上方显示同一完整面板。进入子代理仍统计整棵会话树,费用、上下文用量与上限改用该子代理的消息和活动模型。
40-
41-
连接远程服务器时,可把相同 npm 包名加入本机 `~/.config/opencode/cli.json` 的 `plugins`,仅加载终端入口。配置路径遵循 `XDG_CONFIG_HOME`,没有项目级 `cli.json`。
42-
43-
### 从源码运行
44-
45-
在此仓库中执行:
31+
推荐使用 OpenCode 安装:
4632

4733
```bash
48-
npm ci
49-
npm run typecheck
50-
npm test
51-
npm run build
34+
opencode plugin add @chenlongapps/opencode-token-usage
5235
```
5336

54-
将仓库的绝对路径加入目标项目的 `opencode.json` 或 `opencode.jsonc`,保留已有插件:
37+
也可以在项目的 `opencode.json` 或 `opencode.jsonc` 中配置:
5538

5639
```json
5740
{
58-
"plugins": ["/absolute/path/opencode-token-usage"]
41+
"plugins": ["@chenlongapps/opencode-token-usage"]
5942
}
6043
```
6144

62-
然后在目标项目运行 `opencode`。根目录的 `index.js` 和 `tui.js` 转发到编译产物,适配 2.0.9–2.0.11 的本地目录发现方式。也可先验证独立打包产物:
63-
64-
```bash
65-
npm pack
66-
npm install --prefix /absolute/path/local-plugins ./chenlongapps-opencode-token-usage-0.2.1.tgz
67-
```
68-
69-
此时配置的插件路径为 `/absolute/path/local-plugins/node_modules/@chenlongapps/opencode-token-usage`。包包含编译后的 ESM 和类型声明,无需在使用时编译 JSX。
70-
71-
## 统计口径
72-
73-
- 沿当前会话的 `parentID` 找到根,再分页读取所有后代及其完整消息。进入子代理仍显示同一棵树的累计用量。
74-
- 统计服务端上报的 assistant 和 compaction 消息,包括压缩前历史及失败消息中已记录的用量。不根据文本长度估算 token,不计入没有关联消息的标题生成用量。
75-
- 按会话和消息 ID 保存快照,每次成功刷新替换旧值,重复事件不会累加两次。分叉会话属于独立会话树;继承历史只归原始来源,其副本不重复计费。分叉副本识别依据 OpenCode 2.0.9 的 ID 生成规则。
76-
- `Input` 不含缓存读取或写入;`Output` 不含 `Reasoning`。
77-
- `Total = Input + Output + Reasoning + Cache Read + Cache Write`。
78-
- `Cache Rate = Cache Read ÷ (Input + Cache Read + Cache Write)`;保留一位小数,分母为零时显示 `0.0%`。
79-
- `Cache Write` 和 `Cost` 仅在值大于零时显示。空会话保留其他统计行并显示零;首次读取显示 `Loading…` 和 `—`,首次失败显示 `Unavailable`。刷新失败保留上次完整结果,标注 `Not updated` 并自动重试。
80-
81-
### 性能指标
45+
安装后重启 OpenCode。主会话中的面板位于原生侧边栏;终端需要足够宽,且 `session.sidebar` 应设为 `auto`。宿主在子代理视图中隐藏侧边栏,因此插件会在输入区上方显示同一面板。
8246

83-
`TPS` 统计整棵会话树的模型生成速度,token 口径为 Output + Reasoning。已完成消息使用服务端记录的 `time.created → time.streamed` 总时长和真实 token 加权计算,即 `Σ(Output + Reasoning) ÷ Σ流式时长`。有活动生成时优先显示实时估算:合并所有活动流的 UTF-8 增量,按约 4 字节/token 换算并以 `~` 标记;完成刷新后自动替换为精确值。流式增量不会触发完整历史扫描。
47+
连接远程服务器时,可将包名加入本机 `~/.config/opencode/cli.json` 的 `plugins`,仅加载终端入口;配置路径遵循 `XDG_CONFIG_HOME`。
8448

85-
`TTFT` 是整棵会话树中可测 assistant step 从请求发出到首个模型输出的算术平均值。首输出包括文本、推理和工具输入增量。插件运行期间使用实时事件精确记录;加载历史时仅使用带可靠创建时间的首个 reasoning 或 tool 内容。纯文本历史没有首 token 时间戳,因此不以完成时间伪造样本,也不会拉低平均值。没有可用样本时隐藏对应性能行。
49+
## 指标口径
8650

87-
### 上下文用量
51+
| 指标 | 定义 |
52+
| --- | --- |
53+
| `Input` | 输入 token,不含缓存读取和写入 |
54+
| `Output` | 输出 token,不含推理 token |
55+
| `Reasoning` | 推理 token |
56+
| `Cache Rate` | `Cache Read ÷ (Input + Cache Read + Cache Write)` |
57+
| `Total` | 五类 token 之和 |
58+
| `Context` | 当前会话最后一次已完成压缩后的最新上下文用量,不随子树累计 |
59+
| `Cost` | 按当前会话活动模型重新估算的全树费用,不代表提供商账单 |
60+
| `TPS` | 全树 `Output + Reasoning` 的生成速度;生成中显示 `~` 估算值,完成后显示精确值 |
61+
| `TTFT` | 全树中可测 assistant step 的平均首 token 时间 |
8862

89-
`Context` 是面板的第一行(状态提示之后),只反映**当前查看会话本身**,不随子树累计:取该会话中最后一条带 `tokens` 的 assistant 消息的五类 token 之和,并且只搜索最后一次 `completed` 压缩之后的消息——与 OpenCode 侧边栏显示的口径一致。正在运行或失败的压缩不重置窗口;压缩刚结束而尚无新回复时隐藏该行,不回退到压缩前的数值。正在生成、尚无用量的最后一条消息会被跳过,沿用上一条有上报的消息。
63+
补充说明:
9064

91-
上限取当前查看会话活动模型的 `limit.context`,与 `Cost` 使用同一解析规则,因此切换模型后百分比立即更新。模型没有可用上限(缺失、为零、非有限值)或尚无用量的会话隐藏 `Context` 行。行内格式为 `已用 / 上限 (百分比%)`,百分比保留一位小数,用量超过上限时显示真实值。当前版本不显示进度条。
65+
- 用量覆盖当前会话树中的 assistant 与 compaction 消息,包括未打开的子代理;只使用服务端上报值,不按文本长度估算。
66+
- 分叉会话是独立会话树。继承消息副本只归原始来源,避免重复计费。
67+
- `Context` 仅搜索最后一次 `status === "completed"` 的 compaction 之后;没有可靠用量或模型上限时隐藏。
68+
- `Cost` 使用每条消息的传入 token 选择价格档位,`Output` 与 `Reasoning` 使用输出价格。缺失适用价格时按 OpenCode 官方行为回退为 0。
69+
- 首次读取失败显示 `Unavailable`;后续刷新失败保留上次完整快照、标注 `Not updated` 并自动重试。
9270

93-
### 估算费用
94-
95-
`Cost` 是按**当前查看会话的活动模型**重新估算的全树费用,不是提供商账单,也不累加历史消息中保存的 `cost`。它不使用每条消息自身记录的模型:同一会话里即使多条消息由不同模型生成,也统一按查看时活动模型的价格档位推算,因此混合模型会话的金额**不等于**按各消息实际模型计费之和——它回答的是"把这棵树按当前模型重跑一遍会花多少"。未选定模型时使用该会话位置的默认模型,切换模型后重新计算。
96-
97-
每条消息分别使用其传入 token 数(Input + Cache Read + Cache Write)选择价格档位:严格超过阈值才进入该档,多个档位适用时取最高阈值,否则用基础档。Output 和 Reasoning 都使用输出单价,最后合计各条消息的费用。
98-
99-
没有模型价格或适用档位时按 OpenCode 官方计费实现回退为 **0**。合法的免费模型也按其实际价格计算;价格请求失败会显示未更新状态。这里的“默认价格”并非内置的公开价格目录。
100-
101-
数字使用千位逗号分组并显示为四舍五入后的整数;例如 `1200 → 1,200`、`125000 → 125,000`、`1500000 → 1,500,000`。美元保留两位小数,正数不足一美分显示 `<$0.01`。
102-
103-
## 开发与验证
71+
## 开发
10472

10573
```bash
74+
npm ci
10675
npm run typecheck
10776
npm test
10877
npm run build
10978
npm run test:smoke
11079
```
11180

112-
`test:smoke` 需要本机 OpenCode 2.0.9、2.0.10 或 2.0.11、Python 3、可用的本地端口及 npm 网络访问。它打包并安装真实产物,在临时目录启动隔离的 OpenCode 服务和真实 TUI,通过带延迟的本地模拟提供商检查加载、实时 TPS 与 TTFT、完成后精确 TPS、用量与上下文刷新、真实子代理累计及模型切换。不会修改现有 OpenCode 配置或使用付费模型。终端捕获和测试记录保留在输出的临时路径。
113-
114-
维护者的首次发布、Trusted Publishing 和后续版本流程见 [npm 发布说明](https://github.com/chenlongapps/opencode-token-usage/blob/main/docs/releasing.md)。
115-
116-
2026-09-20 已通过类型检查、29 项自动化测试、构建和上述真实集成验证,详见 [验证记录](docs/verification.md)。
81+
`test:smoke` 会打包真实产物,并在隔离的 OpenCode 与本地模拟提供商中验证加载、刷新、子代理累计、模型切换、TPS 和 TTFT。它需要 Python 3、可用的本地端口和 npm 网络访问,不会修改现有 OpenCode 配置或调用付费模型。
11782

118-
架构:`usage.ts` 处理统计、上下文与格式化,`performance.ts` 处理 TPS、TTFT 与流式事件,`source.ts` 对接 v2 客户端和分页,`controller.ts` 合并刷新、隔离旧请求与处理失败,`tui.tsx` 渲染侧边栏。流式增量只更新内存中的性能指标;用量、会话和模型事件仍通过合并刷新重新分页扫描会话树,以保证历史完整性。超大历史的增量读取优化留待后续版本。
83+
从源码加载时,先构建项目,再将仓库绝对路径加入目标项目的 `plugins`。根目录入口会转发到已编译的 ESM 产物。
11984

120-
紧凑模式、`/usage` 和公开价格目录尚未实现,详见 [ROADMAP.md](ROADMAP.md)。
85+
- [路线图](ROADMAP.md)
86+
- [验证记录](docs/verification.md)
87+
- [发布说明](docs/releasing.md)
12188

12289
## 接口依据
12390

91+
- [OpenCode 2 插件开发](https://opencode.ai/v2/docs/build/plugins/)
12492
- [OpenCode 2 CLI 插件接口](https://opencode.ai/v2/docs/build/plugins/cli/)
125-
- [OpenCode 2 插件加载](https://opencode.ai/v2/docs/build/plugins/)
12693
- [CLI 设置](https://opencode.ai/v2/docs/cli/config/)
12794
- [TokenUsage 定义](https://github.com/anomalyco/opencode/blob/v2/packages/schema/src/token-usage.ts)
12895
- [官方计费实现](https://github.com/anomalyco/opencode/blob/v2/packages/core/src/session/usage.ts)

‎ROADMAP.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,4 @@ TTFT 2.7s
7474
## 后续评估
7575

7676
* [ ] 公开价格目录与更新策略
77-
* [ ] 首次 npm 发布(包元数据、CI、OIDC 发布工作流与本地验证已完成,待账号认证并发布到 registry)
77+
* [x] 首次 npm 发布:`@chenlongapps/opencode-token-usage@0.2.1`

‎docs/releasing.md‎

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,17 @@
11
# npm 发布
22

3-
包名为 `@chenlongapps/opencode-token-usage`。无作用域名称 `opencode-token-usage` 已由其他作者注册,不要修改为该名称。
3+
包名为 [`@chenlongapps/opencode-token-usage`](https://www.npmjs.com/package/@chenlongapps/opencode-token-usage),首次发布版本为 `0.2.1`。无作用域名称 `opencode-token-usage` 已由其他作者注册,不要修改为该名称。
44

5-
## 首次发布
5+
## Trusted Publishing
66

7-
1. 在 npm 创建或登录 `chenlongapps` 用户,或确认当前账号是 `chenlongapps` npm 组织成员并有发布权限。
8-
2. 在干净的 `main` 分支执行:
7+
若尚未配置,在 npm 包设置的 Trusted Publisher 中添加 GitHub Actions:
98

10-
```bash
11-
npm ci
12-
npm run typecheck
13-
npm test
14-
npm run build
15-
npm pack --dry-run
16-
npm login
17-
npm publish
18-
```
9+
- Organization or user:`chenlongapps`
10+
- Repository:`opencode-token-usage`
11+
- Workflow filename:`publish.yml`
12+
- Allowed action:允许 `npm publish`
1913

20-
`publishConfig.access` 已固定为 `public`,`prepublishOnly` 会再次执行类型检查和单元测试,`prepack` 会重新构建发布产物。首次发布需要按 npm 提示完成双因素认证。
21-
22-
3. 发布成功后,在 npm 包设置的 Trusted Publisher 中添加 GitHub Actions:
23-
24-
- Organization or user:`chenlongapps`
25-
- Repository:`opencode-token-usage`
26-
- Workflow filename:`publish.yml`
27-
- Allowed action:允许 `npm publish`
28-
29-
4. 创建 `v0.2.1` GitHub Release。发布工作流会发现该版本已经存在并跳过重复发布。
14+
创建 `v0.2.1` GitHub Release 时,发布工作流会发现该版本已经存在并跳过重复发布。
3015

3116
## 后续版本
3217

‎docs/verification.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
| `npm publish --dry-run` | 通过,完整执行 `prepublishOnly`、`prepack` 并确认 public access;未写入 registry |
1616
| `npm run test:smoke` | 通过,使用实际 `chenlongapps-opencode-token-usage-0.2.1.tgz` 安装产物 |
1717

18-
npm 发布前检查确认无作用域名称 `opencode-token-usage` 已由其他作者占用,因此本项目使用尚未注册且与 GitHub 仓库所有者一致的 `@chenlongapps/opencode-token-usage`。包元数据、公开 registry、GitHub Actions CI、Trusted Publishing/OIDC 发布工作流与首次发布说明已配置;首次实际发布仍需 `chenlongapps` npm scope 的账号权限与双因素认证。`npm audit` 报告 2 个 low、11 个 moderate、0 个 high、0 个 critical,均来自固定的 OpenCode 2.0.9 / OpenTUI / OpenTelemetry 依赖链,当前锁定版本下没有可直接应用的完整修复。
18+
npm 发布前检查确认无作用域名称 `opencode-token-usage` 已由其他作者占用,因此本项目使用与 GitHub 仓库所有者一致的 `@chenlongapps/opencode-token-usage`。`0.2.1` 已发布到 [npm](https://www.npmjs.com/package/@chenlongapps/opencode-token-usage),registry 查询确认 `latest` 指向 `0.2.1`。包元数据、公开 registry、GitHub Actions CI 与 Trusted Publishing/OIDC 发布工作流均已配置。`npm audit` 报告 2 个 low、11 个 moderate、0 个 high、0 个 critical,均来自固定的 OpenCode 2.0.9 / OpenTUI / OpenTelemetry 依赖链,当前锁定版本下没有可直接应用的完整修复。
1919

2020
新增测试覆盖:已完成 assistant 的 Output + Reasoning / 流式总时长加权 TPS;无效时间、零输出与 compaction 排除;reasoning/tool 历史 TTFT、纯文本历史不伪造样本、运行期样本覆盖历史;文本、推理、工具输入三类流式增量;UTF-8 字节估算、重复事件去重、并发活动流合并;无关会话忽略、新建子代理即时纳入、切换会话树清理;流式更新不读取数据源,完成后从估算 TPS 收敛到精确 TPS;性能行位于用量与费用之后,与前一组间隔一行,并保持格式与缺失隐藏。
2121

‎package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"typecheck": "tsc --noEmit",
4949
"test": "tsx --test test/*.test.ts",
5050
"test:smoke": "node scripts/smoke.mjs",
51+
"release:patch": "npm version patch",
5152
"prepublishOnly": "npm run typecheck && npm test",
5253
"prepack": "npm run build"
5354
},

0 commit comments

Comments
 (0)