@chenlongapps/opencode-token-usage 0.4.5 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/README.zh-CN.md +8 -4
- package/dist/context-capture.d.ts +5 -3
- package/dist/context-capture.js +31 -14
- package/dist/context-sources.js +4 -1
- package/dist/controller.d.ts +2 -2
- package/dist/controller.js +7 -5
- package/dist/performance.js +5 -3
- package/dist/prices.generated.d.ts +81 -5
- package/dist/prices.generated.js +11 -5
- package/dist/pricing.d.ts +1 -1
- package/dist/tui.js +227 -206
- package/dist/usage.d.ts +6 -4
- package/dist/usage.js +11 -8
- package/docs/verification.md +92 -0
- package/package.json +9 -9
package/dist/usage.d.ts
CHANGED
|
@@ -128,11 +128,13 @@ export interface ContextUsage {
|
|
|
128
128
|
limit: number;
|
|
129
129
|
percent: number;
|
|
130
130
|
}
|
|
131
|
-
export interface
|
|
132
|
-
usage: ContextUsage;
|
|
131
|
+
export interface RequestDetails {
|
|
133
132
|
tokens: Tokens;
|
|
133
|
+
total: number;
|
|
134
|
+
/** The selected assistant's stream end, completion, or creation time, in that order. */
|
|
135
|
+
time?: number | undefined;
|
|
134
136
|
}
|
|
135
|
-
export declare function
|
|
137
|
+
export declare function requestDetails(messages: readonly UsageMessage[], revertMessageID?: string): RequestDetails | undefined;
|
|
136
138
|
export declare function contextUsage(messages: readonly UsageMessage[], limit?: number, revertMessageID?: string): ContextUsage | undefined;
|
|
137
139
|
export declare function formatTokens(value: number): string;
|
|
138
140
|
export declare const formatCost: (value: number) => string;
|
|
@@ -152,7 +154,7 @@ export declare function bar(percent: number, width: number): {
|
|
|
152
154
|
* One model request: the five categories of the last assistant call plus its cache rate.
|
|
153
155
|
* Compact mode hides zero rows and drops percentages; detailed mode keeps both.
|
|
154
156
|
*/
|
|
155
|
-
export declare function requestRows(details:
|
|
157
|
+
export declare function requestRows(details: RequestDetails, compact: boolean): readonly (readonly [string, string])[];
|
|
156
158
|
/** Tree summary rows for the dialog's detailed Session view, calls included. */
|
|
157
159
|
export declare function summaryRows(summary: Summary): readonly (readonly [string, string])[];
|
|
158
160
|
/** `1 step` reads better than `1 steps` in the dialog's single-line summaries. */
|
package/dist/usage.js
CHANGED
|
@@ -150,13 +150,12 @@ export function summarizeModels(messages, catalog = new Map()) {
|
|
|
150
150
|
})).sort((a, b) => b.cost - a.cost || a.model.localeCompare(b.model));
|
|
151
151
|
}
|
|
152
152
|
const usableLimit = (value) => value !== undefined && Number.isFinite(value) && value > 0;
|
|
153
|
+
const usableTime = (value) => value !== undefined && value >= 0 && Number.isFinite(new Date(value).getTime());
|
|
153
154
|
// Matches the OpenCode 2.0.10 sidebar: the last assistant message with tokens that follows
|
|
154
155
|
// the last completed compaction carries the current context size. Running or failed
|
|
155
|
-
// compactions do not reset it
|
|
156
|
-
//
|
|
157
|
-
export function
|
|
158
|
-
if (!usableLimit(limit))
|
|
159
|
-
return undefined;
|
|
156
|
+
// compactions do not reset it. Missing token reports are skipped, while an explicit
|
|
157
|
+
// zero report is not replaced by older usage. Request details need no model limit.
|
|
158
|
+
export function requestDetails(messages, revertMessageID) {
|
|
160
159
|
// The staged revert excludes its boundary message and every later message.
|
|
161
160
|
// Session.message.list is ascending; an absent marker can occur during a
|
|
162
161
|
// concurrent commit, in which case the ordered ID still gives the cutoff.
|
|
@@ -178,12 +177,16 @@ export function contextDetails(messages, limit, revertMessageID) {
|
|
|
178
177
|
continue;
|
|
179
178
|
const tokens = normalize(message.tokens);
|
|
180
179
|
const used = total(tokens);
|
|
181
|
-
|
|
180
|
+
const time = [message.time?.streamed, message.time?.completed, message.time?.created].find(usableTime);
|
|
181
|
+
return used > 0 ? { tokens, total: used, time } : undefined;
|
|
182
182
|
}
|
|
183
183
|
return undefined;
|
|
184
184
|
}
|
|
185
185
|
export function contextUsage(messages, limit, revertMessageID) {
|
|
186
|
-
|
|
186
|
+
if (!usableLimit(limit))
|
|
187
|
+
return undefined;
|
|
188
|
+
const request = requestDetails(messages, revertMessageID);
|
|
189
|
+
return request ? { used: request.total, limit, percent: request.total / limit * 100 } : undefined;
|
|
187
190
|
}
|
|
188
191
|
export function formatTokens(value) {
|
|
189
192
|
return Math.round(safe(value)).toLocaleString("en-US");
|
|
@@ -251,7 +254,7 @@ export function requestRows(details, compact) {
|
|
|
251
254
|
return [
|
|
252
255
|
...rows.map(([label, count]) => [
|
|
253
256
|
label,
|
|
254
|
-
compact ? formatCompact(count) : `${formatTokens(count)} (${(count / details.
|
|
257
|
+
compact ? formatCompact(count) : `${formatTokens(count)} (${(count / details.total * 100).toFixed(1)}%)`,
|
|
255
258
|
]),
|
|
256
259
|
["Cache Rate", `${(incomingTokens ? t.cache.read / incomingTokens * 100 : 0).toFixed(1)}%`],
|
|
257
260
|
];
|
package/docs/verification.md
CHANGED
|
@@ -1,5 +1,97 @@
|
|
|
1
1
|
# 验证记录
|
|
2
2
|
|
|
3
|
+
## 2026-10-09 · 统计钩子的 MCP 等待上限
|
|
4
|
+
|
|
5
|
+
环境:macOS、Node.js v22.23.2、npm 10.9.8,插件包仍为 0.4.6、SDK 2.0.24,真实宿主为 PATH 中的 OpenCode 2.0.25。未升级版本、提交、推送或发布。
|
|
6
|
+
|
|
7
|
+
MCP 元数据缓存缺失或失效时,共享读取默认最多等待 100 ms,构造参数可注入测试预算。独立定时器结束等待,同时通过 SDK 的 `AbortSignal` 请求中止读取;忽略取消的迟到成功/失败不会更新缓存或清除后续读取。超时或错误时复用旧元数据,不延长缓存 TTL,后续请求可重试;无缓存则跳过本次估算,保留已有估算与时间戳,不写入伪造零值。成功读取的空列表仍是有效缓存。持久化继续按会话顺序异步执行。
|
|
8
|
+
|
|
9
|
+
| 检查 | 结果 |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| `npm run typecheck` | 通过 |
|
|
12
|
+
| `node --import tsx --test test/context-capture.test.ts` | 专项 14 项通过,新增 11 项回归测试 |
|
|
13
|
+
| `npm test` | 129 项通过 |
|
|
14
|
+
| `npm run build` | 通过 |
|
|
15
|
+
| `npm run test:smoke` | 完整通过,打包/隔离安装 + 真实 OpenCode 2.0.25 + 本地模拟提供商 |
|
|
16
|
+
|
|
17
|
+
新增测试覆盖永久挂起、100 ms 默认预算与可注入预算、并发共享读取、TTL/事件失效后的旧缓存回退、空缓存、超时后重试、迟到成功/失败与新读取的竞争、同步/异步错误、定时器清理,以及会话删除、flush 和服务端钩子的有界 MCP 等待。挂起与迟到竞态使用可控 Promise 和模拟时钟验证;真实 smoke 验证正常宿主链路,未在真实宿主中注入 MCP 挂起。Node 22 的 MockTimers 实验性警告和 OpenTUI 安装引擎警告未隐藏。
|
|
18
|
+
|
|
19
|
+
验证产物:`/private/var/folders/rw/bmx6c8hd737brl55m0_ff_b80000gn/T/opencode/token-usage-smoke-Syw70N`。
|
|
20
|
+
|
|
21
|
+
## 2026-10-09 · Last Request 与上下文上限解耦
|
|
22
|
+
|
|
23
|
+
环境:macOS、Node.js v22.23.2、npm 10.9.8,插件包 0.4.6、SDK 2.0.24,真实宿主为 PATH 中的 OpenCode 2.0.25。
|
|
24
|
+
|
|
25
|
+
`requestDetails` 独立提取所选 assistant 的五类 token、总量和消息时间,`contextUsage` 单独校验模型上限。Last Request 的分类占比以请求总量为分母;上限缺失、为零、负值或非有限值时,实测请求仍可显示。时间依次取同一条消息有效的 `streamed`、`completed`、`created`,缺失时隐藏;来源估算的 `capturedAt` 仅显示在 Context Breakdown。
|
|
26
|
+
|
|
27
|
+
| 检查 | 结果 |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `npm run typecheck` | 通过 |
|
|
30
|
+
| `npm test` | 116 项通过,新增 3 项请求明细、时间与边界回归测试,并扩展控制器生命周期断言 |
|
|
31
|
+
| `npm run build` | 通过 |
|
|
32
|
+
| `npm run test:smoke` | 完整通过,打包/隔离安装 + 真实 OpenCode 2.0.25 + 本地模拟提供商 |
|
|
33
|
+
|
|
34
|
+
自动化测试覆盖有效/无效上限切换、请求分类与缓存率、时间优先级及无效日期、压缩与回退边界、子会话本地请求、刷新失败保留快照、跨会话清理,以及来源 RPC 缓慢/失败/返回另一轮请求的估算时间。
|
|
35
|
+
|
|
36
|
+
真实终端验证新增上限为 0 的活动模型:Context Window 显示不可用,Last Request 在紧凑/详细模式下仍显示 `Cache Read 1.0K`/`1,000 (78.7%)` 与 `Cache Rate 83.3%`,切回有效上限后恢复 Context。另核对两个标题各自显示实测 assistant 的流式结束时间和来源估算采样时间,并验证空请求不显示时间。完整 smoke 同时通过 100/48 列布局、子代理全树汇总、TPS/TTFT、定价、真实分叉及已完成压缩与消息排序检查。启动时按既有版本策略提示 2.0.25 未验证,随后实际完成全部检查。
|
|
37
|
+
|
|
38
|
+
验证产物:`/private/var/folders/rw/bmx6c8hd737brl55m0_ff_b80000gn/T/opencode/token-usage-smoke-12xAKR`,其中 `08-unknown-context-limit.txt` 保存未知上限下的详细弹窗。
|
|
39
|
+
|
|
40
|
+
## 2026-10-07 · npm 发布可见性校验“假失败”修复
|
|
41
|
+
|
|
42
|
+
环境:macOS、Node.js v22.23.2、npm 10.9.8,本地包版本为 0.4.5、SDK 为 2.0.24。本轮仅修改发布校验、工作流、测试与文档,未修改价格快照或插件运行时代码,未升级版本、移动标签、提交、推送、重跑 GitHub 工作流或实际发布 npm。
|
|
43
|
+
|
|
44
|
+
只读诊断确认已有真实自动发布链路:
|
|
45
|
+
|
|
46
|
+
- [价格更新运行 37555311596](https://github.com/chenlongapps/opencode-token-usage/actions/runs/37555311596) 由 `schedule` 触发,验证、patch 提交/原子推送、GitHub Release 和 dispatch 均成功。
|
|
47
|
+
- [发布运行 37555363814](https://github.com/chenlongapps/opencode-token-usage/actions/runs/37555363814) 固定在 `v0.4.5`(`66e0584e1f125f2e5012b081014e42d7d8d57d19`)。`npm publish` 成功,生成 provenance,并在 UTC 01:06:28 提示包仍在处理、可能需几分钟才能可用;失败的是 UTC 01:08:21 的 registry 可见性校验。旧实现只查询 12 次、间隔 10 秒,约 2 分钟即超时。
|
|
48
|
+
- 当前 registry 查询已返回目标版本与 `latest` 均为 `0.4.5`,`gitHead` 匹配上述提交,`dist.shasum` 为 `75f8490aa51a974a5d76942a4e1ffa2d9d13fd3c`,与真实发布日志一致。因此不能把该工作流的失败结论当作 npm 未收到版本,更不能为此另升 patch。
|
|
49
|
+
|
|
50
|
+
修复将按次数重试改为默认 10 分钟总时限,使用单调时钟计算剩余预算;每次版本/`latest` 请求最多 30 秒,且不得超过剩余预算,等待同样按剩余时间截短。`NPM_VERIFY_TIMEOUT_MS` 与 `NPM_VERIFY_INTERVAL_MS` 可配置并校验合法性。日志显示轮询进度、当前 `latest` 与具体查询错误;最终超时仍返回非零退出码,在 Actions 摘要中保留最后原因及原标签重试提示,不用 `continue-on-error` 掩盖故障。发布校验步骤上限为 11 分钟,整个任务仍为 20 分钟;已发布版本跳过发布与 `latest` 核验,原有禁止倒退 `latest`、registry 故障不等于版本不存在等保护保持不变。
|
|
51
|
+
|
|
52
|
+
| 检查 | 结果 |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| `npm run typecheck` | 通过 |
|
|
55
|
+
| `node --test test/release.test.mjs` | 发布专项 23 项通过 |
|
|
56
|
+
| `npm test` | 113 项通过,比上轮净增 10 项发布校验回归测试 |
|
|
57
|
+
| `npm run build` | 通过 |
|
|
58
|
+
| `npm pack --dry-run` | 通过,执行 `prepack` 构建,包含 37 个发布文件 |
|
|
59
|
+
| `npm publish --dry-run` | 通过,执行类型检查、113 项测试与构建;未写入 registry |
|
|
60
|
+
| GitHub 工作流 | 三个工作流均通过官方 actionlint 1.7.12 检查,下载产物已校验 SHA-256 |
|
|
61
|
+
| npm 只读查询 | `publish-state` 返回 `published=true`;新版 `verify-published` 确认 `0.4.5` 与 `latest` |
|
|
62
|
+
|
|
63
|
+
回归测试用注入时钟模拟版本在 3 分钟后可见、`latest` 在 4 分钟后更新;同时覆盖 404、HTTP 401/403/429/500/503、网络及无效响应、最后原因保留、单次请求 30 秒上限、请求与等待共用预算、到期后不再发起 `latest` 查询或判定成功,以及真实 AbortSignal 中止挂起请求。CLI 测试预载本地 registry 模拟,不访问真实 npm,验证环境配置、超时非零退出码和失败/成功摘要。
|
|
64
|
+
|
|
65
|
+
以上真实 GitHub 运行属于修复前的已有标签;新校验逻辑尚未在新的真实发布工作流中验证。本次没有重跑 TUI smoke,之前的宿主验证记录保留。修复提交进入 `main` 后仅供后续新标签使用;旧标签不移动,重跑已可见的 `v0.4.5` 会由原实现跳过发布并核验现有版本。
|
|
66
|
+
|
|
67
|
+
## 2026-10-07 · SDK 2.0.24 升级
|
|
68
|
+
|
|
69
|
+
环境:macOS、Node.js v22.23.2、npm 10.9.8,插件包仍为 0.4.4。`@opencode/plugin`、`@opencode/client`、`@opencode/schema` 和 `@opencode/theme` 从 2.0.11 同步精确升级到 2.0.24;锁文件中的全部七个 OpenCode 包均为 2.0.24。OpenTUI 从 0.5.10 同步到 SDK 与 theme 配套的 0.5.14,没有追随独立发布的 0.5.15。未修改价格快照、未升插件包版本、未提交或推送、未实际发布 npm。
|
|
70
|
+
|
|
71
|
+
| 检查 | 结果 |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `npm ci --no-audit --no-fund` | Node 22 下通过,保留 OpenTUI 引擎警告 |
|
|
74
|
+
| `npm run typecheck` | 通过 |
|
|
75
|
+
| `npm test` | 103 项通过,新增两项媒体封装与旧宿主兼容回归测试 |
|
|
76
|
+
| `npm run build` | 通过 |
|
|
77
|
+
| `npm pack --dry-run` | 通过,完整执行 `prepack` 构建,包含 37 个发布文件 |
|
|
78
|
+
| `npm run test:smoke`,默认宿主 2.0.24 | 完整通过,打包、隔离安装、真实服务端与 TUI |
|
|
79
|
+
| `OPENCODE_BIN=… npm run test:smoke`,独立宿主 2.0.22 | 完整通过 |
|
|
80
|
+
| `OPENCODE_BIN=… npm run test:smoke`,独立宿主 2.0.11 | 完整通过 |
|
|
81
|
+
|
|
82
|
+
新版 `@opencode/ai` 将请求媒体从平铺的 `mediaType` / `data` 改为 `media` asset。上下文来源估算现在优先读取 `part.media.mediaType`,同时兼容旧宿主的 `part.mediaType`;有文件名时仍优先按文件名估算,缺少标签时不伪造媒体 token。新增测试覆盖 bytes、base64 和 URL 负载不会计入文本 token,以及旧格式与缺失标签。插件入口、请求钩子、RPC、客户端分页及 TUI 插槽无需迁移,实测五类 token、上下文和计费口径不变。
|
|
83
|
+
|
|
84
|
+
OpenTUI 0.5.14 的原生 Node 运行时声明 Node `>=26.4.0` / Bun `>=1.3.0`。本轮 Node 22 干净安装和打包安装均报告 `EBADENGINE`,未强制绕过或隐藏警告;类型检查、测试与构建不运行原生 Node TUI,真实终端验证使用 OpenCode 自带运行时。因此保留项目 Node 22+ 要求,但不宣称独立 Node 22 原生 TUI 渲染受支持;启用 npm `engine-strict` 时仍须满足该依赖的 Node 引擎要求。
|
|
85
|
+
|
|
86
|
+
三版宿主均保留并通过原有完整断言:空会话、切换到生成中的会话、实时 TPS / TTFT、完成后精确吞吐、`/usage` 的紧凑/详细模式与 100 / 48 列布局、子代理全树累计和浮窗、按消息模型计费、模型切换与原厂价格回退、删除会话清理 RPC,以及真实分叉和 compaction。分叉继承 ID 仍带 `_序号` 后缀,用量只归原来源但占用分叉本地 Context;真实 compaction 仍为 `status === "completed"`,完整升序历史保留压缩前消息,压缩边界后的新 assistant 恢复 Context。全树 Total 5,080、费用 `$0.00504`、上下文上限 128,000 → 32,000 和回退费用 `$0.000149` 均未变化。
|
|
87
|
+
|
|
88
|
+
旧版宿主使用校验 npm SHA-512 完整性的官方 `@opencode/cli-darwin-arm64` 独立二进制,未修改日常 OpenCode 安装、用户配置或调用付费模型。当前 SDK 的已验证宿主列表更新为 2.0.11、2.0.22、2.0.24;2.0.9 / 2.0.10 未在本轮复测,保留下方历史记录,不据 smoke 可运行范围扩展兼容声明。
|
|
89
|
+
|
|
90
|
+
验证产物:
|
|
91
|
+
- OpenCode 2.0.24:`/private/var/folders/rw/bmx6c8hd737brl55m0_ff_b80000gn/T/opencode/token-usage-smoke-gka7v0`。
|
|
92
|
+
- OpenCode 2.0.22:`/private/var/folders/rw/bmx6c8hd737brl55m0_ff_b80000gn/T/opencode/token-usage-smoke-RpSxaf`。
|
|
93
|
+
- OpenCode 2.0.11:`/private/var/folders/rw/bmx6c8hd737brl55m0_ff_b80000gn/T/opencode/token-usage-smoke-NQbaNC`。
|
|
94
|
+
|
|
3
95
|
## 2026-10-05 · 自动价格 patch 与 npm 发布链路(本地验证)
|
|
4
96
|
|
|
5
97
|
环境:macOS、Node.js v22.23.2、插件包仍为 0.4.4,SDK 仍锁定 2.0.11。本轮只修改价格更新与发布自动化、测试和文档,未更新真实价格快照、未推送提交或标签、未创建 GitHub Release,也未实际发布 npm。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chenlongapps/opencode-token-usage",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"description": "Session-tree token usage, live performance, context window and estimated cost for OpenCode 2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"opencode",
|
|
@@ -59,20 +59,20 @@
|
|
|
59
59
|
"registry": "https://registry.npmjs.org/"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@opencode/plugin": "2.0.
|
|
62
|
+
"@opencode/plugin": "2.0.24"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"@opentui/core": "0.5.
|
|
66
|
-
"@opentui/solid": "0.5.
|
|
65
|
+
"@opentui/core": "0.5.14",
|
|
66
|
+
"@opentui/solid": "0.5.14",
|
|
67
67
|
"solid-js": ">=1.9.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@babel/core": "^7.28.0",
|
|
71
|
-
"@opencode/client": "2.0.
|
|
72
|
-
"@opencode/schema": "2.0.
|
|
73
|
-
"@opencode/theme": "2.0.
|
|
74
|
-
"@opentui/core": "0.5.
|
|
75
|
-
"@opentui/solid": "0.5.
|
|
71
|
+
"@opencode/client": "2.0.24",
|
|
72
|
+
"@opencode/schema": "2.0.24",
|
|
73
|
+
"@opencode/theme": "2.0.24",
|
|
74
|
+
"@opentui/core": "0.5.14",
|
|
75
|
+
"@opentui/solid": "0.5.14",
|
|
76
76
|
"@types/node": "^22.0.0",
|
|
77
77
|
"@xterm/headless": "6.0.0",
|
|
78
78
|
"babel-preset-solid": "1.9.12",
|