opencode-go-usage-tui 1.3.0 → 1.3.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/README.md CHANGED
@@ -120,14 +120,15 @@ Cookie 有效期约 1 年,过期后重新获取。
120
120
  - **`/go-lang`**:切换 中文 / English
121
121
  - 用量超过阈值(默认 80%,可用 `OPENCODE_GO_WARN_THRESHOLD` 调整)显示为红色
122
122
  - 点击面板标题可折叠/展开
123
- - 面板标题显示当前插件版本号(如 `v1.3.0`)
123
+ - 面板标题显示当前插件版本号(如 `v1.3.1`)
124
124
 
125
125
  ## 模型请求限额面板
126
126
 
127
- - 独立面板显示各模型的 5小时/每周/每月 请求数上限,表格风格两端对齐
127
+ - 独立面板显示各模型的 5小时/每周/每月 请求数上限,表格风格两端对齐(值与面板右缘对齐)
128
128
  - 从 opencode.ai/docs/go 实时抓取公开数据(无需登录)
129
129
  - 默认每 30 分钟自动刷新(可用 `/go-settings` 或 `pricing_interval_sec` 调整)
130
130
  - 每次刷新自动对比上次数据,变化时 toast 提醒,历史保留最近 10 次到 `go-pricing-data.json`
131
+ - 额度达到 100%(`rate-limited` 状态)时仍正常显示用量与重置时间,不会出现"查询失败"
131
132
 
132
133
  ## 语言
133
134
 
package/README_EN.md CHANGED
@@ -120,14 +120,15 @@ The cookie is valid for about 1 year; get a new one after it expires.
120
120
  - **`/go-lang`**: switch between 中文 / English
121
121
  - Usage above the threshold (default 80%, adjustable via `OPENCODE_GO_WARN_THRESHOLD`) is shown in red
122
122
  - Click the panel title to collapse/expand
123
- - The panel title shows the current plugin version (e.g. `v1.3.0`)
123
+ - The panel title shows the current plugin version (e.g. `v1.3.1`)
124
124
 
125
125
  ## Model request limits panel
126
126
 
127
- - Independent panel showing each model's 5h / weekly / monthly request caps, table style with two-end alignment
127
+ - Independent panel showing each model's 5h / weekly / monthly request caps, table style with values right-aligned to the panel edge
128
128
  - Scraped live from opencode.ai/docs/go (public data, no login)
129
129
  - Auto-refreshes every 30 minutes by default (adjustable via `/go-settings` or `pricing_interval_sec`)
130
130
  - Each refresh diffs against the last snapshot; toast on change; last 10 changes kept in `go-pricing-data.json`
131
+ - When quota hits 100% (`rate-limited` status), usage and reset time still display normally - no "query failed" error
131
132
 
132
133
  ## Language
133
134
 
package/dist/tui.js CHANGED
@@ -460,7 +460,7 @@ function updatePricingStore(newData) {
460
460
  }
461
461
 
462
462
  // src/index.tsx
463
- var VERSION = "1.3.0";
463
+ var VERSION = "1.3.1";
464
464
  var CHECK_INTERVAL = Number(process?.env?.OPENCODE_GO_CHECK_INTERVAL ?? 6e4);
465
465
  var WARN_THRESHOLD = Number(process?.env?.OPENCODE_GO_WARN_THRESHOLD ?? 0.8);
466
466
  var CONFIG_DIR = process?.env?.OPENCODE_CONFIG_DIR || (process?.env?.USERPROFILE ? `${process.env.USERPROFILE}\\.config\\opencode` : "") || process?.env?.HOME + "/.config/opencode";
@@ -692,7 +692,7 @@ async function fetchUsage(workspaceId, authCookie, signal) {
692
692
  };
693
693
  }
694
694
  const extract = (key) => {
695
- const m = text.match(new RegExp(`${key}:[^}]*?\\{status:"ok",resetInSec:(\\d+),usagePercent:(\\d+)\\}`));
695
+ const m = text.match(new RegExp(`${key}:[^}]*?\\{status:"[^"]*",resetInSec:(\\d+),usagePercent:(\\d+)\\}`));
696
696
  if (!m) return null;
697
697
  return {
698
698
  resetInSec: Number(m[1]),
@@ -1080,6 +1080,11 @@ function PricePanel(props) {
1080
1080
  });
1081
1081
  let boxEl;
1082
1082
  let priceController = null;
1083
+ createEffect(() => {
1084
+ if (boxEl && typeof boxEl.width === "number" && boxEl.width > 0) {
1085
+ setPanelWidth(Math.max(20, boxEl.width));
1086
+ }
1087
+ });
1083
1088
  async function refreshPricing() {
1084
1089
  if (priceLoading()) return;
1085
1090
  setPriceLoading(true);
@@ -1137,7 +1142,8 @@ function PricePanel(props) {
1137
1142
  return out + "\u2026";
1138
1143
  }
1139
1144
  function justify(label, value) {
1140
- const gauge = panelWidth() - 4;
1145
+ const outer = boxEl && typeof boxEl.width === "number" && boxEl.width > 0 ? boxEl.width : panelWidth();
1146
+ const gauge = Math.max(10, outer - 4);
1141
1147
  const used = visualWidth(label) + visualWidth(value);
1142
1148
  const gap = Math.max(1, gauge - used);
1143
1149
  return label + " ".repeat(gap) + value;
@@ -1170,7 +1176,10 @@ function PricePanel(props) {
1170
1176
  setPal(p);
1171
1177
  });
1172
1178
  const colors = () => pal();
1173
- const sep = () => "\u2500".repeat(Math.max(1, panelWidth() - 4));
1179
+ const sep = () => {
1180
+ const outer = boxEl && typeof boxEl.width === "number" && boxEl.width > 0 ? boxEl.width : panelWidth();
1181
+ return "\u2500".repeat(Math.max(1, outer - 4));
1182
+ };
1174
1183
  setTimeout(() => {
1175
1184
  const store = loadPricingStore();
1176
1185
  if (store.current.models.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-go-usage-tui",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "OpenCode TUI plugin displaying OpenCode Go usage in the sidebar",
5
5
  "type": "module",
6
6
  "exports": {
package/src/index.tsx CHANGED
@@ -213,7 +213,7 @@ async function fetchUsage(workspaceId: string, authCookie: string, signal?: Abor
213
213
  return { error: "cookie_expired" } as Usage
214
214
  }
215
215
  const extract = (key: string): { resetInSec: number; usagePercent: number } | null => {
216
- const m = text.match(new RegExp(`${key}:[^}]*?\\{status:"ok",resetInSec:(\\d+),usagePercent:(\\d+)\\}`))
216
+ const m = text.match(new RegExp(`${key}:[^}]*?\\{status:"[^"]*",resetInSec:(\\d+),usagePercent:(\\d+)\\}`))
217
217
  if (!m) return null
218
218
  return { resetInSec: Number(m[1]), usagePercent: Number(m[2]) }
219
219
  }
@@ -450,6 +450,13 @@ function PricePanel(props: { theme: TuiThemeCurrent; api: TuiPluginApi }): JSX.E
450
450
  let boxEl: any
451
451
  let priceController: AbortController | null = null
452
452
 
453
+ // 强制同步 panelWidth 与 box 真实宽度(visual-cache 模式,避免首次不触发 onSizeChange)
454
+ createEffect(() => {
455
+ if (boxEl && typeof boxEl.width === "number" && boxEl.width > 0) {
456
+ setPanelWidth(Math.max(20, boxEl.width))
457
+ }
458
+ })
459
+
453
460
  async function refreshPricing() {
454
461
  if (priceLoading()) return
455
462
  setPriceLoading(true)
@@ -511,8 +518,10 @@ function PricePanel(props: { theme: TuiThemeCurrent; api: TuiPluginApi }): JSX.E
511
518
  }
512
519
 
513
520
  // visual-cache 风格:左标签 + 自动填充 + 右值
521
+ // 直接读取 boxEl 实时宽度(避免 panelWidth 信号滞后)
514
522
  function justify(label: string, value: string): string {
515
- const gauge = panelWidth() - 4
523
+ const outer = boxEl && typeof boxEl.width === "number" && boxEl.width > 0 ? boxEl.width : panelWidth()
524
+ const gauge = Math.max(10, outer - 4)
516
525
  const used = visualWidth(label) + visualWidth(value)
517
526
  const gap = Math.max(1, gauge - used)
518
527
  return label + " ".repeat(gap) + value
@@ -540,7 +549,10 @@ function PricePanel(props: { theme: TuiThemeCurrent; api: TuiPluginApi }): JSX.E
540
549
  })
541
550
  const colors = () => pal()
542
551
 
543
- const sep = () => "\u2500".repeat(Math.max(1, panelWidth() - 4))
552
+ const sep = () => {
553
+ const outer = boxEl && typeof boxEl.width === "number" && boxEl.width > 0 ? boxEl.width : panelWidth()
554
+ return "\u2500".repeat(Math.max(1, outer - 4))
555
+ }
544
556
 
545
557
  setTimeout(() => {
546
558
  const store = loadPricingStore()