my-opencode-toolkit 0.2.4 → 0.2.6
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 +4 -3
- package/package.json +2 -1
- package/src/stats.ts +12 -9
package/README.md
CHANGED
|
@@ -136,7 +136,7 @@ OpenCode v2 插件:系统通知、持久目标、定时任务与循环、TUI
|
|
|
136
136
|
- 侧栏统计是进程内数据:重启后第一次打开面板会从已存消息重建(重建瞬间完成的一步可能漏算)
|
|
137
137
|
- 通知依赖系统命令:Windows 用 PowerShell toast,macOS 用 `osascript`,Linux 用 `notify-send`
|
|
138
138
|
- 定时任务按 OpenCode 进程的本地时区解析;不支持秒级字段与 `L` / `W` / `?` 等扩展语法
|
|
139
|
-
-
|
|
139
|
+
- 夏令时:春季拨快时不存在的时间顺延到次日;秋季拨慢时重复的一小时会被跳过(每天只触发一次)
|
|
140
140
|
- 同一会话不要同时开多个 OpenCode 实例执行目标/定时任务;插件存储没有跨进程锁
|
|
141
141
|
- 目标进行中时 cron/loop 让路,避免和续作抢同一轮对话
|
|
142
142
|
- 子代理会话不提供 goal/scheduling 工具,也不会被注入续作
|
|
@@ -172,11 +172,12 @@ OpenCode v2 插件:系统通知、持久目标、定时任务与循环、TUI
|
|
|
172
172
|
|
|
173
173
|
```bash
|
|
174
174
|
pnpm install
|
|
175
|
-
pnpm check # typecheck + lint + 175 单测 +
|
|
175
|
+
pnpm check # typecheck + lint + 175 单测 + 7 bun 测试 + 发布包内容校验
|
|
176
176
|
pnpm test:e2e # 需要本机 opencode 2.x 与 bun,使用隔离的 HOME/DB/config
|
|
177
|
+
pnpm test:e2e:tui # 真实 TUI:PTY 启动 opencode --standalone,打开设置菜单
|
|
177
178
|
```
|
|
178
179
|
|
|
179
|
-
e2e 用假 provider 驱动工具调用,不会请求真实模型;它会在临时目录里启动一个隔离的 OpenCode server
|
|
180
|
+
e2e 用假 provider 驱动工具调用,不会请求真实模型;它会在临时目录里启动一个隔离的 OpenCode server,不读写日常数据。`test:e2e:tui` 通过 ConPTY(Windows)或 openpty(macOS/Linux)驱动真实 TUI,验证 TUI 插件加载、斜杠命令与设置菜单渲染。
|
|
180
181
|
|
|
181
182
|
## 许可证
|
|
182
183
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-opencode-toolkit",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "OpenCode 插件:系统通知、持久目标、定时任务与 TUI 面板",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"test": "vitest run",
|
|
51
51
|
"test:tui": "cd tui-test && bun test",
|
|
52
52
|
"test:e2e": "bun scripts/e2e-load.mjs",
|
|
53
|
+
"test:e2e:tui": "bun scripts/e2e-tui.mjs",
|
|
53
54
|
"test:watch": "vitest"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
package/src/stats.ts
CHANGED
|
@@ -5,8 +5,10 @@ import { asRecord } from "./shared/json.ts"
|
|
|
5
5
|
/** 单个会话的进程内统计。 */
|
|
6
6
|
export type SessionStats = {
|
|
7
7
|
readonly steps: number
|
|
8
|
+
/** 总提示词 token:`input + cache.read + cache.write`。 */
|
|
8
9
|
readonly input: number
|
|
9
10
|
readonly output: number
|
|
11
|
+
/** 缓存命中 token:只算 `cache.read`。 */
|
|
10
12
|
readonly cached: number
|
|
11
13
|
readonly tools: Readonly<Record<string, number>>
|
|
12
14
|
readonly subagents: number
|
|
@@ -70,9 +72,10 @@ export function createStatsTracker(): StatsTracker {
|
|
|
70
72
|
const cache = asRecord(record["cache"]) ?? {}
|
|
71
73
|
const stats = of(sessionID)
|
|
72
74
|
stats.steps += 1
|
|
73
|
-
|
|
75
|
+
// 分母是完整提示词;cache.write 是写入成本,不算命中。
|
|
76
|
+
stats.input += count(record["input"]) + count(cache["read"]) + count(cache["write"])
|
|
74
77
|
stats.output += count(record["output"])
|
|
75
|
-
stats.cached += count(cache["read"])
|
|
78
|
+
stats.cached += count(cache["read"])
|
|
76
79
|
},
|
|
77
80
|
|
|
78
81
|
recordTool(sessionID, tool) {
|
|
@@ -189,9 +192,10 @@ export async function buildStats(ctx: Plugin.Context, sessionID: string): Promis
|
|
|
189
192
|
steps += 1
|
|
190
193
|
const tokens = message.tokens
|
|
191
194
|
if (tokens !== undefined) {
|
|
192
|
-
input
|
|
195
|
+
// 与 recordStep 保持同一口径:input 是完整提示词,cached 只算读命中。
|
|
196
|
+
input += tokens.input + tokens.cache.read + tokens.cache.write
|
|
193
197
|
output += tokens.output
|
|
194
|
-
cached += tokens.cache.read
|
|
198
|
+
cached += tokens.cache.read
|
|
195
199
|
}
|
|
196
200
|
for (const part of message.content) {
|
|
197
201
|
if (part.type !== "tool") continue
|
|
@@ -204,12 +208,11 @@ export async function buildStats(ctx: Plugin.Context, sessionID: string): Promis
|
|
|
204
208
|
}
|
|
205
209
|
|
|
206
210
|
/**
|
|
207
|
-
*
|
|
211
|
+
* 输入:完整提示词 token(含缓存读写)与命中 token(`cache.read`)。
|
|
208
212
|
* 输出:缓存命中率百分比,向下截断到两位小数。
|
|
209
|
-
* 预期:分母为 0 时返回 0;`100` 只代表真实全命中。
|
|
213
|
+
* 预期:分母为 0 时返回 0;结果夹在 0..100;`100` 只代表真实全命中。
|
|
210
214
|
*/
|
|
211
215
|
export function hitRatePercent(input: number, cached: number): number {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
return Math.floor((cached / total) * 10_000) / 100
|
|
216
|
+
if (input <= 0 || cached <= 0) return 0
|
|
217
|
+
return Math.floor(Math.min(1, cached / input) * 10_000) / 100
|
|
215
218
|
}
|