@rejacky/opencode-insights 0.1.11 → 0.1.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/README.md CHANGED
@@ -93,12 +93,13 @@ The `uninstall` command removes plugin config entries and local Insights data; i
93
93
 
94
94
  - Configurable live metrics in the OpenCode session prompt zone.
95
95
  - A collapsible session-wide `Token Usage` sidebar showing total tokens, response count, input/output/reasoning usage, cache read/write usage, and aggregate cache rate. It loads completed responses already present in the session and continues updating live.
96
+ - An opt-in `Go Usage` sidebar showing OpenCode Go rolling/weekly/monthly usage limits for sessions that use the `opencode-go` provider.
96
97
  - Subagent status (running, done, failed, elapsed time, and token/context usage) in the sidebar.
97
98
  - Local capture of OpenCode hook/event data without redaction.
98
99
  - A local web viewer for reconstructed sessions, user turns, hidden request context, system/messages transforms, and assistant thinking/response sequences.
99
100
  - Native OpenCode footer components (project directory and version) remain visible — the plugin does not override `sidebar_footer` or `home_prompt_right` slots.
100
101
 
101
- The right sidebar contains two independent plugin sections: `Token Usage` and `Subagents`. Click either section header to collapse or expand it. Token usage is aggregated across the full session; prompt-right `used` and `cache` values continue to represent the latest completed assistant response.
102
+ The right sidebar contains the plugin sections: `Token Usage`, `Go Usage` (when enabled and the session uses `opencode-go`), and `Subagents`. Click any section header to collapse or expand it. Token usage is aggregated across the full session; prompt-right `used` and `cache` values continue to represent the latest completed assistant response.
102
103
 
103
104
  ## TUI Metrics Configuration
104
105
 
@@ -118,6 +119,28 @@ With a custom database path, the configuration file is created in that database'
118
119
 
119
120
  `promptRightMetrics` controls both the fields and their order. Supported values are `tps`, `avg`, `ttft`, `used`, `cache`, `input`, `output`, and `reasoning`. Values that are not recognized are ignored; an empty or invalid configuration uses the default. Restart OpenCode after editing this file.
120
121
 
122
+ ## Go Usage Configuration
123
+
124
+ The `Go Usage` sidebar shows the rolling (5 hour), weekly, and monthly usage limits of your OpenCode Go subscription for sessions that use the `opencode-go` provider. It is disabled by default and opt-in:
125
+
126
+ ```json
127
+ {
128
+ "goUsage": {
129
+ "enabled": true,
130
+ "cookie": "Fe26.2**...",
131
+ "workspaceID": "wrk_...",
132
+ "refreshMs": 300000
133
+ }
134
+ }
135
+ ```
136
+
137
+ - `enabled` — set to `true` to activate the section. Defaults to `false`.
138
+ - `cookie` — the `auth` session cookie for `opencode.ai` (see below).
139
+ - `workspaceID` — your workspace id, visible in the console URL (`/workspace/<workspaceID>/go`).
140
+ - `refreshMs` — how often to re-fetch usage from the console. Defaults to `300000` (5 minutes); values below 60000 are clamped.
141
+
142
+ To get the cookie, log in to `https://opencode.ai`, open the workspace `/go` page, then copy the `auth` cookie value from your browser's DevTools (Application → Cookies → `https://opencode.ai`). The cookie lasts up to a year; if the section shows an error, copy it again. Restart OpenCode after editing this file.
143
+
121
144
  ## Open The Viewer
122
145
 
123
146
  Start the local web viewer and open it in your browser:
@@ -101,8 +101,15 @@ type InsightsOptions = {
101
101
  dbPath?: unknown;
102
102
  retentionDays?: unknown;
103
103
  };
104
+ type GoUsageConfig = {
105
+ enabled: boolean;
106
+ cookie: string;
107
+ workspaceID: string;
108
+ refreshMs: number;
109
+ };
104
110
  type InsightsConfig = {
105
111
  promptRightMetrics: PromptRightMetric[];
112
+ goUsage: GoUsageConfig;
106
113
  };
107
114
  declare function defaultDataDir(): string;
108
115
  declare function resolveCapturePath(options?: InsightsOptions): string;
@@ -145,4 +152,4 @@ declare class SqliteCaptureStore implements CaptureStore {
145
152
  declare function createCaptureStore(options?: InsightsOptions): CaptureStore;
146
153
  declare function resolveRetentionDays(value: unknown): number;
147
154
 
148
- export { type AssistantResponseUsage as A, renderMetricsText as B, type CaptureRecord as C, DEFAULT_PROMPT_RIGHT_METRICS as D, renderPromptRightMetricsText as E, renderResponseMetricsText as F, renderSessionTokenUsage as G, resolveCapturePath as H, type InsightsConfig as I, JsonlCaptureStore as J, resolveInsightsConfigPath as K, resolveRetentionDays as L, type MessageTiming as M, type PromptRightMetric as P, type SessionAverage as S, type CaptureKind as a, type CaptureStore as b, type InsightsOptions as c, type MetricsState as d, type SessionTokenUsage as e, SqliteCaptureStore as f, type SqliteDb as g, type StreamSample as h, createCaptureStore as i, createMetricsState as j, defaultDataDir as k, estimateStreamTokens as l, extractEventType as m, getSessionTokenUsage as n, normalizeChatHeadersCapture as o, normalizeChatMessageCapture as p, normalizeChatParamsCapture as q, normalizeEventCapture as r, normalizeExperimentalChatMessagesTransformCapture as s, normalizeExperimentalChatSystemTransformCapture as t, normalizeToolCapture as u, openDatabase as v, readInsightsConfig as w, recordAssistantDelta as x, recordAssistantMessage as y, recordToolActivity as z };
155
+ export { type AssistantResponseUsage as A, renderMetricsText as B, type CaptureRecord as C, DEFAULT_PROMPT_RIGHT_METRICS as D, renderPromptRightMetricsText as E, renderResponseMetricsText as F, type GoUsageConfig as G, renderSessionTokenUsage as H, type InsightsConfig as I, JsonlCaptureStore as J, resolveCapturePath as K, resolveInsightsConfigPath as L, type MessageTiming as M, resolveRetentionDays as N, type PromptRightMetric as P, type SessionAverage as S, type CaptureKind as a, type CaptureStore as b, type InsightsOptions as c, type MetricsState as d, type SessionTokenUsage as e, SqliteCaptureStore as f, type SqliteDb as g, type StreamSample as h, createCaptureStore as i, createMetricsState as j, defaultDataDir as k, estimateStreamTokens as l, extractEventType as m, getSessionTokenUsage as n, normalizeChatHeadersCapture as o, normalizeChatMessageCapture as p, normalizeChatParamsCapture as q, normalizeEventCapture as r, normalizeExperimentalChatMessagesTransformCapture as s, normalizeExperimentalChatSystemTransformCapture as t, normalizeToolCapture as u, openDatabase as v, readInsightsConfig as w, recordAssistantDelta as x, recordAssistantMessage as y, recordToolActivity as z };
@@ -268,6 +268,8 @@ import { dirname, join } from "path";
268
268
  import { homedir } from "os";
269
269
  var DEFAULT_RETENTION_DAYS = 1;
270
270
  var DAY_MS = 24 * 60 * 60 * 1e3;
271
+ var DEFAULT_GO_USAGE_REFRESH_MS = 3e5;
272
+ var MIN_GO_USAGE_REFRESH_MS = 6e4;
271
273
  var sequence = 0;
272
274
  function nextID(timestamp) {
273
275
  sequence += 1;
@@ -346,12 +348,26 @@ async function readInsightsConfig(options = {}) {
346
348
  }
347
349
  }
348
350
  function defaultInsightsConfig() {
349
- return { promptRightMetrics: [...DEFAULT_PROMPT_RIGHT_METRICS] };
351
+ return { promptRightMetrics: [...DEFAULT_PROMPT_RIGHT_METRICS], goUsage: defaultGoUsageConfig() };
352
+ }
353
+ function defaultGoUsageConfig() {
354
+ return { enabled: false, cookie: "", workspaceID: "", refreshMs: DEFAULT_GO_USAGE_REFRESH_MS };
350
355
  }
351
356
  function insightsConfigFrom(value) {
352
- if (!isRecord(value) || !Array.isArray(value.promptRightMetrics)) return defaultInsightsConfig();
353
- const metrics = value.promptRightMetrics.filter(isPromptRightMetric);
354
- return metrics.length ? { promptRightMetrics: metrics } : defaultInsightsConfig();
357
+ const record = isRecord(value) ? value : {};
358
+ const metrics = Array.isArray(record.promptRightMetrics) ? record.promptRightMetrics.filter(isPromptRightMetric) : [];
359
+ return {
360
+ promptRightMetrics: metrics.length ? metrics : [...DEFAULT_PROMPT_RIGHT_METRICS],
361
+ goUsage: goUsageConfigFrom(record.goUsage)
362
+ };
363
+ }
364
+ function goUsageConfigFrom(value) {
365
+ const record = isRecord(value) ? value : {};
366
+ const enabled = record.enabled === true;
367
+ const cookie = typeof record.cookie === "string" && record.cookie.length > 0 ? record.cookie : "";
368
+ const workspaceID = typeof record.workspaceID === "string" && record.workspaceID.length > 0 ? record.workspaceID : "";
369
+ const refreshMs = typeof record.refreshMs === "number" && Number.isFinite(record.refreshMs) ? Math.max(MIN_GO_USAGE_REFRESH_MS, Math.trunc(record.refreshMs)) : DEFAULT_GO_USAGE_REFRESH_MS;
370
+ return { enabled, cookie, workspaceID, refreshMs };
355
371
  }
356
372
  function isPromptRightMetric(value) {
357
373
  return value === "tps" || value === "avg" || value === "ttft" || value === "used" || value === "cache" || value === "input" || value === "output" || value === "reasoning";
package/dist/cli.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as CaptureRecord } from './capture-BIiGg2nW.js';
2
+ import { C as CaptureRecord } from './capture-BpktoFGh.js';
3
3
 
4
4
  type HistoryMessage = {
5
5
  id: string;
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  openDatabase,
4
4
  resolveCapturePath
5
- } from "./chunk-3YLLHABZ.js";
5
+ } from "./chunk-RWPY5QOE.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import { execFile as execFile2 } from "child_process";
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Plugin } from '@opencode-ai/plugin';
2
2
  import { TuiPlugin } from '@opencode-ai/plugin/tui';
3
- export { A as AssistantResponseUsage, a as CaptureKind, C as CaptureRecord, b as CaptureStore, D as DEFAULT_PROMPT_RIGHT_METRICS, I as InsightsConfig, c as InsightsOptions, J as JsonlCaptureStore, M as MessageTiming, d as MetricsState, P as PromptRightMetric, S as SessionAverage, e as SessionTokenUsage, f as SqliteCaptureStore, g as SqliteDb, h as StreamSample, i as createCaptureStore, j as createMetricsState, k as defaultDataDir, l as estimateStreamTokens, m as extractEventType, n as getSessionTokenUsage, o as normalizeChatHeadersCapture, p as normalizeChatMessageCapture, q as normalizeChatParamsCapture, r as normalizeEventCapture, s as normalizeExperimentalChatMessagesTransformCapture, t as normalizeExperimentalChatSystemTransformCapture, u as normalizeToolCapture, v as openDatabase, w as readInsightsConfig, x as recordAssistantDelta, y as recordAssistantMessage, z as recordToolActivity, B as renderMetricsText, E as renderPromptRightMetricsText, F as renderResponseMetricsText, G as renderSessionTokenUsage, H as resolveCapturePath, K as resolveInsightsConfigPath, L as resolveRetentionDays } from './capture-BIiGg2nW.js';
3
+ export { A as AssistantResponseUsage, a as CaptureKind, C as CaptureRecord, b as CaptureStore, D as DEFAULT_PROMPT_RIGHT_METRICS, G as GoUsageConfig, I as InsightsConfig, c as InsightsOptions, J as JsonlCaptureStore, M as MessageTiming, d as MetricsState, P as PromptRightMetric, S as SessionAverage, e as SessionTokenUsage, f as SqliteCaptureStore, g as SqliteDb, h as StreamSample, i as createCaptureStore, j as createMetricsState, k as defaultDataDir, l as estimateStreamTokens, m as extractEventType, n as getSessionTokenUsage, o as normalizeChatHeadersCapture, p as normalizeChatMessageCapture, q as normalizeChatParamsCapture, r as normalizeEventCapture, s as normalizeExperimentalChatMessagesTransformCapture, t as normalizeExperimentalChatSystemTransformCapture, u as normalizeToolCapture, v as openDatabase, w as readInsightsConfig, x as recordAssistantDelta, y as recordAssistantMessage, z as recordToolActivity, B as renderMetricsText, E as renderPromptRightMetricsText, F as renderResponseMetricsText, H as renderSessionTokenUsage, K as resolveCapturePath, L as resolveInsightsConfigPath, N as resolveRetentionDays } from './capture-BpktoFGh.js';
4
4
 
5
5
  type SubagentStatus = "running" | "done" | "error";
6
6
  type SubagentInfo = {
package/dist/index.js CHANGED
@@ -38,7 +38,7 @@ import {
38
38
  resolveCapturePath,
39
39
  resolveInsightsConfigPath,
40
40
  resolveRetentionDays
41
- } from "./chunk-3YLLHABZ.js";
41
+ } from "./chunk-RWPY5QOE.js";
42
42
 
43
43
  // src/cli-shim.ts
44
44
  import { existsSync } from "fs";
package/dist/tui.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  recordToolActivity,
13
13
  renderPromptRightMetricsText,
14
14
  renderSessionTokenUsage
15
- } from "./chunk-3YLLHABZ.js";
15
+ } from "./chunk-RWPY5QOE.js";
16
16
 
17
17
  // src/tui.tsx
18
18
  import { createTextAttributes, StyledText } from "@opentui/core";
@@ -37,6 +37,120 @@ function hasRenderStateChanged(previous, next) {
37
37
  return !previous || previous.content !== next.content || previous.visible !== next.visible || previous.height !== next.height;
38
38
  }
39
39
 
40
+ // src/go-usage.ts
41
+ var GoUsageError = class extends Error {
42
+ };
43
+ var USAGE_PATTERN = /(rollingUsage|weeklyUsage|monthlyUsage):\$R\[(\d+)\]=\{([^{}]*)\}/g;
44
+ var KEY_PATTERN = /([a-zA-Z]+):/g;
45
+ function parseGoUsageHtml(html) {
46
+ const usage = {};
47
+ USAGE_PATTERN.lastIndex = 0;
48
+ let match;
49
+ while (match = USAGE_PATTERN.exec(html)) {
50
+ const key = match[1];
51
+ const literal = match[3] ?? "";
52
+ try {
53
+ usage[key] = JSON.parse(`{${literal.replace(KEY_PATTERN, '"$1":')}}`);
54
+ } catch {
55
+ return void 0;
56
+ }
57
+ }
58
+ if (!usage.rollingUsage || !usage.weeklyUsage || !usage.monthlyUsage) return void 0;
59
+ return usage;
60
+ }
61
+ async function fetchGoUsage(input, fetchImpl = fetch) {
62
+ const response = await fetchImpl(`https://opencode.ai/workspace/${input.workspaceID}/go`, {
63
+ headers: {
64
+ "user-agent": "Mozilla/5.0",
65
+ cookie: `auth=${input.cookie}`
66
+ },
67
+ redirect: "manual"
68
+ });
69
+ if (response.status >= 300 && response.status < 400) {
70
+ throw new GoUsageError("console redirected to login; the auth cookie may be expired");
71
+ }
72
+ if (!response.ok) {
73
+ throw new GoUsageError(`console request failed with status ${response.status}`);
74
+ }
75
+ const usage = parseGoUsageHtml(await response.text());
76
+ if (!usage) throw new GoUsageError("could not parse go usage from the console page");
77
+ return usage;
78
+ }
79
+ function formatReset(seconds) {
80
+ const total = Math.max(0, Math.floor(seconds));
81
+ const days = Math.floor(total / 86400);
82
+ const hours = Math.floor(total % 86400 / 3600);
83
+ const minutes = Math.floor(total % 3600 / 60);
84
+ if (days > 0) return hours > 0 ? `${days}d ${hours}h` : `${days}d`;
85
+ if (hours > 0) return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
86
+ return `${minutes}m`;
87
+ }
88
+ function formatGoUsageRow(row) {
89
+ const fill = Math.min(4, Math.ceil(row.usagePercent / 25));
90
+ const bar = "\u2588".repeat(fill) + "\u2591".repeat(4 - fill);
91
+ return `${row.label.padEnd(9)}${`${row.usagePercent}%`.padEnd(3)} ${bar} ${row.reset}`;
92
+ }
93
+ function goUsageSectionVisible(config, usesGoProvider) {
94
+ return usesGoProvider && config.goUsage.enabled && config.goUsage.cookie.length > 0 && config.goUsage.workspaceID.length > 0;
95
+ }
96
+ function createGoProviderTracker() {
97
+ const providers = /* @__PURE__ */ new Map();
98
+ return {
99
+ record(sessionID, providerID) {
100
+ if (providerID) providers.set(sessionID, providerID);
101
+ },
102
+ usesOpenCodeGo(sessionID) {
103
+ return providers.get(sessionID) === "opencode-go";
104
+ }
105
+ };
106
+ }
107
+ function goUsageRows(state, now) {
108
+ if (!state.data) return void 0;
109
+ const elapsedSeconds = state.lastFetchAt === void 0 ? 0 : Math.max(0, (now - state.lastFetchAt) / 1e3);
110
+ return [
111
+ {
112
+ label: "Rolling",
113
+ usagePercent: state.data.rollingUsage.usagePercent,
114
+ reset: formatReset(state.data.rollingUsage.resetInSec - elapsedSeconds)
115
+ },
116
+ {
117
+ label: "Weekly",
118
+ usagePercent: state.data.weeklyUsage.usagePercent,
119
+ reset: formatReset(state.data.weeklyUsage.resetInSec - elapsedSeconds)
120
+ },
121
+ {
122
+ label: "Monthly",
123
+ usagePercent: state.data.monthlyUsage.usagePercent,
124
+ reset: formatReset(state.data.monthlyUsage.resetInSec - elapsedSeconds)
125
+ }
126
+ ];
127
+ }
128
+ function createGoUsageRefresher(config, fetchImpl = fetch) {
129
+ const state = {};
130
+ let inflight;
131
+ async function refresh(now = Date.now()) {
132
+ if (inflight) {
133
+ await inflight;
134
+ return false;
135
+ }
136
+ if (state.lastFetchAt !== void 0 && now - state.lastFetchAt < config.refreshMs) return false;
137
+ inflight = (async () => {
138
+ try {
139
+ state.data = await fetchGoUsage({ cookie: config.cookie, workspaceID: config.workspaceID }, fetchImpl);
140
+ state.error = void 0;
141
+ } catch (error) {
142
+ state.error = error instanceof Error ? error.message : String(error);
143
+ } finally {
144
+ state.lastFetchAt = now;
145
+ inflight = void 0;
146
+ }
147
+ })();
148
+ await inflight;
149
+ return true;
150
+ }
151
+ return { state, refresh };
152
+ }
153
+
40
154
  // src/tui.tsx
41
155
  import { Fragment, jsx, jsxs } from "@opentui/solid/jsx-runtime";
42
156
  function isSessionID(value) {
@@ -119,6 +233,74 @@ function TokenUsageSidebar(props) {
119
233
  }
120
234
  );
121
235
  }
236
+ function GoUsageSidebar(props) {
237
+ let text;
238
+ const [collapsed, setCollapsed] = createSignal(false);
239
+ const titleAttributes = createTextAttributes({ bold: true });
240
+ let previous;
241
+ const toggle = (event) => {
242
+ if (!text || event.y !== text.y) return;
243
+ setCollapsed((prev) => !prev);
244
+ sync();
245
+ };
246
+ const sync = () => {
247
+ if (!text) return;
248
+ const visible = goUsageSectionVisible(props.config, props.tracker.usesOpenCodeGo(props.sessionID));
249
+ if (visible) props.refresh();
250
+ const rows = visible ? goUsageRows(props.state, Date.now()) : void 0;
251
+ const error = props.state.error;
252
+ const showContent = visible && (rows || error);
253
+ const signature = showContent ? JSON.stringify({ collapsed: collapsed(), rows, error }) : "";
254
+ const next = {
255
+ content: signature,
256
+ visible: signature.length > 0,
257
+ height: signature.length > 0 ? "auto" : 0
258
+ };
259
+ if (!hasRenderStateChanged(previous, next)) return;
260
+ previous = next;
261
+ text.visible = next.visible;
262
+ text.height = next.height;
263
+ text.content = showContent ? renderGoUsageSidebar(rows, error, props.api, titleAttributes, collapsed()) : "";
264
+ props.api.renderer.requestRender();
265
+ };
266
+ const unsubscribe = props.subscribe(sync);
267
+ const unsubscribeGoUsage = props.goUsageSubscribe(sync);
268
+ const timer = setInterval(sync, 1e3);
269
+ onCleanup(() => {
270
+ unsubscribe();
271
+ unsubscribeGoUsage();
272
+ clearInterval(timer);
273
+ });
274
+ return /* @__PURE__ */ jsx(
275
+ "text",
276
+ {
277
+ ref: (ref) => {
278
+ text = ref;
279
+ sync();
280
+ },
281
+ onMouseDown: toggle,
282
+ fg: props.api.theme.current.textMuted,
283
+ children: ""
284
+ }
285
+ );
286
+ }
287
+ function renderGoUsageSidebar(rows, error, api, titleAttributes, collapsed) {
288
+ const chunks = [
289
+ textChunk(`${collapsed ? "\u25B6" : "\u25BC"} Go Usage
290
+ `, api.theme.current.text, titleAttributes)
291
+ ];
292
+ if (!collapsed) {
293
+ if (rows && rows.length > 0) {
294
+ for (const [index, row] of rows.entries()) {
295
+ if (index > 0) chunks.push(textChunk("\n"));
296
+ chunks.push(textChunk(formatGoUsageRow(row), api.theme.current.textMuted));
297
+ }
298
+ } else if (error) {
299
+ chunks.push(textChunk(`Go usage: ${error}`, api.theme.current.error));
300
+ }
301
+ }
302
+ return new StyledText(chunks);
303
+ }
122
304
  function SubagentSidebar(props) {
123
305
  let text;
124
306
  const [collapsed, setCollapsed] = createSignal(false);
@@ -238,7 +420,13 @@ var tui = async (api, options) => {
238
420
  const subagents = createSubagentState();
239
421
  const metricListeners = createListenerRegistry();
240
422
  const subagentListeners = createListenerRegistry();
423
+ const goUsageListeners = createListenerRegistry();
241
424
  const hydratedSessions = /* @__PURE__ */ new Set();
425
+ const goProviderTracker = createGoProviderTracker();
426
+ const goUsage = createGoUsageRefresher(config.goUsage);
427
+ const refreshGoUsage = async () => {
428
+ if (await goUsage.refresh()) goUsageListeners.notify();
429
+ };
242
430
  const hydrateSessionMetrics = async (sessionID) => {
243
431
  if (!isSessionID(sessionID) || hydratedSessions.has(sessionID)) return;
244
432
  hydratedSessions.add(sessionID);
@@ -247,6 +435,8 @@ var tui = async (api, options) => {
247
435
  const messages = response.data ?? [];
248
436
  for (const message of messages) {
249
437
  const info = message.info;
438
+ const providerID = info.providerID;
439
+ goProviderTracker.record(sessionID, typeof providerID === "string" ? providerID : void 0);
250
440
  if (info.role !== "assistant" || typeof info.time.completed !== "number") continue;
251
441
  const input = {
252
442
  sessionID: info.sessionID,
@@ -279,6 +469,9 @@ var tui = async (api, options) => {
279
469
  const offMessage = api.event.on("message.updated", (evt) => {
280
470
  const info = evt.properties.info;
281
471
  if (applySubagentEvent(subagents, evt)) subagentListeners.notify();
472
+ const sessionID = info.sessionID ?? evt.properties.sessionID;
473
+ const providerID = info.providerID ?? info.model?.providerID;
474
+ goProviderTracker.record(sessionID, typeof providerID === "string" ? providerID : void 0);
282
475
  if (info.role !== "assistant") return;
283
476
  const messageInput = {
284
477
  sessionID: info.sessionID ?? evt.properties.sessionID,
@@ -308,6 +501,13 @@ var tui = async (api, options) => {
308
501
  });
309
502
  const offSessionUpdated = api.event.on("session.updated", (evt) => {
310
503
  if (applySubagentEvent(subagents, evt)) subagentListeners.notify();
504
+ const info = evt.properties.info;
505
+ const sessionID = typeof info?.id === "string" ? info.id : void 0;
506
+ const providerID = info?.model?.providerID;
507
+ if (sessionID && typeof providerID === "string") {
508
+ goProviderTracker.record(sessionID, providerID);
509
+ metricListeners.notify();
510
+ }
311
511
  });
312
512
  const offSessionStatus = api.event.on("session.status", (evt) => {
313
513
  if (applySubagentEvent(subagents, evt)) subagentListeners.notify();
@@ -347,6 +547,19 @@ var tui = async (api, options) => {
347
547
  hydrate: () => void hydrateSessionMetrics(props.session_id)
348
548
  }
349
549
  ),
550
+ /* @__PURE__ */ jsx(
551
+ GoUsageSidebar,
552
+ {
553
+ api,
554
+ state: goUsage.state,
555
+ config,
556
+ tracker: goProviderTracker,
557
+ sessionID: props.session_id,
558
+ subscribe: metricListeners.subscribe,
559
+ goUsageSubscribe: goUsageListeners.subscribe,
560
+ refresh: () => void refreshGoUsage()
561
+ }
562
+ ),
350
563
  /* @__PURE__ */ jsx(
351
564
  SubagentSidebar,
352
565
  {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@rejacky/opencode-insights",
4
- "version": "0.1.11",
4
+ "version": "0.1.13",
5
5
  "description": "OpenCode plugin for local request capture, TPS metrics, and subagent status visibility.",
6
6
  "type": "module",
7
7
  "author": "opencode-insights contributors",
@@ -68,18 +68,18 @@
68
68
  },
69
69
  "peerDependencies": {
70
70
  "@opencode-ai/plugin": ">=1.15.0 <2",
71
- "@opentui/core": ">=0.4.0 <0.5",
72
- "@opentui/solid": ">=0.4.0 <0.5",
73
- "solid-js": "1.9.12"
71
+ "@opentui/core": ">=0.4.0 <0.6",
72
+ "@opentui/solid": ">=0.4.0 <0.6",
73
+ "solid-js": "^1.9.12"
74
74
  },
75
75
  "devDependencies": {
76
76
  "@opencode-ai/plugin": "^1.17.13",
77
- "@opentui/core": "^0.4.3",
78
- "@opentui/solid": "^0.4.3",
77
+ "@opentui/core": "^0.5.1",
78
+ "@opentui/solid": "^0.5.1",
79
79
  "@types/better-sqlite3": "^7.6.13",
80
80
  "@types/node": "^24.12.2",
81
81
  "@types/sql.js": "^1.4.11",
82
- "solid-js": "1.9.12",
82
+ "solid-js": "^1.9.12",
83
83
  "tsup": "^8.5.1",
84
84
  "typescript": "^6.0.3",
85
85
  "vitest": "^4.1.10"