opencode-visual-cache 1.2.14 → 1.2.15-beta.1
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 +21 -21
- package/dist/_version.d.ts +1 -1
- package/dist/_version.js +1 -1
- package/dist/index.js +3 -2
- package/dist/tui.js +1533 -0
- package/package.json +65 -62
- package/src/_version.ts +1 -1
- package/src/index.tsx +1185 -1184
package/dist/tui.js
ADDED
|
@@ -0,0 +1,1533 @@
|
|
|
1
|
+
// src/index.tsx
|
|
2
|
+
import { createComponent as _$createComponent } from "@opentui/solid";
|
|
3
|
+
import { effect as _$effect } from "@opentui/solid";
|
|
4
|
+
import { createTextNode as _$createTextNode } from "@opentui/solid";
|
|
5
|
+
import { insertNode as _$insertNode } from "@opentui/solid";
|
|
6
|
+
import { insert as _$insert } from "@opentui/solid";
|
|
7
|
+
import { setProp as _$setProp } from "@opentui/solid";
|
|
8
|
+
import { use as _$use } from "@opentui/solid";
|
|
9
|
+
import { spread as _$spread } from "@opentui/solid";
|
|
10
|
+
import { mergeProps as _$mergeProps } from "@opentui/solid";
|
|
11
|
+
import { memo as _$memo } from "@opentui/solid";
|
|
12
|
+
import { createElement as _$createElement } from "@opentui/solid";
|
|
13
|
+
import { createMemo, createSignal, createEffect, onMount, onCleanup, Show, untrack } from "solid-js";
|
|
14
|
+
|
|
15
|
+
// src/_version.ts
|
|
16
|
+
var PLUGIN_VERSION = "1.2.14";
|
|
17
|
+
|
|
18
|
+
// src/index.tsx
|
|
19
|
+
function charColumns(c) {
|
|
20
|
+
const code = c.codePointAt(0) ?? 0;
|
|
21
|
+
if (code < 32) return 0;
|
|
22
|
+
if (code < 127) return 1;
|
|
23
|
+
if (code < 160) return 0;
|
|
24
|
+
if (code >= 4352 && code <= 4447 || // Hangul Jamo
|
|
25
|
+
code >= 11904 && code <= 42191 || // CJK Radicals … Yi
|
|
26
|
+
code >= 44032 && code <= 55203 || // Hangul
|
|
27
|
+
code >= 63744 && code <= 64255 || // CJK Compat
|
|
28
|
+
code >= 65040 && code <= 65135 || // Vertical / Compat
|
|
29
|
+
code >= 65281 && code <= 65376 || // Fullwidth
|
|
30
|
+
code >= 65504 && code <= 65510 || // Fullwidth signs
|
|
31
|
+
code >= 127744 && code <= 128591 || // Misc Symbols (emoji)
|
|
32
|
+
code >= 131072 && code <= 262141)
|
|
33
|
+
return 2;
|
|
34
|
+
return 1;
|
|
35
|
+
}
|
|
36
|
+
function visualWidth(s) {
|
|
37
|
+
let w = 0;
|
|
38
|
+
for (const c of s) w += charColumns(c);
|
|
39
|
+
return w;
|
|
40
|
+
}
|
|
41
|
+
function truncateVisual(s, maxCols) {
|
|
42
|
+
if (visualWidth(s) <= maxCols) return s;
|
|
43
|
+
let result = "", w = 0;
|
|
44
|
+
for (const c of s) {
|
|
45
|
+
const cw = charColumns(c);
|
|
46
|
+
if (w + cw > maxCols - 1) {
|
|
47
|
+
result += "\u2026";
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
result += c;
|
|
51
|
+
w += cw;
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
var DEBUG_LANG = typeof process !== "undefined" ? process.env?.CACHE_TUI_LANG : void 0;
|
|
56
|
+
var LANG_ZH = DEBUG_LANG ? DEBUG_LANG === "zh" : (() => {
|
|
57
|
+
try {
|
|
58
|
+
return Intl.DateTimeFormat().resolvedOptions().locale.startsWith("zh");
|
|
59
|
+
} catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
})();
|
|
63
|
+
var ZH_T = {
|
|
64
|
+
title: "\u7F13\u5B58\u7EDF\u8BA1",
|
|
65
|
+
hit: "\u547D\u4E2D\u7387",
|
|
66
|
+
totalHit: "\u603B\u547D\u4E2D:",
|
|
67
|
+
read: "\u7F13\u5B58\u8BFB:",
|
|
68
|
+
write: "\u7F13\u5B58\u5199:",
|
|
69
|
+
miss: "\u672A\u547D\u4E2D:",
|
|
70
|
+
out: "\u8F93\u51FA:",
|
|
71
|
+
cost: "\u8D39\u7528:",
|
|
72
|
+
saved: "\u7D2F\u8BA1\u8282\u7701:",
|
|
73
|
+
model: "\u6A21\u578B:",
|
|
74
|
+
provider: "\u63D0\u4F9B\u5546:",
|
|
75
|
+
rate: "\u5355\u4EF7:",
|
|
76
|
+
hitFolded: "\u547D\u4E2D",
|
|
77
|
+
inputRate: "\u8F93\u5165",
|
|
78
|
+
cacheRate: "\u7F13\u5B58",
|
|
79
|
+
writeRate: "\u5199\u5165",
|
|
80
|
+
noData: "\u7B49\u5F85\u7F13\u5B58\u6570\u636E...",
|
|
81
|
+
tok: "tok",
|
|
82
|
+
distTitle: "\u4F30\u7B97 Token \u5206\u5E03",
|
|
83
|
+
distSys: "\u7CFB\u7EDF\u63D0\u793A:",
|
|
84
|
+
distUser: "\u7528\u6237:",
|
|
85
|
+
distAgent: "Agent \u6307\u4EE4:",
|
|
86
|
+
distTool: "Tool \u8C03\u7528:",
|
|
87
|
+
distRes: "Tool \u7ED3\u679C:",
|
|
88
|
+
distTotal: "\u603B\u8BA1:",
|
|
89
|
+
distOut: "\u8F93\u51FA:",
|
|
90
|
+
secDetail: "\u660E\u7EC6",
|
|
91
|
+
secModel: "\u6A21\u578B",
|
|
92
|
+
secSkills: "\u5DF2\u52A0\u8F7D\u6280\u80FD"
|
|
93
|
+
};
|
|
94
|
+
var EN_T = {
|
|
95
|
+
title: "Token Cache",
|
|
96
|
+
hit: "Hit",
|
|
97
|
+
totalHit: "Total Hit:",
|
|
98
|
+
read: "Read:",
|
|
99
|
+
write: "Write:",
|
|
100
|
+
miss: "Miss:",
|
|
101
|
+
out: "Out:",
|
|
102
|
+
cost: "Cost:",
|
|
103
|
+
saved: "Total Saved:",
|
|
104
|
+
model: "Model:",
|
|
105
|
+
provider: "Provider:",
|
|
106
|
+
rate: "Rate:",
|
|
107
|
+
hitFolded: "hit",
|
|
108
|
+
inputRate: "in",
|
|
109
|
+
cacheRate: "cache",
|
|
110
|
+
writeRate: "write",
|
|
111
|
+
noData: "Waiting for cache data...",
|
|
112
|
+
tok: "tok",
|
|
113
|
+
distTitle: "Estimated Token Dist.",
|
|
114
|
+
distSys: "System:",
|
|
115
|
+
distUser: "User:",
|
|
116
|
+
distAgent: "Agent Instr:",
|
|
117
|
+
distTool: "Tool Call:",
|
|
118
|
+
distRes: "Tool Result:",
|
|
119
|
+
distTotal: "Total:",
|
|
120
|
+
distOut: "Output:",
|
|
121
|
+
secDetail: "Detail",
|
|
122
|
+
secModel: "Model",
|
|
123
|
+
secSkills: "Loaded Skills"
|
|
124
|
+
};
|
|
125
|
+
function rgb(raw) {
|
|
126
|
+
if (typeof raw === "string" && raw.startsWith("#")) {
|
|
127
|
+
const h = raw.slice(1);
|
|
128
|
+
return {
|
|
129
|
+
r: parseInt(h.slice(0, 2), 16),
|
|
130
|
+
g: parseInt(h.slice(2, 4), 16),
|
|
131
|
+
b: parseInt(h.slice(4, 6), 16)
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (raw && typeof raw === "object") {
|
|
135
|
+
const o = raw;
|
|
136
|
+
if (typeof o.r === "number" && typeof o.g === "number" && typeof o.b === "number") {
|
|
137
|
+
const scale = o.r > 1 || o.g > 1 || o.b > 1 ? 1 : 255;
|
|
138
|
+
return {
|
|
139
|
+
r: Math.round(o.r * scale),
|
|
140
|
+
g: Math.round(o.g * scale),
|
|
141
|
+
b: Math.round(o.b * scale)
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
function saturation(r, g, b) {
|
|
148
|
+
const max = Math.max(r, g, b) / 255;
|
|
149
|
+
const min = Math.min(r, g, b) / 255;
|
|
150
|
+
const delta = max - min;
|
|
151
|
+
if (delta === 0) return 0;
|
|
152
|
+
const L = (max + min) / 2;
|
|
153
|
+
return L <= 0.5 ? delta / (max + min) : delta / (2 - max - min);
|
|
154
|
+
}
|
|
155
|
+
function desaturateTo(raw, maxSat, fallback) {
|
|
156
|
+
const c = rgb(raw);
|
|
157
|
+
if (!c) return fallback;
|
|
158
|
+
const sat = saturation(c.r, c.g, c.b);
|
|
159
|
+
if (sat <= maxSat) {
|
|
160
|
+
return "#" + [c.r, c.g, c.b].map((v) => v.toString(16).padStart(2, "0")).join("");
|
|
161
|
+
}
|
|
162
|
+
const luma = c.r * 0.299 + c.g * 0.587 + c.b * 0.114;
|
|
163
|
+
let lo = 0, hi = 1;
|
|
164
|
+
for (let i = 0; i < 12; i++) {
|
|
165
|
+
const mid = (lo + hi) / 2;
|
|
166
|
+
const nr2 = Math.round(c.r + (luma - c.r) * mid);
|
|
167
|
+
const ng2 = Math.round(c.g + (luma - c.g) * mid);
|
|
168
|
+
const nb2 = Math.round(c.b + (luma - c.b) * mid);
|
|
169
|
+
if (saturation(nr2, ng2, nb2) > maxSat) lo = mid;
|
|
170
|
+
else hi = mid;
|
|
171
|
+
}
|
|
172
|
+
const nr = Math.round(c.r + (luma - c.r) * hi);
|
|
173
|
+
const ng = Math.round(c.g + (luma - c.g) * hi);
|
|
174
|
+
const nb = Math.round(c.b + (luma - c.b) * hi);
|
|
175
|
+
return "#" + [nr, ng, nb].map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
|
|
176
|
+
}
|
|
177
|
+
var FALLBACK = {
|
|
178
|
+
primary: "#8B9DAF",
|
|
179
|
+
text: "#C5C5BB",
|
|
180
|
+
muted: "#7A7A72",
|
|
181
|
+
success: "#9CAF8B",
|
|
182
|
+
warning: "#C5B88D",
|
|
183
|
+
error: "#B08A8A",
|
|
184
|
+
border: "#6B6B63"
|
|
185
|
+
};
|
|
186
|
+
var MAX_SAT = 0.28;
|
|
187
|
+
function progressBar(percent, width) {
|
|
188
|
+
const clamped = Math.max(0, Math.min(100, percent));
|
|
189
|
+
const filled = Math.round(clamped / 100 * width);
|
|
190
|
+
const empty = Math.max(0, width - filled);
|
|
191
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
192
|
+
}
|
|
193
|
+
function fmt(n) {
|
|
194
|
+
if (n >= 1e6) return (n / 1e6).toFixed(1) + "M";
|
|
195
|
+
if (n >= 1e4) return (n / 1e3).toFixed(1) + "K";
|
|
196
|
+
return n.toLocaleString("en-US");
|
|
197
|
+
}
|
|
198
|
+
function num(v) {
|
|
199
|
+
return typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
200
|
+
}
|
|
201
|
+
function fmtCost(n, symbol = "$", rate = 1) {
|
|
202
|
+
const v = n * rate;
|
|
203
|
+
if (v >= 1) return symbol + v.toFixed(2);
|
|
204
|
+
if (v >= 0.01) return symbol + v.toFixed(3);
|
|
205
|
+
return symbol + v.toFixed(4);
|
|
206
|
+
}
|
|
207
|
+
function estimateTokens(text) {
|
|
208
|
+
if (!text || text.length === 0) return 0;
|
|
209
|
+
let ascii = 0;
|
|
210
|
+
let cjk = 0;
|
|
211
|
+
for (const c of text) {
|
|
212
|
+
const code = c.codePointAt(0) ?? 0;
|
|
213
|
+
if (code >= 19968 && code <= 40959) cjk++;
|
|
214
|
+
else if (code >= 12352 && code <= 12543) cjk++;
|
|
215
|
+
else if (code >= 44032 && code <= 55203) cjk++;
|
|
216
|
+
else if (code >= 4352 && code <= 4607) cjk++;
|
|
217
|
+
else if (code >= 11904 && code <= 12031) cjk++;
|
|
218
|
+
else ascii++;
|
|
219
|
+
}
|
|
220
|
+
const trimmed = text.trimStart();
|
|
221
|
+
const strippedFence = trimmed.replace(/^\x60{3}\w*\s*\n?/, "");
|
|
222
|
+
const jsonLike = (strippedFence.startsWith("{") || strippedFence.startsWith("[")) && /"[^"]+"\s*:/.test(text);
|
|
223
|
+
const codeLike = !jsonLike && /```|^import |^export |^function |^const |^let |^var |^class |^interface |^type |^def |^fn |^pub |^use |^mod |^package /m.test(text);
|
|
224
|
+
const asciiPerToken = jsonLike ? 3.5 : codeLike ? 3.5 : 4;
|
|
225
|
+
return Math.max(1, Math.ceil(ascii / asciiPerToken + cjk / 1));
|
|
226
|
+
}
|
|
227
|
+
var CURRENCIES = {
|
|
228
|
+
USD: "$",
|
|
229
|
+
CNY: "\xA5",
|
|
230
|
+
EUR: "\u20AC",
|
|
231
|
+
JPY: "JP\xA5",
|
|
232
|
+
GBP: "\xA3",
|
|
233
|
+
KRW: "\u20A9"
|
|
234
|
+
};
|
|
235
|
+
var DEFAULT_RATES = {
|
|
236
|
+
USD: 1,
|
|
237
|
+
CNY: 7.2,
|
|
238
|
+
EUR: 0.92,
|
|
239
|
+
JPY: 150,
|
|
240
|
+
GBP: 0.79,
|
|
241
|
+
KRW: 1350
|
|
242
|
+
};
|
|
243
|
+
var MIN_PANEL_WIDTH = 20;
|
|
244
|
+
var DEFAULT_PANEL_WIDTH = 26;
|
|
245
|
+
var LABEL_GAP = 1;
|
|
246
|
+
var BAR_BRACKETS = 2;
|
|
247
|
+
var BAR_GAP = 1;
|
|
248
|
+
var PCT_FIXED_WIDTH = 5;
|
|
249
|
+
var HEADER_PREFIX = 2;
|
|
250
|
+
var UNIT_GAP = 1;
|
|
251
|
+
function TokenCachePanel(props) {
|
|
252
|
+
const [panelWidth, setPanelWidth] = createSignal(DEFAULT_PANEL_WIDTH);
|
|
253
|
+
const [open, setOpen] = createSignal(true);
|
|
254
|
+
const [detailOpen, setDetailOpen] = createSignal(true);
|
|
255
|
+
const [modelOpen, setModelOpen] = createSignal(true);
|
|
256
|
+
const [distOpen, setDistOpen] = createSignal(false);
|
|
257
|
+
const [skillsOpen, setSkillsOpen] = createSignal(true);
|
|
258
|
+
let boxEl;
|
|
259
|
+
const {
|
|
260
|
+
currencySymbol,
|
|
261
|
+
setCurrencySymbol,
|
|
262
|
+
exchangeRate,
|
|
263
|
+
setExchangeRate,
|
|
264
|
+
langZH,
|
|
265
|
+
setLangZH,
|
|
266
|
+
sectionDetail,
|
|
267
|
+
setSectionDetail,
|
|
268
|
+
sectionModel,
|
|
269
|
+
setSectionModel,
|
|
270
|
+
sectionDist,
|
|
271
|
+
setSectionDist,
|
|
272
|
+
sectionSkills,
|
|
273
|
+
setSectionSkills,
|
|
274
|
+
borderVisible,
|
|
275
|
+
setBorderVisible
|
|
276
|
+
} = props.signals;
|
|
277
|
+
const t = createMemo(() => langZH() ? ZH_T : EN_T);
|
|
278
|
+
const [lastDist, setLastDist] = createSignal({
|
|
279
|
+
system: 0,
|
|
280
|
+
user: 0,
|
|
281
|
+
agent: 0,
|
|
282
|
+
toolCall: 0,
|
|
283
|
+
toolResult: 0,
|
|
284
|
+
output: 0,
|
|
285
|
+
apiOutput: 0,
|
|
286
|
+
apiInput: 0,
|
|
287
|
+
stepCost: 0
|
|
288
|
+
});
|
|
289
|
+
const [lastHasDist, setLastHasDist] = createSignal(false);
|
|
290
|
+
const [dataSignal, setDataSignal] = createSignal({
|
|
291
|
+
hitRate: 0,
|
|
292
|
+
read: 0,
|
|
293
|
+
write: 0,
|
|
294
|
+
freshInput: 0,
|
|
295
|
+
output: 0,
|
|
296
|
+
cost: 0,
|
|
297
|
+
saved: 0,
|
|
298
|
+
model: "",
|
|
299
|
+
inputRate: 0,
|
|
300
|
+
cacheReadRate: 0,
|
|
301
|
+
cacheWriteRate: 0,
|
|
302
|
+
hasPricing: false,
|
|
303
|
+
hasData: false,
|
|
304
|
+
trend: 0,
|
|
305
|
+
hasTrendData: false,
|
|
306
|
+
providerName: "",
|
|
307
|
+
sessionHitRate: 0,
|
|
308
|
+
dist: {
|
|
309
|
+
system: 0,
|
|
310
|
+
user: 0,
|
|
311
|
+
agent: 0,
|
|
312
|
+
toolCall: 0,
|
|
313
|
+
toolResult: 0,
|
|
314
|
+
output: 0,
|
|
315
|
+
apiOutput: 0,
|
|
316
|
+
apiInput: 0,
|
|
317
|
+
stepCost: 0
|
|
318
|
+
},
|
|
319
|
+
hasDistData: false,
|
|
320
|
+
skills: [],
|
|
321
|
+
hasSkills: false
|
|
322
|
+
});
|
|
323
|
+
const [refreshTick, setRefreshTick] = createSignal(0);
|
|
324
|
+
createEffect(() => {
|
|
325
|
+
const sid = props.sessionId;
|
|
326
|
+
void refreshTick();
|
|
327
|
+
void partVersion();
|
|
328
|
+
const msgs = props.api.state.session.messages(sid);
|
|
329
|
+
const session = typeof props.api.state.session.get === "function" ? props.api.state.session.get(sid) : void 0;
|
|
330
|
+
let input = session?.tokens?.input ?? 0;
|
|
331
|
+
let read = session?.tokens?.cache?.read ?? 0;
|
|
332
|
+
let write = session?.tokens?.cache?.write ?? 0;
|
|
333
|
+
let output = session?.tokens?.output ?? 0;
|
|
334
|
+
let cost = session?.cost ?? 0;
|
|
335
|
+
let pid = session?.model?.providerID ?? "";
|
|
336
|
+
let mid = session?.model?.id ?? "";
|
|
337
|
+
const fallbackTokens = session?.tokens == null;
|
|
338
|
+
const fallbackCost = session?.cost == null;
|
|
339
|
+
const fallbackModel = !pid || !mid;
|
|
340
|
+
let prevMsgHitRate = -1, lastMsgHitRate = -1;
|
|
341
|
+
for (const msg of msgs) {
|
|
342
|
+
if (msg.role !== "assistant") continue;
|
|
343
|
+
const t2 = msg.tokens;
|
|
344
|
+
if (!t2) continue;
|
|
345
|
+
const mit = num(t2.input) + num(t2.cache?.read), mrt = num(t2.cache?.read);
|
|
346
|
+
if (mit > 0) {
|
|
347
|
+
prevMsgHitRate = lastMsgHitRate;
|
|
348
|
+
lastMsgHitRate = mrt / mit * 100;
|
|
349
|
+
}
|
|
350
|
+
if (fallbackTokens) {
|
|
351
|
+
input += num(t2.input);
|
|
352
|
+
read += num(t2.cache?.read);
|
|
353
|
+
write += num(t2.cache?.write);
|
|
354
|
+
output += num(t2.output);
|
|
355
|
+
}
|
|
356
|
+
if (fallbackCost) {
|
|
357
|
+
cost += num(msg.cost);
|
|
358
|
+
}
|
|
359
|
+
if (fallbackModel && msg.providerID && msg.modelID) {
|
|
360
|
+
pid = msg.providerID;
|
|
361
|
+
mid = msg.modelID;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
let saved = 0, inputRate = 0, cacheReadRate = 0, cacheWriteRate = 0;
|
|
365
|
+
if (read > 0 && pid && mid && Array.isArray(props.api.state.provider)) for (const provider of props.api.state.provider) {
|
|
366
|
+
if (provider.id !== pid) continue;
|
|
367
|
+
const model2 = provider.models[mid];
|
|
368
|
+
if (!model2?.cost) continue;
|
|
369
|
+
inputRate = num(model2.cost.input);
|
|
370
|
+
cacheReadRate = num(model2.cost.cache?.read);
|
|
371
|
+
cacheWriteRate = num(model2.cost.cache?.write);
|
|
372
|
+
if (inputRate > cacheReadRate) saved = read * (inputRate - cacheReadRate) / 1e6;
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
const hitRate = lastMsgHitRate >= 0 ? lastMsgHitRate : 0;
|
|
376
|
+
const freshTotal = input + read, sessionHitRate = freshTotal > 0 ? read / freshTotal * 100 : 0;
|
|
377
|
+
const model = mid.split("/").pop() ?? mid, hasPricing = inputRate > 0 || cacheReadRate > 0 || cacheWriteRate > 0;
|
|
378
|
+
const hasTrendData = prevMsgHitRate >= 0 && lastMsgHitRate >= 0;
|
|
379
|
+
const trend = hasTrendData ? lastMsgHitRate - prevMsgHitRate : 0, providerName = pid || "";
|
|
380
|
+
const distData = untrack(() => {
|
|
381
|
+
let dist = {
|
|
382
|
+
system: 0,
|
|
383
|
+
user: 0,
|
|
384
|
+
agent: 0,
|
|
385
|
+
toolCall: 0,
|
|
386
|
+
toolResult: 0,
|
|
387
|
+
output: 0,
|
|
388
|
+
apiOutput: 0,
|
|
389
|
+
apiInput: 0,
|
|
390
|
+
stepCost: 0
|
|
391
|
+
};
|
|
392
|
+
let hasDistData = false;
|
|
393
|
+
const loadedSkills = /* @__PURE__ */ new Map();
|
|
394
|
+
try {
|
|
395
|
+
const cfg = props.api.state.config;
|
|
396
|
+
const agentName = String(session?.agent ?? cfg?.default_agent ?? "build");
|
|
397
|
+
const agents = cfg?.agent;
|
|
398
|
+
const agentCfg = agents?.[agentName];
|
|
399
|
+
const sysPrompt = typeof agentCfg?.prompt === "string" ? agentCfg.prompt : "";
|
|
400
|
+
if (sysPrompt) dist.system = estimateTokens(sysPrompt);
|
|
401
|
+
let lastAssMsg;
|
|
402
|
+
for (const msg of msgs) {
|
|
403
|
+
if (msg.role === "user") {
|
|
404
|
+
const um = msg;
|
|
405
|
+
if (um.system) dist.system += estimateTokens(um.system);
|
|
406
|
+
let parts = [];
|
|
407
|
+
try {
|
|
408
|
+
parts = props.api.state.part(msg.id);
|
|
409
|
+
} catch {
|
|
410
|
+
}
|
|
411
|
+
for (const p of parts) {
|
|
412
|
+
if (p.type === "text" && !p.synthetic && !p.ignored) dist.user += estimateTokens(p.text);
|
|
413
|
+
else if (p.type === "file") {
|
|
414
|
+
const fp = p;
|
|
415
|
+
if (fp.source?.text?.value) dist.user += estimateTokens(fp.source.text.value);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
} else if (msg.role === "assistant") {
|
|
419
|
+
const am = msg;
|
|
420
|
+
dist.output += num(am.tokens?.output);
|
|
421
|
+
let parts = [];
|
|
422
|
+
try {
|
|
423
|
+
parts = props.api.state.part(msg.id);
|
|
424
|
+
} catch {
|
|
425
|
+
}
|
|
426
|
+
for (const p of parts) {
|
|
427
|
+
if (p.type === "tool") {
|
|
428
|
+
const tp = p;
|
|
429
|
+
let rawInput = "";
|
|
430
|
+
try {
|
|
431
|
+
rawInput = tp.state.raw ?? (tp.state.input != null ? JSON.stringify(tp.state.input) : "");
|
|
432
|
+
} catch {
|
|
433
|
+
}
|
|
434
|
+
if (rawInput) dist.toolCall += estimateTokens(rawInput);
|
|
435
|
+
if (tp.state.status === "completed") {
|
|
436
|
+
const c = tp.state;
|
|
437
|
+
if (c.output) dist.toolResult += estimateTokens(c.output);
|
|
438
|
+
} else if (tp.state.status === "error") {
|
|
439
|
+
const e = tp.state;
|
|
440
|
+
if (e.error) dist.toolResult += estimateTokens(e.error);
|
|
441
|
+
}
|
|
442
|
+
if (tp.tool === "skill" && tp.state.status === "completed") {
|
|
443
|
+
let name = tp.state.metadata?.name;
|
|
444
|
+
if (typeof name !== "string") {
|
|
445
|
+
const m = typeof tp.state.output === "string" ? tp.state.output.match(/^#{1,2}\s*Skill:\s*(.+)/m) : null;
|
|
446
|
+
if (m) name = m[1].trim();
|
|
447
|
+
}
|
|
448
|
+
if (typeof name === "string") {
|
|
449
|
+
const tokens = typeof tp.state.output === "string" ? estimateTokens(tp.state.output) : 0;
|
|
450
|
+
const existing = loadedSkills.get(name);
|
|
451
|
+
if (!existing || existing.tokens < tokens) {
|
|
452
|
+
loadedSkills.set(name, {
|
|
453
|
+
name,
|
|
454
|
+
tokens
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
} else if (p.type === "reasoning") dist.agent += estimateTokens(p.text);
|
|
460
|
+
else if (p.type === "subtask") {
|
|
461
|
+
const sub = p;
|
|
462
|
+
dist.agent += estimateTokens(sub.prompt || sub.description || "");
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
468
|
+
if (msgs[i].role !== "assistant") continue;
|
|
469
|
+
const t2 = msgs[i].tokens;
|
|
470
|
+
if (t2 && (t2.input > 0 || (t2.cache?.read ?? 0) > 0)) {
|
|
471
|
+
lastAssMsg = msgs[i];
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
dist.apiInput = num(lastAssMsg?.tokens?.input) + num(lastAssMsg?.tokens?.cache?.read);
|
|
476
|
+
dist.apiOutput = num(lastAssMsg?.tokens?.output);
|
|
477
|
+
hasDistData = dist.system + dist.user + dist.agent + dist.toolCall + dist.toolResult > 0 || dist.apiOutput > 0 || dist.apiInput > 0;
|
|
478
|
+
} catch {
|
|
479
|
+
}
|
|
480
|
+
const finalDist = hasDistData ? dist : lastDist(), finalHasDist = hasDistData || lastHasDist();
|
|
481
|
+
const skills = [...loadedSkills.values()];
|
|
482
|
+
return {
|
|
483
|
+
finalDist,
|
|
484
|
+
finalHasDist,
|
|
485
|
+
skills
|
|
486
|
+
};
|
|
487
|
+
});
|
|
488
|
+
setDataSignal({
|
|
489
|
+
hitRate,
|
|
490
|
+
read,
|
|
491
|
+
write,
|
|
492
|
+
freshInput: input,
|
|
493
|
+
output,
|
|
494
|
+
cost,
|
|
495
|
+
saved,
|
|
496
|
+
model,
|
|
497
|
+
inputRate,
|
|
498
|
+
cacheReadRate,
|
|
499
|
+
cacheWriteRate,
|
|
500
|
+
hasPricing,
|
|
501
|
+
hasData: read > 0 || write > 0 || input > 0 || output > 0 || cost > 0,
|
|
502
|
+
trend,
|
|
503
|
+
hasTrendData,
|
|
504
|
+
providerName,
|
|
505
|
+
sessionHitRate,
|
|
506
|
+
dist: distData.finalDist,
|
|
507
|
+
hasDistData: distData.finalHasDist,
|
|
508
|
+
skills: distData.skills,
|
|
509
|
+
hasSkills: distData.skills.length > 0
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
const data = createMemo(() => {
|
|
513
|
+
return dataSignal();
|
|
514
|
+
});
|
|
515
|
+
createEffect(() => {
|
|
516
|
+
const d = data();
|
|
517
|
+
if (d.hasDistData) {
|
|
518
|
+
setLastDist({
|
|
519
|
+
...d.dist
|
|
520
|
+
});
|
|
521
|
+
setLastHasDist(true);
|
|
522
|
+
try {
|
|
523
|
+
props.api.kv.set(`${KV_PREFIX}.dist_snapshot`, {
|
|
524
|
+
...d.dist
|
|
525
|
+
});
|
|
526
|
+
} catch {
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
const [partVersion, setPartVersion] = createSignal(0);
|
|
531
|
+
const KV_PREFIX = "cache_panel";
|
|
532
|
+
const persistFold = (key, val) => {
|
|
533
|
+
try {
|
|
534
|
+
props.api.kv.set(`${KV_PREFIX}.${key}`, val);
|
|
535
|
+
} catch {
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
onMount(() => {
|
|
539
|
+
setPanelWidth(DEFAULT_PANEL_WIDTH);
|
|
540
|
+
try {
|
|
541
|
+
setOpen(Boolean(props.api.kv.get(`${KV_PREFIX}.open`, false)));
|
|
542
|
+
setDetailOpen(Boolean(props.api.kv.get(`${KV_PREFIX}.detail`, true)));
|
|
543
|
+
setModelOpen(Boolean(props.api.kv.get(`${KV_PREFIX}.model`, true)));
|
|
544
|
+
setDistOpen(Boolean(props.api.kv.get(`${KV_PREFIX}.dist`, false)));
|
|
545
|
+
setSkillsOpen(Boolean(props.api.kv.get(`${KV_PREFIX}.skills`, true)));
|
|
546
|
+
} catch {
|
|
547
|
+
}
|
|
548
|
+
const doRestore = () => {
|
|
549
|
+
try {
|
|
550
|
+
const sym = props.api.kv.get(`${KV_PREFIX}.currency`);
|
|
551
|
+
const rate = props.api.kv.get(`${KV_PREFIX}.rate`);
|
|
552
|
+
if (typeof sym === "string") setCurrencySymbol(sym);
|
|
553
|
+
if (typeof rate === "number" && rate > 0) setExchangeRate(rate);
|
|
554
|
+
setSectionDetail(Boolean(props.api.kv.get(`${KV_PREFIX}.section.detail`, true)));
|
|
555
|
+
setSectionModel(Boolean(props.api.kv.get(`${KV_PREFIX}.section.model`, true)));
|
|
556
|
+
setSectionDist(Boolean(props.api.kv.get(`${KV_PREFIX}.section.dist`, true)));
|
|
557
|
+
setSectionSkills(Boolean(props.api.kv.get(`${KV_PREFIX}.section.skills`, true)));
|
|
558
|
+
const bv = props.api.kv.get(`${KV_PREFIX}.border`, true);
|
|
559
|
+
setBorderVisible(bv !== false);
|
|
560
|
+
const savedLang = props.api.kv.get(`${KV_PREFIX}.lang`);
|
|
561
|
+
if (savedLang === "zh" || savedLang === "en") {
|
|
562
|
+
setLangZH(savedLang === "zh");
|
|
563
|
+
}
|
|
564
|
+
const cachedDist = props.api.kv.get(`${KV_PREFIX}.dist_snapshot`);
|
|
565
|
+
if (cachedDist) {
|
|
566
|
+
setLastDist(cachedDist);
|
|
567
|
+
setLastHasDist(true);
|
|
568
|
+
}
|
|
569
|
+
} catch {
|
|
570
|
+
}
|
|
571
|
+
if (boxEl && typeof boxEl.width === "number" && boxEl.width > 0) {
|
|
572
|
+
setPanelWidth(Math.max(MIN_PANEL_WIDTH, boxEl.width));
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
if (props.api.kv.ready) {
|
|
576
|
+
doRestore();
|
|
577
|
+
} else {
|
|
578
|
+
const MAX_POLL = 100;
|
|
579
|
+
let tries = 0;
|
|
580
|
+
const pollRestore = () => {
|
|
581
|
+
if (!props.api.kv.ready) {
|
|
582
|
+
if (++tries > MAX_POLL) {
|
|
583
|
+
doRestore();
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
setTimeout(pollRestore, 10);
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
doRestore();
|
|
590
|
+
};
|
|
591
|
+
pollRestore();
|
|
592
|
+
}
|
|
593
|
+
let partTimer;
|
|
594
|
+
const bumpPartVersion = () => {
|
|
595
|
+
clearTimeout(partTimer);
|
|
596
|
+
partTimer = setTimeout(() => setPartVersion((v) => v + 1), 100);
|
|
597
|
+
};
|
|
598
|
+
const unsubPart = props.api.event.on("message.part.updated", () => {
|
|
599
|
+
bumpPartVersion();
|
|
600
|
+
setRefreshTick((v) => v + 1);
|
|
601
|
+
});
|
|
602
|
+
const unsubMsg = props.api.event.on("message.updated", () => {
|
|
603
|
+
bumpPartVersion();
|
|
604
|
+
setRefreshTick((v) => v + 1);
|
|
605
|
+
});
|
|
606
|
+
const unsubSession = props.api.event.on("session.updated", () => {
|
|
607
|
+
setRefreshTick((v) => v + 1);
|
|
608
|
+
});
|
|
609
|
+
setRefreshTick((v) => v + 1);
|
|
610
|
+
onCleanup(() => {
|
|
611
|
+
clearTimeout(partTimer);
|
|
612
|
+
unsubPart();
|
|
613
|
+
unsubMsg();
|
|
614
|
+
unsubSession();
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
const pal = createMemo(() => {
|
|
618
|
+
const t2 = props.theme;
|
|
619
|
+
const sat = (k, fb) => desaturateTo(t2[k], MAX_SAT, fb);
|
|
620
|
+
return {
|
|
621
|
+
primary: sat("primary", FALLBACK.primary),
|
|
622
|
+
text: sat("text", FALLBACK.text),
|
|
623
|
+
muted: sat("textMuted", FALLBACK.muted),
|
|
624
|
+
success: sat("success", FALLBACK.success),
|
|
625
|
+
warning: sat("warning", FALLBACK.warning),
|
|
626
|
+
error: sat("error", FALLBACK.error),
|
|
627
|
+
border: sat("border", FALLBACK.border)
|
|
628
|
+
};
|
|
629
|
+
});
|
|
630
|
+
const hitColor = createMemo(() => {
|
|
631
|
+
const r = data().hitRate;
|
|
632
|
+
if (r >= 85) return pal().success;
|
|
633
|
+
if (r >= 70) return pal().warning;
|
|
634
|
+
return pal().error;
|
|
635
|
+
});
|
|
636
|
+
const gutter = createMemo(() => borderVisible() ? 6 : 0);
|
|
637
|
+
const sep = createMemo(() => "\u2500".repeat(Math.max(1, panelWidth() - gutter())));
|
|
638
|
+
function trendLabel(t2) {
|
|
639
|
+
return (t2 > 0 ? "\u2191" : t2 < 0 ? "\u2193" : "-") + (t2 !== 0 ? Math.abs(t2).toFixed(1) + "%" : "");
|
|
640
|
+
}
|
|
641
|
+
const barW = createMemo(() => {
|
|
642
|
+
const trendSpace = data().hasTrendData ? LABEL_GAP + visualWidth(trendLabel(data().trend)) : 0;
|
|
643
|
+
const overhead = visualWidth(t().hit) + LABEL_GAP + BAR_BRACKETS + BAR_GAP + PCT_FIXED_WIDTH + trendSpace + gutter();
|
|
644
|
+
return Math.max(3, panelWidth() - overhead);
|
|
645
|
+
});
|
|
646
|
+
const bar = createMemo(() => progressBar(data().hitRate, barW()));
|
|
647
|
+
const pct = createMemo(() => (Math.floor(data().hitRate * 10) / 10).toFixed(1) + "%");
|
|
648
|
+
createEffect(() => {
|
|
649
|
+
borderVisible();
|
|
650
|
+
if (boxEl && typeof boxEl.width === "number" && boxEl.width > 0) {
|
|
651
|
+
const w = Math.max(MIN_PANEL_WIDTH, boxEl.width);
|
|
652
|
+
setPanelWidth((prev) => prev === w ? prev : w);
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
const justify = (label, value, unit = "") => {
|
|
656
|
+
const gauge = panelWidth() - gutter();
|
|
657
|
+
const used = visualWidth(label) + visualWidth(value) + (unit ? visualWidth(unit) + UNIT_GAP : 0);
|
|
658
|
+
const gap = Math.max(1, gauge - used);
|
|
659
|
+
return label + " ".repeat(gap) + value + (unit ? " " + unit : "");
|
|
660
|
+
};
|
|
661
|
+
return (() => {
|
|
662
|
+
var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("span"), _el$4 = _$createElement("span"), _el$5 = _$createElement("b");
|
|
663
|
+
_$insertNode(_el$, _el$2);
|
|
664
|
+
var _ref$ = boxEl;
|
|
665
|
+
typeof _ref$ === "function" ? _$use(_ref$, _el$) : boxEl = _el$;
|
|
666
|
+
_$spread(_el$, _$mergeProps({
|
|
667
|
+
get border() {
|
|
668
|
+
return borderVisible();
|
|
669
|
+
}
|
|
670
|
+
}, () => borderVisible() ? {
|
|
671
|
+
borderColor: pal().border
|
|
672
|
+
} : {}, {
|
|
673
|
+
"paddingTop": 0,
|
|
674
|
+
"paddingBottom": 0,
|
|
675
|
+
get paddingLeft() {
|
|
676
|
+
return borderVisible() ? 2 : 0;
|
|
677
|
+
},
|
|
678
|
+
get paddingRight() {
|
|
679
|
+
return borderVisible() ? 2 : 0;
|
|
680
|
+
},
|
|
681
|
+
"flexDirection": "column",
|
|
682
|
+
"gap": 0,
|
|
683
|
+
"onSizeChange": () => {
|
|
684
|
+
const w = boxEl ? Math.max(MIN_PANEL_WIDTH, boxEl.width ?? 0) : DEFAULT_PANEL_WIDTH;
|
|
685
|
+
setPanelWidth((prev) => prev === w ? prev : w);
|
|
686
|
+
}
|
|
687
|
+
}), true);
|
|
688
|
+
_$insertNode(_el$2, _el$3);
|
|
689
|
+
_$insertNode(_el$2, _el$4);
|
|
690
|
+
_$setProp(_el$2, "onMouseUp", () => setOpen((o) => {
|
|
691
|
+
const n = !o;
|
|
692
|
+
persistFold("open", n);
|
|
693
|
+
return n;
|
|
694
|
+
}));
|
|
695
|
+
_$insert(_el$3, () => open() ? "\u25BC " : "\u25B6 ");
|
|
696
|
+
_$insertNode(_el$4, _el$5);
|
|
697
|
+
_$insert(_el$5, () => t().title);
|
|
698
|
+
_$insert(_el$4, _$createComponent(Show, {
|
|
699
|
+
get when() {
|
|
700
|
+
return open();
|
|
701
|
+
},
|
|
702
|
+
get children() {
|
|
703
|
+
var _el$6 = _$createElement("span"), _el$7 = _$createTextNode(` (v`), _el$8 = _$createTextNode(`)`);
|
|
704
|
+
_$insertNode(_el$6, _el$7);
|
|
705
|
+
_$insertNode(_el$6, _el$8);
|
|
706
|
+
_$insert(_el$6, PLUGIN_VERSION, _el$8);
|
|
707
|
+
_$effect((_$p) => _$setProp(_el$6, "style", {
|
|
708
|
+
fg: pal().muted
|
|
709
|
+
}, _$p));
|
|
710
|
+
return _el$6;
|
|
711
|
+
}
|
|
712
|
+
}), null);
|
|
713
|
+
_$insert(_el$2, _$createComponent(Show, {
|
|
714
|
+
get when() {
|
|
715
|
+
return _$memo(() => !!!open())() && data().hasData;
|
|
716
|
+
},
|
|
717
|
+
get children() {
|
|
718
|
+
return [_$createComponent(Show, {
|
|
719
|
+
get when() {
|
|
720
|
+
return data().hasTrendData;
|
|
721
|
+
},
|
|
722
|
+
get children() {
|
|
723
|
+
return [(() => {
|
|
724
|
+
var _el$9 = _$createElement("span");
|
|
725
|
+
_$insert(_el$9, () => " ".repeat(Math.max(1, panelWidth() - gutter() - HEADER_PREFIX - visualWidth(t().title) - visualWidth(pct() + " " + t().hitFolded + " " + trendLabel(data().trend)))));
|
|
726
|
+
return _el$9;
|
|
727
|
+
})(), (() => {
|
|
728
|
+
var _el$0 = _$createElement("span"), _el$1 = _$createTextNode(` `);
|
|
729
|
+
_$insertNode(_el$0, _el$1);
|
|
730
|
+
_$insert(_el$0, pct, _el$1);
|
|
731
|
+
_$insert(_el$0, () => t().hitFolded, null);
|
|
732
|
+
_$effect((_$p) => _$setProp(_el$0, "style", {
|
|
733
|
+
fg: hitColor()
|
|
734
|
+
}, _$p));
|
|
735
|
+
return _el$0;
|
|
736
|
+
})(), (() => {
|
|
737
|
+
var _el$10 = _$createElement("span"), _el$11 = _$createTextNode(` `);
|
|
738
|
+
_$insertNode(_el$10, _el$11);
|
|
739
|
+
_$insert(_el$10, () => trendLabel(data().trend), null);
|
|
740
|
+
_$effect((_$p) => _$setProp(_el$10, "style", {
|
|
741
|
+
fg: data().trend !== 0 ? data().trend > 0 ? pal().success : pal().error : pal().text
|
|
742
|
+
}, _$p));
|
|
743
|
+
return _el$10;
|
|
744
|
+
})()];
|
|
745
|
+
}
|
|
746
|
+
}), _$createComponent(Show, {
|
|
747
|
+
get when() {
|
|
748
|
+
return !data().hasTrendData;
|
|
749
|
+
},
|
|
750
|
+
get children() {
|
|
751
|
+
return [(() => {
|
|
752
|
+
var _el$12 = _$createElement("span");
|
|
753
|
+
_$insert(_el$12, () => " ".repeat(Math.max(1, panelWidth() - gutter() - HEADER_PREFIX - visualWidth(t().title) - visualWidth(pct() + " " + t().hitFolded))));
|
|
754
|
+
return _el$12;
|
|
755
|
+
})(), (() => {
|
|
756
|
+
var _el$13 = _$createElement("span"), _el$14 = _$createTextNode(` `);
|
|
757
|
+
_$insertNode(_el$13, _el$14);
|
|
758
|
+
_$insert(_el$13, pct, _el$14);
|
|
759
|
+
_$insert(_el$13, () => t().hitFolded, null);
|
|
760
|
+
_$effect((_$p) => _$setProp(_el$13, "style", {
|
|
761
|
+
fg: hitColor()
|
|
762
|
+
}, _$p));
|
|
763
|
+
return _el$13;
|
|
764
|
+
})()];
|
|
765
|
+
}
|
|
766
|
+
})];
|
|
767
|
+
}
|
|
768
|
+
}), null);
|
|
769
|
+
_$insert(_el$, _$createComponent(Show, {
|
|
770
|
+
get when() {
|
|
771
|
+
return open();
|
|
772
|
+
},
|
|
773
|
+
get children() {
|
|
774
|
+
return _$createComponent(Show, {
|
|
775
|
+
get when() {
|
|
776
|
+
return data().hasData;
|
|
777
|
+
},
|
|
778
|
+
get fallback() {
|
|
779
|
+
return [(() => {
|
|
780
|
+
var _el$52 = _$createElement("text");
|
|
781
|
+
_$insert(_el$52, sep);
|
|
782
|
+
_$effect((_$p) => _$setProp(_el$52, "fg", pal().muted, _$p));
|
|
783
|
+
return _el$52;
|
|
784
|
+
})(), (() => {
|
|
785
|
+
var _el$53 = _$createElement("text"), _el$54 = _$createElement("span"), _el$56 = _$createElement("span");
|
|
786
|
+
_$insertNode(_el$53, _el$54);
|
|
787
|
+
_$insertNode(_el$53, _el$56);
|
|
788
|
+
_$insertNode(_el$54, _$createTextNode(`> `));
|
|
789
|
+
_$insert(_el$56, () => t().noData);
|
|
790
|
+
_$effect((_p$) => {
|
|
791
|
+
var _v$1 = {
|
|
792
|
+
fg: pal().muted
|
|
793
|
+
}, _v$10 = {
|
|
794
|
+
fg: pal().muted
|
|
795
|
+
};
|
|
796
|
+
_v$1 !== _p$.e && (_p$.e = _$setProp(_el$54, "style", _v$1, _p$.e));
|
|
797
|
+
_v$10 !== _p$.t && (_p$.t = _$setProp(_el$56, "style", _v$10, _p$.t));
|
|
798
|
+
return _p$;
|
|
799
|
+
}, {
|
|
800
|
+
e: void 0,
|
|
801
|
+
t: void 0
|
|
802
|
+
});
|
|
803
|
+
return _el$53;
|
|
804
|
+
})()];
|
|
805
|
+
},
|
|
806
|
+
get children() {
|
|
807
|
+
return [(() => {
|
|
808
|
+
var _el$15 = _$createElement("text");
|
|
809
|
+
_$insert(_el$15, sep);
|
|
810
|
+
_$effect((_$p) => _$setProp(_el$15, "fg", pal().muted, _$p));
|
|
811
|
+
return _el$15;
|
|
812
|
+
})(), (() => {
|
|
813
|
+
var _el$16 = _$createElement("text"), _el$17 = _$createElement("span"), _el$18 = _$createTextNode(` `), _el$19 = _$createElement("span"), _el$20 = _$createTextNode(`[`), _el$21 = _$createTextNode(`] `), _el$22 = _$createElement("span");
|
|
814
|
+
_$insertNode(_el$16, _el$17);
|
|
815
|
+
_$insertNode(_el$16, _el$19);
|
|
816
|
+
_$insertNode(_el$16, _el$22);
|
|
817
|
+
_$insertNode(_el$17, _el$18);
|
|
818
|
+
_$insert(_el$17, () => t().hit, _el$18);
|
|
819
|
+
_$insertNode(_el$19, _el$20);
|
|
820
|
+
_$insertNode(_el$19, _el$21);
|
|
821
|
+
_$insert(_el$19, bar, _el$21);
|
|
822
|
+
_$insert(_el$22, pct);
|
|
823
|
+
_$insert(_el$16, _$createComponent(Show, {
|
|
824
|
+
get when() {
|
|
825
|
+
return data().hasTrendData;
|
|
826
|
+
},
|
|
827
|
+
get children() {
|
|
828
|
+
var _el$23 = _$createElement("span"), _el$24 = _$createTextNode(` `);
|
|
829
|
+
_$insertNode(_el$23, _el$24);
|
|
830
|
+
_$insert(_el$23, () => trendLabel(data().trend), null);
|
|
831
|
+
_$effect((_$p) => _$setProp(_el$23, "style", {
|
|
832
|
+
fg: data().trend !== 0 ? data().trend > 0 ? pal().success : pal().error : pal().text
|
|
833
|
+
}, _$p));
|
|
834
|
+
return _el$23;
|
|
835
|
+
}
|
|
836
|
+
}), null);
|
|
837
|
+
_$effect((_p$) => {
|
|
838
|
+
var _v$ = {
|
|
839
|
+
fg: pal().text
|
|
840
|
+
}, _v$2 = {
|
|
841
|
+
fg: hitColor()
|
|
842
|
+
}, _v$3 = {
|
|
843
|
+
fg: pal().text
|
|
844
|
+
};
|
|
845
|
+
_v$ !== _p$.e && (_p$.e = _$setProp(_el$17, "style", _v$, _p$.e));
|
|
846
|
+
_v$2 !== _p$.t && (_p$.t = _$setProp(_el$19, "style", _v$2, _p$.t));
|
|
847
|
+
_v$3 !== _p$.a && (_p$.a = _$setProp(_el$22, "style", _v$3, _p$.a));
|
|
848
|
+
return _p$;
|
|
849
|
+
}, {
|
|
850
|
+
e: void 0,
|
|
851
|
+
t: void 0,
|
|
852
|
+
a: void 0
|
|
853
|
+
});
|
|
854
|
+
return _el$16;
|
|
855
|
+
})(), (() => {
|
|
856
|
+
var _el$25 = _$createElement("text");
|
|
857
|
+
_$insert(_el$25, () => justify(t().totalHit, (Math.floor(data().sessionHitRate * 10) / 10).toFixed(1) + "%"));
|
|
858
|
+
_$effect((_$p) => _$setProp(_el$25, "fg", pal().muted, _$p));
|
|
859
|
+
return _el$25;
|
|
860
|
+
})(), _$createComponent(Show, {
|
|
861
|
+
get when() {
|
|
862
|
+
return sectionDetail();
|
|
863
|
+
},
|
|
864
|
+
get children() {
|
|
865
|
+
return [(() => {
|
|
866
|
+
var _el$26 = _$createElement("text"), _el$27 = _$createElement("span"), _el$28 = _$createElement("span"), _el$29 = _$createElement("b"), _el$30 = _$createElement("span");
|
|
867
|
+
_$insertNode(_el$26, _el$27);
|
|
868
|
+
_$insertNode(_el$26, _el$28);
|
|
869
|
+
_$insertNode(_el$26, _el$30);
|
|
870
|
+
_$setProp(_el$26, "onMouseUp", () => setDetailOpen((o) => {
|
|
871
|
+
const n = !o;
|
|
872
|
+
persistFold("detail", n);
|
|
873
|
+
return n;
|
|
874
|
+
}));
|
|
875
|
+
_$insert(_el$27, () => detailOpen() ? "\u25BC " : "\u25B6 ");
|
|
876
|
+
_$insertNode(_el$28, _el$29);
|
|
877
|
+
_$insert(_el$29, () => t().secDetail);
|
|
878
|
+
_$insert(_el$30, () => sep().slice(visualWidth((detailOpen() ? "\u25BC " : "\u25B6 ") + t().secDetail)));
|
|
879
|
+
_$effect((_p$) => {
|
|
880
|
+
var _v$4 = {
|
|
881
|
+
fg: pal().muted
|
|
882
|
+
}, _v$5 = {
|
|
883
|
+
fg: pal().primary
|
|
884
|
+
}, _v$6 = {
|
|
885
|
+
fg: pal().muted
|
|
886
|
+
};
|
|
887
|
+
_v$4 !== _p$.e && (_p$.e = _$setProp(_el$27, "style", _v$4, _p$.e));
|
|
888
|
+
_v$5 !== _p$.t && (_p$.t = _$setProp(_el$28, "style", _v$5, _p$.t));
|
|
889
|
+
_v$6 !== _p$.a && (_p$.a = _$setProp(_el$30, "style", _v$6, _p$.a));
|
|
890
|
+
return _p$;
|
|
891
|
+
}, {
|
|
892
|
+
e: void 0,
|
|
893
|
+
t: void 0,
|
|
894
|
+
a: void 0
|
|
895
|
+
});
|
|
896
|
+
return _el$26;
|
|
897
|
+
})(), _$createComponent(Show, {
|
|
898
|
+
get when() {
|
|
899
|
+
return detailOpen();
|
|
900
|
+
},
|
|
901
|
+
get children() {
|
|
902
|
+
return [_$createComponent(Show, {
|
|
903
|
+
get when() {
|
|
904
|
+
return data().read > 0;
|
|
905
|
+
},
|
|
906
|
+
get children() {
|
|
907
|
+
var _el$31 = _$createElement("text");
|
|
908
|
+
_$insert(_el$31, () => justify(t().read, fmt(data().read), t().tok));
|
|
909
|
+
_$effect((_$p) => _$setProp(_el$31, "fg", pal().muted, _$p));
|
|
910
|
+
return _el$31;
|
|
911
|
+
}
|
|
912
|
+
}), _$createComponent(Show, {
|
|
913
|
+
get when() {
|
|
914
|
+
return data().write > 0;
|
|
915
|
+
},
|
|
916
|
+
get children() {
|
|
917
|
+
var _el$32 = _$createElement("text");
|
|
918
|
+
_$insert(_el$32, () => justify(t().write, fmt(data().write), t().tok));
|
|
919
|
+
_$effect((_$p) => _$setProp(_el$32, "fg", pal().muted, _$p));
|
|
920
|
+
return _el$32;
|
|
921
|
+
}
|
|
922
|
+
}), (() => {
|
|
923
|
+
var _el$33 = _$createElement("text");
|
|
924
|
+
_$insert(_el$33, () => justify(t().miss, fmt(data().freshInput), t().tok));
|
|
925
|
+
_$effect((_$p) => _$setProp(_el$33, "fg", pal().muted, _$p));
|
|
926
|
+
return _el$33;
|
|
927
|
+
})(), (() => {
|
|
928
|
+
var _el$34 = _$createElement("text");
|
|
929
|
+
_$insert(_el$34, () => justify(t().out, fmt(data().output), t().tok));
|
|
930
|
+
_$effect((_$p) => _$setProp(_el$34, "fg", pal().muted, _$p));
|
|
931
|
+
return _el$34;
|
|
932
|
+
})(), _$createComponent(Show, {
|
|
933
|
+
get when() {
|
|
934
|
+
return data().saved > 0;
|
|
935
|
+
},
|
|
936
|
+
get children() {
|
|
937
|
+
var _el$35 = _$createElement("text"), _el$36 = _$createElement("span"), _el$37 = _$createElement("span"), _el$38 = _$createElement("span"), _el$39 = _$createTextNode(`~`);
|
|
938
|
+
_$insertNode(_el$35, _el$36);
|
|
939
|
+
_$insertNode(_el$35, _el$37);
|
|
940
|
+
_$insertNode(_el$35, _el$38);
|
|
941
|
+
_$insert(_el$36, () => t().saved);
|
|
942
|
+
_$insert(_el$37, () => " ".repeat(Math.max(1, panelWidth() - gutter() - visualWidth(t().saved) - visualWidth("~" + fmtCost(data().saved, currencySymbol(), exchangeRate())))));
|
|
943
|
+
_$insertNode(_el$38, _el$39);
|
|
944
|
+
_$insert(_el$38, () => fmtCost(data().saved, currencySymbol(), exchangeRate()), null);
|
|
945
|
+
_$effect((_p$) => {
|
|
946
|
+
var _v$7 = {
|
|
947
|
+
fg: pal().muted
|
|
948
|
+
}, _v$8 = {
|
|
949
|
+
fg: pal().success
|
|
950
|
+
};
|
|
951
|
+
_v$7 !== _p$.e && (_p$.e = _$setProp(_el$36, "style", _v$7, _p$.e));
|
|
952
|
+
_v$8 !== _p$.t && (_p$.t = _$setProp(_el$38, "style", _v$8, _p$.t));
|
|
953
|
+
return _p$;
|
|
954
|
+
}, {
|
|
955
|
+
e: void 0,
|
|
956
|
+
t: void 0
|
|
957
|
+
});
|
|
958
|
+
return _el$35;
|
|
959
|
+
}
|
|
960
|
+
})];
|
|
961
|
+
}
|
|
962
|
+
})];
|
|
963
|
+
}
|
|
964
|
+
}), _$createComponent(Show, {
|
|
965
|
+
get when() {
|
|
966
|
+
return sectionModel();
|
|
967
|
+
},
|
|
968
|
+
get children() {
|
|
969
|
+
return [_$memo(() => (() => {
|
|
970
|
+
var _el$57 = _$createElement("text"), _el$58 = _$createElement("span"), _el$59 = _$createElement("span"), _el$60 = _$createElement("b"), _el$61 = _$createElement("span");
|
|
971
|
+
_$insertNode(_el$57, _el$58);
|
|
972
|
+
_$insertNode(_el$57, _el$59);
|
|
973
|
+
_$insertNode(_el$57, _el$61);
|
|
974
|
+
_$setProp(_el$57, "onMouseUp", () => setModelOpen((o) => {
|
|
975
|
+
const n = !o;
|
|
976
|
+
persistFold("model", n);
|
|
977
|
+
return n;
|
|
978
|
+
}));
|
|
979
|
+
_$insert(_el$58, () => modelOpen() ? "\u25BC " : "\u25B6 ");
|
|
980
|
+
_$insertNode(_el$59, _el$60);
|
|
981
|
+
_$insert(_el$60, () => t().secModel);
|
|
982
|
+
_$insert(_el$61, () => sep().slice(visualWidth((modelOpen() ? "\u25BC " : "\u25B6 ") + t().secModel)));
|
|
983
|
+
_$effect((_p$) => {
|
|
984
|
+
var _v$11 = {
|
|
985
|
+
fg: pal().muted
|
|
986
|
+
}, _v$12 = {
|
|
987
|
+
fg: pal().primary
|
|
988
|
+
}, _v$13 = {
|
|
989
|
+
fg: pal().muted
|
|
990
|
+
};
|
|
991
|
+
_v$11 !== _p$.e && (_p$.e = _$setProp(_el$58, "style", _v$11, _p$.e));
|
|
992
|
+
_v$12 !== _p$.t && (_p$.t = _$setProp(_el$59, "style", _v$12, _p$.t));
|
|
993
|
+
_v$13 !== _p$.a && (_p$.a = _$setProp(_el$61, "style", _v$13, _p$.a));
|
|
994
|
+
return _p$;
|
|
995
|
+
}, {
|
|
996
|
+
e: void 0,
|
|
997
|
+
t: void 0,
|
|
998
|
+
a: void 0
|
|
999
|
+
});
|
|
1000
|
+
return _el$57;
|
|
1001
|
+
})()), _$createComponent(Show, {
|
|
1002
|
+
get when() {
|
|
1003
|
+
return modelOpen();
|
|
1004
|
+
},
|
|
1005
|
+
get children() {
|
|
1006
|
+
return [(() => {
|
|
1007
|
+
var _el$40 = _$createElement("text");
|
|
1008
|
+
_$insert(_el$40, () => justify(t().cost, fmtCost(data().cost, currencySymbol(), exchangeRate())));
|
|
1009
|
+
_$effect((_$p) => _$setProp(_el$40, "fg", pal().text, _$p));
|
|
1010
|
+
return _el$40;
|
|
1011
|
+
})(), _$createComponent(Show, {
|
|
1012
|
+
get when() {
|
|
1013
|
+
return data().providerName;
|
|
1014
|
+
},
|
|
1015
|
+
get children() {
|
|
1016
|
+
var _el$41 = _$createElement("text");
|
|
1017
|
+
_$insert(_el$41, () => justify(t().provider, data().providerName));
|
|
1018
|
+
_$effect((_$p) => _$setProp(_el$41, "fg", pal().muted, _$p));
|
|
1019
|
+
return _el$41;
|
|
1020
|
+
}
|
|
1021
|
+
}), (() => {
|
|
1022
|
+
var _el$42 = _$createElement("text");
|
|
1023
|
+
_$insert(_el$42, () => justify(t().model, data().model));
|
|
1024
|
+
_$effect((_$p) => _$setProp(_el$42, "fg", pal().muted, _$p));
|
|
1025
|
+
return _el$42;
|
|
1026
|
+
})(), _$createComponent(Show, {
|
|
1027
|
+
get when() {
|
|
1028
|
+
return data().hasPricing;
|
|
1029
|
+
},
|
|
1030
|
+
get children() {
|
|
1031
|
+
return [(() => {
|
|
1032
|
+
var _el$43 = _$createElement("text");
|
|
1033
|
+
_$insert(_el$43, () => justify(t().rate, currencySymbol() + (data().inputRate * exchangeRate()).toFixed(2) + "/M " + t().inputRate));
|
|
1034
|
+
_$effect((_$p) => _$setProp(_el$43, "fg", pal().muted, _$p));
|
|
1035
|
+
return _el$43;
|
|
1036
|
+
})(), _$createComponent(Show, {
|
|
1037
|
+
get when() {
|
|
1038
|
+
return data().cacheReadRate > 0;
|
|
1039
|
+
},
|
|
1040
|
+
get children() {
|
|
1041
|
+
var _el$44 = _$createElement("text");
|
|
1042
|
+
_$insert(_el$44, () => justify("", currencySymbol() + (data().cacheReadRate * exchangeRate()).toFixed(2) + "/M " + t().cacheRate));
|
|
1043
|
+
_$effect((_$p) => _$setProp(_el$44, "fg", pal().muted, _$p));
|
|
1044
|
+
return _el$44;
|
|
1045
|
+
}
|
|
1046
|
+
}), _$createComponent(Show, {
|
|
1047
|
+
get when() {
|
|
1048
|
+
return data().cacheWriteRate > 0;
|
|
1049
|
+
},
|
|
1050
|
+
get children() {
|
|
1051
|
+
var _el$45 = _$createElement("text");
|
|
1052
|
+
_$insert(_el$45, () => justify("", currencySymbol() + (data().cacheWriteRate * exchangeRate()).toFixed(2) + "/M " + t().writeRate));
|
|
1053
|
+
_$effect((_$p) => _$setProp(_el$45, "fg", pal().muted, _$p));
|
|
1054
|
+
return _el$45;
|
|
1055
|
+
}
|
|
1056
|
+
})];
|
|
1057
|
+
}
|
|
1058
|
+
})];
|
|
1059
|
+
}
|
|
1060
|
+
})];
|
|
1061
|
+
}
|
|
1062
|
+
}), _$createComponent(Show, {
|
|
1063
|
+
get when() {
|
|
1064
|
+
return sectionDist();
|
|
1065
|
+
},
|
|
1066
|
+
get children() {
|
|
1067
|
+
return _$createComponent(Show, {
|
|
1068
|
+
get when() {
|
|
1069
|
+
return data().hasDistData;
|
|
1070
|
+
},
|
|
1071
|
+
get children() {
|
|
1072
|
+
return [_$memo(() => (() => {
|
|
1073
|
+
var _el$62 = _$createElement("text"), _el$63 = _$createElement("span"), _el$64 = _$createElement("span"), _el$65 = _$createElement("b"), _el$66 = _$createElement("span");
|
|
1074
|
+
_$insertNode(_el$62, _el$63);
|
|
1075
|
+
_$insertNode(_el$62, _el$64);
|
|
1076
|
+
_$insertNode(_el$62, _el$66);
|
|
1077
|
+
_$setProp(_el$62, "onMouseUp", () => setDistOpen((o) => {
|
|
1078
|
+
const n = !o;
|
|
1079
|
+
persistFold("dist", n);
|
|
1080
|
+
return n;
|
|
1081
|
+
}));
|
|
1082
|
+
_$insert(_el$63, () => distOpen() ? "\u25BC " : "\u25B6 ");
|
|
1083
|
+
_$insertNode(_el$64, _el$65);
|
|
1084
|
+
_$insert(_el$65, () => t().distTitle);
|
|
1085
|
+
_$insert(_el$66, () => sep().slice(visualWidth((distOpen() ? "\u25BC " : "\u25B6 ") + t().distTitle)));
|
|
1086
|
+
_$effect((_p$) => {
|
|
1087
|
+
var _v$14 = {
|
|
1088
|
+
fg: pal().muted
|
|
1089
|
+
}, _v$15 = {
|
|
1090
|
+
fg: pal().primary
|
|
1091
|
+
}, _v$16 = {
|
|
1092
|
+
fg: pal().muted
|
|
1093
|
+
};
|
|
1094
|
+
_v$14 !== _p$.e && (_p$.e = _$setProp(_el$63, "style", _v$14, _p$.e));
|
|
1095
|
+
_v$15 !== _p$.t && (_p$.t = _$setProp(_el$64, "style", _v$15, _p$.t));
|
|
1096
|
+
_v$16 !== _p$.a && (_p$.a = _$setProp(_el$66, "style", _v$16, _p$.a));
|
|
1097
|
+
return _p$;
|
|
1098
|
+
}, {
|
|
1099
|
+
e: void 0,
|
|
1100
|
+
t: void 0,
|
|
1101
|
+
a: void 0
|
|
1102
|
+
});
|
|
1103
|
+
return _el$62;
|
|
1104
|
+
})()), _$createComponent(Show, {
|
|
1105
|
+
get when() {
|
|
1106
|
+
return distOpen();
|
|
1107
|
+
},
|
|
1108
|
+
get children() {
|
|
1109
|
+
return [_$createComponent(Show, {
|
|
1110
|
+
get when() {
|
|
1111
|
+
return data().dist.system > 0;
|
|
1112
|
+
},
|
|
1113
|
+
get children() {
|
|
1114
|
+
var _el$46 = _$createElement("text");
|
|
1115
|
+
_$insert(_el$46, () => justify(t().distSys, fmt(data().dist.system), t().tok));
|
|
1116
|
+
_$effect((_$p) => _$setProp(_el$46, "fg", pal().muted, _$p));
|
|
1117
|
+
return _el$46;
|
|
1118
|
+
}
|
|
1119
|
+
}), _$createComponent(Show, {
|
|
1120
|
+
get when() {
|
|
1121
|
+
return data().dist.user > 0;
|
|
1122
|
+
},
|
|
1123
|
+
get children() {
|
|
1124
|
+
var _el$47 = _$createElement("text");
|
|
1125
|
+
_$insert(_el$47, () => justify(t().distUser, fmt(data().dist.user), t().tok));
|
|
1126
|
+
_$effect((_$p) => _$setProp(_el$47, "fg", pal().muted, _$p));
|
|
1127
|
+
return _el$47;
|
|
1128
|
+
}
|
|
1129
|
+
}), _$createComponent(Show, {
|
|
1130
|
+
get when() {
|
|
1131
|
+
return data().dist.agent > 0;
|
|
1132
|
+
},
|
|
1133
|
+
get children() {
|
|
1134
|
+
var _el$48 = _$createElement("text");
|
|
1135
|
+
_$insert(_el$48, () => justify(t().distAgent, fmt(data().dist.agent), t().tok));
|
|
1136
|
+
_$effect((_$p) => _$setProp(_el$48, "fg", pal().muted, _$p));
|
|
1137
|
+
return _el$48;
|
|
1138
|
+
}
|
|
1139
|
+
}), _$createComponent(Show, {
|
|
1140
|
+
get when() {
|
|
1141
|
+
return data().dist.toolCall > 0;
|
|
1142
|
+
},
|
|
1143
|
+
get children() {
|
|
1144
|
+
var _el$49 = _$createElement("text");
|
|
1145
|
+
_$insert(_el$49, () => justify(t().distTool, fmt(data().dist.toolCall), t().tok));
|
|
1146
|
+
_$effect((_$p) => _$setProp(_el$49, "fg", pal().muted, _$p));
|
|
1147
|
+
return _el$49;
|
|
1148
|
+
}
|
|
1149
|
+
}), _$createComponent(Show, {
|
|
1150
|
+
get when() {
|
|
1151
|
+
return data().dist.toolResult > 0;
|
|
1152
|
+
},
|
|
1153
|
+
get children() {
|
|
1154
|
+
var _el$50 = _$createElement("text");
|
|
1155
|
+
_$insert(_el$50, () => justify(t().distRes, fmt(data().dist.toolResult), t().tok));
|
|
1156
|
+
_$effect((_$p) => _$setProp(_el$50, "fg", pal().muted, _$p));
|
|
1157
|
+
return _el$50;
|
|
1158
|
+
}
|
|
1159
|
+
}), (() => {
|
|
1160
|
+
var _el$51 = _$createElement("text");
|
|
1161
|
+
_$insert(_el$51, () => justify(t().distTotal, fmt(data().dist.apiInput), t().tok));
|
|
1162
|
+
_$effect((_$p) => _$setProp(_el$51, "fg", pal().text, _$p));
|
|
1163
|
+
return _el$51;
|
|
1164
|
+
})()];
|
|
1165
|
+
}
|
|
1166
|
+
})];
|
|
1167
|
+
}
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
}), _$createComponent(Show, {
|
|
1171
|
+
get when() {
|
|
1172
|
+
return sectionSkills();
|
|
1173
|
+
},
|
|
1174
|
+
get children() {
|
|
1175
|
+
return _$createComponent(Show, {
|
|
1176
|
+
get when() {
|
|
1177
|
+
return data().hasSkills;
|
|
1178
|
+
},
|
|
1179
|
+
get children() {
|
|
1180
|
+
return [_$memo(() => (() => {
|
|
1181
|
+
var _el$67 = _$createElement("text"), _el$68 = _$createElement("span"), _el$69 = _$createElement("span"), _el$70 = _$createElement("b"), _el$71 = _$createElement("span"), _el$72 = _$createTextNode(` (`), _el$73 = _$createTextNode(`)`), _el$74 = _$createElement("span");
|
|
1182
|
+
_$insertNode(_el$67, _el$68);
|
|
1183
|
+
_$insertNode(_el$67, _el$69);
|
|
1184
|
+
_$insertNode(_el$67, _el$71);
|
|
1185
|
+
_$insertNode(_el$67, _el$74);
|
|
1186
|
+
_$setProp(_el$67, "onMouseUp", () => setSkillsOpen((o) => {
|
|
1187
|
+
const n = !o;
|
|
1188
|
+
persistFold("skills", n);
|
|
1189
|
+
return n;
|
|
1190
|
+
}));
|
|
1191
|
+
_$insert(_el$68, () => skillsOpen() ? "\u25BC " : "\u25B6 ");
|
|
1192
|
+
_$insertNode(_el$69, _el$70);
|
|
1193
|
+
_$insert(_el$70, () => t().secSkills);
|
|
1194
|
+
_$insertNode(_el$71, _el$72);
|
|
1195
|
+
_$insertNode(_el$71, _el$73);
|
|
1196
|
+
_$insert(_el$71, () => data().skills.length, _el$73);
|
|
1197
|
+
_$insert(_el$74, () => sep().slice(visualWidth((skillsOpen() ? "\u25BC " : "\u25B6 ") + t().secSkills + ` (${data().skills.length})`)));
|
|
1198
|
+
_$effect((_p$) => {
|
|
1199
|
+
var _v$17 = {
|
|
1200
|
+
fg: pal().muted
|
|
1201
|
+
}, _v$18 = {
|
|
1202
|
+
fg: pal().primary
|
|
1203
|
+
}, _v$19 = {
|
|
1204
|
+
fg: pal().muted
|
|
1205
|
+
}, _v$20 = {
|
|
1206
|
+
fg: pal().muted
|
|
1207
|
+
};
|
|
1208
|
+
_v$17 !== _p$.e && (_p$.e = _$setProp(_el$68, "style", _v$17, _p$.e));
|
|
1209
|
+
_v$18 !== _p$.t && (_p$.t = _$setProp(_el$69, "style", _v$18, _p$.t));
|
|
1210
|
+
_v$19 !== _p$.a && (_p$.a = _$setProp(_el$71, "style", _v$19, _p$.a));
|
|
1211
|
+
_v$20 !== _p$.o && (_p$.o = _$setProp(_el$74, "style", _v$20, _p$.o));
|
|
1212
|
+
return _p$;
|
|
1213
|
+
}, {
|
|
1214
|
+
e: void 0,
|
|
1215
|
+
t: void 0,
|
|
1216
|
+
a: void 0,
|
|
1217
|
+
o: void 0
|
|
1218
|
+
});
|
|
1219
|
+
return _el$67;
|
|
1220
|
+
})()), _$createComponent(Show, {
|
|
1221
|
+
get when() {
|
|
1222
|
+
return skillsOpen();
|
|
1223
|
+
},
|
|
1224
|
+
get children() {
|
|
1225
|
+
return data().skills.map((sk) => {
|
|
1226
|
+
const rightW = visualWidth(fmt(sk.tokens)) + UNIT_GAP + visualWidth(t().tok);
|
|
1227
|
+
const maxLabel = Math.max(4, panelWidth() - gutter() - rightW - 1);
|
|
1228
|
+
const label = truncateVisual(sk.name, maxLabel);
|
|
1229
|
+
return (() => {
|
|
1230
|
+
var _el$75 = _$createElement("text");
|
|
1231
|
+
_$insert(_el$75, () => justify(label, fmt(sk.tokens), t().tok));
|
|
1232
|
+
_$effect((_$p) => _$setProp(_el$75, "fg", pal().muted, _$p));
|
|
1233
|
+
return _el$75;
|
|
1234
|
+
})();
|
|
1235
|
+
});
|
|
1236
|
+
}
|
|
1237
|
+
})];
|
|
1238
|
+
}
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
})];
|
|
1242
|
+
}
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
}), null);
|
|
1246
|
+
_$effect((_p$) => {
|
|
1247
|
+
var _v$9 = {
|
|
1248
|
+
fg: pal().muted
|
|
1249
|
+
}, _v$0 = {
|
|
1250
|
+
fg: pal().primary
|
|
1251
|
+
};
|
|
1252
|
+
_v$9 !== _p$.e && (_p$.e = _$setProp(_el$3, "style", _v$9, _p$.e));
|
|
1253
|
+
_v$0 !== _p$.t && (_p$.t = _$setProp(_el$4, "style", _v$0, _p$.t));
|
|
1254
|
+
return _p$;
|
|
1255
|
+
}, {
|
|
1256
|
+
e: void 0,
|
|
1257
|
+
t: void 0
|
|
1258
|
+
});
|
|
1259
|
+
return _el$;
|
|
1260
|
+
})();
|
|
1261
|
+
}
|
|
1262
|
+
function createSidebarSlot(api, signals) {
|
|
1263
|
+
return {
|
|
1264
|
+
order: 55,
|
|
1265
|
+
slots: {
|
|
1266
|
+
sidebar_content(ctx, input) {
|
|
1267
|
+
return _$createComponent(TokenCachePanel, {
|
|
1268
|
+
get theme() {
|
|
1269
|
+
return ctx.theme.current;
|
|
1270
|
+
},
|
|
1271
|
+
api,
|
|
1272
|
+
get sessionId() {
|
|
1273
|
+
return input.session_id;
|
|
1274
|
+
},
|
|
1275
|
+
signals
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
var tui = async (api) => {
|
|
1282
|
+
const [currencySymbol, setCurrencySymbol] = createSignal("$");
|
|
1283
|
+
const [exchangeRate, setExchangeRate] = createSignal(1);
|
|
1284
|
+
const [sectionDetail, setSectionDetail] = createSignal(true);
|
|
1285
|
+
const [sectionModel, setSectionModel] = createSignal(true);
|
|
1286
|
+
const [sectionDist, setSectionDist] = createSignal(true);
|
|
1287
|
+
const [sectionSkills, setSectionSkills] = createSignal(true);
|
|
1288
|
+
const [borderVisible, setBorderVisible] = createSignal(true);
|
|
1289
|
+
const [langZH, setLangZH] = createSignal(LANG_ZH);
|
|
1290
|
+
const signals = {
|
|
1291
|
+
currencySymbol,
|
|
1292
|
+
setCurrencySymbol,
|
|
1293
|
+
exchangeRate,
|
|
1294
|
+
setExchangeRate,
|
|
1295
|
+
langZH,
|
|
1296
|
+
setLangZH,
|
|
1297
|
+
sectionDetail,
|
|
1298
|
+
setSectionDetail,
|
|
1299
|
+
sectionModel,
|
|
1300
|
+
setSectionModel,
|
|
1301
|
+
sectionDist,
|
|
1302
|
+
setSectionDist,
|
|
1303
|
+
sectionSkills,
|
|
1304
|
+
setSectionSkills,
|
|
1305
|
+
borderVisible,
|
|
1306
|
+
setBorderVisible
|
|
1307
|
+
};
|
|
1308
|
+
api.slots.register(createSidebarSlot(api, signals));
|
|
1309
|
+
const KV_PREFIX = "cache_panel";
|
|
1310
|
+
api.command?.register(() => [{
|
|
1311
|
+
title: "Cache: Set Currency",
|
|
1312
|
+
value: "cache.currency",
|
|
1313
|
+
description: "Change the currency unit for cost display",
|
|
1314
|
+
slash: {
|
|
1315
|
+
name: "cache-currency"
|
|
1316
|
+
},
|
|
1317
|
+
onSelect: (dialog) => {
|
|
1318
|
+
dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
|
|
1319
|
+
title: "Select Currency",
|
|
1320
|
+
get options() {
|
|
1321
|
+
return Object.entries(CURRENCIES).map(([code, sym]) => ({
|
|
1322
|
+
title: `${code} (${sym})`,
|
|
1323
|
+
value: code
|
|
1324
|
+
}));
|
|
1325
|
+
},
|
|
1326
|
+
onSelect: (opt) => {
|
|
1327
|
+
const sym = CURRENCIES[opt.value] ?? "$";
|
|
1328
|
+
const defRate = DEFAULT_RATES[opt.value] ?? 1;
|
|
1329
|
+
api.kv.set(`${KV_PREFIX}.currency`, sym);
|
|
1330
|
+
api.kv.set(`${KV_PREFIX}.rate`, defRate);
|
|
1331
|
+
signals.setCurrencySymbol(sym);
|
|
1332
|
+
signals.setExchangeRate(defRate);
|
|
1333
|
+
api.ui.toast({
|
|
1334
|
+
message: `Currency: ${opt.value} (${sym}), rate: ${defRate}`
|
|
1335
|
+
});
|
|
1336
|
+
dialog?.clear();
|
|
1337
|
+
}
|
|
1338
|
+
}));
|
|
1339
|
+
}
|
|
1340
|
+
}, {
|
|
1341
|
+
title: "Cache: Set Exchange Rate",
|
|
1342
|
+
value: "cache.rate",
|
|
1343
|
+
description: "Set the exchange rate multiplier for the selected currency",
|
|
1344
|
+
slash: {
|
|
1345
|
+
name: "cache-rate"
|
|
1346
|
+
},
|
|
1347
|
+
onSelect: (dialog) => {
|
|
1348
|
+
dialog?.replace(() => _$createComponent(api.ui.DialogPrompt, {
|
|
1349
|
+
title: "Exchange Rate",
|
|
1350
|
+
description: () => (() => {
|
|
1351
|
+
var _el$76 = _$createElement("text");
|
|
1352
|
+
_$insertNode(_el$76, _$createTextNode(`Enter the exchange rate from USD to your currency (e.g. 7.2 for CNY)`));
|
|
1353
|
+
return _el$76;
|
|
1354
|
+
})(),
|
|
1355
|
+
placeholder: "1.0",
|
|
1356
|
+
get value() {
|
|
1357
|
+
return String(api.kv.get(`${KV_PREFIX}.rate`, 1));
|
|
1358
|
+
},
|
|
1359
|
+
onConfirm: (val) => {
|
|
1360
|
+
const n = parseFloat(val);
|
|
1361
|
+
if (n > 0) {
|
|
1362
|
+
api.kv.set(`${KV_PREFIX}.rate`, n);
|
|
1363
|
+
signals.setExchangeRate(n);
|
|
1364
|
+
api.ui.toast({
|
|
1365
|
+
message: `Exchange rate set to ${n}`
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
dialog?.clear();
|
|
1369
|
+
}
|
|
1370
|
+
}));
|
|
1371
|
+
}
|
|
1372
|
+
}, {
|
|
1373
|
+
title: "Cache: Toggle Section",
|
|
1374
|
+
value: "cache.section",
|
|
1375
|
+
description: "Show or hide a sidebar section",
|
|
1376
|
+
slash: {
|
|
1377
|
+
name: "cache-section"
|
|
1378
|
+
},
|
|
1379
|
+
onSelect: (dialog) => {
|
|
1380
|
+
const detailOn = Boolean(api.kv.get(`${KV_PREFIX}.section.detail`, true));
|
|
1381
|
+
const modelOn = Boolean(api.kv.get(`${KV_PREFIX}.section.model`, true));
|
|
1382
|
+
const distOn = Boolean(api.kv.get(`${KV_PREFIX}.section.dist`, true));
|
|
1383
|
+
const skillsOn = Boolean(api.kv.get(`${KV_PREFIX}.section.skills`, true));
|
|
1384
|
+
const borderOn = Boolean(api.kv.get(`${KV_PREFIX}.border`, true));
|
|
1385
|
+
dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
|
|
1386
|
+
title: "Toggle Section",
|
|
1387
|
+
options: [{
|
|
1388
|
+
title: `Token Detail [${detailOn ? "ON" : "OFF"}]`,
|
|
1389
|
+
value: "detail"
|
|
1390
|
+
}, {
|
|
1391
|
+
title: `Model & Pricing [${modelOn ? "ON" : "OFF"}]`,
|
|
1392
|
+
value: "model"
|
|
1393
|
+
}, {
|
|
1394
|
+
title: `Token Dist. [${distOn ? "ON" : "OFF"}]`,
|
|
1395
|
+
value: "dist"
|
|
1396
|
+
}, {
|
|
1397
|
+
title: `Loaded Skills [${skillsOn ? "ON" : "OFF"}]`,
|
|
1398
|
+
value: "skills"
|
|
1399
|
+
}, {
|
|
1400
|
+
title: `Panel Border [${borderOn ? "ON" : "OFF"}]`,
|
|
1401
|
+
value: "border"
|
|
1402
|
+
}],
|
|
1403
|
+
onSelect: (opt) => {
|
|
1404
|
+
if (opt.value === "border") {
|
|
1405
|
+
const cur = Boolean(api.kv.get(`${KV_PREFIX}.border`, true));
|
|
1406
|
+
api.kv.set(`${KV_PREFIX}.border`, !cur);
|
|
1407
|
+
signals.setBorderVisible(!cur);
|
|
1408
|
+
api.ui.toast({
|
|
1409
|
+
message: `Panel border ${!cur ? "shown" : "hidden"}`
|
|
1410
|
+
});
|
|
1411
|
+
} else {
|
|
1412
|
+
const key = `${KV_PREFIX}.section.${opt.value}`;
|
|
1413
|
+
const cur = Boolean(api.kv.get(key, true));
|
|
1414
|
+
api.kv.set(key, !cur);
|
|
1415
|
+
if (opt.value === "detail") signals.setSectionDetail(!cur);
|
|
1416
|
+
if (opt.value === "model") signals.setSectionModel(!cur);
|
|
1417
|
+
if (opt.value === "dist") signals.setSectionDist(!cur);
|
|
1418
|
+
if (opt.value === "skills") signals.setSectionSkills(!cur);
|
|
1419
|
+
api.ui.toast({
|
|
1420
|
+
message: `${opt.value} section ${!cur ? "shown" : "hidden"}`
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
dialog?.clear();
|
|
1424
|
+
}
|
|
1425
|
+
}));
|
|
1426
|
+
}
|
|
1427
|
+
}, {
|
|
1428
|
+
title: "Cache: Show Config",
|
|
1429
|
+
value: "cache.config",
|
|
1430
|
+
description: "Display the current plugin configuration",
|
|
1431
|
+
slash: {
|
|
1432
|
+
name: "cache-config"
|
|
1433
|
+
},
|
|
1434
|
+
onSelect: (dialog) => {
|
|
1435
|
+
const sym = api.kv.get(`${KV_PREFIX}.currency`) ?? "$";
|
|
1436
|
+
const rate = api.kv.get(`${KV_PREFIX}.rate`) ?? 1;
|
|
1437
|
+
const detail = Boolean(api.kv.get(`${KV_PREFIX}.section.detail`, true));
|
|
1438
|
+
const model = Boolean(api.kv.get(`${KV_PREFIX}.section.model`, true));
|
|
1439
|
+
const dist = Boolean(api.kv.get(`${KV_PREFIX}.section.dist`, true));
|
|
1440
|
+
const skills = Boolean(api.kv.get(`${KV_PREFIX}.section.skills`, true));
|
|
1441
|
+
api.ui.toast({
|
|
1442
|
+
title: "Cache Panel Config",
|
|
1443
|
+
message: `Currency: ${sym} | Rate: ${rate} | Detail: ${detail ? "ON" : "OFF"} | Model: ${model ? "ON" : "OFF"} | Dist: ${dist ? "ON" : "OFF"} | Skills: ${skills ? "ON" : "OFF"}`,
|
|
1444
|
+
duration: 8e3
|
|
1445
|
+
});
|
|
1446
|
+
dialog?.clear();
|
|
1447
|
+
}
|
|
1448
|
+
}, {
|
|
1449
|
+
title: "Cache: Switch Language",
|
|
1450
|
+
value: "cache.lang",
|
|
1451
|
+
description: "Switch between Chinese and English display",
|
|
1452
|
+
slash: {
|
|
1453
|
+
name: "cache-lang"
|
|
1454
|
+
},
|
|
1455
|
+
onSelect: (dialog) => {
|
|
1456
|
+
const cur = langZH();
|
|
1457
|
+
dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
|
|
1458
|
+
title: "Display Language",
|
|
1459
|
+
options: [{
|
|
1460
|
+
title: `\u4E2D\u6587 ${cur ? "\u2713" : ""}`,
|
|
1461
|
+
value: "zh"
|
|
1462
|
+
}, {
|
|
1463
|
+
title: `English ${cur ? "" : "\u2713"}`,
|
|
1464
|
+
value: "en"
|
|
1465
|
+
}],
|
|
1466
|
+
onSelect: (opt) => {
|
|
1467
|
+
const zh = opt.value === "zh";
|
|
1468
|
+
api.kv.set(`${KV_PREFIX}.lang`, opt.value);
|
|
1469
|
+
setLangZH(zh);
|
|
1470
|
+
api.ui.toast({
|
|
1471
|
+
message: zh ? "\u8BED\u8A00\u5DF2\u5207\u6362\u4E3A\u4E2D\u6587" : "Switched to English"
|
|
1472
|
+
});
|
|
1473
|
+
dialog?.clear();
|
|
1474
|
+
}
|
|
1475
|
+
}));
|
|
1476
|
+
}
|
|
1477
|
+
}, {
|
|
1478
|
+
title: "Cache: Debug Skills Detection",
|
|
1479
|
+
value: "cache.debug-skills",
|
|
1480
|
+
description: "Dump all tool parts found in the current session for skill detection debugging",
|
|
1481
|
+
slash: {
|
|
1482
|
+
name: "cache-debug-skills"
|
|
1483
|
+
},
|
|
1484
|
+
onSelect: () => {
|
|
1485
|
+
const rt = api.route.current;
|
|
1486
|
+
if (rt.name !== "session" || !rt.params) {
|
|
1487
|
+
api.ui.toast({
|
|
1488
|
+
message: "Please run this command inside a session",
|
|
1489
|
+
variant: "warning"
|
|
1490
|
+
});
|
|
1491
|
+
return;
|
|
1492
|
+
}
|
|
1493
|
+
const sid = String(rt.params.sessionID);
|
|
1494
|
+
const msgs = api.state.session.messages(sid);
|
|
1495
|
+
const byTool = {};
|
|
1496
|
+
const skillParts = [];
|
|
1497
|
+
for (const msg of msgs) {
|
|
1498
|
+
if (msg.role !== "assistant") continue;
|
|
1499
|
+
let parts = [];
|
|
1500
|
+
try {
|
|
1501
|
+
parts = api.state.part(msg.id);
|
|
1502
|
+
} catch {
|
|
1503
|
+
}
|
|
1504
|
+
for (const p of parts) {
|
|
1505
|
+
if (p.type === "tool") {
|
|
1506
|
+
const t = String(p.tool ?? "?");
|
|
1507
|
+
byTool[t] = (byTool[t] ?? 0) + 1;
|
|
1508
|
+
if (t === "skill") {
|
|
1509
|
+
const meta = p.state?.metadata;
|
|
1510
|
+
const rootMeta = p.metadata;
|
|
1511
|
+
skillParts.push(`state.metadata=${JSON.stringify(meta)} | root.metadata=${JSON.stringify(rootMeta)} | state.title="${p.state?.title}" | state.output[:80]="${String(p.state?.output ?? "").slice(0, 80)}"`);
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
const summary = Object.entries(byTool).map(([k, v]) => `${k}: ${v}`).join(" | ");
|
|
1517
|
+
const extra = skillParts.length > 0 ? "\n\nSkill parts:\n" + skillParts.join("\n") : "\n\n\u26A0 No skill tool parts found \u2014 AI may be reading SKILL.md instead. Try: 'Use the skill tool to load karpathy-guidelines'";
|
|
1518
|
+
api.ui.toast({
|
|
1519
|
+
title: `Tool Summary (${Object.keys(byTool).length} types)`,
|
|
1520
|
+
message: summary + extra,
|
|
1521
|
+
duration: 15e3
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
}]);
|
|
1525
|
+
};
|
|
1526
|
+
var mod = {
|
|
1527
|
+
id: "opencode-visual-cache",
|
|
1528
|
+
tui
|
|
1529
|
+
};
|
|
1530
|
+
var index_default = mod;
|
|
1531
|
+
export {
|
|
1532
|
+
index_default as default
|
|
1533
|
+
};
|