@jack-yang/opencode-tps-meter 1.1.2 → 1.3.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jack Yang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -4,7 +4,7 @@ English | [中文](./README.zh-CN.md)
4
4
 
5
5
  A TUI plugin for [opencode](https://opencode.ai) that displays real-time LLM output speed metrics next to the session prompt.
6
6
 
7
- [![npm version](https://img.shields.io/npm/v/@jack-yang/opencode-tps-meter)](https://www.npmjs.com/package/@jack-yang/opencode-tps-meter) [![license](https://img.shields.io/npm/l/@jack-yang/opencode-tps-meter)](https://www.npmjs.com/package/@jack-yang/opencode-tps-meter) [![stars](https://img.shields.io/github/stars/yangwudong/opencode-tps-meter)](https://github.com/yangwudong/opencode-tps-meter) ![opencode](https://img.shields.io/badge/opencode-1.17.20-tested-blue)
7
+ [![npm version](https://img.shields.io/npm/v/@jack-yang/opencode-tps-meter)](https://www.npmjs.com/package/@jack-yang/opencode-tps-meter) [![license](https://img.shields.io/npm/l/@jack-yang/opencode-tps-meter)](https://www.npmjs.com/package/@jack-yang/opencode-tps-meter) [![stars](https://img.shields.io/github/stars/yangwudong/opencode-tps-meter)](https://github.com/yangwudong/opencode-tps-meter) ![opencode](https://img.shields.io/badge/opencode-1.x%20%2F%202.x-blue)
8
8
 
9
9
  ## Display
10
10
 
@@ -21,7 +21,7 @@ TPS 42.5 | AVG 38.2 | TTFT 0.8s ⠒⠑⠂
21
21
  - **TPS** — current tokens per second (live, color-coded)
22
22
  - **AVG** — session-wide cumulative average from completed messages (color-coded)
23
23
  - **TTFT** — time to first token, shown immediately on first token, persists until next generation (color-coded)
24
- - **Thinking stream** — while reasoning streams, a FIFO particle stream (newest dot on the left, fading right, color shifts over time) appears to the right of TTFT. Only rendered while thinking — no space is reserved when idle.
24
+ - **Thinking stream** — while reasoning streams, a FIFO particle stream (newest dot on the left, fading right, color shifts over time) appears to the right of TTFT. Each cell has its own color (a gradient fading to muted). Only rendered while thinking — no space is reserved when idle.
25
25
 
26
26
  ## Color Tiers
27
27
 
@@ -44,17 +44,24 @@ TPS 42.5 | AVG 38.2 | TTFT 0.8s ⠒⠑⠂
44
44
 
45
45
  ## Installation
46
46
 
47
- > **Important:** This plugin must be configured in `tui.json`, **not** `opencode.json`.
47
+ One package supports both opencode 1.x and 2.x — pick the section for your version.
48
+
49
+ > **Important (opencode 1.x):** the plugin must be configured in `tui.json`, **not** `opencode.json`.
50
+ > **opencode 2.x:** terminal-client plugins live in `cli.json` (installed under the `plugins` key). If you upgrade to 2.x, your `tui.json` is migrated automatically.
48
51
 
49
52
  ### One command (recommended)
50
53
 
51
54
  ```bash
55
+ # opencode 1.x
52
56
  opencode plugin @jack-yang/opencode-tps-meter -g
57
+
58
+ # opencode 2.x
59
+ opencode plugin add @jack-yang/opencode-tps-meter
53
60
  ```
54
61
 
55
62
  Installs the plugin and updates your config. Restart opencode — done. (Applies default options; to customize, use the tuple form in [Configuration](#configuration).)
56
63
 
57
- ### Manual: npm
64
+ ### Manual: npm (opencode 1.x)
58
65
 
59
66
  Add `@jack-yang/opencode-tps-meter` to the `plugin` array in `~/.config/opencode/tui.json`:
60
67
 
@@ -66,6 +73,18 @@ Add `@jack-yang/opencode-tps-meter` to the `plugin` array in `~/.config/opencode
66
73
  }
67
74
  ```
68
75
 
76
+ ### Manual: npm (opencode 2.x)
77
+
78
+ Add the package to the `plugins` array in `~/.config/opencode/cli.json`:
79
+
80
+ ```json
81
+ {
82
+ "plugins": [
83
+ "@jack-yang/opencode-tps-meter"
84
+ ]
85
+ }
86
+ ```
87
+
69
88
  ### GitHub
70
89
 
71
90
  ```json
@@ -98,7 +117,9 @@ curl -o ~/.config/opencode/tps-meter.tsx https://raw.githubusercontent.com/yangw
98
117
 
99
118
  ## Configuration
100
119
 
101
- All options are optional — defaults are sane. Pass them via the tuple form in `tui.json`:
120
+ All options are optional — defaults are sane.
121
+
122
+ **opencode 1.x** — tuple form in `tui.json`:
102
123
 
103
124
  ```json
104
125
  {
@@ -119,30 +140,53 @@ All options are optional — defaults are sane. Pass them via the tuple form in
119
140
  }
120
141
  ```
121
142
 
143
+ **opencode 2.x** — object form in `cli.json` (same options):
144
+
145
+ ```json
146
+ {
147
+ "plugins": [
148
+ {
149
+ "package": "@jack-yang/opencode-tps-meter",
150
+ "options": {
151
+ "spinner": { "theme": "tech", "cells": 6 },
152
+ "tiers": { "tps": { "slow": 20, "normal": 50, "fast": 100 } }
153
+ }
154
+ }
155
+ ]
156
+ }
157
+ ```
158
+
122
159
  | Option | Default | Description |
123
160
  |---|---|---|
124
161
  | `spinner.theme` | `"tech"` | Color preset: `"tech"` (cyan→blue→purple) or `"red"` (KITT-style red). `"none"` disables the thinking stream. |
125
- | `spinner.colors` | _from theme_ | Custom gradient (hex strings); overrides `theme`. |
126
- | `spinner.intervalMs` | `100` | Particle stream frame interval (ms). |
127
- | `spinner.cells` | `6` | Number of cells (width) of the thinking stream. |
162
+ | `spinner.colors` | _from theme_ | Custom gradient (hex strings `#rgb` / `#rrggbb` / `#rrggbbaa`); overrides `theme`. Invalid entries are ignored. |
163
+ | `spinner.intervalMs` | `100` | Particle stream frame interval (ms), clamped to 40–1000. |
164
+ | `spinner.cells` | `6` | Number of cells (width) of the thinking stream, clamped to 2–16. |
128
165
  | `tiers.tps` | `{20,50,100}` | TPS/AVG thresholds (slow/normal/fast, in TPS); above `fast` is "faster". |
129
166
  | `tiers.ttft` | `{10000,20000}` | TTFT thresholds in ms (fast/ok); above `ok` is "slow". |
130
167
 
168
+ Tier values must be positive and ascending; otherwise the defaults are used.
169
+ | `slot` | `"prompt.footer.status"` | opencode 2.x only: which TUI slot the meter renders into. |
170
+
131
171
  ## How It Works
132
172
 
133
173
  ### Live TPS
134
174
 
135
- Tracks text/reasoning delta events in a rolling 5-second window. Uses wall-clock duration (`now - oldest sample`) instead of inter-arrival time sums to avoid inflation from network buffering.
175
+ Tracks text, reasoning and tool-argument delta events in a rolling 5-second window (so a model writing a large file through a tool call still shows a speed). Uses wall-clock duration (`now - oldest sample`) instead of inter-arrival time sums to avoid inflation from network buffering.
136
176
 
137
- Token estimation uses `ceil(byteLength / 4)` with a **calibration factor**: when a message completes, the estimated token count is compared against actual `tokens.output + tokens.reasoning` from the message metadata, and a running median ratio corrects future estimates.
177
+ Token estimation uses `ceil(byteLength / 4)` with a **calibration factor**: when a message completes, the estimated token count is compared against the actual `tokens.output` (+ `tokens.reasoning` when reasoning was streamed) from the message metadata, and a running median ratio corrects future estimates.
138
178
 
139
179
  ### AVG
140
180
 
141
- Session-wide cumulative average from all completed messages: `sum(actual tokens) / sum(generation durations)`. Updates when a message completes. Generation duration = `last delta - first delta` per message (excludes tool execution time and TTFT).
181
+ Session-wide cumulative average from all completed messages: `sum(actual tokens) / sum(generation durations)`. Updates when a message completes. Generation duration = `last delta - first delta` per step, where deltas include text, reasoning and tool-call arguments (excludes tool execution time and TTFT).
182
+
183
+ To avoid inflated numbers:
184
+ - reasoning tokens are only counted when the reasoning was actually streamed (some models report reasoning tokens without streaming them);
185
+ - a step that made tool calls but whose arguments were not streamed (older opencode versions) is excluded from AVG and calibration instead of being guessed.
142
186
 
143
187
  ### TTFT
144
188
 
145
- Time from message creation (`info.time.created`) to the first text/reasoning delta. Displayed immediately when the first token arrives, and persists until the next generation starts.
189
+ Time from step start (`info.time.created`) to the first output delta (text, reasoning or tool arguments). Displayed immediately when the first token arrives, and persists until the next generation starts.
146
190
 
147
191
  ## Development
148
192
 
@@ -150,15 +194,16 @@ Time from message creation (`info.time.created`) to the first text/reasoning del
150
194
  git clone https://github.com/yangwudong/opencode-tps-meter.git
151
195
  cd opencode-tps-meter
152
196
  npm install
153
- npm test
197
+ npm test # unit tests
198
+ npm run typecheck # tsc, 0 errors expected
154
199
  ```
155
200
 
156
- Pure measurement functions (`measure.ts`) have 29 unit tests. The TUI plugin (`tui.tsx`) is a standalone single file (all functions inline) for direct deployment.
201
+ Pure measurement logic lives in `measure.ts` (67 unit tests). The TUI plugin (`tui.tsx`) is a standalone single file for direct deployment; it embeds an identical copy of the pure region — edit `measure.ts`, then run `npm run sync-region` (`test/sync.test.ts` fails if they drift).
157
202
 
158
203
  ## Requirements
159
204
 
160
- - opencode >= 1.4.3 (tested on 1.17.20)
205
+ - opencode 1.x >= 1.4.3 (tested on 1.17.20 / 1.18.30) or opencode 2.x
161
206
 
162
207
  ## License
163
208
 
164
- MIT
209
+ [MIT](./LICENSE)
package/README.zh-CN.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  一个 [opencode](https://opencode.ai) 的 TUI 插件,在输入框旁边实时显示 LLM 输出速度指标。
6
6
 
7
- [![npm version](https://img.shields.io/npm/v/@jack-yang/opencode-tps-meter)](https://www.npmjs.com/package/@jack-yang/opencode-tps-meter) [![license](https://img.shields.io/npm/l/@jack-yang/opencode-tps-meter)](https://www.npmjs.com/package/@jack-yang/opencode-tps-meter) [![stars](https://img.shields.io/github/stars/yangwudong/opencode-tps-meter)](https://github.com/yangwudong/opencode-tps-meter) ![opencode](https://img.shields.io/badge/opencode-1.17.20-tested-blue)
7
+ [![npm version](https://img.shields.io/npm/v/@jack-yang/opencode-tps-meter)](https://www.npmjs.com/package/@jack-yang/opencode-tps-meter) [![license](https://img.shields.io/npm/l/@jack-yang/opencode-tps-meter)](https://www.npmjs.com/package/@jack-yang/opencode-tps-meter) [![stars](https://img.shields.io/github/stars/yangwudong/opencode-tps-meter)](https://github.com/yangwudong/opencode-tps-meter) ![opencode](https://img.shields.io/badge/opencode-1.x%20%2F%202.x-blue)
8
8
 
9
9
  ## 显示效果
10
10
 
@@ -21,7 +21,7 @@ TPS 42.5 | AVG 38.2 | TTFT 0.8s ⠒⠑⠂
21
21
  - **TPS** — 当前每秒 token 数(实时跳动,带颜色)
22
22
  - **AVG** — 整个会话的累计平均速度(消息完成后更新,带颜色)
23
23
  - **TTFT** — 首个 token 的等待时间,第一个 token 到达即显示,保留到下次生成(带颜色)
24
- - **思考粒子条** — 推理流式输出时,TTFT 右侧出现一个 FIFO 粒子流(左侧最新、向右渐暗,颜色随时间渐变)。仅在思考时渲染,空闲时不占位。
24
+ - **思考粒子条** — 推理流式输出时,TTFT 右侧出现一个 FIFO 粒子流(左侧最新、向右渐暗,颜色随时间渐变)。每一格单独着色(渐变淡出到 muted)。仅在思考时渲染,空闲时不占位。
25
25
 
26
26
  ## 颜色等级
27
27
 
@@ -44,17 +44,24 @@ TPS 42.5 | AVG 38.2 | TTFT 0.8s ⠒⠑⠂
44
44
 
45
45
  ## 安装
46
46
 
47
- > **注意:** 本插件必须配置在 `tui.json` 中,**不是** `opencode.json`。
47
+ 一个包同时支持 opencode 1.x 和 2.x,按你的版本选择对应方式。
48
+
49
+ > **注意(opencode 1.x):** 插件必须配置在 `tui.json` 中,**不是** `opencode.json`。
50
+ > **opencode 2.x:** 终端客户端插件配置在 `cli.json` 的 `plugins` 键下。升级到 2.x 时,`tui.json` 会被自动迁移。
48
51
 
49
52
  ### 一条命令(推荐)
50
53
 
51
54
  ```bash
55
+ # opencode 1.x
52
56
  opencode plugin @jack-yang/opencode-tps-meter -g
57
+
58
+ # opencode 2.x
59
+ opencode plugin add @jack-yang/opencode-tps-meter
53
60
  ```
54
61
 
55
- 安装插件并更新配置。重启 opencode 即可。(使用默认配置;如需自定义,见下方[配置](#配置)的元组形式。)
62
+ 安装插件并更新配置。重启 opencode 即可。(使用默认配置;如需自定义,见下方[配置](#配置)。)
56
63
 
57
- ### 手动:npm
64
+ ### 手动:npm(opencode 1.x)
58
65
 
59
66
  在 `~/.config/opencode/tui.json` 的 `plugin` 数组中添加 `@jack-yang/opencode-tps-meter`:
60
67
 
@@ -66,6 +73,18 @@ opencode plugin @jack-yang/opencode-tps-meter -g
66
73
  }
67
74
  ```
68
75
 
76
+ ### 手动:npm(opencode 2.x)
77
+
78
+ 在 `~/.config/opencode/cli.json` 的 `plugins` 数组中添加:
79
+
80
+ ```json
81
+ {
82
+ "plugins": [
83
+ "@jack-yang/opencode-tps-meter"
84
+ ]
85
+ }
86
+ ```
87
+
69
88
  ### GitHub
70
89
 
71
90
  ```json
@@ -98,7 +117,9 @@ curl -o ~/.config/opencode/tps-meter.tsx https://raw.githubusercontent.com/yangw
98
117
 
99
118
  ## 配置
100
119
 
101
- 所有配置项都是可选的——默认值即开即用。通过 `tui.json` 的元组形式传入:
120
+ 所有配置项都是可选的——默认值即开即用。
121
+
122
+ **opencode 1.x** —— `tui.json` 的元组形式:
102
123
 
103
124
  ```json
104
125
  {
@@ -119,32 +140,55 @@ curl -o ~/.config/opencode/tps-meter.tsx https://raw.githubusercontent.com/yangw
119
140
  }
120
141
  ```
121
142
 
143
+ **opencode 2.x** —— `cli.json` 的对象形式(配置项相同):
144
+
145
+ ```json
146
+ {
147
+ "plugins": [
148
+ {
149
+ "package": "@jack-yang/opencode-tps-meter",
150
+ "options": {
151
+ "spinner": { "theme": "tech", "cells": 6 },
152
+ "tiers": { "tps": { "slow": 20, "normal": 50, "fast": 100 } }
153
+ }
154
+ }
155
+ ]
156
+ }
157
+ ```
158
+
122
159
  | 配置项 | 默认值 | 说明 |
123
160
  |---|---|---|
124
161
  | `spinner.theme` | `"tech"` | 配色预设:`"tech"`(青→蓝→紫)或 `"red"`(KITT 风格红)。`"none"` 关闭思考粒子流。 |
125
- | `spinner.colors` | _随 theme_ | 自定义渐变(十六进制字符串数组);覆盖 theme。 |
126
- | `spinner.intervalMs` | `100` | 粒子流帧间隔(毫秒)。 |
127
- | `spinner.cells` | `6` | 粒子流格数(宽度)。 |
162
+ | `spinner.colors` | _随 theme_ | 自定义渐变(十六进制字符串 `#rgb` / `#rrggbb` / `#rrggbbaa`);覆盖 theme。无效项会被忽略。 |
163
+ | `spinner.intervalMs` | `100` | 粒子流帧间隔(毫秒),限制在 40–1000。 |
164
+ | `spinner.cells` | `6` | 粒子流格数(宽度),限制在 2–16。 |
128
165
  | `tiers.tps` | `{20,50,100}` | TPS/AVG 阈值(慢/正常/快,单位 TPS);超过 fast 为"很快"。 |
129
166
  | `tiers.ttft` | `{10000,20000}` | TTFT 阈值(毫秒,快/正常);超过 ok 为"慢"。 |
130
167
 
131
- > 一条命令安装(`opencode plugin ...`)使用默认值;如需自定义,改用上面的元组形式。
168
+ 阈值必须为正数且递增,否则使用默认值。
169
+ | `slot` | `"prompt.footer.status"` | 仅 opencode 2.x:仪表渲染到的 TUI slot。 |
170
+
171
+ > 一条命令安装(`opencode plugin ...`)使用默认值;如需自定义,改用上面的元组/对象形式。
132
172
 
133
173
  ## 工作原理
134
174
 
135
175
  ### 实时 TPS
136
176
 
137
- 在 5 秒滚动窗口内追踪文本/推理的 delta 事件。使用壁钟时长(`当前时间 - 最早样本时间`)而非间隔时间累加,避免网络批量传输导致的 TPS 虚高。
177
+ 在 5 秒滚动窗口内追踪文本、推理和工具参数的 delta 事件(模型通过工具调用写大文件时也有速度显示)。使用壁钟时长(`当前时间 - 最早样本时间`)而非间隔时间累加,避免网络批量传输导致的 TPS 虚高。
138
178
 
139
- Token 估算使用 `ceil(字节数 / 4)`,并带有**校准因子**:消息完成时,将估算的 token 数与实际的 `tokens.output + tokens.reasoning` 对比,用中位数比率自动修正后续估算。
179
+ Token 估算使用 `ceil(字节数 / 4)`,并带有**校准因子**:消息完成时,将估算的 token 数与实际的 `tokens.output`(推理确实流式输出时再加上 `tokens.reasoning`)对比,用中位数比率自动修正后续估算。
140
180
 
141
181
  ### AVG
142
182
 
143
- 所有已完成消息的会话级累计平均值:`总实际 token 数 / 总生成时长`。消息完成时更新。生成时长 = 每条消息的 `最后 delta - 首个 delta`(不含工具执行时间和 TTFT)。
183
+ 所有已完成消息的会话级累计平均值:`总实际 token 数 / 总生成时长`。消息完成时更新。生成时长 = 每个 step 的 `最后 delta - 首个 delta`,delta 包括文本、推理和工具调用参数(不含工具执行时间和 TTFT)。
184
+
185
+ 为避免数值虚高:
186
+ - 只有推理内容确实流式输出时才计入 reasoning token(有些模型只上报 reasoning token 而不流式输出推理);
187
+ - 发起了工具调用、但工具参数没有流式输出的 step(旧版 opencode)直接不计入 AVG 和校准,而不是去猜。
144
188
 
145
189
  ### TTFT
146
190
 
147
- 从消息创建(`info.time.created`)到第一个文本/推理 delta 的时间。第一个 token 到达时立即显示,保留到下次生成开始。
191
+ 从 step 开始(`info.time.created`)到第一个输出 delta(文本、推理或工具参数)的时间。第一个 token 到达时立即显示,保留到下次生成开始。
148
192
 
149
193
  ## 开发
150
194
 
@@ -152,15 +196,16 @@ Token 估算使用 `ceil(字节数 / 4)`,并带有**校准因子**:消息完
152
196
  git clone https://github.com/yangwudong/opencode-tps-meter.git
153
197
  cd opencode-tps-meter
154
198
  npm install
155
- npm test
199
+ npm test # 单元测试
200
+ npm run typecheck # tsc,应为 0 错误
156
201
  ```
157
202
 
158
- 纯计算函数(`measure.ts`)有 29 个单元测试。TUI 插件(`tui.tsx`)是独立的单文件(所有函数内联),可直接部署。
203
+ 纯计算逻辑在 `measure.ts`(67 个单元测试)。TUI 插件(`tui.tsx`)是独立的单文件,可直接部署;它内嵌了一份完全相同的纯计算区——修改 `measure.ts` 后运行 `npm run sync-region`(两份不一致时 `test/sync.test.ts` 会失败)。
159
204
 
160
205
  ## 环境要求
161
206
 
162
- - opencode >= 1.4.3(已在 1.17.20 测试)
207
+ - opencode 1.x >= 1.4.3(已在 1.17.20 / 1.18.30 测试)或 opencode 2.x
163
208
 
164
209
  ## 许可证
165
210
 
166
- MIT
211
+ [MIT](./LICENSE)
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@jack-yang/opencode-tps-meter",
4
- "version": "1.1.2",
4
+ "version": "1.3.0",
5
5
  "description": "Live TPS/AVG/TTFT meter plugin for OpenCode TUI with color-coded speed tiers",
6
6
  "type": "module",
7
7
  "exports": {
8
+ ".": {
9
+ "import": "./tui.tsx"
10
+ },
8
11
  "./tui": {
9
12
  "import": "./tui.tsx"
10
13
  }
@@ -24,7 +27,9 @@
24
27
  },
25
28
  "scripts": {
26
29
  "test": "vitest run",
27
- "test:watch": "vitest"
30
+ "test:watch": "vitest",
31
+ "typecheck": "tsc --noEmit --jsx react-jsx --jsxImportSource @opentui/solid --module esnext --target esnext --moduleResolution bundler --skipLibCheck tui.tsx measure.ts",
32
+ "sync-region": "node scripts/sync-region.mjs"
28
33
  },
29
34
  "files": [
30
35
  "tui.tsx",