@jack-yang/pi-tps-meter 0.3.0 → 1.0.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/CHANGELOG.md +9 -0
- package/README.md +1 -0
- package/extensions/index.ts +13 -7
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.0.0] - 2026-11-04
|
|
4
|
+
|
|
5
|
+
First stable release; the behaviour is that of 0.3.0, reviewed before freezing it.
|
|
6
|
+
|
|
7
|
+
- Declare `@earendil-works/pi-tui` as a peer dependency: footer mode imports it at runtime (pi
|
|
8
|
+
supplies it, as it does `@earendil-works/pi-coding-agent`).
|
|
9
|
+
- Footer mode no longer deep-copies all of pi's settings on every frame to read the
|
|
10
|
+
auto-compaction flag; it re-reads the setting at most once a second.
|
|
11
|
+
|
|
3
12
|
## [0.3.0] - 2026-11-04
|
|
4
13
|
|
|
5
14
|
- New default display `footer`: the meter sits at the right end of pi's footer line with the
|
package/README.md
CHANGED
|
@@ -148,6 +148,7 @@ TTFT 从 `turn_start` 开始计时(在 pi 里,一个 turn 就是一次模型
|
|
|
148
148
|
- toolcall delta 计入 TPS 和校准,因为 pi 的 `usage.output` 包含工具调用参数的 token;原版只统计文本和推理。TTFT 仍然只认文本和思考。
|
|
149
149
|
- 权威 token 数直接用 `usage.output`:pi 的 output 已经包含推理 token,原版需要把 output 和 reasoning 相加。
|
|
150
150
|
- 思考粒子流已移植(配色预设、渐变、FIFO 流动、配置项都和原版一致),并做了原版想做但受限于 opencode 做不到的一点:每个粒子单独着色,真正从亮到暗渐隐(原版受 opentui 限制,整串只能用一种颜色)。右对齐时粒子流放在读数左边、方向镜像,读数本身不会移动。
|
|
151
|
+
- 显示位置:原版在 opencode 输入框右侧的 slot 里;pi 没有对应的位置,默认放在 footer 目录行右端(包装 pi 自己的 footer,不替换),另有 `right` / `status` / `widget` 可选。
|
|
151
152
|
- 颜色用 ANSI 基本色:红 31、黄 33、绿 32、青 36,标签用暗色;原版用的是 opencode 主题槽位。
|
|
152
153
|
|
|
153
154
|
## 已知限制
|
package/extensions/index.ts
CHANGED
|
@@ -144,7 +144,7 @@ export function createTpsMeter(pi: ExtensionAPI, deps: Deps = {}): void {
|
|
|
144
144
|
const m = entry.message
|
|
145
145
|
if (m.stopReason === "error" || m.stopReason === "aborted") continue
|
|
146
146
|
const physical = ctxRef.modelRegistry.find(m.provider, m.model)
|
|
147
|
-
return physical ? { model: physical, thinkingLevel:
|
|
147
|
+
return physical ? { model: physical, thinkingLevel: m.thinkingLevel } : undefined
|
|
148
148
|
}
|
|
149
149
|
return undefined
|
|
150
150
|
},
|
|
@@ -156,15 +156,12 @@ export function createTpsMeter(pi: ExtensionAPI, deps: Deps = {}): void {
|
|
|
156
156
|
const registry = ctxRef?.modelRegistry
|
|
157
157
|
const model = ctxRef?.model
|
|
158
158
|
if (!registry || model?.provider !== provider || !registry.isUsingOAuth(model)) return false
|
|
159
|
-
|
|
160
|
-
return p?.auth?.oauth?.isSubscription === true
|
|
159
|
+
return registry.getProvider(provider)?.auth.oauth?.isSubscription === true
|
|
161
160
|
},
|
|
162
161
|
},
|
|
163
162
|
getContextUsage: () => ctxRef?.getContextUsage(),
|
|
164
163
|
}
|
|
165
164
|
|
|
166
|
-
// If pi's footer cannot be wrapped (an older or newer pi changed it), never leave the user
|
|
167
|
-
// without a footer: restore pi's, fall back to the line below the editor, say so once.
|
|
168
165
|
// If pi's footer cannot be wrapped (an older or newer pi changed it), never leave the user
|
|
169
166
|
// without a footer: fall back to the line below the editor (leaving footer mode is what restores
|
|
170
167
|
// pi's own footer, in render()) and say so once. A mount that is no longer current (the mode
|
|
@@ -176,6 +173,16 @@ export function createTpsMeter(pi: ExtensionAPI, deps: Deps = {}): void {
|
|
|
176
173
|
render()
|
|
177
174
|
}
|
|
178
175
|
|
|
176
|
+
// pi feeds its own footer the auto-compaction flag whenever it changes; ours has to read the
|
|
177
|
+
// setting. pi.getSettings() deep-copies all settings, and the footer renders on every frame, so
|
|
178
|
+
// the flag is re-read at most once a second (a toggle in /settings shows up within that).
|
|
179
|
+
let autoCompact = { value: true, readAt: Number.NEGATIVE_INFINITY }
|
|
180
|
+
const autoCompactEnabled = (): boolean => {
|
|
181
|
+
const now = Date.now()
|
|
182
|
+
if (now - autoCompact.readAt >= 1_000) autoCompact = { value: pi.getSettings().compaction?.enabled ?? true, readAt: now }
|
|
183
|
+
return autoCompact.value
|
|
184
|
+
}
|
|
185
|
+
|
|
179
186
|
const mountFooter = (target: UI, epoch: number): void => {
|
|
180
187
|
loadFooterKit().then((kit) => {
|
|
181
188
|
if (epoch !== mountEpoch || ui !== target) return
|
|
@@ -187,8 +194,7 @@ export function createTpsMeter(pi: ExtensionAPI, deps: Deps = {}): void {
|
|
|
187
194
|
return {
|
|
188
195
|
render(width: number): string[] {
|
|
189
196
|
try {
|
|
190
|
-
|
|
191
|
-
inner.setAutoCompactEnabled(pi.getSettings().compaction?.enabled ?? true)
|
|
197
|
+
inner.setAutoCompactEnabled(autoCompactEnabled())
|
|
192
198
|
const lines = inner.render(width)
|
|
193
199
|
if (lines.length > 0 && shownLine) lines[0] = mergeFooterLine(lines[0], shownLine, width, fns)
|
|
194
200
|
return lines
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@jack-yang/pi-tps-meter",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"description": "Live TPS / AVG / TTFT meter for the pi coding agent, calibrated against authoritative token counts (port of opencode-tps-meter)",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"keywords": [
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
"node": ">=22.19.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@earendil-works/pi-coding-agent": "*"
|
|
45
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
46
|
+
"@earendil-works/pi-tui": "*"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
48
49
|
"@types/node": "^24.0.0",
|