opencode-go-usage-tui 1.3.1 → 1.3.2

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/tui.js CHANGED
@@ -50,14 +50,14 @@ var ZH_T = {
50
50
  onboardConfigTitle: "Welcome to Go Usage / \u6B22\u8FCE\u4F7F\u7528 Go \u7528\u91CF",
51
51
  onboardConfigDesc: "First-time setup / \u9996\u6B21\u4F7F\u7528\u9700\u914D\u7F6E\u8D26\u53F7",
52
52
  setupCanceled: "\u5DF2\u53D6\u6D88\u914D\u7F6E\uFF0C\u8F93\u5165 /go-config \u53EF\u91CD\u65B0\u8BBE\u7F6E",
53
- // ── 模型价格表 ──
54
- priceTitle: "\u6A21\u578B\u4EF7\u683C",
55
- priceLoading: "\u6293\u53D6\u4EF7\u683C\u4E2D...",
56
- priceError: "\u4EF7\u683C\u6293\u53D6\u5931\u8D25",
53
+ // ── 模型限额表 ──
54
+ priceTitle: "\u6A21\u578B\u9650\u989D",
55
+ priceLoading: "\u6293\u53D6\u9650\u989D\u4E2D...",
56
+ priceError: "\u9650\u989D\u6293\u53D6\u5931\u8D25",
57
57
  priceUpdated: "\u66F4\u65B0\u65F6\u95F4",
58
- priceChanged: "\u4EF7\u683C\u6709\u53D8\u5316",
58
+ priceChanged: "\u9650\u989D\u6709\u53D8\u5316",
59
59
  priceNoChange: "\u65E0\u53D8\u5316",
60
- priceChangesSummary: "{t} \u9879\u53D8\u5316\uFF1A{a} \u65B0\u589E / {r} \u4E0B\u67B6 / {p} \u4EF7\u683C / {l} \u9650\u989D",
60
+ priceChangesSummary: "{t}\u9879\u53D8\u5316 \u65B0\u589E{a}/\u4E0B\u67B6{r}/\u9650\u989D{l}",
61
61
  priceVariantTag: "{n}\u4E2A\u6863\u4F4D",
62
62
  priceInput: "\u8F93\u5165",
63
63
  priceOutput: "\u8F93\u51FA",
@@ -68,24 +68,32 @@ var ZH_T = {
68
68
  priceReqWeek: "\u5468\u8BF7\u6C42",
69
69
  priceReqMonth: "\u6708\u8BF7\u6C42",
70
70
  priceModelCol: "\u6A21\u578B",
71
- priceReqs: "\u8BF7\u6C42\u6570(5h/\u5468/\u6708)",
71
+ priceReqs: "\u4E0A\u9650($)",
72
72
  priceSdk: "SDK",
73
73
  priceDiffUp: "\u2191{v}",
74
74
  priceDiffDown: "\u2193{v}",
75
75
  priceDiffSame: "=",
76
- priceChartTitle: "\u4EF7\u683C\u53D8\u5316\u8BB0\u5F55",
76
+ priceChartTitle: "\u9650\u989D\u53D8\u5316\u8BB0\u5F55",
77
77
  priceChartEmpty: "\u6682\u65E0\u53D8\u5316\u8BB0\u5F55",
78
78
  priceChartAdded: "\u65B0\u589E: {n}",
79
79
  priceChartChanged: "\u53D8\u5316: {n}",
80
80
  priceChartRemoved: "\u79FB\u9664: {n}",
81
- priceCollapse: "\u4EF7\u683C\u8868",
82
- priceExpand: "\u4EF7\u683C\u8868",
81
+ priceCollapse: "\u9650\u989D\u8868",
82
+ priceExpand: "\u9650\u989D\u8868",
83
+ priceRetention: "\u4FDD\u7559\u671F",
84
+ priceTraining: "\u8BAD\u7EC3",
85
+ priceTier: "\u6863\u4F4D",
86
+ changelogTitle: "\u6700\u8FD1\u53D8\u5316",
87
+ typeAdded: "\u65B0\u589E",
88
+ typeRemoved: "\u4E0B\u67B6",
89
+ typePricing: "\u4EF7\u683C",
90
+ typeLimits: "\u9650\u989D",
83
91
  settingsTitle: "Go \u7528\u91CF\u8BBE\u7F6E",
84
92
  settingsDesc: "\u5173\u6CE8\u6A21\u578B\u3001\u5237\u65B0\u95F4\u9694\u8BBE\u7F6E",
85
93
  settingsFocus: "\u5173\u6CE8\u7684\u6A21\u578B",
86
94
  settingsRefresh: "\u5237\u65B0\u95F4\u9694 (\u79D2)",
87
95
  settingsRefreshUsage: "\u7528\u91CF\u5237\u65B0\u95F4\u9694 (\u79D2)",
88
- settingsRefreshPricing: "\u4EF7\u683C\u5237\u65B0\u95F4\u9694 (\u79D2)",
96
+ settingsRefreshPricing: "\u9650\u989D\u5237\u65B0\u95F4\u9694 (\u79D2)",
89
97
  settingsSaved: "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58",
90
98
  settingsCanceled: "\u5DF2\u53D6\u6D88\u8BBE\u7F6E",
91
99
  focusAll: "\u5168\u90E8\u9009\u62E9",
@@ -131,14 +139,14 @@ var EN_T = {
131
139
  onboardConfigTitle: "Welcome to Go Usage / \u6B22\u8FCE\u4F7F\u7528 Go \u7528\u91CF",
132
140
  onboardConfigDesc: "First-time setup / \u9996\u6B21\u4F7F\u7528\u9700\u914D\u7F6E\u8D26\u53F7",
133
141
  setupCanceled: "Setup canceled, run /go-config to reconfigure",
134
- // ── 模型价格表 ──
135
- priceTitle: "Model Pricing",
136
- priceLoading: "Fetching pricing...",
137
- priceError: "Pricing fetch failed",
138
- priceUpdated: "Pricing updated",
139
- priceChanged: "Pricing changed",
142
+ // ── 模型限额表 ──
143
+ priceTitle: "Model Limits",
144
+ priceLoading: "Fetching limits...",
145
+ priceError: "Limit fetch failed",
146
+ priceUpdated: "Limits updated",
147
+ priceChanged: "Limits changed",
140
148
  priceNoChange: "No changes",
141
- priceChangesSummary: "{t} change(s): {a} added / {r} removed / {p} price / {l} limit",
149
+ priceChangesSummary: "{t} changes +{a} -{r} ~{l}",
142
150
  priceVariantTag: "{n} tiers",
143
151
  priceInput: "In",
144
152
  priceOutput: "Out",
@@ -149,24 +157,32 @@ var EN_T = {
149
157
  priceReqWeek: "Wk req",
150
158
  priceReqMonth: "Mo req",
151
159
  priceModelCol: "Model",
152
- priceReqs: "Requests (5h/wk/mo)",
160
+ priceReqs: "Limit ($)",
153
161
  priceSdk: "SDK",
154
162
  priceDiffUp: "\u2191{v}",
155
163
  priceDiffDown: "\u2193{v}",
156
164
  priceDiffSame: "=",
157
- priceChartTitle: "Price change history",
165
+ priceChartTitle: "Limit change history",
158
166
  priceChartEmpty: "No change history yet",
159
167
  priceChartAdded: "Added: {n}",
160
168
  priceChartChanged: "Changed: {n}",
161
169
  priceChartRemoved: "Removed: {n}",
162
- priceCollapse: "Pricing",
163
- priceExpand: "Pricing",
170
+ priceCollapse: "Limits",
171
+ priceExpand: "Limits",
172
+ priceRetention: "Retention",
173
+ priceTraining: "Training",
174
+ priceTier: "Tier",
175
+ changelogTitle: "Recent changes",
176
+ typeAdded: "Added",
177
+ typeRemoved: "Removed",
178
+ typePricing: "Pricing",
179
+ typeLimits: "Limit",
164
180
  settingsTitle: "Go Usage Settings",
165
181
  settingsDesc: "Focused models, refresh interval settings",
166
182
  settingsFocus: "Focused models",
167
183
  settingsRefresh: "Refresh interval (sec)",
168
184
  settingsRefreshUsage: "Usage refresh interval (sec)",
169
- settingsRefreshPricing: "Pricing refresh interval (sec)",
185
+ settingsRefreshPricing: "Limit refresh interval (sec)",
170
186
  settingsSaved: "Settings saved",
171
187
  settingsCanceled: "Settings canceled",
172
188
  focusAll: "Select all",
@@ -303,7 +319,7 @@ async function fetchPricing() {
303
319
  if (!priceGroupMap.has(key)) priceGroupMap.set(key, []);
304
320
  priceGroupMap.get(key).push({ baseName, variant, row });
305
321
  }
306
- const models = [];
322
+ const modelMap = /* @__PURE__ */ new Map();
307
323
  for (const row of limitRows.slice(1)) {
308
324
  if (row.length < 4) continue;
309
325
  const name = row[0];
@@ -325,7 +341,7 @@ async function fetchPricing() {
325
341
  const allOutputs = variants.map((v) => v.pricing.output).filter((v) => v !== null);
326
342
  const allReads = variants.map((v) => v.pricing.cachedRead).filter((v) => v !== null);
327
343
  const allWrites = variants.map((v) => v.pricing.cachedWrite).filter((v) => v !== null);
328
- models.push({
344
+ const model = {
329
345
  id,
330
346
  name,
331
347
  variants,
@@ -345,8 +361,20 @@ async function fetchPricing() {
345
361
  sdk: endpointRow ? endpointRow[3] || "" : "",
346
362
  training: retentionRow ? retentionRow[1] || "" : "",
347
363
  retention: retentionRow ? retentionRow[2] || "" : ""
348
- });
364
+ };
365
+ if (modelMap.has(key)) {
366
+ const existing = modelMap.get(key);
367
+ const merged = new Map(existing.variants.map((v) => [v.label, v]));
368
+ for (const v of model.variants) if (!merged.has(v.label)) merged.set(v.label, v);
369
+ const mv = [...merged.values()];
370
+ existing.variants = mv;
371
+ if (mv.length === 1) existing.pricing = mv[0].pricing;
372
+ modelMap.set(key, existing);
373
+ } else {
374
+ modelMap.set(key, model);
375
+ }
349
376
  }
377
+ const models = [...modelMap.values()];
350
378
  return { fetchTime: (/* @__PURE__ */ new Date()).toISOString(), models };
351
379
  }
352
380
  function comparePricing(oldData, newData) {
@@ -460,7 +488,7 @@ function updatePricingStore(newData) {
460
488
  }
461
489
 
462
490
  // src/index.tsx
463
- var VERSION = "1.3.1";
491
+ var VERSION = "1.3.2";
464
492
  var CHECK_INTERVAL = Number(process?.env?.OPENCODE_GO_CHECK_INTERVAL ?? 6e4);
465
493
  var WARN_THRESHOLD = Number(process?.env?.OPENCODE_GO_WARN_THRESHOLD ?? 0.8);
466
494
  var CONFIG_DIR = process?.env?.OPENCODE_CONFIG_DIR || (process?.env?.USERPROFILE ? `${process.env.USERPROFILE}\\.config\\opencode` : "") || process?.env?.HOME + "/.config/opencode";
@@ -931,7 +959,11 @@ function GoUsagePanel(props) {
931
959
  _$insertNode(_el$10, _el$11);
932
960
  _$insertNode(_el$10, _el$12);
933
961
  _$insertNode(_el$10, _el$14);
934
- _$setProp(_el$10, "onMouseUp", () => setOpen((o) => !o));
962
+ _$setProp(_el$10, "selectable", false);
963
+ _$setProp(_el$10, "onMouseUp", (e) => {
964
+ e.preventDefault();
965
+ setOpen((o) => !o);
966
+ });
935
967
  _$insert(_el$11, () => open() ? "\u25BC " : "\u25B6 ");
936
968
  _$insertNode(_el$12, _el$13);
937
969
  _$insert(_el$13, () => t("panelTitle"));
@@ -1073,6 +1105,9 @@ function PricePanel(props) {
1073
1105
  const [priceError, setPriceError] = createSignal("");
1074
1106
  const [priceLoading, setPriceLoading] = createSignal(false);
1075
1107
  const [panelWidth, setPanelWidth] = createSignal(24);
1108
+ const [changedModels, setChangedModels] = createSignal(/* @__PURE__ */ new Map());
1109
+ const [expandedId, setExpandedId] = createSignal(null);
1110
+ const [mounted, setMounted] = createSignal(false);
1076
1111
  const [cfg, setCfg] = createSignal(loadConfig());
1077
1112
  createEffect(() => {
1078
1113
  void configTick();
@@ -1080,7 +1115,11 @@ function PricePanel(props) {
1080
1115
  });
1081
1116
  let boxEl;
1082
1117
  let priceController = null;
1118
+ onMount(() => {
1119
+ setTimeout(() => setMounted(true), 100);
1120
+ });
1083
1121
  createEffect(() => {
1122
+ mounted();
1084
1123
  if (boxEl && typeof boxEl.width === "number" && boxEl.width > 0) {
1085
1124
  setPanelWidth(Math.max(20, boxEl.width));
1086
1125
  }
@@ -1100,6 +1139,14 @@ function PricePanel(props) {
1100
1139
  if (prev && prev.fetchTime !== data.fetchTime) {
1101
1140
  const diff = comparePricing(prev, data);
1102
1141
  if (diff.hasChanges) {
1142
+ const m = /* @__PURE__ */ new Map();
1143
+ for (const c of diff.changes) {
1144
+ if (c.type === "removed") continue;
1145
+ const cat = c.type === "added" ? "added" : c.type === "pricing" ? "pricing" : "limits";
1146
+ if (!m.has(c.modelId)) m.set(c.modelId, /* @__PURE__ */ new Set());
1147
+ m.get(c.modelId).add(cat);
1148
+ }
1149
+ setChangedModels(m);
1103
1150
  props.api.toast({
1104
1151
  variant: "info",
1105
1152
  title: t("priceChanged"),
@@ -1107,11 +1154,14 @@ function PricePanel(props) {
1107
1154
  t: diff.summary.total,
1108
1155
  a: diff.summary.added,
1109
1156
  r: diff.summary.removed,
1110
- p: diff.summary.priceChanges,
1111
1157
  l: diff.summary.limitChanges
1112
1158
  })
1113
1159
  });
1160
+ } else {
1161
+ setChangedModels(/* @__PURE__ */ new Map());
1114
1162
  }
1163
+ } else {
1164
+ setChangedModels(/* @__PURE__ */ new Map());
1115
1165
  }
1116
1166
  } catch {
1117
1167
  setPriceError(t("priceError"));
@@ -1120,10 +1170,6 @@ function PricePanel(props) {
1120
1170
  priceController = null;
1121
1171
  }
1122
1172
  }
1123
- function formatCount(n) {
1124
- if (n >= 1e3) return (n / 1e3).toFixed(1).replace(/\.0$/, "") + "k";
1125
- return String(n);
1126
- }
1127
1173
  function visualPadEnd(s, w) {
1128
1174
  const cur = visualWidth(s);
1129
1175
  if (cur >= w) return s;
@@ -1149,17 +1195,92 @@ function PricePanel(props) {
1149
1195
  return label + " ".repeat(gap) + value;
1150
1196
  }
1151
1197
  function renderLimitRow(m) {
1198
+ const cats = changedModels().get(m.id);
1199
+ const expanded = expandedId() === m.id;
1152
1200
  const name = abbreviateName(m.name, 18);
1153
- const req = `${formatCount(m.limits.fiveHour)}/${formatCount(m.limits.weekly)}/${formatCount(m.limits.monthly)}`;
1154
- return (() => {
1155
- var _el$30 = _$createElement("text"), _el$31 = _$createElement("span");
1156
- _$insertNode(_el$30, _el$31);
1157
- _$insert(_el$31, () => justify(name, req));
1158
- _$effect((_$p) => _$setProp(_el$31, "style", {
1159
- fg: colors().text
1160
- }, _$p));
1201
+ const req = m.usageLimit != null ? `$${m.usageLimit}` : "\u2014";
1202
+ const fg = cats?.has("added") ? colors().success : cats?.has("pricing") ? colors().primary : cats?.has("limits") ? colors().warning : colors().text;
1203
+ const ind = expanded ? " \u25BE" : " \u25B8";
1204
+ const row = (() => {
1205
+ var _el$30 = _$createElement("text");
1206
+ _$setProp(_el$30, "fg", fg);
1207
+ _$setProp(_el$30, "selectable", false);
1208
+ _$setProp(_el$30, "onMouseUp", (e) => {
1209
+ e.preventDefault();
1210
+ setExpandedId(expanded ? null : m.id);
1211
+ });
1212
+ _$insert(_el$30, () => justify(name, req + ind));
1161
1213
  return _el$30;
1162
1214
  })();
1215
+ if (!expanded) return row;
1216
+ return [row, _$memo(() => renderPriceDetail(m))];
1217
+ }
1218
+ function renderPriceDetail(m) {
1219
+ const prev = pricingStore()?.previous?.models.find((x) => x.id === m.id);
1220
+ const prevVariants = prev?.variants;
1221
+ const arrow = (cur, old) => {
1222
+ if (old == null || cur == null || old === cur) return "";
1223
+ return cur > old ? " \u2191" : " \u2193";
1224
+ };
1225
+ const fmt = (cur, old) => cur == null ? "-" : `$${cur} /MTok${arrow(cur, old)}`;
1226
+ const pad13 = (s) => visualPadEnd(s, 13);
1227
+ const lines = [];
1228
+ const tiers = m.variants;
1229
+ const hasTiers = tiers.length > 1;
1230
+ if (hasTiers) {
1231
+ tiers.forEach((v, ti) => {
1232
+ const isLastTier = ti === tiers.length - 1;
1233
+ lines.push((() => {
1234
+ var _el$31 = _$createElement("text");
1235
+ _$insert(_el$31, () => ` \u251C ${t("priceTier")}: ${v.label}`);
1236
+ _$effect((_$p) => _$setProp(_el$31, "fg", colors().muted, _$p));
1237
+ return _el$31;
1238
+ })());
1239
+ const inner = isLastTier ? " " : "\u2502";
1240
+ const prevV = prevVariants?.find((p) => p.label === v.label) ?? prevVariants?.[ti];
1241
+ const fields = [[t("priceInput"), fmt(v.pricing.input, prevV?.pricing.input)], [t("priceOutput"), fmt(v.pricing.output, prevV?.pricing.output)], [t("priceCacheRead"), fmt(v.pricing.cachedRead, prevV?.pricing.cachedRead)], [t("priceCacheWrite"), fmt(v.pricing.cachedWrite, prevV?.pricing.cachedWrite)]];
1242
+ for (const [fl, fv] of fields) {
1243
+ lines.push((() => {
1244
+ var _el$32 = _$createElement("text");
1245
+ _$insert(_el$32, () => pad13(` ${inner} ${fl}:`) + fv);
1246
+ _$effect((_$p) => _$setProp(_el$32, "fg", colors().muted, _$p));
1247
+ return _el$32;
1248
+ })());
1249
+ }
1250
+ });
1251
+ } else {
1252
+ const v = tiers[0];
1253
+ const fields = [[t("priceInput"), fmt(v.pricing.input, prev?.pricing.input)], [t("priceOutput"), fmt(v.pricing.output, prev?.pricing.output)], [t("priceCacheRead"), fmt(v.pricing.cachedRead, prev?.pricing.cachedRead)], [t("priceCacheWrite"), fmt(v.pricing.cachedWrite, prev?.pricing.cachedWrite)]];
1254
+ for (const [fl, fv] of fields) {
1255
+ lines.push((() => {
1256
+ var _el$33 = _$createElement("text");
1257
+ _$insert(_el$33, () => pad13(` \u251C ${fl}:`) + fv);
1258
+ _$effect((_$p) => _$setProp(_el$33, "fg", colors().muted, _$p));
1259
+ return _el$33;
1260
+ })());
1261
+ }
1262
+ }
1263
+ const fmtFull = (n) => n > 0 ? n.toLocaleString("en-US") : "\u2014";
1264
+ const limitFields = [[t("priceReq5h"), fmtFull(m.limits.fiveHour)], [t("priceReqWeek"), fmtFull(m.limits.weekly)], [t("priceReqMonth"), fmtFull(m.limits.monthly)]];
1265
+ for (const [fl, fv] of limitFields) {
1266
+ lines.push((() => {
1267
+ var _el$34 = _$createElement("text");
1268
+ _$insert(_el$34, () => pad13(` \u251C ${fl}:`) + fv);
1269
+ _$effect((_$p) => _$setProp(_el$34, "fg", colors().muted, _$p));
1270
+ return _el$34;
1271
+ })());
1272
+ }
1273
+ const meta = [[t("priceSdk"), m.sdk || "-"], [t("priceRetention"), m.retention || "-"], [t("priceTraining"), m.training || "-"]];
1274
+ meta.forEach(([ml, mv], i) => {
1275
+ const conn = i < meta.length - 1 ? "\u251C" : "\u2514";
1276
+ lines.push((() => {
1277
+ var _el$35 = _$createElement("text");
1278
+ _$insert(_el$35, () => pad13(` ${conn} ${ml}:`) + mv);
1279
+ _$effect((_$p) => _$setProp(_el$35, "fg", colors().muted, _$p));
1280
+ return _el$35;
1281
+ })());
1282
+ });
1283
+ return lines;
1163
1284
  }
1164
1285
  const [pal, setPal] = createSignal({
1165
1286
  ...FALLBACK
@@ -1190,60 +1311,60 @@ function PricePanel(props) {
1190
1311
  setInterval(() => refreshPricing(), loadConfig().pricingIntervalMs);
1191
1312
  }, 2e3);
1192
1313
  return (() => {
1193
- var _el$32 = _$createElement("box"), _el$33 = _$createElement("text"), _el$34 = _$createElement("span"), _el$35 = _$createElement("span"), _el$36 = _$createElement("b"), _el$40 = _$createElement("span");
1194
- _$insertNode(_el$32, _el$33);
1314
+ var _el$36 = _$createElement("box"), _el$37 = _$createElement("text"), _el$38 = _$createElement("span"), _el$39 = _$createElement("span"), _el$40 = _$createElement("b"), _el$44 = _$createElement("span");
1315
+ _$insertNode(_el$36, _el$37);
1195
1316
  var _ref$2 = boxEl;
1196
- typeof _ref$2 === "function" ? _$use(_ref$2, _el$32) : boxEl = _el$32;
1197
- _$setProp(_el$32, "border", true);
1198
- _$setProp(_el$32, "paddingLeft", 1);
1199
- _$setProp(_el$32, "paddingRight", 1);
1200
- _$setProp(_el$32, "flexDirection", "column");
1201
- _$setProp(_el$32, "gap", 0);
1202
- _$setProp(_el$32, "onSizeChange", () => {
1317
+ typeof _ref$2 === "function" ? _$use(_ref$2, _el$36) : boxEl = _el$36;
1318
+ _$setProp(_el$36, "border", true);
1319
+ _$setProp(_el$36, "paddingLeft", 1);
1320
+ _$setProp(_el$36, "paddingRight", 1);
1321
+ _$setProp(_el$36, "flexDirection", "column");
1322
+ _$setProp(_el$36, "gap", 0);
1323
+ _$setProp(_el$36, "onSizeChange", () => {
1203
1324
  if (resizeTimeout) clearTimeout(resizeTimeout);
1204
1325
  resizeTimeout = setTimeout(() => {
1205
1326
  const w = boxEl ? Math.max(20, boxEl.width ?? 24) : 24;
1206
1327
  setPanelWidth(w);
1207
1328
  }, 100);
1208
1329
  });
1209
- _$insertNode(_el$33, _el$34);
1210
- _$insertNode(_el$33, _el$35);
1211
- _$insertNode(_el$33, _el$40);
1212
- _$setProp(_el$33, "onMouseUp", () => setOpen((o) => !o));
1213
- _$insert(_el$34, () => open() ? "\u25BC " : "\u25B6 ");
1214
- _$insertNode(_el$35, _el$36);
1215
- _$insert(_el$36, () => t("priceTitle"));
1216
- _$insert(_el$33, _$createComponent(Show, {
1330
+ _$insertNode(_el$37, _el$38);
1331
+ _$insertNode(_el$37, _el$39);
1332
+ _$insertNode(_el$37, _el$44);
1333
+ _$setProp(_el$37, "onMouseUp", () => setOpen((o) => !o));
1334
+ _$insert(_el$38, () => open() ? "\u25BC " : "\u25B6 ");
1335
+ _$insertNode(_el$39, _el$40);
1336
+ _$insert(_el$40, () => t("priceTitle"));
1337
+ _$insert(_el$37, _$createComponent(Show, {
1217
1338
  get when() {
1218
1339
  return sharedPricing();
1219
1340
  },
1220
1341
  get children() {
1221
- var _el$37 = _$createElement("span"), _el$38 = _$createTextNode(` (`), _el$39 = _$createTextNode(`)`);
1222
- _$insertNode(_el$37, _el$38);
1223
- _$insertNode(_el$37, _el$39);
1224
- _$insert(_el$37, () => sharedPricing().models.length, _el$39);
1225
- _$effect((_$p) => _$setProp(_el$37, "style", {
1342
+ var _el$41 = _$createElement("span"), _el$42 = _$createTextNode(` (`), _el$43 = _$createTextNode(`)`);
1343
+ _$insertNode(_el$41, _el$42);
1344
+ _$insertNode(_el$41, _el$43);
1345
+ _$insert(_el$41, () => sharedPricing().models.length, _el$43);
1346
+ _$effect((_$p) => _$setProp(_el$41, "style", {
1226
1347
  fg: colors().muted
1227
1348
  }, _$p));
1228
- return _el$37;
1349
+ return _el$41;
1229
1350
  }
1230
- }), _el$40);
1231
- _$insert(_el$40, () => sep().slice(visualWidth((open() ? "\u25BC " : "\u25B6 ") + t("priceTitle") + (sharedPricing() ? ` (${sharedPricing().models.length})` : ""))));
1232
- _$insert(_el$32, _$createComponent(Show, {
1351
+ }), _el$44);
1352
+ _$insert(_el$44, () => sep().slice(visualWidth((open() ? "\u25BC " : "\u25B6 ") + t("priceTitle") + (sharedPricing() ? ` (${sharedPricing().models.length})` : ""))));
1353
+ _$insert(_el$36, _$createComponent(Show, {
1233
1354
  get when() {
1234
1355
  return open();
1235
1356
  },
1236
1357
  get children() {
1237
1358
  return [(() => {
1238
- var _el$41 = _$createElement("text");
1239
- _$insert(_el$41, () => justify(t("priceModelCol"), t("priceReqs")));
1240
- _$effect((_$p) => _$setProp(_el$41, "fg", colors().muted, _$p));
1241
- return _el$41;
1359
+ var _el$45 = _$createElement("text");
1360
+ _$insert(_el$45, () => justify(t("priceModelCol"), t("priceReqs")));
1361
+ _$effect((_$p) => _$setProp(_el$45, "fg", colors().muted, _$p));
1362
+ return _el$45;
1242
1363
  })(), (() => {
1243
- var _el$42 = _$createElement("text");
1244
- _$insert(_el$42, sep);
1245
- _$effect((_$p) => _$setProp(_el$42, "fg", colors().muted, _$p));
1246
- return _el$42;
1364
+ var _el$46 = _$createElement("text");
1365
+ _$insert(_el$46, sep);
1366
+ _$effect((_$p) => _$setProp(_el$46, "fg", colors().muted, _$p));
1367
+ return _el$46;
1247
1368
  })(), _$createComponent(Show, {
1248
1369
  get when() {
1249
1370
  return priceLoading() || !sharedPricing();
@@ -1255,45 +1376,75 @@ function PricePanel(props) {
1255
1376
  },
1256
1377
  get fallback() {
1257
1378
  return (() => {
1258
- var _el$46 = _$createElement("text");
1259
- _$insert(_el$46, () => t("priceLoading"));
1260
- _$effect((_$p) => _$setProp(_el$46, "fg", colors().muted, _$p));
1261
- return _el$46;
1379
+ var _el$53 = _$createElement("text");
1380
+ _$insert(_el$53, () => t("priceLoading"));
1381
+ _$effect((_$p) => _$setProp(_el$53, "fg", colors().muted, _$p));
1382
+ return _el$53;
1262
1383
  })();
1263
1384
  },
1264
1385
  get children() {
1265
1386
  return [_$memo(() => sharedPricing().models.filter((m) => {
1266
1387
  return cfg().focusModels.length === 0 || cfg().focusModels.includes(m.id);
1267
1388
  }).map((m) => renderLimitRow(m))), (() => {
1268
- var _el$44 = _$createElement("text");
1269
- _$insert(_el$44, () => justify(t("priceUpdated"), new Date(sharedPricing().fetchTime).toLocaleTimeString()));
1270
- _$effect((_$p) => _$setProp(_el$44, "fg", colors().muted, _$p));
1271
- return _el$44;
1389
+ var _el$48 = _$createElement("text");
1390
+ _$insert(_el$48, () => justify(t("priceUpdated"), new Date(sharedPricing().fetchTime).toLocaleTimeString()));
1391
+ _$effect((_$p) => _$setProp(_el$48, "fg", colors().muted, _$p));
1392
+ return _el$48;
1272
1393
  })(), _$createComponent(Show, {
1273
1394
  get when() {
1274
1395
  return _$memo(() => !!pricingStore())() && pricingStore().history.length > 0;
1275
1396
  },
1276
1397
  get children() {
1277
- var _el$45 = _$createElement("text");
1278
- _$insert(_el$45, () => t("priceChangesSummary", {
1398
+ var _el$49 = _$createElement("text");
1399
+ _$insert(_el$49, () => t("priceChangesSummary", {
1279
1400
  t: pricingStore().history[0].summary.total,
1280
1401
  a: pricingStore().history[0].summary.added,
1281
1402
  r: pricingStore().history[0].summary.removed,
1282
- p: pricingStore().history[0].summary.priceChanges,
1283
1403
  l: pricingStore().history[0].summary.limitChanges
1284
1404
  }));
1285
- _$effect((_$p) => _$setProp(_el$45, "fg", colors().warning, _$p));
1286
- return _el$45;
1405
+ _$effect((_$p) => _$setProp(_el$49, "fg", colors().warning, _$p));
1406
+ return _el$49;
1407
+ }
1408
+ }), _$createComponent(Show, {
1409
+ get when() {
1410
+ return changedModels().size > 0;
1411
+ },
1412
+ get children() {
1413
+ var _el$50 = _$createElement("text");
1414
+ _$insertNode(_el$50, _$createTextNode(`\u7EFF=\u65B0\u589E \u84DD=\u4EF7\u683C \u6A59=\u9650\u989D\xB7\u70B9\u51FB\u5C55\u5F00`));
1415
+ _$effect((_$p) => _$setProp(_el$50, "fg", colors().muted, _$p));
1416
+ return _el$50;
1417
+ }
1418
+ }), _$createComponent(Show, {
1419
+ get when() {
1420
+ return _$memo(() => !!(pricingStore() && pricingStore().history.length > 0))() && pricingStore().history[0].summary.total > 0;
1421
+ },
1422
+ get children() {
1423
+ return [(() => {
1424
+ var _el$52 = _$createElement("text");
1425
+ _$insert(_el$52, () => `${t("changelogTitle")} (${new Date(pricingStore().history[0].fetchTime).toLocaleTimeString()})`);
1426
+ _$effect((_$p) => _$setProp(_el$52, "fg", colors().muted, _$p));
1427
+ return _el$52;
1428
+ })(), _$memo(() => pricingStore().history[0].changes.slice(0, 12).map((c) => {
1429
+ const label = c.type === "added" ? t("typeAdded") : c.type === "removed" ? t("typeRemoved") : c.type === "pricing" ? t("typePricing") : t("typeLimits");
1430
+ const fg = c.type === "added" ? colors().success : c.type === "removed" ? colors().error : c.type === "pricing" ? colors().primary : colors().warning;
1431
+ return (() => {
1432
+ var _el$54 = _$createElement("text");
1433
+ _$setProp(_el$54, "fg", fg);
1434
+ _$insert(_el$54, () => ` ${label} ${abbreviateName(c.modelName, 20)}`);
1435
+ return _el$54;
1436
+ })();
1437
+ }))];
1287
1438
  }
1288
1439
  })];
1289
1440
  }
1290
1441
  });
1291
1442
  },
1292
1443
  get children() {
1293
- var _el$43 = _$createElement("text");
1294
- _$insert(_el$43, () => t("priceLoading"));
1295
- _$effect((_$p) => _$setProp(_el$43, "fg", colors().muted, _$p));
1296
- return _el$43;
1444
+ var _el$47 = _$createElement("text");
1445
+ _$insert(_el$47, () => t("priceLoading"));
1446
+ _$effect((_$p) => _$setProp(_el$47, "fg", colors().muted, _$p));
1447
+ return _el$47;
1297
1448
  }
1298
1449
  })];
1299
1450
  }
@@ -1306,10 +1457,10 @@ function PricePanel(props) {
1306
1457
  }, _v$12 = {
1307
1458
  fg: colors().muted
1308
1459
  };
1309
- _v$1 !== _p$.e && (_p$.e = _$setProp(_el$32, "borderColor", _v$1, _p$.e));
1310
- _v$10 !== _p$.t && (_p$.t = _$setProp(_el$34, "style", _v$10, _p$.t));
1311
- _v$11 !== _p$.a && (_p$.a = _$setProp(_el$35, "style", _v$11, _p$.a));
1312
- _v$12 !== _p$.o && (_p$.o = _$setProp(_el$40, "style", _v$12, _p$.o));
1460
+ _v$1 !== _p$.e && (_p$.e = _$setProp(_el$36, "borderColor", _v$1, _p$.e));
1461
+ _v$10 !== _p$.t && (_p$.t = _$setProp(_el$38, "style", _v$10, _p$.t));
1462
+ _v$11 !== _p$.a && (_p$.a = _$setProp(_el$39, "style", _v$11, _p$.a));
1463
+ _v$12 !== _p$.o && (_p$.o = _$setProp(_el$44, "style", _v$12, _p$.o));
1313
1464
  return _p$;
1314
1465
  }, {
1315
1466
  e: void 0,
@@ -1317,7 +1468,7 @@ function PricePanel(props) {
1317
1468
  a: void 0,
1318
1469
  o: void 0
1319
1470
  });
1320
- return _el$32;
1471
+ return _el$36;
1321
1472
  })();
1322
1473
  }
1323
1474
  function createSidebarSlot(api) {
@@ -1356,9 +1507,9 @@ function runConfigDialog(api, dialog) {
1356
1507
  return t("wsPromptTitle");
1357
1508
  },
1358
1509
  description: () => (() => {
1359
- var _el$47 = _$createElement("text");
1360
- _$insert(_el$47, () => t("wsPromptDesc"));
1361
- return _el$47;
1510
+ var _el$55 = _$createElement("text");
1511
+ _$insert(_el$55, () => t("wsPromptDesc"));
1512
+ return _el$55;
1362
1513
  })(),
1363
1514
  get placeholder() {
1364
1515
  return t("wsPlaceholder");
@@ -1377,9 +1528,9 @@ function runConfigDialog(api, dialog) {
1377
1528
  return t("cookiePromptTitle");
1378
1529
  },
1379
1530
  description: () => (() => {
1380
- var _el$48 = _$createElement("text");
1381
- _$insert(_el$48, () => t("cookiePromptDesc"));
1382
- return _el$48;
1531
+ var _el$56 = _$createElement("text");
1532
+ _$insert(_el$56, () => t("cookiePromptDesc"));
1533
+ return _el$56;
1383
1534
  })(),
1384
1535
  get placeholder() {
1385
1536
  return t("cookiePlaceholder");
@@ -1527,9 +1678,9 @@ function runSettingsDialog(api, dialog) {
1527
1678
  return t("settingsRefreshUsage");
1528
1679
  },
1529
1680
  description: () => (() => {
1530
- var _el$49 = _$createElement("text");
1531
- _$insertNode(_el$49, _$createTextNode(`\u8F93\u5165\u79D2\u6570\uFF08\u9ED8\u8BA4 60\uFF09`));
1532
- return _el$49;
1681
+ var _el$57 = _$createElement("text");
1682
+ _$insertNode(_el$57, _$createTextNode(`\u8F93\u5165\u79D2\u6570\uFF08\u9ED8\u8BA4 60\uFF09`));
1683
+ return _el$57;
1533
1684
  })(),
1534
1685
  placeholder: "60",
1535
1686
  onConfirm: (val) => {
@@ -1556,9 +1707,9 @@ function runSettingsDialog(api, dialog) {
1556
1707
  return t("settingsRefreshPricing");
1557
1708
  },
1558
1709
  description: () => (() => {
1559
- var _el$51 = _$createElement("text");
1560
- _$insertNode(_el$51, _$createTextNode(`\u8F93\u5165\u79D2\u6570\uFF08\u9ED8\u8BA4 1800\uFF09`));
1561
- return _el$51;
1710
+ var _el$59 = _$createElement("text");
1711
+ _$insertNode(_el$59, _$createTextNode(`\u8F93\u5165\u79D2\u6570\uFF08\u9ED8\u8BA4 1800\uFF09`));
1712
+ return _el$59;
1562
1713
  })(),
1563
1714
  placeholder: "1800",
1564
1715
  onConfirm: (val) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-go-usage-tui",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "OpenCode TUI plugin displaying OpenCode Go usage in the sidebar",
5
5
  "type": "module",
6
6
  "exports": {