opencode-visual-cache 1.2.9-beta.0 → 1.2.10
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 +2 -0
- package/dist/_version.d.ts +1 -1
- package/dist/_version.js +1 -1
- package/dist/index.js +122 -155
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/index.tsx +1008 -1081
package/README.md
CHANGED
|
@@ -134,6 +134,8 @@ npm install -g opencode-visual-cache@latest
|
|
|
134
134
|
|
|
135
135
|
通过 `/cache-section` 切换后即时生效,无需重启。此外,该命令还可以开关面板的**外边框**——关闭后内容会顶格显示,释放额外空间。
|
|
136
136
|
|
|
137
|
+
> **关于 Token 分布数值**:分布面板中"总计"为最后一次 API 调用的精确 token 数,"系统提示"/"用户"等分项为字符级 BPE 估算值。分项之和通常小于总计,差值主要来自 OpenCode 运行时注入的系统提示组成部分,包括环境信息、Skill 目录、工具 Schema 定义等(详见 [`system.ts`](https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/session/system.ts)、[`tools.ts`](https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/session/tools.ts))。这些内容不在 agent 配置的 `prompt` 字段中,因此插件无法估算,属于预期行为。
|
|
138
|
+
|
|
137
139
|
---
|
|
138
140
|
|
|
139
141
|
## 5. 更新
|
package/dist/_version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PLUGIN_VERSION = "1.2.
|
|
1
|
+
export declare const PLUGIN_VERSION = "1.2.10";
|
package/dist/_version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// auto-generated
|
|
2
|
-
export const PLUGIN_VERSION = "1.2.
|
|
2
|
+
export const PLUGIN_VERSION = "1.2.10";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@opentui/solid/jsx-runtime";
|
|
2
|
-
import { createMemo, createSignal, createEffect, onMount, onCleanup, Show } from "solid-js";
|
|
2
|
+
import { createMemo, createSignal, createEffect, onMount, onCleanup, Show, untrack } from "solid-js";
|
|
3
3
|
import { PLUGIN_VERSION } from "./_version";
|
|
4
4
|
// ── terminal-width helpers ────────────────────────────────────────
|
|
5
5
|
// CJK characters occupy 2 terminal columns; padEnd/padStart count
|
|
@@ -216,7 +216,7 @@ function fmt(n) {
|
|
|
216
216
|
if (n >= 1_000_000)
|
|
217
217
|
return (n / 1_000_000).toFixed(1) + "M";
|
|
218
218
|
if (n >= 10_000)
|
|
219
|
-
return
|
|
219
|
+
return (n / 1_000).toFixed(1) + "K";
|
|
220
220
|
return n.toLocaleString("en-US");
|
|
221
221
|
}
|
|
222
222
|
function num(v) {
|
|
@@ -256,16 +256,19 @@ function estimateTokens(text) {
|
|
|
256
256
|
else
|
|
257
257
|
ascii++;
|
|
258
258
|
}
|
|
259
|
-
//
|
|
260
|
-
// token
|
|
261
|
-
//
|
|
259
|
+
// Real BPE tokenizers (cl100k_base, o200k_base) average ~3.5-4.0
|
|
260
|
+
// ASCII chars/token for both JSON and source code — close to prose.
|
|
261
|
+
// The old 2.0 / 2.5 ratios matched minified-JS extremes, not typical
|
|
262
|
+
// payloads, and systematically over-estimated token counts.
|
|
262
263
|
const trimmed = text.trimStart();
|
|
263
|
-
|
|
264
|
+
// Strip markdown code-fence prefix so that ```json … is detected as JSON
|
|
265
|
+
const strippedFence = trimmed.replace(/^\x60{3}\w*\s*\n?/, "");
|
|
266
|
+
const jsonLike = (strippedFence.startsWith("{") || strippedFence.startsWith("["))
|
|
264
267
|
&& /"[^"]+"\s*:/.test(text);
|
|
265
268
|
const codeLike = !jsonLike
|
|
266
269
|
&& /```|^import |^export |^function |^const |^let |^var |^class |^interface |^type |^def |^fn |^pub |^use |^mod |^package /m.test(text);
|
|
267
|
-
const asciiPerToken = jsonLike ?
|
|
268
|
-
return Math.max(1, Math.ceil(ascii / asciiPerToken + cjk / 1.
|
|
270
|
+
const asciiPerToken = jsonLike ? 3.5 : codeLike ? 3.5 : 4;
|
|
271
|
+
return Math.max(1, Math.ceil(ascii / asciiPerToken + cjk / 1.0));
|
|
269
272
|
}
|
|
270
273
|
const CURRENCIES = {
|
|
271
274
|
USD: "$", CNY: "¥", EUR: "€", JPY: "JP¥", GBP: "£", KRW: "₩",
|
|
@@ -306,29 +309,33 @@ function TokenCachePanel(props) {
|
|
|
306
309
|
output: 0, apiOutput: 0, apiInput: 0, stepCost: 0,
|
|
307
310
|
});
|
|
308
311
|
const [lastHasDist, setLastHasDist] = createSignal(false);
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
312
|
+
const [dataSignal, setDataSignal] = createSignal({
|
|
313
|
+
hitRate: 0, read: 0, write: 0, freshInput: 0, output: 0,
|
|
314
|
+
cost: 0, saved: 0, model: "", inputRate: 0, cacheReadRate: 0, cacheWriteRate: 0,
|
|
315
|
+
hasPricing: false, hasData: false, trend: 0, hasTrendData: false,
|
|
316
|
+
providerName: "", sessionHitRate: 0,
|
|
317
|
+
dist: { system: 0, user: 0, agent: 0, toolCall: 0, toolResult: 0, output: 0, apiOutput: 0, apiInput: 0, stepCost: 0 },
|
|
318
|
+
hasDistData: false,
|
|
319
|
+
});
|
|
320
|
+
const [refreshTick, setRefreshTick] = createSignal(0);
|
|
321
|
+
createEffect(() => {
|
|
322
|
+
const sid = props.sessionId;
|
|
323
|
+
void refreshTick();
|
|
324
|
+
void partVersion();
|
|
325
|
+
// 自然追踪 messages 和 provider(SDK 数据就绪时自动重新执行)
|
|
326
|
+
const msgs = props.api.state.session.messages(sid);
|
|
327
|
+
let input = 0, read = 0, write = 0, output = 0, cost = 0, pid = "", mid = "";
|
|
328
|
+
let prevMsgHitRate = -1, lastMsgHitRate = -1;
|
|
321
329
|
for (const msg of msgs) {
|
|
322
330
|
if (msg.role !== "assistant")
|
|
323
331
|
continue;
|
|
324
332
|
const t = msg.tokens;
|
|
325
333
|
if (!t)
|
|
326
334
|
continue;
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
if (msgInputTokens > 0) {
|
|
335
|
+
const mit = num(t.input) + num(t.cache?.read), mrt = num(t.cache?.read);
|
|
336
|
+
if (mit > 0) {
|
|
330
337
|
prevMsgHitRate = lastMsgHitRate;
|
|
331
|
-
lastMsgHitRate = (
|
|
338
|
+
lastMsgHitRate = (mrt / mit) * 100;
|
|
332
339
|
}
|
|
333
340
|
input += num(t.input);
|
|
334
341
|
read += num(t.cache?.read);
|
|
@@ -340,12 +347,8 @@ function TokenCachePanel(props) {
|
|
|
340
347
|
mid = msg.modelID;
|
|
341
348
|
}
|
|
342
349
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
let inputRate = 0;
|
|
346
|
-
let cacheReadRate = 0;
|
|
347
|
-
let cacheWriteRate = 0;
|
|
348
|
-
if (read > 0 && pid && mid) {
|
|
350
|
+
let saved = 0, inputRate = 0, cacheReadRate = 0, cacheWriteRate = 0;
|
|
351
|
+
if (read > 0 && pid && mid)
|
|
349
352
|
for (const provider of props.api.state.provider) {
|
|
350
353
|
if (provider.id !== pid)
|
|
351
354
|
continue;
|
|
@@ -355,152 +358,115 @@ function TokenCachePanel(props) {
|
|
|
355
358
|
inputRate = num(model.cost.input);
|
|
356
359
|
cacheReadRate = num(model.cost.cache?.read);
|
|
357
360
|
cacheWriteRate = num(model.cost.cache?.write);
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
saved = (read * diff) / 1_000_000;
|
|
361
|
+
if (inputRate > cacheReadRate)
|
|
362
|
+
saved = (read * (inputRate - cacheReadRate)) / 1_000_000;
|
|
361
363
|
break;
|
|
362
364
|
}
|
|
363
|
-
}
|
|
364
|
-
// `input` from the API represents fresh (non-cached) tokens.
|
|
365
365
|
const hitRate = lastMsgHitRate >= 0 ? lastMsgHitRate : 0;
|
|
366
|
-
|
|
367
|
-
const
|
|
368
|
-
const sessionHitRate = freshTotal > 0 ? (read / freshTotal) * 100 : 0;
|
|
369
|
-
const model = mid.split("/").pop() ?? mid;
|
|
370
|
-
const hasPricing = inputRate > 0 || cacheReadRate > 0 || cacheWriteRate > 0;
|
|
371
|
-
let trend = 0;
|
|
366
|
+
const freshTotal = input + read, sessionHitRate = freshTotal > 0 ? (read / freshTotal) * 100 : 0;
|
|
367
|
+
const model = mid.split("/").pop() ?? mid, hasPricing = inputRate > 0 || cacheReadRate > 0 || cacheWriteRate > 0;
|
|
372
368
|
const hasTrendData = prevMsgHitRate >= 0 && lastMsgHitRate >= 0;
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
// Wrapped in try-catch so a part fetching failure never crashes the panel.
|
|
379
|
-
let dist = { system: 0, user: 0, agent: 0, toolCall: 0, toolResult: 0, output: 0, apiOutput: 0, apiInput: 0, stepCost: 0 };
|
|
380
|
-
let hasDistData = false;
|
|
381
|
-
try {
|
|
382
|
-
partVersion(); // track part changes for reactivity
|
|
383
|
-
dist = { system: 0, user: 0, agent: 0, toolCall: 0, toolResult: 0, output: 0, apiOutput: 0, apiInput: 0, stepCost: 0 };
|
|
384
|
-
// Read agent system prompt once before the message loop. Reading it
|
|
385
|
-
// inside the per-user-message branch risks transient unavailability
|
|
386
|
-
// (api.state.config not yet resolved during streaming) silently
|
|
387
|
-
// resetting a previously-computed value and causing display flicker.
|
|
369
|
+
const trend = hasTrendData ? lastMsgHitRate - prevMsgHitRate : 0, providerName = pid || "";
|
|
370
|
+
// untrack 只包裹已知触发死锁的 API
|
|
371
|
+
const distData = untrack(() => {
|
|
372
|
+
let dist = { system: 0, user: 0, agent: 0, toolCall: 0, toolResult: 0, output: 0, apiOutput: 0, apiInput: 0, stepCost: 0 };
|
|
373
|
+
let hasDistData = false;
|
|
388
374
|
try {
|
|
389
|
-
const session = props.api.state.session.get(props.
|
|
390
|
-
const cfg = props.api.state.config;
|
|
375
|
+
const session = props.api.state.session.get(sid), cfg = props.api.state.config;
|
|
391
376
|
const agentName = String(session?.agent ?? cfg?.default_agent ?? "build");
|
|
392
377
|
const agents = cfg?.agent;
|
|
393
378
|
const agentCfg = agents?.[agentName];
|
|
394
379
|
const sysPrompt = typeof agentCfg?.prompt === "string" ? agentCfg.prompt : "";
|
|
395
380
|
if (sysPrompt)
|
|
396
381
|
dist.system = estimateTokens(sysPrompt);
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
parts = props.api.state.part(msg.id);
|
|
407
|
-
}
|
|
408
|
-
catch { }
|
|
409
|
-
for (const p of parts) {
|
|
410
|
-
if (p.type === "text" && !p.synthetic && !p.ignored) {
|
|
411
|
-
dist.user += estimateTokens(p.text);
|
|
382
|
+
let lastAssMsg;
|
|
383
|
+
for (const msg of msgs) {
|
|
384
|
+
if (msg.role === "user") {
|
|
385
|
+
const um = msg;
|
|
386
|
+
if (um.system)
|
|
387
|
+
dist.system += estimateTokens(um.system);
|
|
388
|
+
let parts = [];
|
|
389
|
+
try {
|
|
390
|
+
parts = props.api.state.part(msg.id);
|
|
412
391
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
if (
|
|
416
|
-
dist.user += estimateTokens(
|
|
392
|
+
catch { }
|
|
393
|
+
for (const p of parts) {
|
|
394
|
+
if (p.type === "text" && !p.synthetic && !p.ignored)
|
|
395
|
+
dist.user += estimateTokens(p.text);
|
|
396
|
+
else if (p.type === "file") {
|
|
397
|
+
const fp = p;
|
|
398
|
+
if (fp.source?.text?.value)
|
|
399
|
+
dist.user += estimateTokens(fp.source.text.value);
|
|
400
|
+
}
|
|
417
401
|
}
|
|
418
402
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
// Tool call input (params)
|
|
432
|
-
let rawInput = "";
|
|
433
|
-
try {
|
|
434
|
-
rawInput = tp.state.raw ?? JSON.stringify(tp.state.input);
|
|
435
|
-
}
|
|
436
|
-
catch {
|
|
403
|
+
else if (msg.role === "assistant") {
|
|
404
|
+
const am = msg;
|
|
405
|
+
dist.output += num(am.tokens?.output);
|
|
406
|
+
let parts = [];
|
|
407
|
+
try {
|
|
408
|
+
parts = props.api.state.part(msg.id);
|
|
409
|
+
}
|
|
410
|
+
catch { }
|
|
411
|
+
for (const p of parts) {
|
|
412
|
+
if (p.type === "tool") {
|
|
413
|
+
const tp = p;
|
|
414
|
+
let rawInput = "";
|
|
437
415
|
try {
|
|
438
|
-
rawInput = JSON.stringify(tp.state);
|
|
416
|
+
rawInput = tp.state.raw ?? (tp.state.input != null ? JSON.stringify(tp.state.input) : "");
|
|
439
417
|
}
|
|
440
418
|
catch { }
|
|
419
|
+
if (rawInput)
|
|
420
|
+
dist.toolCall += estimateTokens(rawInput);
|
|
421
|
+
if (tp.state.status === "completed") {
|
|
422
|
+
const c = tp.state;
|
|
423
|
+
if (c.output)
|
|
424
|
+
dist.toolResult += estimateTokens(c.output);
|
|
425
|
+
}
|
|
426
|
+
else if (tp.state.status === "error") {
|
|
427
|
+
const e = tp.state;
|
|
428
|
+
if (e.error)
|
|
429
|
+
dist.toolResult += estimateTokens(e.error);
|
|
430
|
+
}
|
|
441
431
|
}
|
|
442
|
-
if (
|
|
443
|
-
dist.
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
if (completed.output)
|
|
448
|
-
dist.toolResult += estimateTokens(completed.output);
|
|
449
|
-
}
|
|
450
|
-
else if (tp.state.status === "error") {
|
|
451
|
-
const errored = tp.state;
|
|
452
|
-
if (errored.error)
|
|
453
|
-
dist.toolResult += estimateTokens(errored.error);
|
|
432
|
+
else if (p.type === "reasoning")
|
|
433
|
+
dist.agent += estimateTokens(p.text);
|
|
434
|
+
else if (p.type === "subtask") {
|
|
435
|
+
const sub = p;
|
|
436
|
+
dist.agent += estimateTokens(sub.prompt || sub.description || "");
|
|
454
437
|
}
|
|
455
438
|
}
|
|
456
|
-
else if (p.type === "reasoning") {
|
|
457
|
-
dist.agent += estimateTokens(p.text);
|
|
458
|
-
}
|
|
459
|
-
else if (p.type === "subtask") {
|
|
460
|
-
const sub = p;
|
|
461
|
-
dist.agent += estimateTokens(sub.prompt || sub.description || "");
|
|
462
|
-
}
|
|
463
|
-
else if (p.type === "step-finish") {
|
|
464
|
-
// StepFinishPart carries API-exact per-call token counts.
|
|
465
|
-
// Sum across all step-finish parts (one per API call in tool loops).
|
|
466
|
-
const sf = p;
|
|
467
|
-
dist.apiInput += sf.tokens?.input ?? 0;
|
|
468
|
-
dist.apiOutput += sf.tokens?.output ?? 0;
|
|
469
|
-
}
|
|
470
439
|
}
|
|
471
440
|
}
|
|
441
|
+
// 从后往前找最后一条有 token 数据的 assistant 消息(避免取到 streaming 中未填充的消息)
|
|
442
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
443
|
+
if (msgs[i].role !== "assistant")
|
|
444
|
+
continue;
|
|
445
|
+
const t = msgs[i].tokens;
|
|
446
|
+
if (t && (t.input > 0 || (t.cache?.read ?? 0) > 0)) {
|
|
447
|
+
lastAssMsg = msgs[i];
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
// 取最后一条有数据消息的总输入(含缓存读)作为当前 context 大小
|
|
452
|
+
dist.apiInput = num(lastAssMsg?.tokens?.input) + num(lastAssMsg?.tokens?.cache?.read);
|
|
453
|
+
dist.apiOutput = num(lastAssMsg?.tokens?.output);
|
|
454
|
+
hasDistData = dist.system + dist.user + dist.agent + dist.toolCall + dist.toolResult > 0 || dist.apiOutput > 0 || dist.apiInput > 0;
|
|
472
455
|
}
|
|
473
|
-
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
// system bucket rather than replacing the local estimate.
|
|
481
|
-
const overhead = Math.max(0, apiTotalInput - totalInput);
|
|
482
|
-
if (overhead >= 50) {
|
|
483
|
-
dist.system += overhead;
|
|
484
|
-
}
|
|
485
|
-
hasDistData = totalInput > 0 || finalOutput > 0 || apiTotalInput > 0;
|
|
486
|
-
}
|
|
487
|
-
catch {
|
|
488
|
-
// Graceful degradation — dist stays at zeroes
|
|
489
|
-
}
|
|
490
|
-
// Fall back to last known-good distribution while api.state.part()
|
|
491
|
-
// is re-hydrating after a view switch.
|
|
492
|
-
const finalDist = hasDistData ? dist : lastDist();
|
|
493
|
-
const finalHasDist = hasDistData || lastHasDist();
|
|
494
|
-
return {
|
|
495
|
-
hitRate, read, write, freshInput: input, output,
|
|
496
|
-
cost, saved, model, inputRate, cacheReadRate, cacheWriteRate, hasPricing,
|
|
456
|
+
catch { }
|
|
457
|
+
const finalDist = hasDistData ? dist : lastDist(), finalHasDist = hasDistData || lastHasDist();
|
|
458
|
+
return { finalDist, finalHasDist };
|
|
459
|
+
});
|
|
460
|
+
setDataSignal({
|
|
461
|
+
hitRate, read, write, freshInput: input, output, cost, saved, model,
|
|
462
|
+
inputRate, cacheReadRate, cacheWriteRate, hasPricing,
|
|
497
463
|
hasData: read > 0 || write > 0 || input > 0 || output > 0 || cost > 0,
|
|
498
|
-
trend, hasTrendData,
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
464
|
+
trend, hasTrendData, providerName, sessionHitRate,
|
|
465
|
+
dist: distData.finalDist, hasDistData: distData.finalHasDist,
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
const data = createMemo(() => {
|
|
469
|
+
return dataSignal();
|
|
504
470
|
});
|
|
505
471
|
// Persist the last valid distribution so that data() can fall back
|
|
506
472
|
// to it while api.state.part() is re-hydrating after a view switch.
|
|
@@ -600,8 +566,9 @@ function TokenCachePanel(props) {
|
|
|
600
566
|
clearTimeout(partTimer);
|
|
601
567
|
partTimer = setTimeout(() => setPartVersion((v) => v + 1), 100);
|
|
602
568
|
};
|
|
603
|
-
const unsubPart = props.api.event.on("message.part.updated", bumpPartVersion);
|
|
604
|
-
const unsubMsg = props.api.event.on("message.updated", bumpPartVersion);
|
|
569
|
+
const unsubPart = props.api.event.on("message.part.updated", () => { bumpPartVersion(); setRefreshTick(v => v + 1); });
|
|
570
|
+
const unsubMsg = props.api.event.on("message.updated", () => { bumpPartVersion(); setRefreshTick(v => v + 1); });
|
|
571
|
+
setRefreshTick(v => v + 1);
|
|
605
572
|
onCleanup(() => { clearTimeout(partTimer); unsubPart(); unsubMsg(); });
|
|
606
573
|
});
|
|
607
574
|
// ── colours ──
|
|
@@ -662,7 +629,7 @@ function TokenCachePanel(props) {
|
|
|
662
629
|
// boxEl.width may be undefined before the first measurement — guard with 0
|
|
663
630
|
const w = boxEl ? Math.max(MIN_PANEL_WIDTH, boxEl.width ?? 0) : DEFAULT_PANEL_WIDTH;
|
|
664
631
|
setPanelWidth((prev) => (prev === w ? prev : w));
|
|
665
|
-
}, children: [_jsxs("text", { onMouseUp: () => setOpen((o) => { const n = !o; persistFold("open", n); return n; }), children: [_jsx("span", { style: { fg: pal().muted }, children: open() ? "\u25bc " : "\u25b6 " }), _jsxs("span", { style: { fg: pal().primary }, children: [_jsx("b", { children: T.title }), _jsx(Show, { when: open(), children: _jsxs("span", { style: { fg: pal().muted }, children: [" (v", PLUGIN_VERSION, ")"] }) })] }), _jsxs(Show, { when: !open() && data().hasData, children: [_jsxs(Show, { when: data().hasTrendData, children: [_jsx("span", { children: " ".repeat(Math.max(1, panelWidth() - gutter() - HEADER_PREFIX - visualWidth(T.title) - visualWidth(pct() + " " + T.hitFolded + " " + trendLabel(data().trend)))) }), _jsxs("span", { style: { fg: hitColor() }, children: [pct(), " ", T.hitFolded] }), _jsxs("span", { style: { fg: data().trend !== 0 ? (data().trend > 0 ? pal().success : pal().error) : pal().text }, children: [" ", trendLabel(data().trend)] })] }), _jsxs(Show, { when: !data().hasTrendData, children: [_jsx("span", { children: " ".repeat(Math.max(1, panelWidth() - gutter() - HEADER_PREFIX - visualWidth(T.title) - visualWidth(pct() + " " + T.hitFolded))) }), _jsxs("span", { style: { fg: hitColor() }, children: [pct(), " ", T.hitFolded] })] })] })] }), _jsx(Show, { when: open(), children: _jsxs(Show, { when: data().hasData, fallback: _jsxs(_Fragment, { children: [_jsx("text", { fg: pal().muted, children: sep() }), _jsxs("text", { children: [_jsx("span", { style: { fg: pal().muted }, children: "> " }), _jsx("span", { style: { fg: pal().muted }, children: T.noData })] })] }), children: [_jsx("text", { fg: pal().muted, children: sep() }), _jsxs("text", { children: [_jsxs("span", { style: { fg: pal().text }, children: [T.hit, " "] }), _jsxs("span", { style: { fg: hitColor() }, children: ["[", bar(), "] "] }), _jsx("span", { style: { fg: pal().text }, children: pct() }), _jsx(Show, { when: data().hasTrendData, children: _jsxs("span", { style: { fg: data().trend !== 0 ? (data().trend > 0 ? pal().success : pal().error) : pal().text }, children: [" ", trendLabel(data().trend)] }) })] }), _jsx("text", { fg: pal().muted, children: justify(T.totalHit, (Math.floor(data().sessionHitRate * 10) / 10).toFixed(1) + "%") }), _jsxs(Show, { when: sectionDetail(), children: [_jsxs("text", { onMouseUp: () => setDetailOpen((o) => { const n = !o; persistFold("detail", n); return n; }), children: [_jsx("span", { style: { fg: pal().muted }, children: detailOpen() ? "\u25bc " : "\u25b6 " }), _jsx("span", { style: { fg: pal().primary }, children: _jsx("b", { children: T.secDetail }) }), _jsx("span", { style: { fg: pal().muted }, children: sep().slice(visualWidth((detailOpen() ? "\u25bc " : "\u25b6 ") + T.secDetail)) })] }), _jsxs(Show, { when: detailOpen(), children: [_jsx(Show, { when: data().read > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.read, fmt(data().read), T.tok) }) }), _jsx(Show, { when: data().write > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.write, fmt(data().write), T.tok) }) }), _jsx("text", { fg: pal().muted, children: justify(T.miss, fmt(data().freshInput), T.tok) }), _jsx("text", { fg: pal().muted, children: justify(T.out, fmt(data().output), T.tok) }), _jsx(Show, { when: data().saved > 0, children: _jsxs("text", { children: [_jsx("span", { style: { fg: pal().muted }, children: T.saved }), _jsx("span", { children: " ".repeat(Math.max(1, panelWidth() - gutter() - visualWidth(T.saved) - visualWidth("~" + fmtCost(data().saved, currencySymbol(), exchangeRate())))) }), _jsxs("span", { style: { fg: pal().success }, children: ["~", fmtCost(data().saved, currencySymbol(), exchangeRate())] })] }) })] })] }), _jsxs(Show, { when: sectionModel(), children: [_jsxs("text", { onMouseUp: () => setModelOpen((o) => { const n = !o; persistFold("model", n); return n; }), children: [_jsx("span", { style: { fg: pal().muted }, children: modelOpen() ? "\u25bc " : "\u25b6 " }), _jsx("span", { style: { fg: pal().primary }, children: _jsx("b", { children: T.secModel }) }), _jsx("span", { style: { fg: pal().muted }, children: sep().slice(visualWidth((modelOpen() ? "\u25bc " : "\u25b6 ") + T.secModel)) })] }), _jsxs(Show, { when: modelOpen(), children: [_jsx("text", { fg: pal().text, children: justify(T.cost, fmtCost(data().cost, currencySymbol(), exchangeRate())) }), _jsx(Show, { when: data().providerName, children: _jsx("text", { fg: pal().muted, children: justify(T.provider, data().providerName) }) }), _jsx("text", { fg: pal().muted, children: justify(T.model, data().model) }), _jsxs(Show, { when: data().hasPricing, children: [_jsx("text", { fg: pal().muted, children: justify(T.rate, currencySymbol() + (data().inputRate * exchangeRate()).toFixed(2) + "/M " + T.inputRate) }), _jsx(Show, { when: data().cacheReadRate > 0, children: _jsx("text", { fg: pal().muted, children: justify("", currencySymbol() + (data().cacheReadRate * exchangeRate()).toFixed(2) + "/M " + T.cacheRate) }) }), _jsx(Show, { when: data().cacheWriteRate > 0, children: _jsx("text", { fg: pal().muted, children: justify("", currencySymbol() + (data().cacheWriteRate * exchangeRate()).toFixed(2) + "/M " + T.writeRate) }) })] })] })] }), _jsx(Show, { when: sectionDist(), children: _jsxs(Show, { when: data().hasDistData, children: [_jsxs("text", { onMouseUp: () => setDistOpen((o) => { const n = !o; persistFold("dist", n); return n; }), children: [_jsx("span", { style: { fg: pal().muted }, children: distOpen() ? "\u25bc " : "\u25b6 " }), _jsx("span", { style: { fg: pal().primary }, children: _jsx("b", { children: T.distTitle }) }), _jsx("span", { style: { fg: pal().muted }, children: sep().slice(visualWidth((distOpen() ? "\u25bc " : "\u25b6 ") + T.distTitle)) })] }), _jsxs(Show, { when: distOpen(), children: [_jsx(Show, { when: data().dist.system > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.distSys, fmt(data().dist.system), T.tok) }) }), _jsx(Show, { when: data().dist.user > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.distUser, fmt(data().dist.user), T.tok) }) }), _jsx(Show, { when: data().dist.agent > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.distAgent, fmt(data().dist.agent), T.tok) }) }), _jsx(Show, { when: data().dist.toolCall > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.distTool, fmt(data().dist.toolCall), T.tok) }) }), _jsx(Show, { when: data().dist.toolResult > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.distRes, fmt(data().dist.toolResult), T.tok) }) }), _jsx("text", { fg: pal().text, children: justify(T.distTotal, fmt(data().dist.
|
|
632
|
+
}, children: [_jsxs("text", { onMouseUp: () => setOpen((o) => { const n = !o; persistFold("open", n); return n; }), children: [_jsx("span", { style: { fg: pal().muted }, children: open() ? "\u25bc " : "\u25b6 " }), _jsxs("span", { style: { fg: pal().primary }, children: [_jsx("b", { children: T.title }), _jsx(Show, { when: open(), children: _jsxs("span", { style: { fg: pal().muted }, children: [" (v", PLUGIN_VERSION, ")"] }) })] }), _jsxs(Show, { when: !open() && data().hasData, children: [_jsxs(Show, { when: data().hasTrendData, children: [_jsx("span", { children: " ".repeat(Math.max(1, panelWidth() - gutter() - HEADER_PREFIX - visualWidth(T.title) - visualWidth(pct() + " " + T.hitFolded + " " + trendLabel(data().trend)))) }), _jsxs("span", { style: { fg: hitColor() }, children: [pct(), " ", T.hitFolded] }), _jsxs("span", { style: { fg: data().trend !== 0 ? (data().trend > 0 ? pal().success : pal().error) : pal().text }, children: [" ", trendLabel(data().trend)] })] }), _jsxs(Show, { when: !data().hasTrendData, children: [_jsx("span", { children: " ".repeat(Math.max(1, panelWidth() - gutter() - HEADER_PREFIX - visualWidth(T.title) - visualWidth(pct() + " " + T.hitFolded))) }), _jsxs("span", { style: { fg: hitColor() }, children: [pct(), " ", T.hitFolded] })] })] })] }), _jsx(Show, { when: open(), children: _jsxs(Show, { when: data().hasData, fallback: _jsxs(_Fragment, { children: [_jsx("text", { fg: pal().muted, children: sep() }), _jsxs("text", { children: [_jsx("span", { style: { fg: pal().muted }, children: "> " }), _jsx("span", { style: { fg: pal().muted }, children: T.noData })] })] }), children: [_jsx("text", { fg: pal().muted, children: sep() }), _jsxs("text", { children: [_jsxs("span", { style: { fg: pal().text }, children: [T.hit, " "] }), _jsxs("span", { style: { fg: hitColor() }, children: ["[", bar(), "] "] }), _jsx("span", { style: { fg: pal().text }, children: pct() }), _jsx(Show, { when: data().hasTrendData, children: _jsxs("span", { style: { fg: data().trend !== 0 ? (data().trend > 0 ? pal().success : pal().error) : pal().text }, children: [" ", trendLabel(data().trend)] }) })] }), _jsx("text", { fg: pal().muted, children: justify(T.totalHit, (Math.floor(data().sessionHitRate * 10) / 10).toFixed(1) + "%") }), _jsxs(Show, { when: sectionDetail(), children: [_jsxs("text", { onMouseUp: () => setDetailOpen((o) => { const n = !o; persistFold("detail", n); return n; }), children: [_jsx("span", { style: { fg: pal().muted }, children: detailOpen() ? "\u25bc " : "\u25b6 " }), _jsx("span", { style: { fg: pal().primary }, children: _jsx("b", { children: T.secDetail }) }), _jsx("span", { style: { fg: pal().muted }, children: sep().slice(visualWidth((detailOpen() ? "\u25bc " : "\u25b6 ") + T.secDetail)) })] }), _jsxs(Show, { when: detailOpen(), children: [_jsx(Show, { when: data().read > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.read, fmt(data().read), T.tok) }) }), _jsx(Show, { when: data().write > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.write, fmt(data().write), T.tok) }) }), _jsx("text", { fg: pal().muted, children: justify(T.miss, fmt(data().freshInput), T.tok) }), _jsx("text", { fg: pal().muted, children: justify(T.out, fmt(data().output), T.tok) }), _jsx(Show, { when: data().saved > 0, children: _jsxs("text", { children: [_jsx("span", { style: { fg: pal().muted }, children: T.saved }), _jsx("span", { children: " ".repeat(Math.max(1, panelWidth() - gutter() - visualWidth(T.saved) - visualWidth("~" + fmtCost(data().saved, currencySymbol(), exchangeRate())))) }), _jsxs("span", { style: { fg: pal().success }, children: ["~", fmtCost(data().saved, currencySymbol(), exchangeRate())] })] }) })] })] }), _jsxs(Show, { when: sectionModel(), children: [_jsxs("text", { onMouseUp: () => setModelOpen((o) => { const n = !o; persistFold("model", n); return n; }), children: [_jsx("span", { style: { fg: pal().muted }, children: modelOpen() ? "\u25bc " : "\u25b6 " }), _jsx("span", { style: { fg: pal().primary }, children: _jsx("b", { children: T.secModel }) }), _jsx("span", { style: { fg: pal().muted }, children: sep().slice(visualWidth((modelOpen() ? "\u25bc " : "\u25b6 ") + T.secModel)) })] }), _jsxs(Show, { when: modelOpen(), children: [_jsx("text", { fg: pal().text, children: justify(T.cost, fmtCost(data().cost, currencySymbol(), exchangeRate())) }), _jsx(Show, { when: data().providerName, children: _jsx("text", { fg: pal().muted, children: justify(T.provider, data().providerName) }) }), _jsx("text", { fg: pal().muted, children: justify(T.model, data().model) }), _jsxs(Show, { when: data().hasPricing, children: [_jsx("text", { fg: pal().muted, children: justify(T.rate, currencySymbol() + (data().inputRate * exchangeRate()).toFixed(2) + "/M " + T.inputRate) }), _jsx(Show, { when: data().cacheReadRate > 0, children: _jsx("text", { fg: pal().muted, children: justify("", currencySymbol() + (data().cacheReadRate * exchangeRate()).toFixed(2) + "/M " + T.cacheRate) }) }), _jsx(Show, { when: data().cacheWriteRate > 0, children: _jsx("text", { fg: pal().muted, children: justify("", currencySymbol() + (data().cacheWriteRate * exchangeRate()).toFixed(2) + "/M " + T.writeRate) }) })] })] })] }), _jsx(Show, { when: sectionDist(), children: _jsxs(Show, { when: data().hasDistData, children: [_jsxs("text", { onMouseUp: () => setDistOpen((o) => { const n = !o; persistFold("dist", n); return n; }), children: [_jsx("span", { style: { fg: pal().muted }, children: distOpen() ? "\u25bc " : "\u25b6 " }), _jsx("span", { style: { fg: pal().primary }, children: _jsx("b", { children: T.distTitle }) }), _jsx("span", { style: { fg: pal().muted }, children: sep().slice(visualWidth((distOpen() ? "\u25bc " : "\u25b6 ") + T.distTitle)) })] }), _jsxs(Show, { when: distOpen(), children: [_jsx(Show, { when: data().dist.system > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.distSys, fmt(data().dist.system), T.tok) }) }), _jsx(Show, { when: data().dist.user > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.distUser, fmt(data().dist.user), T.tok) }) }), _jsx(Show, { when: data().dist.agent > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.distAgent, fmt(data().dist.agent), T.tok) }) }), _jsx(Show, { when: data().dist.toolCall > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.distTool, fmt(data().dist.toolCall), T.tok) }) }), _jsx(Show, { when: data().dist.toolResult > 0, children: _jsx("text", { fg: pal().muted, children: justify(T.distRes, fmt(data().dist.toolResult), T.tok) }) }), _jsx("text", { fg: pal().text, children: justify(T.distTotal, fmt(data().dist.apiInput), T.tok) })] })] }) })] }) })] }));
|
|
666
633
|
}
|
|
667
634
|
// ---------------------------------------------------------------------------
|
|
668
635
|
// Plugin entry
|
package/package.json
CHANGED
package/src/_version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// auto-generated
|
|
2
|
-
export const PLUGIN_VERSION="1.2.
|
|
2
|
+
export const PLUGIN_VERSION="1.2.10";
|