@jeffreyjyz/opencode-command-code 0.3.12 → 0.3.13

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/index.js CHANGED
@@ -4063,7 +4063,7 @@ var commandCodeV2 = {
4063
4063
  // package.json
4064
4064
  var package_default = {
4065
4065
  name: "@jeffreyjyz/opencode-command-code",
4066
- version: "0.3.12",
4066
+ version: "0.3.13",
4067
4067
  description: "Command Code provider + usage dashboard for opencode: two providers (Anthropic wire for Claude, OpenAI wire for everything else) against api.commandcode.ai, live model list, plan gating, /cmd-usage. Requires the cmduse CLI for usage rendering.",
4068
4068
  type: "module",
4069
4069
  main: "dist/index.js",
@@ -16,8 +16,14 @@ export declare function periodStart(usage: {
16
16
  * missing or unreadable, so callers can fall back to omitting the row.
17
17
  * Matching is on the canonical key: the session id and the stored modelID can
18
18
  * differ by vendor prefix/punctuation.
19
+ *
20
+ * Given a `sessionID`, the scan is scoped to that conversation and `sinceMs` is
21
+ * ignored — the panel shows "this model in this session" beside the session's
22
+ * own total, and two figures measuring different windows than each other read
23
+ * as a bug (the billing period had just rolled over, so the model row said 129
24
+ * while the session said 2.7K).
19
25
  */
20
- export declare function loadModelUsage(modelID: string, sinceMs: number, path?: string): ModelUsage | null;
26
+ export declare function loadModelUsage(modelID: string, sinceMs: number, path?: string, sessionID?: string): ModelUsage | null;
21
27
  /**
22
28
  * Requests and cost for one session, so the panel can show what this
23
29
  * conversation has spent rather than only the period-to-date figure. Null when
package/dist/tui.js CHANGED
@@ -2087,20 +2087,14 @@ function usageDbPath() {
2087
2087
  const base = process.env.XDG_DATA_HOME ?? join3(homedir3(), ".local", "share");
2088
2088
  return join3(base, "opencode", "opencode.db");
2089
2089
  }
2090
- function periodStart(usage, now = Date.now()) {
2091
- if (typeof usage.periodStartAt === "number")
2092
- return usage.periodStartAt;
2093
- const end = usage.periodEnd ? Date.parse(`${usage.periodEnd}T23:59:59`) : Number.NaN;
2094
- if (!Number.isFinite(end))
2095
- return now - 30 * 24 * 60 * 60 * 1000;
2096
- const start = new Date(end);
2097
- start.setMonth(start.getMonth() - 1);
2098
- return start.getTime();
2099
- }
2100
2090
  function usage(value) {
2101
2091
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
2102
2092
  }
2103
- function loadModelUsage(modelID, sinceMs, path = usageDbPath()) {
2093
+ function hasV2(db) {
2094
+ const row = db.query("SELECT 1 AS found FROM sqlite_master WHERE type = 'table' AND name = 'session_message'").get();
2095
+ return Boolean(row);
2096
+ }
2097
+ function loadModelUsage(modelID, sinceMs, path = usageDbPath(), sessionID) {
2104
2098
  let db;
2105
2099
  try {
2106
2100
  db = new Database(path, {
@@ -2110,8 +2104,26 @@ function loadModelUsage(modelID, sinceMs, path = usageDbPath()) {
2110
2104
  return null;
2111
2105
  }
2112
2106
  try {
2107
+ if (hasV2(db)) {
2108
+ const rows = db.query(`SELECT json_extract(data, '$.model.id') AS model, count(*) AS c
2109
+ FROM session_message
2110
+ WHERE type = 'assistant'
2111
+ ${sessionID ? "AND session_id = ?" : "AND time_created >= ?"}
2112
+ GROUP BY model`).all(sessionID ?? sinceMs);
2113
+ const key = modelKey(modelID);
2114
+ let requests = 0;
2115
+ for (const row of rows) {
2116
+ if (row.model && modelKey(row.model) === key)
2117
+ requests += row.c;
2118
+ }
2119
+ return {
2120
+ requests,
2121
+ cost: 0
2122
+ };
2123
+ }
2113
2124
  const rows = db.query(`SELECT data, time_created FROM message
2114
- WHERE data LIKE '%"tokens"%' AND time_created >= ?`).all(sinceMs);
2125
+ WHERE data LIKE '%"tokens"%'
2126
+ ${sessionID ? "AND session_id = ?" : "AND time_created >= ?"}`).all(sessionID ?? sinceMs);
2115
2127
  const key = modelKey(modelID);
2116
2128
  const seen = new Set;
2117
2129
  let requests = 0;
@@ -2154,6 +2166,14 @@ function loadSessionUsage(sessionID, path = usageDbPath()) {
2154
2166
  return null;
2155
2167
  }
2156
2168
  try {
2169
+ if (hasV2(db)) {
2170
+ const totals = db.query("SELECT cost FROM session_v2 WHERE id = ?").get(sessionID);
2171
+ const counted = db.query("SELECT count(*) AS c FROM session_message WHERE session_id = ? AND type = 'assistant'").get(sessionID);
2172
+ return {
2173
+ requests: counted.c,
2174
+ cost: typeof totals?.cost === "number" ? totals.cost : 0
2175
+ };
2176
+ }
2157
2177
  const rows = db.query(`SELECT id, data FROM message
2158
2178
  WHERE session_id = ? AND data LIKE '%"tokens"%'`).all(sessionID);
2159
2179
  const seen = new Set;
@@ -2186,7 +2206,7 @@ function loadSessionUsage(sessionID, path = usageDbPath()) {
2186
2206
  }
2187
2207
 
2188
2208
  // src/sidebar/useRows.ts
2189
- var POLL_MS = 60000;
2209
+ var POLL_MS = 20000;
2190
2210
  function sessionKind(providerID) {
2191
2211
  if (!providerID)
2192
2212
  return "unknown";
@@ -2237,10 +2257,10 @@ function useRows(activeModelId, providerID, sessionID) {
2237
2257
  const [sessionUsage, setSessionUsage] = createSignal();
2238
2258
  const [wasOurs, setWasOurs] = createSignal(false);
2239
2259
  loadMeta().then(setMeta).catch(() => {});
2240
- const refreshModelUsage = (id, sinceMs) => {
2260
+ const refreshModelUsage = (id) => {
2241
2261
  if (!id)
2242
2262
  return;
2243
- const fresh = loadModelUsage(id, sinceMs);
2263
+ const fresh = loadModelUsage(id, 0, usageDbPath(), sessionID());
2244
2264
  if (fresh)
2245
2265
  rememberModelUsage(id, fresh);
2246
2266
  setModelUsage(lastModelUsage);
@@ -2255,7 +2275,7 @@ function useRows(activeModelId, providerID, sessionID) {
2255
2275
  const snapshot = await loadUsage();
2256
2276
  rememberSnapshot(snapshot);
2257
2277
  setUsage(usageRows(snapshot));
2258
- refreshModelUsage(activeModelId(), periodStart(snapshot));
2278
+ refreshModelUsage(activeModelId());
2259
2279
  } else if (kind === "go" || kind === "zen") {
2260
2280
  setZen(await loadZen());
2261
2281
  }
@@ -2272,9 +2292,10 @@ function useRows(activeModelId, providerID, sessionID) {
2272
2292
  });
2273
2293
  createEffect(() => {
2274
2294
  const id = activeModelId();
2275
- if (sessionKind(providerID()) !== "ours" || !id)
2295
+ const session = sessionID();
2296
+ if (sessionKind(providerID()) !== "ours" || !id || !session)
2276
2297
  return;
2277
- refreshModelUsage(id, periodStart(lastSnapshot ?? {}));
2298
+ refreshModelUsage(id);
2278
2299
  });
2279
2300
  const usageFor = (id) => {
2280
2301
  const seen = modelUsage();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeffreyjyz/opencode-command-code",
3
- "version": "0.3.12",
3
+ "version": "0.3.13",
4
4
  "description": "Command Code provider + usage dashboard for opencode: two providers (Anthropic wire for Claude, OpenAI wire for everything else) against api.commandcode.ai, live model list, plan gating, /cmd-usage. Requires the cmduse CLI for usage rendering.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",