@leo000001/opencode-quota-sidebar 1.0.3 → 1.2.0

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
@@ -17,6 +17,8 @@ Add the package name to `plugin` in your `opencode.json`. OpenCode uses Bun to i
17
17
  }
18
18
  ```
19
19
 
20
+ Note for OpenCode `>=1.2.15`: TUI settings (`theme`/`keybinds`/`tui`) moved to `tui.json`, but plugin loading still stays in `opencode.json` (`plugin: []`).
21
+
20
22
  ## Development (build from source)
21
23
 
22
24
  ```bash
@@ -105,6 +107,7 @@ memory on startup. Chunk files remain on disk for historical range scans.
105
107
 
106
108
  - Node.js: >= 18 (for `fetch` + `AbortController`)
107
109
  - OpenCode: plugin SDK `@opencode-ai/plugin` ^1.2.10
110
+ - OpenCode config split: if you are on `>=1.2.15`, keep this plugin in `opencode.json` and keep TUI-only keys in `tui.json`.
108
111
 
109
112
  ## Optional commands
110
113
 
package/dist/cost.js CHANGED
@@ -65,9 +65,12 @@ export function guessModelCostDivisor(rates) {
65
65
  : MODEL_COST_DIVISOR_PER_TOKEN;
66
66
  }
67
67
  export function calcEquivalentApiCostForMessage(message, rates) {
68
+ // For providers that expose reasoning tokens separately, they are still
69
+ // billed as output/completion tokens (same unit price). Our UI also merges
70
+ // reasoning into the single Output statistic, so API cost should match that.
71
+ const billedOutput = message.tokens.output + message.tokens.reasoning;
68
72
  const rawCost = message.tokens.input * rates.input +
69
- // API cost intentionally excludes reasoning tokens.
70
- message.tokens.output * rates.output +
73
+ billedOutput * rates.output +
71
74
  message.tokens.cache.read * rates.cacheRead +
72
75
  message.tokens.cache.write * rates.cacheWrite;
73
76
  const divisor = guessModelCostDivisor(rates);
@@ -159,18 +159,19 @@ async function fetchRightCodeQuota(ctx) {
159
159
  const dailyTotal = matched.reduce((sum, subscription) => sum + subscription.dailyTotal, 0);
160
160
  const dailyRemaining = matched.reduce((sum, subscription) => sum + subscription.dailyRemaining, 0);
161
161
  const dailyPercent = dailyTotal > 0 ? (dailyRemaining / dailyTotal) * 100 : undefined;
162
- const expiry = matched.reduce((acc, subscription) => {
163
- if (!subscription.expiresAt)
164
- return acc;
165
- const current = Date.parse(subscription.expiresAt);
166
- if (Number.isNaN(current))
167
- return acc;
162
+ const parsedExpiries = matched
163
+ .map((subscription) => subscription.expiresAt)
164
+ .filter((iso) => typeof iso === 'string' && !!iso)
165
+ .map((iso) => ({ iso, ts: Date.parse(iso) }))
166
+ .filter((item) => !Number.isNaN(item.ts));
167
+ const uniqueExpiryTimestamps = new Set(parsedExpiries.map((e) => e.ts));
168
+ const hasMultipleExpiries = uniqueExpiryTimestamps.size > 1;
169
+ const expiry = parsedExpiries.reduce((acc, item) => {
168
170
  if (!acc)
169
- return subscription.expiresAt;
171
+ return item.iso;
170
172
  const existing = Date.parse(acc);
171
- if (Number.isNaN(existing) || current < existing) {
172
- return subscription.expiresAt;
173
- }
173
+ if (Number.isNaN(existing) || item.ts < existing)
174
+ return item.iso;
174
175
  return acc;
175
176
  }, undefined);
176
177
  const windows = [
@@ -179,7 +180,7 @@ async function fetchRightCodeQuota(ctx) {
179
180
  showPercent: false,
180
181
  remainingPercent: dailyPercent,
181
182
  resetAt: expiry,
182
- resetLabel: 'Exp',
183
+ resetLabel: hasMultipleExpiries ? 'Exp+' : 'Exp',
183
184
  },
184
185
  ];
185
186
  const names = matched.map((subscription) => subscription.name).join(', ');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leo000001/opencode-quota-sidebar",
3
- "version": "1.0.3",
3
+ "version": "1.2.0",
4
4
  "description": "OpenCode plugin that shows quota and token usage in session titles",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",