opencode-usage-total 0.1.8 → 0.1.9

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.
Files changed (2) hide show
  1. package/dist/index.js +47 -32
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  import { createRoot, createSignal } from "solid-js";
7
7
 
8
8
  // package.json
9
- var version = "0.1.8";
9
+ var version = "0.1.9";
10
10
 
11
11
  // helpers.ts
12
12
  function safeNum(value) {
@@ -32,7 +32,9 @@ function fmtCost(n) {
32
32
  return `$${n.toFixed(2)}`;
33
33
  }
34
34
  function modelTokens(m) {
35
- return m.tokensInput + m.tokensOutput + m.tokensReasoning + m.tokensCacheRead + m.tokensCacheWrite;
35
+ return safeNum(
36
+ m.tokensInput + m.tokensOutput + m.tokensReasoning + m.tokensCacheRead + m.tokensCacheWrite
37
+ );
36
38
  }
37
39
 
38
40
  // usage-total-tui.tsx
@@ -81,11 +83,15 @@ var tui = async (api) => {
81
83
  } catch {
82
84
  }
83
85
  initialized = false;
86
+ lastToastTime = 0;
84
87
  };
85
88
  try {
86
89
  if (api.lifecycle?.onDispose) {
87
90
  api.lifecycle.onDispose(cleanup);
88
91
  }
92
+ if (!api.lifecycle?.onDispose && api.lifecycle?.signal) {
93
+ api.lifecycle.signal.addEventListener("abort", cleanup, { once: true });
94
+ }
89
95
  createRoot((dispose) => {
90
96
  solidDispose = dispose;
91
97
  const [modelState, setModelState] = createSignal({});
@@ -140,7 +146,9 @@ var tui = async (api) => {
140
146
  loadedSessions.add(sessionID);
141
147
  const saved = api.kv?.get?.(kvKey(sessionID));
142
148
  if (saved && saved.length > 0) {
143
- const valid = Array.isArray(saved) && typeof saved[0].provider === "string" && typeof saved[0].model === "string" && typeof saved[0].agent === "string";
149
+ const valid = Array.isArray(saved) && saved.every(
150
+ (m) => typeof m?.provider === "string" && typeof m?.model === "string" && typeof m?.agent === "string" && Number.isFinite(m?.cost) && Number.isFinite(m?.tokensInput) && Number.isFinite(m?.tokensOutput) && Number.isFinite(m?.tokensReasoning) && Number.isFinite(m?.tokensCacheRead) && Number.isFinite(m?.tokensCacheWrite)
151
+ );
144
152
  if (!valid) {
145
153
  api.ui?.toast?.({
146
154
  message: "usage-total: discarded corrupt saved model data",
@@ -219,36 +227,43 @@ var tui = async (api) => {
219
227
  }
220
228
  }
221
229
  unsub = api.event?.on?.("message.updated", (event) => {
222
- const info = event?.properties?.info;
223
- if (!info) return;
224
- const eventSessionID = info.sessionID;
225
- if (!eventSessionID) return;
226
- let provider;
227
- let model;
228
- let agent;
229
- let cost = 0;
230
- let tokens = {};
231
- if (info.role === "user") {
232
- const mdl = info.model;
233
- provider = mdl?.providerID ?? UNKNOWN_ID;
234
- model = mdl?.modelID ?? UNKNOWN_ID;
235
- agent = info.agent ?? DEFAULT_AGENT;
236
- } else if (info.role === "assistant") {
237
- provider = info.providerID ?? UNKNOWN_ID;
238
- model = info.modelID ?? UNKNOWN_ID;
239
- agent = info.agent ?? info.mode ?? DEFAULT_AGENT;
240
- cost = safeNum(info.cost);
241
- tokens = {
242
- input: safeNum(info.tokens?.input),
243
- output: safeNum(info.tokens?.output),
244
- reasoning: safeNum(info.tokens?.reasoning),
245
- cacheRead: safeNum(info.tokens?.cache?.read),
246
- cacheWrite: safeNum(info.tokens?.cache?.write)
247
- };
248
- } else {
249
- return;
230
+ try {
231
+ const info = event?.properties?.info;
232
+ if (!info) return;
233
+ const eventSessionID = info.sessionID;
234
+ if (!eventSessionID) return;
235
+ let provider;
236
+ let model;
237
+ let agent;
238
+ let cost = 0;
239
+ let tokens = {};
240
+ if (info.role === "user") {
241
+ const mdl = info.model;
242
+ provider = mdl?.providerID ?? UNKNOWN_ID;
243
+ model = mdl?.modelID ?? UNKNOWN_ID;
244
+ agent = info.agent ?? DEFAULT_AGENT;
245
+ } else if (info.role === "assistant") {
246
+ provider = info.providerID ?? UNKNOWN_ID;
247
+ model = info.modelID ?? UNKNOWN_ID;
248
+ agent = info.agent ?? info.mode ?? DEFAULT_AGENT;
249
+ cost = safeNum(info.cost);
250
+ tokens = {
251
+ input: safeNum(info.tokens?.input),
252
+ output: safeNum(info.tokens?.output),
253
+ reasoning: safeNum(info.tokens?.reasoning),
254
+ cacheRead: safeNum(info.tokens?.cache?.read),
255
+ cacheWrite: safeNum(info.tokens?.cache?.write)
256
+ };
257
+ } else {
258
+ return;
259
+ }
260
+ trackModel(eventSessionID, { provider, model, agent }, cost, tokens);
261
+ } catch {
262
+ api.ui?.toast?.({
263
+ message: "usage-total: error processing message",
264
+ variant: "error"
265
+ });
250
266
  }
251
- trackModel(eventSessionID, { provider, model, agent }, cost, tokens);
252
267
  });
253
268
  api.slots?.register?.({
254
269
  order: 200,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-usage-total",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Track model usage, tokens, and costs per agent in the OpenCode TUI sidebar",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",