opencode-visual-cache 1.7.0-beta.3 → 1.7.0-beta.5
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/dist/_version.d.ts +1 -1
- package/dist/_version.js +1 -1
- package/dist/balance-providers.js +27 -1
- package/dist/index.js +4 -1
- package/dist/tui.js +31 -2
- package/dist/v2/index.js +1 -1
- package/dist/v2/status.d.ts +3 -1
- package/dist/v2/status.js +12 -2
- package/dist/v2.js +104 -73
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/balance-providers.ts +25 -1
- package/src/core/color.ts +108 -108
- package/src/core/currency.ts +46 -46
- package/src/core/estimate.ts +36 -36
- package/src/core/format.ts +81 -81
- package/src/core/index.ts +5 -5
- package/src/core/types.ts +17 -17
- package/src/index.tsx +3 -0
- package/src/panel/panel-api.ts +104 -104
- package/src/v2/data.ts +112 -112
- package/src/v2/index.tsx +187 -187
- package/src/v2/sidebar.tsx +69 -69
- package/src/v2/status.tsx +108 -96
- package/src/v2/theme.ts +19 -19
- package/src/v2/types.ts +159 -159
- package/src/v2/v2-panel-api.ts +177 -177
- package/tui/index.js +1 -1
package/dist/_version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PLUGIN_VERSION = "1.7.0-beta.
|
|
1
|
+
export declare const PLUGIN_VERSION = "1.7.0-beta.5";
|
package/dist/_version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// auto-generated
|
|
2
|
-
export const PLUGIN_VERSION = "1.7.0-beta.
|
|
2
|
+
export const PLUGIN_VERSION = "1.7.0-beta.5";
|
|
@@ -103,8 +103,34 @@ const moonshotProvider = {
|
|
|
103
103
|
return [{ currency: "CNY", total: String(balance) }];
|
|
104
104
|
},
|
|
105
105
|
};
|
|
106
|
+
const hyperProvider = {
|
|
107
|
+
id: "hyper",
|
|
108
|
+
name: "Charm Hyper",
|
|
109
|
+
keyPlaceholder: "sk-hyper-...",
|
|
110
|
+
async fetchBalance(apiKey, signal) {
|
|
111
|
+
// 官方接口:GET /v1/credits → {"balance": 98}(积分余额)
|
|
112
|
+
const res = await fetch("https://hyper.charm.land/v1/credits", {
|
|
113
|
+
headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
|
|
114
|
+
signal,
|
|
115
|
+
});
|
|
116
|
+
if (!res.ok) {
|
|
117
|
+
if (res.status === 401)
|
|
118
|
+
throw new BalanceError("401");
|
|
119
|
+
if (res.status === 403)
|
|
120
|
+
throw new BalanceError("403");
|
|
121
|
+
throw new BalanceError(String(res.status));
|
|
122
|
+
}
|
|
123
|
+
const json = await res.json();
|
|
124
|
+
const balance = json.balance;
|
|
125
|
+
if (typeof balance === "undefined" || balance === null)
|
|
126
|
+
throw new BalanceError("EMPTY");
|
|
127
|
+
// hyper 积分换算:100 积分 = $5,即 1 积分 = $0.05
|
|
128
|
+
const usd = (Number(balance) * 0.05).toFixed(2);
|
|
129
|
+
return [{ currency: "USD", total: usd }];
|
|
130
|
+
},
|
|
131
|
+
};
|
|
106
132
|
/** 已注册的 provider 列表(按需追加新适配器)。 */
|
|
107
|
-
export const balanceProviders = [deepseekProvider, siliconflowProvider, openrouterProvider, moonshotProvider];
|
|
133
|
+
export const balanceProviders = [deepseekProvider, siliconflowProvider, openrouterProvider, moonshotProvider, hyperProvider];
|
|
108
134
|
/** 按 id 取 provider;未知 id 回退到第一个。 */
|
|
109
135
|
export function getBalanceProvider(id) {
|
|
110
136
|
return balanceProviders.find((p) => p.id === id) ?? balanceProviders[0] ?? deepseekProvider;
|
package/dist/index.js
CHANGED
|
@@ -425,7 +425,10 @@ const tui = async (api) => {
|
|
|
425
425
|
order: 55,
|
|
426
426
|
slots: {
|
|
427
427
|
session_prompt(_ctx, input) {
|
|
428
|
-
return (_jsx(api.ui.Prompt, { sessionID: input.session_id, visible: input.visible, disabled: input.disabled, onSubmit: input.on_submit, ref: input.ref, hint: _jsx(BottomStatusBar, { api: api, signals: signals, sessionId: input.session_id })
|
|
428
|
+
return (_jsx(api.ui.Prompt, { sessionID: input.session_id, visible: input.visible, disabled: input.disabled, onSubmit: input.on_submit, ref: input.ref, hint: _jsx(BottomStatusBar, { api: api, signals: signals, sessionId: input.session_id }),
|
|
429
|
+
// 接管 session_prompt 后需透传宿主的 session_prompt_right 插槽,
|
|
430
|
+
// 否则 oc-tps 等依赖该插槽的插件无法显示;无注册时 Slot 为 null。
|
|
431
|
+
right: _jsx(api.ui.Slot, { name: "session_prompt_right", session_id: input.session_id }) }));
|
|
429
432
|
},
|
|
430
433
|
},
|
|
431
434
|
});
|
package/dist/tui.js
CHANGED
|
@@ -95,7 +95,28 @@ var moonshotProvider = {
|
|
|
95
95
|
return [{ currency: "CNY", total: String(balance) }];
|
|
96
96
|
}
|
|
97
97
|
};
|
|
98
|
-
var
|
|
98
|
+
var hyperProvider = {
|
|
99
|
+
id: "hyper",
|
|
100
|
+
name: "Charm Hyper",
|
|
101
|
+
keyPlaceholder: "sk-hyper-...",
|
|
102
|
+
async fetchBalance(apiKey, signal) {
|
|
103
|
+
const res = await fetch("https://hyper.charm.land/v1/credits", {
|
|
104
|
+
headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
|
|
105
|
+
signal
|
|
106
|
+
});
|
|
107
|
+
if (!res.ok) {
|
|
108
|
+
if (res.status === 401) throw new BalanceError("401");
|
|
109
|
+
if (res.status === 403) throw new BalanceError("403");
|
|
110
|
+
throw new BalanceError(String(res.status));
|
|
111
|
+
}
|
|
112
|
+
const json = await res.json();
|
|
113
|
+
const balance = json.balance;
|
|
114
|
+
if (typeof balance === "undefined" || balance === null) throw new BalanceError("EMPTY");
|
|
115
|
+
const usd = (Number(balance) * 0.05).toFixed(2);
|
|
116
|
+
return [{ currency: "USD", total: usd }];
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var balanceProviders = [deepseekProvider, siliconflowProvider, openrouterProvider, moonshotProvider, hyperProvider];
|
|
99
120
|
function getBalanceProvider(id) {
|
|
100
121
|
return balanceProviders.find((p) => p.id === id) ?? balanceProviders[0] ?? deepseekProvider;
|
|
101
122
|
}
|
|
@@ -684,7 +705,7 @@ import { createElement as _$createElement } from "@opentui/solid";
|
|
|
684
705
|
import { createMemo, createSignal, createEffect, onMount, onCleanup, Show, untrack } from "solid-js";
|
|
685
706
|
|
|
686
707
|
// src/_version.ts
|
|
687
|
-
var PLUGIN_VERSION = "1.7.0-beta.
|
|
708
|
+
var PLUGIN_VERSION = "1.7.0-beta.5";
|
|
688
709
|
|
|
689
710
|
// src/panel/TokenCachePanel.tsx
|
|
690
711
|
var MIN_PANEL_WIDTH = 20;
|
|
@@ -2415,6 +2436,14 @@ var tui = async (api) => {
|
|
|
2415
2436
|
return input.session_id;
|
|
2416
2437
|
}
|
|
2417
2438
|
});
|
|
2439
|
+
},
|
|
2440
|
+
get right() {
|
|
2441
|
+
return _$createComponent2(api.ui.Slot, {
|
|
2442
|
+
name: "session_prompt_right",
|
|
2443
|
+
get session_id() {
|
|
2444
|
+
return input.session_id;
|
|
2445
|
+
}
|
|
2446
|
+
});
|
|
2418
2447
|
}
|
|
2419
2448
|
});
|
|
2420
2449
|
}
|
package/dist/v2/index.js
CHANGED
|
@@ -154,7 +154,7 @@ const mod = {
|
|
|
154
154
|
// 底部状态栏(完整口径与 V1 一致;余额读共享 signals.balanceState)
|
|
155
155
|
context.ui.slot({
|
|
156
156
|
append: "prompt.footer.status",
|
|
157
|
-
render: (props) => (_jsx(StatusView, { context: context, signals: signals, sessionID: String(props.sessionID ?? "") })),
|
|
157
|
+
render: (props) => (_jsx(StatusView, { context: context, api: api, signals: signals, sessionID: String(props.sessionID ?? "") })),
|
|
158
158
|
});
|
|
159
159
|
// 偏好持久化(实验:storage.store 用法验证)
|
|
160
160
|
context.storage.store("opencode-visual-cache.panel", { initial: { collapsed: false } });
|
package/dist/v2/status.d.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
2
|
import type { Context } from "./types";
|
|
3
|
-
import type { PanelSignals } from "../panel/panel-api";
|
|
3
|
+
import type { PanelApi, PanelSignals } from "../panel/panel-api";
|
|
4
4
|
/**
|
|
5
5
|
* 底部状态栏(prompt.footer.status)——对齐 V1 BottomStatusBar 统计段口径:
|
|
6
6
|
* 单条命中率(最后一条有 token 的 assistant 消息)+ 趋势 + Tokens 总量 + 余额。
|
|
7
7
|
* 余额读共享 signals.balanceState(PluginRoot 驱动轮询);provider 不支持余额时隐藏余额段(对齐 V1)。
|
|
8
8
|
* 颜色经 mapTheme(V1 形状)——与侧边栏命中率颜色同源,保证两处一致。
|
|
9
|
+
* 显隐受 signals.sectionBottom 控制(/cache-section 切换),启动时从 kv 恢复偏好(对齐 V1)。
|
|
9
10
|
*/
|
|
10
11
|
export declare function StatusView(props: {
|
|
11
12
|
context: Context;
|
|
13
|
+
api: PanelApi;
|
|
12
14
|
signals: PanelSignals;
|
|
13
15
|
sessionID: string;
|
|
14
16
|
}): import("solid-js").JSX.Element;
|
package/dist/v2/status.js
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
import { jsx as _jsx } from "@opentui/solid/jsx-runtime";
|
|
2
2
|
/** @jsxImportSource @opentui/solid */
|
|
3
|
-
import { createMemo, For, Show } from "solid-js";
|
|
3
|
+
import { createMemo, For, onMount, Show } from "solid-js";
|
|
4
4
|
import { collectLastHitRate } from "./data";
|
|
5
5
|
import { desaturateTo, fmtCompact, formatBalanceText, MAX_SAT, FALLBACK, visualWidth } from "../core";
|
|
6
6
|
import { createT } from "../i18n";
|
|
7
7
|
import { mapTheme } from "./theme";
|
|
8
|
+
const KV_PREFIX = "cache_panel";
|
|
8
9
|
/**
|
|
9
10
|
* 底部状态栏(prompt.footer.status)——对齐 V1 BottomStatusBar 统计段口径:
|
|
10
11
|
* 单条命中率(最后一条有 token 的 assistant 消息)+ 趋势 + Tokens 总量 + 余额。
|
|
11
12
|
* 余额读共享 signals.balanceState(PluginRoot 驱动轮询);provider 不支持余额时隐藏余额段(对齐 V1)。
|
|
12
13
|
* 颜色经 mapTheme(V1 形状)——与侧边栏命中率颜色同源,保证两处一致。
|
|
14
|
+
* 显隐受 signals.sectionBottom 控制(/cache-section 切换),启动时从 kv 恢复偏好(对齐 V1)。
|
|
13
15
|
*/
|
|
14
16
|
export function StatusView(props) {
|
|
15
17
|
const t = createT(() => props.signals.langCode());
|
|
18
|
+
// 恢复显隐偏好(默认显示;关闭时隐藏统计段,与宿主默认 hint 行一致)
|
|
19
|
+
onMount(() => {
|
|
20
|
+
try {
|
|
21
|
+
const v = props.api.kv.get(`${KV_PREFIX}.section.bottom`, true);
|
|
22
|
+
props.signals.setSectionBottom(v !== false);
|
|
23
|
+
}
|
|
24
|
+
catch { }
|
|
25
|
+
});
|
|
16
26
|
// 与侧边栏 TokenCachePanel 同一颜色来源(mapTheme → desaturateTo)
|
|
17
27
|
const pal = createMemo(() => {
|
|
18
28
|
const th = mapTheme(props.context.theme);
|
|
@@ -79,5 +89,5 @@ export function StatusView(props) {
|
|
|
79
89
|
w += visualWidth(sg.text);
|
|
80
90
|
return w;
|
|
81
91
|
});
|
|
82
|
-
return (_jsx(Show, { when: segsW() > 0, children: _jsx("text", { children: _jsx(For, { each: segs(), children: (sg) => _jsx("span", { style: { fg: sg.color }, children: sg.text }) }) }) }));
|
|
92
|
+
return (_jsx(Show, { when: segsW() > 0 && stats().hitRate >= 0 && props.signals.sectionBottom(), children: _jsx("text", { children: _jsx(For, { each: segs(), children: (sg) => _jsx("span", { style: { fg: sg.color }, children: sg.text }) }) }) }));
|
|
83
93
|
}
|
package/dist/v2.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/v2/index.tsx
|
|
2
2
|
import { createComponent as _$createComponent3 } from "@opentui/solid";
|
|
3
|
-
import { createSignal as createSignal2, createEffect as createEffect2, onMount as
|
|
3
|
+
import { createSignal as createSignal2, createEffect as createEffect2, onMount as onMount3, onCleanup as onCleanup2, untrack as untrack2 } from "solid-js";
|
|
4
4
|
|
|
5
5
|
// src/v2/v2-panel-api.ts
|
|
6
6
|
function createPanelApi(context) {
|
|
@@ -252,7 +252,28 @@ var moonshotProvider = {
|
|
|
252
252
|
return [{ currency: "CNY", total: String(balance) }];
|
|
253
253
|
}
|
|
254
254
|
};
|
|
255
|
-
var
|
|
255
|
+
var hyperProvider = {
|
|
256
|
+
id: "hyper",
|
|
257
|
+
name: "Charm Hyper",
|
|
258
|
+
keyPlaceholder: "sk-hyper-...",
|
|
259
|
+
async fetchBalance(apiKey, signal) {
|
|
260
|
+
const res = await fetch("https://hyper.charm.land/v1/credits", {
|
|
261
|
+
headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
|
|
262
|
+
signal
|
|
263
|
+
});
|
|
264
|
+
if (!res.ok) {
|
|
265
|
+
if (res.status === 401) throw new BalanceError("401");
|
|
266
|
+
if (res.status === 403) throw new BalanceError("403");
|
|
267
|
+
throw new BalanceError(String(res.status));
|
|
268
|
+
}
|
|
269
|
+
const json = await res.json();
|
|
270
|
+
const balance = json.balance;
|
|
271
|
+
if (typeof balance === "undefined" || balance === null) throw new BalanceError("EMPTY");
|
|
272
|
+
const usd = (Number(balance) * 0.05).toFixed(2);
|
|
273
|
+
return [{ currency: "USD", total: usd }];
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
var balanceProviders = [deepseekProvider, siliconflowProvider, openrouterProvider, moonshotProvider, hyperProvider];
|
|
256
277
|
function getBalanceProvider(id) {
|
|
257
278
|
return balanceProviders.find((p) => p.id === id) ?? balanceProviders[0] ?? deepseekProvider;
|
|
258
279
|
}
|
|
@@ -822,7 +843,7 @@ function estimateTokens(text) {
|
|
|
822
843
|
}
|
|
823
844
|
|
|
824
845
|
// src/_version.ts
|
|
825
|
-
var PLUGIN_VERSION = "1.7.0-beta.
|
|
846
|
+
var PLUGIN_VERSION = "1.7.0-beta.5";
|
|
826
847
|
|
|
827
848
|
// src/panel/TokenCachePanel.tsx
|
|
828
849
|
var MIN_PANEL_WIDTH = 20;
|
|
@@ -964,7 +985,7 @@ function TokenCachePanel(props) {
|
|
|
964
985
|
lastMainSid = sid;
|
|
965
986
|
if (props.signals.overrideSessionId()) {
|
|
966
987
|
props.signals.setOverrideSessionId(void 0);
|
|
967
|
-
props.api.kv.set(`${
|
|
988
|
+
props.api.kv.set(`${KV_PREFIX4}.session`, "");
|
|
968
989
|
}
|
|
969
990
|
}
|
|
970
991
|
});
|
|
@@ -1196,7 +1217,7 @@ function TokenCachePanel(props) {
|
|
|
1196
1217
|
});
|
|
1197
1218
|
setLastHasDist(true);
|
|
1198
1219
|
try {
|
|
1199
|
-
props.api.kv.set(`${
|
|
1220
|
+
props.api.kv.set(`${KV_PREFIX4}.dist_snapshot`, {
|
|
1200
1221
|
...d.dist
|
|
1201
1222
|
});
|
|
1202
1223
|
} catch {
|
|
@@ -1204,53 +1225,53 @@ function TokenCachePanel(props) {
|
|
|
1204
1225
|
}
|
|
1205
1226
|
});
|
|
1206
1227
|
const [partVersion, setPartVersion] = createSignal(0);
|
|
1207
|
-
const
|
|
1228
|
+
const KV_PREFIX4 = "cache_panel";
|
|
1208
1229
|
const persistFold = (key, val) => {
|
|
1209
1230
|
try {
|
|
1210
|
-
props.api.kv.set(`${
|
|
1231
|
+
props.api.kv.set(`${KV_PREFIX4}.${key}`, val);
|
|
1211
1232
|
} catch {
|
|
1212
1233
|
}
|
|
1213
1234
|
};
|
|
1214
1235
|
onMount(() => {
|
|
1215
1236
|
setPanelWidth(DEFAULT_PANEL_WIDTH);
|
|
1216
1237
|
try {
|
|
1217
|
-
setOpen(Boolean(props.api.kv.get(`${
|
|
1218
|
-
setDetailOpen(Boolean(props.api.kv.get(`${
|
|
1219
|
-
setModelOpen(Boolean(props.api.kv.get(`${
|
|
1220
|
-
setDistOpen(Boolean(props.api.kv.get(`${
|
|
1221
|
-
setSkillsOpen(Boolean(props.api.kv.get(`${
|
|
1238
|
+
setOpen(Boolean(props.api.kv.get(`${KV_PREFIX4}.open`, false)));
|
|
1239
|
+
setDetailOpen(Boolean(props.api.kv.get(`${KV_PREFIX4}.detail`, true)));
|
|
1240
|
+
setModelOpen(Boolean(props.api.kv.get(`${KV_PREFIX4}.model`, true)));
|
|
1241
|
+
setDistOpen(Boolean(props.api.kv.get(`${KV_PREFIX4}.dist`, false)));
|
|
1242
|
+
setSkillsOpen(Boolean(props.api.kv.get(`${KV_PREFIX4}.skills`, true)));
|
|
1222
1243
|
} catch {
|
|
1223
1244
|
}
|
|
1224
1245
|
const doRestore = () => {
|
|
1225
1246
|
try {
|
|
1226
|
-
const sym = props.api.kv.get(`${
|
|
1227
|
-
const rate = props.api.kv.get(`${
|
|
1247
|
+
const sym = props.api.kv.get(`${KV_PREFIX4}.currency`);
|
|
1248
|
+
const rate = props.api.kv.get(`${KV_PREFIX4}.rate`);
|
|
1228
1249
|
if (typeof sym === "string") setCurrencySymbol(sym);
|
|
1229
1250
|
if (typeof rate === "number" && rate > 0) setExchangeRate(rate);
|
|
1230
|
-
const balCur = props.api.kv.get(`${
|
|
1251
|
+
const balCur = props.api.kv.get(`${KV_PREFIX4}.balance_currency`);
|
|
1231
1252
|
if (typeof balCur === "string") setBalanceCurrency(balCur);
|
|
1232
|
-
const savedProvider = props.api.kv.get(`${
|
|
1253
|
+
const savedProvider = props.api.kv.get(`${KV_PREFIX4}.balance.provider`);
|
|
1233
1254
|
if (typeof savedProvider === "string" && balanceProviders.some((p) => p.id === savedProvider)) {
|
|
1234
1255
|
setBalanceProviderId(savedProvider);
|
|
1235
1256
|
setBalanceUnsupported(false);
|
|
1236
1257
|
}
|
|
1237
|
-
const savedAuto = props.api.kv.get(`${
|
|
1258
|
+
const savedAuto = props.api.kv.get(`${KV_PREFIX4}.balance.auto`);
|
|
1238
1259
|
if (typeof savedAuto === "boolean") setAutoBalance(savedAuto);
|
|
1239
|
-
const legacyKey = props.api.kv.get(`${
|
|
1260
|
+
const legacyKey = props.api.kv.get(`${KV_PREFIX4}.ds_key`, "");
|
|
1240
1261
|
if (legacyKey) {
|
|
1241
|
-
const dsKey = props.api.kv.get(`${
|
|
1242
|
-
if (!dsKey) props.api.kv.set(`${
|
|
1243
|
-
props.api.kv.set(`${
|
|
1262
|
+
const dsKey = props.api.kv.get(`${KV_PREFIX4}.balance.deepseek.key`, "");
|
|
1263
|
+
if (!dsKey) props.api.kv.set(`${KV_PREFIX4}.balance.deepseek.key`, legacyKey);
|
|
1264
|
+
props.api.kv.set(`${KV_PREFIX4}.ds_key`, "");
|
|
1244
1265
|
}
|
|
1245
1266
|
props.signals.setBalanceRefresh(props.signals.balanceRefresh() + 1);
|
|
1246
|
-
setSectionDetail(Boolean(props.api.kv.get(`${
|
|
1247
|
-
setSectionModel(Boolean(props.api.kv.get(`${
|
|
1248
|
-
setSectionDist(Boolean(props.api.kv.get(`${
|
|
1249
|
-
setSectionSkills(Boolean(props.api.kv.get(`${
|
|
1250
|
-
setSectionBalance(Boolean(props.api.kv.get(`${
|
|
1251
|
-
const bv = props.api.kv.get(`${
|
|
1267
|
+
setSectionDetail(Boolean(props.api.kv.get(`${KV_PREFIX4}.section.detail`, true)));
|
|
1268
|
+
setSectionModel(Boolean(props.api.kv.get(`${KV_PREFIX4}.section.model`, true)));
|
|
1269
|
+
setSectionDist(Boolean(props.api.kv.get(`${KV_PREFIX4}.section.dist`, true)));
|
|
1270
|
+
setSectionSkills(Boolean(props.api.kv.get(`${KV_PREFIX4}.section.skills`, true)));
|
|
1271
|
+
setSectionBalance(Boolean(props.api.kv.get(`${KV_PREFIX4}.section.balance`, true)));
|
|
1272
|
+
const bv = props.api.kv.get(`${KV_PREFIX4}.border`, true);
|
|
1252
1273
|
setBorderVisible(bv !== false);
|
|
1253
|
-
const cachedDist = props.api.kv.get(`${
|
|
1274
|
+
const cachedDist = props.api.kv.get(`${KV_PREFIX4}.dist_snapshot`);
|
|
1254
1275
|
if (cachedDist) {
|
|
1255
1276
|
setLastDist(cachedDist);
|
|
1256
1277
|
setLastHasDist(true);
|
|
@@ -2133,7 +2154,8 @@ import { effect as _$effect2 } from "@opentui/solid";
|
|
|
2133
2154
|
import { insert as _$insert2 } from "@opentui/solid";
|
|
2134
2155
|
import { createComponent as _$createComponent2 } from "@opentui/solid";
|
|
2135
2156
|
import { createElement as _$createElement2 } from "@opentui/solid";
|
|
2136
|
-
import {
|
|
2157
|
+
import { memo as _$memo2 } from "@opentui/solid";
|
|
2158
|
+
import { createMemo as createMemo2, For, onMount as onMount2, Show as Show2 } from "solid-js";
|
|
2137
2159
|
|
|
2138
2160
|
// src/v2/data.ts
|
|
2139
2161
|
function collectLastHitRate(context, sessionID) {
|
|
@@ -2186,8 +2208,16 @@ function mapTheme(theme) {
|
|
|
2186
2208
|
}
|
|
2187
2209
|
|
|
2188
2210
|
// src/v2/status.tsx
|
|
2211
|
+
var KV_PREFIX = "cache_panel";
|
|
2189
2212
|
function StatusView(props) {
|
|
2190
2213
|
const t = createT(() => props.signals.langCode());
|
|
2214
|
+
onMount2(() => {
|
|
2215
|
+
try {
|
|
2216
|
+
const v = props.api.kv.get(`${KV_PREFIX}.section.bottom`, true);
|
|
2217
|
+
props.signals.setSectionBottom(v !== false);
|
|
2218
|
+
} catch {
|
|
2219
|
+
}
|
|
2220
|
+
});
|
|
2191
2221
|
const pal = createMemo2(() => {
|
|
2192
2222
|
const th = mapTheme(props.context.theme);
|
|
2193
2223
|
const sat = (k, fb) => desaturateTo(th[k], MAX_SAT, fb);
|
|
@@ -2267,7 +2297,7 @@ function StatusView(props) {
|
|
|
2267
2297
|
});
|
|
2268
2298
|
return _$createComponent2(Show2, {
|
|
2269
2299
|
get when() {
|
|
2270
|
-
return segsW() > 0;
|
|
2300
|
+
return _$memo2(() => !!(segsW() > 0 && stats().hitRate >= 0))() && props.signals.sectionBottom();
|
|
2271
2301
|
},
|
|
2272
2302
|
get children() {
|
|
2273
2303
|
var _el$ = _$createElement2("text");
|
|
@@ -2290,7 +2320,7 @@ function StatusView(props) {
|
|
|
2290
2320
|
}
|
|
2291
2321
|
|
|
2292
2322
|
// src/v2/commands.ts
|
|
2293
|
-
var
|
|
2323
|
+
var KV_PREFIX2 = "cache_panel";
|
|
2294
2324
|
function extractToolParts(msg) {
|
|
2295
2325
|
if (!Array.isArray(msg?.content)) return [];
|
|
2296
2326
|
return msg.content.filter((p) => p?.type === "tool");
|
|
@@ -2319,13 +2349,13 @@ function currentSessionID(context) {
|
|
|
2319
2349
|
function makeCommands(context, api, signals) {
|
|
2320
2350
|
const t = () => createT(() => signals.langCode());
|
|
2321
2351
|
const providerOptionTitle = (p, current) => {
|
|
2322
|
-
const hasManual = !!api.kv.get(`${
|
|
2352
|
+
const hasManual = !!api.kv.get(`${KV_PREFIX2}.balance.${p.id}.key`, "");
|
|
2323
2353
|
const hasAuto = !hasManual && !!findOpencodeKeyV2(context, p);
|
|
2324
2354
|
const mark = hasManual ? t()("keyUser") : hasAuto ? t()("keyOpenCode") : t()("keyNotSet");
|
|
2325
2355
|
return p.name + mark + (current && p.id === current ? " *" : "");
|
|
2326
2356
|
};
|
|
2327
2357
|
const promptBalanceKey = async (provider) => {
|
|
2328
|
-
const current = api.kv.get(`${
|
|
2358
|
+
const current = api.kv.get(`${KV_PREFIX2}.balance.${provider.id}.key`, "") ?? "";
|
|
2329
2359
|
const val = await context.ui.dialog.prompt({
|
|
2330
2360
|
title: provider.name,
|
|
2331
2361
|
message: t()("balKeyPrompt", { p: provider.name }),
|
|
@@ -2341,7 +2371,7 @@ function makeCommands(context, api, signals) {
|
|
|
2341
2371
|
} else {
|
|
2342
2372
|
key = input;
|
|
2343
2373
|
}
|
|
2344
|
-
await api.kv.set(`${
|
|
2374
|
+
await api.kv.set(`${KV_PREFIX2}.balance.${provider.id}.key`, key);
|
|
2345
2375
|
signals.setBalanceRefresh(signals.balanceRefresh() + 1);
|
|
2346
2376
|
context.ui.toast.show({ message: key ? t()("keySaved") : t()("keyCleared") });
|
|
2347
2377
|
};
|
|
@@ -2365,9 +2395,9 @@ function makeCommands(context, api, signals) {
|
|
|
2365
2395
|
if (!opt) return;
|
|
2366
2396
|
const sym = CURRENCIES[opt] ?? "$";
|
|
2367
2397
|
const defRate = DEFAULT_RATES[opt] ?? 1;
|
|
2368
|
-
await api.kv.set(`${
|
|
2369
|
-
await api.kv.set(`${
|
|
2370
|
-
await api.kv.set(`${
|
|
2398
|
+
await api.kv.set(`${KV_PREFIX2}.currency`, sym);
|
|
2399
|
+
await api.kv.set(`${KV_PREFIX2}.rate`, defRate);
|
|
2400
|
+
await api.kv.set(`${KV_PREFIX2}.balance_currency`, opt);
|
|
2371
2401
|
signals.setBalanceCurrency(opt);
|
|
2372
2402
|
signals.setCurrencySymbol(sym);
|
|
2373
2403
|
signals.setExchangeRate(defRate);
|
|
@@ -2391,7 +2421,7 @@ function makeCommands(context, api, signals) {
|
|
|
2391
2421
|
if (val === void 0) return;
|
|
2392
2422
|
const n = parseFloat(val);
|
|
2393
2423
|
if (n > 0) {
|
|
2394
|
-
await api.kv.set(`${
|
|
2424
|
+
await api.kv.set(`${KV_PREFIX2}.rate`, n);
|
|
2395
2425
|
signals.setExchangeRate(n);
|
|
2396
2426
|
context.ui.toast.show({ message: t()("rateSet", { r: n }) });
|
|
2397
2427
|
}
|
|
@@ -2406,13 +2436,13 @@ function makeCommands(context, api, signals) {
|
|
|
2406
2436
|
palette: true,
|
|
2407
2437
|
slash: { name: "cache-section" },
|
|
2408
2438
|
run: async () => {
|
|
2409
|
-
const detailOn = Boolean(api.kv.get(`${
|
|
2410
|
-
const modelOn = Boolean(api.kv.get(`${
|
|
2411
|
-
const distOn = Boolean(api.kv.get(`${
|
|
2412
|
-
const skillsOn = Boolean(api.kv.get(`${
|
|
2413
|
-
const balanceOn = Boolean(api.kv.get(`${
|
|
2414
|
-
const bottomOn = Boolean(api.kv.get(`${
|
|
2415
|
-
const borderOn = Boolean(api.kv.get(`${
|
|
2439
|
+
const detailOn = Boolean(api.kv.get(`${KV_PREFIX2}.section.detail`, true));
|
|
2440
|
+
const modelOn = Boolean(api.kv.get(`${KV_PREFIX2}.section.model`, true));
|
|
2441
|
+
const distOn = Boolean(api.kv.get(`${KV_PREFIX2}.section.dist`, true));
|
|
2442
|
+
const skillsOn = Boolean(api.kv.get(`${KV_PREFIX2}.section.skills`, true));
|
|
2443
|
+
const balanceOn = Boolean(api.kv.get(`${KV_PREFIX2}.section.balance`, true));
|
|
2444
|
+
const bottomOn = Boolean(api.kv.get(`${KV_PREFIX2}.section.bottom`, true));
|
|
2445
|
+
const borderOn = Boolean(api.kv.get(`${KV_PREFIX2}.border`, true));
|
|
2416
2446
|
const labels = {
|
|
2417
2447
|
detail: t()("secDetail"),
|
|
2418
2448
|
model: t()("secModel"),
|
|
@@ -2437,12 +2467,12 @@ function makeCommands(context, api, signals) {
|
|
|
2437
2467
|
});
|
|
2438
2468
|
if (!opt) return;
|
|
2439
2469
|
if (opt === "border") {
|
|
2440
|
-
const cur = Boolean(api.kv.get(`${
|
|
2441
|
-
await api.kv.set(`${
|
|
2470
|
+
const cur = Boolean(api.kv.get(`${KV_PREFIX2}.border`, true));
|
|
2471
|
+
await api.kv.set(`${KV_PREFIX2}.border`, !cur);
|
|
2442
2472
|
signals.setBorderVisible(!cur);
|
|
2443
2473
|
context.ui.toast.show({ message: !cur ? t()("borderShown") : t()("borderHidden") });
|
|
2444
2474
|
} else {
|
|
2445
|
-
const key = `${
|
|
2475
|
+
const key = `${KV_PREFIX2}.section.${opt}`;
|
|
2446
2476
|
const cur = Boolean(api.kv.get(key, true));
|
|
2447
2477
|
await api.kv.set(key, !cur);
|
|
2448
2478
|
if (opt === "detail") signals.setSectionDetail(!cur);
|
|
@@ -2465,14 +2495,14 @@ function makeCommands(context, api, signals) {
|
|
|
2465
2495
|
palette: true,
|
|
2466
2496
|
slash: { name: "cache-config" },
|
|
2467
2497
|
run: () => {
|
|
2468
|
-
const sym = api.kv.get(`${
|
|
2469
|
-
const rate = api.kv.get(`${
|
|
2470
|
-
const detail = Boolean(api.kv.get(`${
|
|
2471
|
-
const model = Boolean(api.kv.get(`${
|
|
2472
|
-
const dist = Boolean(api.kv.get(`${
|
|
2473
|
-
const skills = Boolean(api.kv.get(`${
|
|
2474
|
-
const balance = Boolean(api.kv.get(`${
|
|
2475
|
-
const bottom = Boolean(api.kv.get(`${
|
|
2498
|
+
const sym = api.kv.get(`${KV_PREFIX2}.currency`) ?? "$";
|
|
2499
|
+
const rate = api.kv.get(`${KV_PREFIX2}.rate`) ?? 1;
|
|
2500
|
+
const detail = Boolean(api.kv.get(`${KV_PREFIX2}.section.detail`, true));
|
|
2501
|
+
const model = Boolean(api.kv.get(`${KV_PREFIX2}.section.model`, true));
|
|
2502
|
+
const dist = Boolean(api.kv.get(`${KV_PREFIX2}.section.dist`, true));
|
|
2503
|
+
const skills = Boolean(api.kv.get(`${KV_PREFIX2}.section.skills`, true));
|
|
2504
|
+
const balance = Boolean(api.kv.get(`${KV_PREFIX2}.section.balance`, true));
|
|
2505
|
+
const bottom = Boolean(api.kv.get(`${KV_PREFIX2}.section.bottom`, true));
|
|
2476
2506
|
const on = (v) => v ? "ON" : "OFF";
|
|
2477
2507
|
context.ui.toast.show({
|
|
2478
2508
|
title: t()("panelConfigTitle"),
|
|
@@ -2507,7 +2537,7 @@ function makeCommands(context, api, signals) {
|
|
|
2507
2537
|
}))
|
|
2508
2538
|
});
|
|
2509
2539
|
if (!opt) return;
|
|
2510
|
-
await api.kv.set(`${
|
|
2540
|
+
await api.kv.set(`${KV_PREFIX2}.lang`, opt);
|
|
2511
2541
|
signals.setLangCode(opt);
|
|
2512
2542
|
context.ui.toast.show({ message: t()("langSwitched") });
|
|
2513
2543
|
}
|
|
@@ -2537,18 +2567,18 @@ function makeCommands(context, api, signals) {
|
|
|
2537
2567
|
if (!opt) return;
|
|
2538
2568
|
if (opt === "__auto__") {
|
|
2539
2569
|
const next = !auto;
|
|
2540
|
-
await api.kv.set(`${
|
|
2570
|
+
await api.kv.set(`${KV_PREFIX2}.balance.auto`, next);
|
|
2541
2571
|
signals.setAutoBalance(next);
|
|
2542
2572
|
context.ui.toast.show({ message: next ? t()("autoSwitchOn") : t()("autoSwitchOff") });
|
|
2543
2573
|
} else {
|
|
2544
2574
|
const provider = getBalanceProvider(opt);
|
|
2545
|
-
await api.kv.set(`${
|
|
2546
|
-
await api.kv.set(`${
|
|
2575
|
+
await api.kv.set(`${KV_PREFIX2}.balance.provider`, provider.id);
|
|
2576
|
+
await api.kv.set(`${KV_PREFIX2}.balance.auto`, false);
|
|
2547
2577
|
signals.setBalanceProviderId(provider.id);
|
|
2548
2578
|
signals.setAutoBalance(false);
|
|
2549
2579
|
signals.setBalanceUnsupported(false);
|
|
2550
2580
|
signals.setBalanceRefresh(signals.balanceRefresh() + 1);
|
|
2551
|
-
const hasKey = !!api.kv.get(`${
|
|
2581
|
+
const hasKey = !!api.kv.get(`${KV_PREFIX2}.balance.${provider.id}.key`, "");
|
|
2552
2582
|
if (!hasKey) {
|
|
2553
2583
|
await promptBalanceKey(provider);
|
|
2554
2584
|
} else {
|
|
@@ -2575,8 +2605,8 @@ function makeCommands(context, api, signals) {
|
|
|
2575
2605
|
});
|
|
2576
2606
|
if (!opt) return;
|
|
2577
2607
|
const provider = getBalanceProvider(opt);
|
|
2578
|
-
await api.kv.set(`${
|
|
2579
|
-
await api.kv.set(`${
|
|
2608
|
+
await api.kv.set(`${KV_PREFIX2}.balance.provider`, provider.id);
|
|
2609
|
+
await api.kv.set(`${KV_PREFIX2}.balance.auto`, false);
|
|
2580
2610
|
signals.setBalanceProviderId(provider.id);
|
|
2581
2611
|
signals.setAutoBalance(false);
|
|
2582
2612
|
signals.setBalanceRefresh(signals.balanceRefresh() + 1);
|
|
@@ -2663,7 +2693,7 @@ function makeCommands(context, api, signals) {
|
|
|
2663
2693
|
return true;
|
|
2664
2694
|
});
|
|
2665
2695
|
if (unique.length > 0) {
|
|
2666
|
-
const currentSid = signals.overrideSessionId() ?? api.kv.get(`${
|
|
2696
|
+
const currentSid = signals.overrideSessionId() ?? api.kv.get(`${KV_PREFIX2}.session`, "");
|
|
2667
2697
|
const options = unique.map((c, i) => ({
|
|
2668
2698
|
title: `${i + 1}. ${c.title}`,
|
|
2669
2699
|
value: c.value,
|
|
@@ -2682,11 +2712,11 @@ function makeCommands(context, api, signals) {
|
|
|
2682
2712
|
if (!opt) return;
|
|
2683
2713
|
if (opt === backValue) {
|
|
2684
2714
|
signals.setOverrideSessionId(void 0);
|
|
2685
|
-
await api.kv.set(`${
|
|
2715
|
+
await api.kv.set(`${KV_PREFIX2}.session`, "");
|
|
2686
2716
|
context.ui.toast.show({ message: t()("backToMain") });
|
|
2687
2717
|
} else {
|
|
2688
2718
|
signals.setOverrideSessionId(opt);
|
|
2689
|
-
await api.kv.set(`${
|
|
2719
|
+
await api.kv.set(`${KV_PREFIX2}.session`, opt);
|
|
2690
2720
|
context.ui.toast.show({ message: t()("subAgentSwitched", { s: opt.slice(0, 24) + "\u2026" }) });
|
|
2691
2721
|
}
|
|
2692
2722
|
} else {
|
|
@@ -2699,7 +2729,7 @@ function makeCommands(context, api, signals) {
|
|
|
2699
2729
|
const sid = val.trim();
|
|
2700
2730
|
if (sid) {
|
|
2701
2731
|
signals.setOverrideSessionId(sid);
|
|
2702
|
-
await api.kv.set(`${
|
|
2732
|
+
await api.kv.set(`${KV_PREFIX2}.session`, sid);
|
|
2703
2733
|
context.ui.toast.show({ message: t()("subAgentSwitched", { s: sid.slice(0, 24) + "\u2026" }) });
|
|
2704
2734
|
}
|
|
2705
2735
|
}
|
|
@@ -2715,7 +2745,7 @@ function makeCommands(context, api, signals) {
|
|
|
2715
2745
|
slash: { name: "cache-session-back" },
|
|
2716
2746
|
run: async () => {
|
|
2717
2747
|
signals.setOverrideSessionId(void 0);
|
|
2718
|
-
await api.kv.set(`${
|
|
2748
|
+
await api.kv.set(`${KV_PREFIX2}.session`, "");
|
|
2719
2749
|
context.ui.toast.show({ message: t()("backToMain") });
|
|
2720
2750
|
}
|
|
2721
2751
|
}
|
|
@@ -2723,7 +2753,7 @@ function makeCommands(context, api, signals) {
|
|
|
2723
2753
|
}
|
|
2724
2754
|
|
|
2725
2755
|
// src/v2/index.tsx
|
|
2726
|
-
var
|
|
2756
|
+
var KV_PREFIX3 = "cache_panel";
|
|
2727
2757
|
var BALANCE_POLL_MS = 5 * 60 * 1e3;
|
|
2728
2758
|
var DEBUG_LANG = typeof process !== "undefined" ? process.env?.CACHE_TUI_LANG : void 0;
|
|
2729
2759
|
var INIT_LANG = DEBUG_LANG !== void 0 && LANG_META.some((m) => m.code === DEBUG_LANG) ? DEBUG_LANG : detectLang();
|
|
@@ -2795,9 +2825,9 @@ function PluginRoot(props) {
|
|
|
2795
2825
|
mode: "global",
|
|
2796
2826
|
commands: makeCommands(props.context, props.api, props.signals)
|
|
2797
2827
|
}));
|
|
2798
|
-
|
|
2828
|
+
onMount3(() => {
|
|
2799
2829
|
try {
|
|
2800
|
-
const saved = props.api.kv.get(`${
|
|
2830
|
+
const saved = props.api.kv.get(`${KV_PREFIX3}.lang`);
|
|
2801
2831
|
if (saved && LANG_META.some((m) => m.code === saved)) {
|
|
2802
2832
|
props.signals.setLangCode(saved);
|
|
2803
2833
|
}
|
|
@@ -2806,7 +2836,7 @@ function PluginRoot(props) {
|
|
|
2806
2836
|
});
|
|
2807
2837
|
const pollBalance = async () => {
|
|
2808
2838
|
const provider = getBalanceProvider(props.signals.balanceProviderId());
|
|
2809
|
-
const key = props.api.kv.get(`${
|
|
2839
|
+
const key = props.api.kv.get(`${KV_PREFIX3}.balance.${provider.id}.key`, "") || findOpencodeKeyV2(props.context, provider);
|
|
2810
2840
|
const set = props.signals.setBalanceState;
|
|
2811
2841
|
if (props.signals.balanceUnsupported()) {
|
|
2812
2842
|
set({
|
|
@@ -2883,7 +2913,7 @@ function PluginRoot(props) {
|
|
|
2883
2913
|
lastSlotSid = sid;
|
|
2884
2914
|
if (props.signals.overrideSessionId()) {
|
|
2885
2915
|
props.signals.setOverrideSessionId(void 0);
|
|
2886
|
-
void props.api.kv.set(`${
|
|
2916
|
+
void props.api.kv.set(`${KV_PREFIX3}.session`, "");
|
|
2887
2917
|
}
|
|
2888
2918
|
}
|
|
2889
2919
|
});
|
|
@@ -2922,6 +2952,7 @@ var mod = {
|
|
|
2922
2952
|
append: "prompt.footer.status",
|
|
2923
2953
|
render: (props) => _$createComponent3(StatusView, {
|
|
2924
2954
|
context,
|
|
2955
|
+
api,
|
|
2925
2956
|
signals,
|
|
2926
2957
|
get sessionID() {
|
|
2927
2958
|
return String(props.sessionID ?? "");
|
package/package.json
CHANGED
package/src/_version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// auto-generated
|
|
2
|
-
export const PLUGIN_VERSION="1.7.0-beta.
|
|
2
|
+
export const PLUGIN_VERSION="1.7.0-beta.5";
|
package/src/balance-providers.ts
CHANGED
|
@@ -125,8 +125,32 @@ const moonshotProvider: BalanceProvider = {
|
|
|
125
125
|
},
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
const hyperProvider: BalanceProvider = {
|
|
129
|
+
id: "hyper",
|
|
130
|
+
name: "Charm Hyper",
|
|
131
|
+
keyPlaceholder: "sk-hyper-...",
|
|
132
|
+
async fetchBalance(apiKey, signal) {
|
|
133
|
+
// 官方接口:GET /v1/credits → {"balance": 98}(积分余额)
|
|
134
|
+
const res = await fetch("https://hyper.charm.land/v1/credits", {
|
|
135
|
+
headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
|
|
136
|
+
signal,
|
|
137
|
+
})
|
|
138
|
+
if (!res.ok) {
|
|
139
|
+
if (res.status === 401) throw new BalanceError("401")
|
|
140
|
+
if (res.status === 403) throw new BalanceError("403")
|
|
141
|
+
throw new BalanceError(String(res.status))
|
|
142
|
+
}
|
|
143
|
+
const json = await res.json() as { balance?: string | number }
|
|
144
|
+
const balance = json.balance
|
|
145
|
+
if (typeof balance === "undefined" || balance === null) throw new BalanceError("EMPTY")
|
|
146
|
+
// hyper 积分换算:100 积分 = $5,即 1 积分 = $0.05
|
|
147
|
+
const usd = (Number(balance) * 0.05).toFixed(2)
|
|
148
|
+
return [{ currency: "USD", total: usd }]
|
|
149
|
+
},
|
|
150
|
+
}
|
|
151
|
+
|
|
128
152
|
/** 已注册的 provider 列表(按需追加新适配器)。 */
|
|
129
|
-
export const balanceProviders: BalanceProvider[] = [deepseekProvider, siliconflowProvider, openrouterProvider, moonshotProvider]
|
|
153
|
+
export const balanceProviders: BalanceProvider[] = [deepseekProvider, siliconflowProvider, openrouterProvider, moonshotProvider, hyperProvider]
|
|
130
154
|
|
|
131
155
|
/** 按 id 取 provider;未知 id 回退到第一个。 */
|
|
132
156
|
export function getBalanceProvider(id: string): BalanceProvider {
|