@rejacky/opencode-insights 0.3.1 → 0.4.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 +55 -13
- package/dist/{capture-CwesXqmX.d.ts → capture-DJVWBRum.d.ts} +9 -2
- package/dist/{chunk-SGXZJVYX.js → chunk-ODCIUSCV.js} +19 -0
- package/dist/{chunk-RZGCLQ2M.js → chunk-ROQFQXIH.js} +48 -6
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +3 -6
- package/dist/index.d.ts +8 -2
- package/dist/index.js +9 -3
- package/dist/tui.js +183 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -94,13 +94,14 @@ The `uninstall` command removes plugin config entries and local Insights data; i
|
|
|
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
96
|
- An opt-in `Go Usage` sidebar showing OpenCode Go rolling/weekly/monthly usage limits for sessions that use the `opencode-go` provider.
|
|
97
|
+
- An opt-in `Copilot Usage` sidebar showing GitHub Copilot premium-interaction quota, usage bar, and days until reset for sessions that use the `github-copilot` provider.
|
|
97
98
|
- Subagent status (running, done, failed, elapsed time, and token/context usage) in the sidebar.
|
|
98
99
|
- A collapsible `Session Analysis` sidebar showing the active session's aggregated activity (tool calls, skills, auto-compactions, warnings, model requests, subagent tree). Click it to open a detail dialog; its vertical scrollbar appears only when the content overflows the dialog.
|
|
99
100
|
- Local capture of OpenCode hook/event data without redaction.
|
|
100
101
|
- A local web viewer for reconstructed sessions, user turns, hidden request context, system/messages transforms, and assistant thinking/response sequences.
|
|
101
102
|
- Native OpenCode footer components (project directory and version) remain visible — the plugin does not override `sidebar_footer` or `home_prompt_right` slots.
|
|
102
103
|
|
|
103
|
-
The right sidebar contains the plugin sections: `Token Usage`, `Go Usage` (when enabled and the session uses `opencode-go`), `Subagents`, and `Session Analysis`. 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.
|
|
104
|
+
The right sidebar contains the plugin sections: `Token Usage`, `Go Usage` (when enabled and the session uses `opencode-go`), `Copilot Usage` (when enabled and the session uses `github-copilot`), `Subagents`, and `Session Analysis`. 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.
|
|
104
105
|
|
|
105
106
|
## TUI Metrics Configuration
|
|
106
107
|
|
|
@@ -120,27 +121,67 @@ With a custom database path, the configuration file is created in that database'
|
|
|
120
121
|
|
|
121
122
|
`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.
|
|
122
123
|
|
|
123
|
-
##
|
|
124
|
+
## Provider Usage Configuration
|
|
124
125
|
|
|
125
|
-
The
|
|
126
|
+
The plugin can show usage sidebar sections for the AI provider used by the current session. Each section is opt-in, disabled by default, and only appears when the session uses the matching provider.
|
|
126
127
|
|
|
127
|
-
```
|
|
128
|
+
```jsonc
|
|
128
129
|
{
|
|
130
|
+
"promptRightMetrics": ["tps", "avg", "used", "cache"],
|
|
129
131
|
"goUsage": {
|
|
130
|
-
"enabled":
|
|
131
|
-
"cookie": "
|
|
132
|
-
"workspaceID": "
|
|
132
|
+
"enabled": false,
|
|
133
|
+
"cookie": "",
|
|
134
|
+
"workspaceID": "",
|
|
135
|
+
"refreshMs": 300000
|
|
136
|
+
},
|
|
137
|
+
"copilotUsage": {
|
|
138
|
+
"enabled": false,
|
|
139
|
+
"token": "",
|
|
133
140
|
"refreshMs": 300000
|
|
134
141
|
}
|
|
135
142
|
}
|
|
136
143
|
```
|
|
137
144
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
145
|
+
### Go Usage
|
|
146
|
+
|
|
147
|
+
Shows rolling (5 hour), weekly, and monthly usage limits for OpenCode Go subscriptions. Only visible when the session uses the `opencode-go` provider.
|
|
148
|
+
|
|
149
|
+
```jsonc
|
|
150
|
+
"goUsage": {
|
|
151
|
+
"enabled": true, // set to true to activate
|
|
152
|
+
"cookie": "Fe26.2**...", // auth session cookie from opencode.ai
|
|
153
|
+
"workspaceID": "wrk_...", // visible in the console URL
|
|
154
|
+
"refreshMs": 300000 // poll interval (min 60000)
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
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.
|
|
159
|
+
|
|
160
|
+
### Copilot Usage
|
|
161
|
+
|
|
162
|
+
Shows GitHub Copilot premium-interaction quota (used/total, progress bar, days until reset). Only visible when the session uses the `github-copilot` provider.
|
|
163
|
+
|
|
164
|
+
```jsonc
|
|
165
|
+
"copilotUsage": {
|
|
166
|
+
"enabled": true, // set to true to activate
|
|
167
|
+
"token": "", // optional: manual token override
|
|
168
|
+
"refreshMs": 300000 // poll interval (min 60000)
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The `token` field is optional. If empty, the plugin reads the token from OpenCode's auth store (`~/.local/share/opencode/auth.json` → `github-copilot.access`). No manual setup is needed if you authenticate with Copilot through OpenCode.
|
|
173
|
+
|
|
174
|
+
The section displays:
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
▼ Copilot
|
|
178
|
+
Premium 84% ████████░░ 7d
|
|
179
|
+
2942 / 3500
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
When the quota is exhausted and overage is permitted, the bar fills to 100% and the percentage reflects actual usage.
|
|
142
183
|
|
|
143
|
-
|
|
184
|
+
Restart OpenCode after editing this file.
|
|
144
185
|
|
|
145
186
|
## Open The Viewer
|
|
146
187
|
|
|
@@ -254,7 +295,8 @@ comments allowed). The plugin creates it on first run with `dbPath` commented ou
|
|
|
254
295
|
// "dbPath": "/absolute/path/to/insights.sqlite",
|
|
255
296
|
"retentionDays": 1,
|
|
256
297
|
"promptRightMetrics": ["tps", "avg", "used", "cache"],
|
|
257
|
-
"goUsage": { "enabled": false, "cookie": "", "workspaceID": "", "refreshMs": 300000 }
|
|
298
|
+
"goUsage": { "enabled": false, "cookie": "", "workspaceID": "", "refreshMs": 300000 },
|
|
299
|
+
"copilotUsage": { "enabled": false, "token": "", "refreshMs": 300000 }
|
|
258
300
|
}
|
|
259
301
|
```
|
|
260
302
|
|
|
@@ -78,7 +78,7 @@ declare function renderPromptRightMetricsText(state: MetricsState, sessionID: st
|
|
|
78
78
|
metrics?: PromptRightMetric[];
|
|
79
79
|
}): string;
|
|
80
80
|
declare function getSessionTokenUsage(state: MetricsState, sessionID: string): SessionTokenUsage | undefined;
|
|
81
|
-
declare function renderSessionTokenUsage(state: MetricsState, sessionID: string): string;
|
|
81
|
+
declare function renderSessionTokenUsage(state: MetricsState, sessionID: string, subagentTokens?: number): string;
|
|
82
82
|
|
|
83
83
|
type CaptureKind = "chat.message" | "chat.params" | "chat.headers" | "experimental.chat.messages.transform" | "experimental.chat.system.transform" | "event" | "tool.execute.before" | "tool.execute.after";
|
|
84
84
|
type CaptureRecord = {
|
|
@@ -107,9 +107,15 @@ type GoUsageConfig = {
|
|
|
107
107
|
workspaceID: string;
|
|
108
108
|
refreshMs: number;
|
|
109
109
|
};
|
|
110
|
+
type CopilotUsageConfig = {
|
|
111
|
+
enabled: boolean;
|
|
112
|
+
token: string;
|
|
113
|
+
refreshMs: number;
|
|
114
|
+
};
|
|
110
115
|
type InsightsConfig = {
|
|
111
116
|
promptRightMetrics: PromptRightMetric[];
|
|
112
117
|
goUsage: GoUsageConfig;
|
|
118
|
+
copilotUsage: CopilotUsageConfig;
|
|
113
119
|
dbPath?: string | undefined;
|
|
114
120
|
retentionDays?: number | undefined;
|
|
115
121
|
};
|
|
@@ -119,6 +125,7 @@ declare function resolveInsightsConfigPath(options?: InsightsOptions): string;
|
|
|
119
125
|
declare function resolveLegacyInsightsConfigPath(options?: InsightsOptions): string;
|
|
120
126
|
declare function readInsightsConfig(options?: InsightsOptions): Promise<InsightsConfig>;
|
|
121
127
|
declare function insightsOptionsFromConfig(config: InsightsConfig, dataDir?: string): InsightsOptions;
|
|
128
|
+
declare function resolveCopilotToken(config: CopilotUsageConfig): string;
|
|
122
129
|
declare function normalizeChatMessageCapture(input: unknown, output: unknown, timestamp?: number): CaptureRecord;
|
|
123
130
|
declare function normalizeChatParamsCapture(input: unknown, output: unknown, timestamp?: number): CaptureRecord;
|
|
124
131
|
declare function normalizeChatHeadersCapture(input: unknown, output: unknown, timestamp?: number): CaptureRecord;
|
|
@@ -156,4 +163,4 @@ declare class SqliteCaptureStore implements CaptureStore {
|
|
|
156
163
|
declare function createCaptureStore(options?: InsightsOptions): CaptureStore;
|
|
157
164
|
declare function resolveRetentionDays(value: unknown): number;
|
|
158
165
|
|
|
159
|
-
export { type AssistantResponseUsage as A,
|
|
166
|
+
export { type AssistantResponseUsage as A, recordAssistantMessage as B, type CaptureRecord as C, DEFAULT_PROMPT_RIGHT_METRICS as D, recordToolActivity as E, renderMetricsText as F, type GoUsageConfig as G, renderPromptRightMetricsText as H, type InsightsConfig as I, JsonlCaptureStore as J, renderResponseMetricsText as K, renderSessionTokenUsage as L, type MessageTiming as M, resolveCapturePath as N, resolveCopilotToken as O, type PromptRightMetric as P, resolveInsightsConfigPath as Q, resolveLegacyInsightsConfigPath as R, type SessionAverage as S, resolveRetentionDays as T, type CaptureKind as a, type CaptureStore as b, type CopilotUsageConfig as c, type InsightsOptions as d, type MetricsState as e, type SessionTokenUsage as f, SqliteCaptureStore as g, type SqliteDb as h, type StreamSample as i, createCaptureStore as j, createMetricsState as k, defaultDataDir as l, estimateStreamTokens as m, extractEventType as n, getSessionTokenUsage as o, insightsOptionsFromConfig as p, normalizeChatHeadersCapture as q, normalizeChatMessageCapture as r, normalizeChatParamsCapture as s, normalizeEventCapture as t, normalizeExperimentalChatMessagesTransformCapture as u, normalizeExperimentalChatSystemTransformCapture as v, normalizeToolCapture as w, openDatabase as x, readInsightsConfig as y, recordAssistantDelta as z };
|
|
@@ -225,6 +225,20 @@ function buildSessionAnalysisRows(state, rootSessionID) {
|
|
|
225
225
|
function createSubagentState(activityStore) {
|
|
226
226
|
return { children: {}, totalExecuted: 0, ...activityStore ? { activityStore } : {} };
|
|
227
227
|
}
|
|
228
|
+
function recordSubagentFromSessionInfo(state, session) {
|
|
229
|
+
if (!session.parentID || !session.id || session.id === session.parentID) return;
|
|
230
|
+
if (state.children[session.id]) return;
|
|
231
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
232
|
+
state.children[session.id] = {
|
|
233
|
+
id: session.id,
|
|
234
|
+
parentID: session.parentID,
|
|
235
|
+
title: session.title ?? "subagent",
|
|
236
|
+
status: "done",
|
|
237
|
+
startedAt: now,
|
|
238
|
+
updatedAt: now
|
|
239
|
+
};
|
|
240
|
+
state.totalExecuted += 1;
|
|
241
|
+
}
|
|
228
242
|
function applySubagentEvent(state, event) {
|
|
229
243
|
const created = extractTaskToolSubagent(event) ?? extractSubagent(event) ?? updateExistingSubagent(state, event);
|
|
230
244
|
if (!created) return false;
|
|
@@ -275,6 +289,9 @@ function getSubagentItems(state, parentID) {
|
|
|
275
289
|
return b.startedAt.localeCompare(a.startedAt);
|
|
276
290
|
});
|
|
277
291
|
}
|
|
292
|
+
function sumSubagentTokens(state, parentID) {
|
|
293
|
+
return getSubagentItems(state, parentID).reduce((sum, child) => sum + (child.tokens?.total ?? 0), 0);
|
|
294
|
+
}
|
|
278
295
|
function pruneStaleSubagents(state, options = {}) {
|
|
279
296
|
const now = options.now ?? Date.now();
|
|
280
297
|
const staleMs = options.staleMs ?? 18e4;
|
|
@@ -535,9 +552,11 @@ export {
|
|
|
535
552
|
treeSubagentCount,
|
|
536
553
|
buildSessionAnalysisRows,
|
|
537
554
|
createSubagentState,
|
|
555
|
+
recordSubagentFromSessionInfo,
|
|
538
556
|
applySubagentEvent,
|
|
539
557
|
renderSubagentStatus,
|
|
540
558
|
getSubagentItems,
|
|
559
|
+
sumSubagentTokens,
|
|
541
560
|
pruneStaleSubagents,
|
|
542
561
|
getSubagentSidebarModel,
|
|
543
562
|
getSubagentSidebarRowAtLine,
|
|
@@ -136,21 +136,28 @@ function renderPromptRightMetricsText(state, sessionID, options = {}) {
|
|
|
136
136
|
function getSessionTokenUsage(state, sessionID) {
|
|
137
137
|
return state.sessionTokenUsageByID[sessionID];
|
|
138
138
|
}
|
|
139
|
-
function renderSessionTokenUsage(state, sessionID) {
|
|
139
|
+
function renderSessionTokenUsage(state, sessionID, subagentTokens = 0) {
|
|
140
140
|
const usage = getSessionTokenUsage(state, sessionID);
|
|
141
141
|
if (!usage) return "";
|
|
142
|
+
const grandTotal = usage.totalTokens + subagentTokens;
|
|
142
143
|
const cachePromptTokens = usage.inputTokens + usage.cacheReadTokens;
|
|
143
144
|
const cacheRate = cachePromptTokens > 0 ? usage.cacheReadTokens / cachePromptTokens * 100 : void 0;
|
|
144
|
-
|
|
145
|
+
const lines = [
|
|
145
146
|
"Token Usage",
|
|
146
|
-
`${formatTokenCount(
|
|
147
|
+
`${formatTokenCount(grandTotal)} total \xB7 ${usage.responseCount} responses`
|
|
148
|
+
];
|
|
149
|
+
if (subagentTokens > 0) {
|
|
150
|
+
lines.push(`${formatTokenCount(subagentTokens)} used by subagents`);
|
|
151
|
+
}
|
|
152
|
+
lines.push(
|
|
147
153
|
`${formatTokenCount(usage.inputTokens)} input`,
|
|
148
154
|
`${formatTokenCount(usage.outputTokens)} output`,
|
|
149
155
|
`${formatTokenCount(usage.reasoningTokens)} reasoning`,
|
|
150
156
|
`${formatTokenCount(usage.cacheReadTokens)} cache read`,
|
|
151
157
|
`${formatTokenCount(usage.cacheWriteTokens)} cache write`,
|
|
152
158
|
`${cacheRate === void 0 ? "-" : formatPercent(cacheRate)} cache rate`
|
|
153
|
-
|
|
159
|
+
);
|
|
160
|
+
return lines.join("\n");
|
|
154
161
|
}
|
|
155
162
|
function pruneSamples(state, now = Date.now()) {
|
|
156
163
|
for (const [sessionID, samples] of Object.entries(state.streamSamplesBySession)) {
|
|
@@ -270,7 +277,9 @@ import { parse } from "jsonc-parser";
|
|
|
270
277
|
var DEFAULT_RETENTION_DAYS = 1;
|
|
271
278
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
272
279
|
var DEFAULT_GO_USAGE_REFRESH_MS = 3e5;
|
|
280
|
+
var DEFAULT_COPILOT_USAGE_REFRESH_MS = 3e5;
|
|
273
281
|
var MIN_GO_USAGE_REFRESH_MS = 6e4;
|
|
282
|
+
var MIN_COPILOT_USAGE_REFRESH_MS = 6e4;
|
|
274
283
|
var sequence = 0;
|
|
275
284
|
function nextID(timestamp) {
|
|
276
285
|
sequence += 1;
|
|
@@ -370,7 +379,8 @@ function defaultInsightsConfigJsonc() {
|
|
|
370
379
|
' // "dbPath": "/absolute/path/to/insights.sqlite",',
|
|
371
380
|
` "retentionDays": ${DEFAULT_RETENTION_DAYS},`,
|
|
372
381
|
` "promptRightMetrics": ${JSON.stringify(DEFAULT_PROMPT_RIGHT_METRICS)},`,
|
|
373
|
-
` "goUsage": ${JSON.stringify(defaultGoUsageConfig())}
|
|
382
|
+
` "goUsage": ${JSON.stringify(defaultGoUsageConfig())},`,
|
|
383
|
+
` "copilotUsage": ${JSON.stringify(defaultCopilotUsageConfig())}`,
|
|
374
384
|
"}",
|
|
375
385
|
""
|
|
376
386
|
].join("\n");
|
|
@@ -379,11 +389,18 @@ function insightsOptionsFromConfig(config, dataDir) {
|
|
|
379
389
|
return compactUndefined({ dataDir, dbPath: config.dbPath, retentionDays: config.retentionDays });
|
|
380
390
|
}
|
|
381
391
|
function defaultInsightsConfig() {
|
|
382
|
-
return {
|
|
392
|
+
return {
|
|
393
|
+
promptRightMetrics: [...DEFAULT_PROMPT_RIGHT_METRICS],
|
|
394
|
+
goUsage: defaultGoUsageConfig(),
|
|
395
|
+
copilotUsage: defaultCopilotUsageConfig()
|
|
396
|
+
};
|
|
383
397
|
}
|
|
384
398
|
function defaultGoUsageConfig() {
|
|
385
399
|
return { enabled: false, cookie: "", workspaceID: "", refreshMs: DEFAULT_GO_USAGE_REFRESH_MS };
|
|
386
400
|
}
|
|
401
|
+
function defaultCopilotUsageConfig() {
|
|
402
|
+
return { enabled: false, token: "", refreshMs: DEFAULT_COPILOT_USAGE_REFRESH_MS };
|
|
403
|
+
}
|
|
387
404
|
function insightsConfigFrom(value) {
|
|
388
405
|
const record = isRecord(value) ? value : {};
|
|
389
406
|
const metrics = Array.isArray(record.promptRightMetrics) ? record.promptRightMetrics.filter(isPromptRightMetric) : [];
|
|
@@ -393,6 +410,7 @@ function insightsConfigFrom(value) {
|
|
|
393
410
|
return {
|
|
394
411
|
promptRightMetrics: metrics.length ? metrics : [...DEFAULT_PROMPT_RIGHT_METRICS],
|
|
395
412
|
goUsage: goUsageConfigFrom(record.goUsage),
|
|
413
|
+
copilotUsage: copilotUsageConfigFrom(record.copilotUsage),
|
|
396
414
|
dbPath,
|
|
397
415
|
retentionDays
|
|
398
416
|
};
|
|
@@ -405,9 +423,32 @@ function goUsageConfigFrom(value) {
|
|
|
405
423
|
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;
|
|
406
424
|
return { enabled, cookie, workspaceID, refreshMs };
|
|
407
425
|
}
|
|
426
|
+
function copilotUsageConfigFrom(value) {
|
|
427
|
+
const record = isRecord(value) ? value : {};
|
|
428
|
+
const enabled = record.enabled === true;
|
|
429
|
+
const token = typeof record.token === "string" && record.token.length > 0 ? record.token : "";
|
|
430
|
+
const refreshMs = typeof record.refreshMs === "number" && Number.isFinite(record.refreshMs) ? Math.max(MIN_COPILOT_USAGE_REFRESH_MS, Math.trunc(record.refreshMs)) : DEFAULT_COPILOT_USAGE_REFRESH_MS;
|
|
431
|
+
return { enabled, token, refreshMs };
|
|
432
|
+
}
|
|
408
433
|
function isPromptRightMetric(value) {
|
|
409
434
|
return value === "tps" || value === "avg" || value === "ttft" || value === "used" || value === "cache" || value === "input" || value === "output" || value === "reasoning";
|
|
410
435
|
}
|
|
436
|
+
function resolveCopilotToken(config) {
|
|
437
|
+
if (config.token.length > 0) return config.token;
|
|
438
|
+
try {
|
|
439
|
+
const authPath = join(homedir(), ".local/share/opencode/auth.json");
|
|
440
|
+
if (!existsSync(authPath)) return "";
|
|
441
|
+
const raw = readFileSync(authPath, "utf8");
|
|
442
|
+
const auth = JSON.parse(raw);
|
|
443
|
+
const copilot = isRecord(auth?.["github-copilot"]) ? auth["github-copilot"] : void 0;
|
|
444
|
+
if (!copilot) return "";
|
|
445
|
+
const access = typeof copilot.access === "string" ? copilot.access : "";
|
|
446
|
+
const refresh = typeof copilot.refresh === "string" ? copilot.refresh : "";
|
|
447
|
+
return access || refresh;
|
|
448
|
+
} catch {
|
|
449
|
+
return "";
|
|
450
|
+
}
|
|
451
|
+
}
|
|
411
452
|
function normalizeChatMessageCapture(input, output, timestamp = Date.now()) {
|
|
412
453
|
const inputRecord = isRecord(input) ? input : {};
|
|
413
454
|
const model = isRecord(inputRecord.model) ? inputRecord.model : void 0;
|
|
@@ -747,6 +788,7 @@ export {
|
|
|
747
788
|
resolveLegacyInsightsConfigPath,
|
|
748
789
|
readInsightsConfig,
|
|
749
790
|
insightsOptionsFromConfig,
|
|
791
|
+
resolveCopilotToken,
|
|
750
792
|
normalizeChatMessageCapture,
|
|
751
793
|
normalizeChatParamsCapture,
|
|
752
794
|
normalizeChatHeadersCapture,
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
readInsightsConfig,
|
|
5
5
|
resolveCapturePath,
|
|
6
6
|
resolveInsightsConfigPath
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ROQFQXIH.js";
|
|
8
8
|
|
|
9
9
|
// src/cli.ts
|
|
10
10
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -217,21 +217,19 @@ function buildRequestHistory(records) {
|
|
|
217
217
|
continue;
|
|
218
218
|
}
|
|
219
219
|
if (type === "message.part.updated" || type === "message.part.delta") {
|
|
220
|
+
if (type === "message.part.delta") continue;
|
|
220
221
|
const part = isRecord(properties.part) ? properties.part : {};
|
|
221
222
|
const sessionID = optionalString(part.sessionID) ?? optionalString(properties.sessionID);
|
|
222
223
|
const messageID = optionalString(part.messageID) ?? optionalString(properties.messageID);
|
|
223
224
|
if (!sessionID || !messageID) continue;
|
|
224
225
|
const partType = optionalString(part.type);
|
|
225
|
-
const field = optionalString(properties.field);
|
|
226
|
-
const delta = optionalString(properties.delta);
|
|
227
226
|
const text = optionalString(part.text);
|
|
228
227
|
const reasonText = optionalString(part.text) ?? optionalString(part.markdown);
|
|
229
228
|
const targetResponse = responses.get(`${sessionID}:${messageID}`);
|
|
230
229
|
if (targetResponse) {
|
|
231
|
-
targetResponse.events.push(record.payload);
|
|
230
|
+
if (partType === "tool") targetResponse.events.push(record.payload);
|
|
232
231
|
if (partType === "text" && text !== void 0) targetResponse.text = text;
|
|
233
232
|
if (partType === "reasoning" && reasonText !== void 0) targetResponse.reasoning = reasonText;
|
|
234
|
-
if (type === "message.part.delta" && field === "text" && delta !== void 0) targetResponse.text += delta;
|
|
235
233
|
continue;
|
|
236
234
|
}
|
|
237
235
|
if (partType !== "text" && partType !== "reasoning") continue;
|
|
@@ -376,7 +374,6 @@ function viewerCaptureSql(limit) {
|
|
|
376
374
|
and event_type in (
|
|
377
375
|
'message.updated',
|
|
378
376
|
'message.part.updated',
|
|
379
|
-
'message.part.delta',
|
|
380
377
|
'session.updated',
|
|
381
378
|
'session.created'
|
|
382
379
|
)
|
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, G as GoUsageConfig, I as InsightsConfig,
|
|
3
|
+
export { A as AssistantResponseUsage, a as CaptureKind, C as CaptureRecord, b as CaptureStore, c as CopilotUsageConfig, D as DEFAULT_PROMPT_RIGHT_METRICS, G as GoUsageConfig, I as InsightsConfig, d as InsightsOptions, J as JsonlCaptureStore, M as MessageTiming, e as MetricsState, P as PromptRightMetric, S as SessionAverage, f as SessionTokenUsage, g as SqliteCaptureStore, h as SqliteDb, i as StreamSample, j as createCaptureStore, k as createMetricsState, l as defaultDataDir, m as estimateStreamTokens, n as extractEventType, o as getSessionTokenUsage, p as insightsOptionsFromConfig, q as normalizeChatHeadersCapture, r as normalizeChatMessageCapture, s as normalizeChatParamsCapture, t as normalizeEventCapture, u as normalizeExperimentalChatMessagesTransformCapture, v as normalizeExperimentalChatSystemTransformCapture, w as normalizeToolCapture, x as openDatabase, y as readInsightsConfig, z as recordAssistantDelta, B as recordAssistantMessage, E as recordToolActivity, F as renderMetricsText, H as renderPromptRightMetricsText, K as renderResponseMetricsText, L as renderSessionTokenUsage, N as resolveCapturePath, O as resolveCopilotToken, Q as resolveInsightsConfigPath, R as resolveLegacyInsightsConfigPath, T as resolveRetentionDays } from './capture-DJVWBRum.js';
|
|
4
4
|
|
|
5
5
|
type SessionActivity = {
|
|
6
6
|
toolCalls: number;
|
|
@@ -58,11 +58,17 @@ type SubagentSidebarModel = {
|
|
|
58
58
|
rows: SubagentSidebarRow[];
|
|
59
59
|
};
|
|
60
60
|
declare function createSubagentState(activityStore?: ActivityState): SubagentState;
|
|
61
|
+
declare function recordSubagentFromSessionInfo(state: SubagentState, session: {
|
|
62
|
+
id: string;
|
|
63
|
+
parentID?: string;
|
|
64
|
+
title?: string;
|
|
65
|
+
}): void;
|
|
61
66
|
declare function applySubagentEvent(state: SubagentState, event: unknown): boolean;
|
|
62
67
|
declare function renderSubagentStatus(state: SubagentState, options?: {
|
|
63
68
|
now?: number;
|
|
64
69
|
}): string;
|
|
65
70
|
declare function getSubagentItems(state: SubagentState, parentID?: string): SubagentInfo[];
|
|
71
|
+
declare function sumSubagentTokens(state: SubagentState, parentID: string): number;
|
|
66
72
|
declare function pruneStaleSubagents(state: SubagentState, options?: {
|
|
67
73
|
now?: number;
|
|
68
74
|
staleMs?: number;
|
|
@@ -89,4 +95,4 @@ declare const _default: {
|
|
|
89
95
|
server: Plugin;
|
|
90
96
|
};
|
|
91
97
|
|
|
92
|
-
export { OpenCodeInsights, type SubagentInfo, type SubagentSidebarModel, type SubagentSidebarRow, type SubagentState, type SubagentStatus, applySubagentEvent, createSubagentState, _default as default, getSubagentItems, getSubagentSidebarModel, getSubagentSidebarRowAtLine, id, pruneStaleSubagents, renderSubagentFooter, renderSubagentSidebar, renderSubagentStatus, server, rootTui as tui };
|
|
98
|
+
export { OpenCodeInsights, type SubagentInfo, type SubagentSidebarModel, type SubagentSidebarRow, type SubagentState, type SubagentStatus, applySubagentEvent, createSubagentState, _default as default, getSubagentItems, getSubagentSidebarModel, getSubagentSidebarRowAtLine, id, pruneStaleSubagents, recordSubagentFromSessionInfo, renderSubagentFooter, renderSubagentSidebar, renderSubagentStatus, server, sumSubagentTokens, rootTui as tui };
|
package/dist/index.js
CHANGED
|
@@ -5,10 +5,12 @@ import {
|
|
|
5
5
|
getSubagentSidebarModel,
|
|
6
6
|
getSubagentSidebarRowAtLine,
|
|
7
7
|
pruneStaleSubagents,
|
|
8
|
+
recordSubagentFromSessionInfo,
|
|
8
9
|
renderSubagentFooter,
|
|
9
10
|
renderSubagentSidebar,
|
|
10
|
-
renderSubagentStatus
|
|
11
|
-
|
|
11
|
+
renderSubagentStatus,
|
|
12
|
+
sumSubagentTokens
|
|
13
|
+
} from "./chunk-ODCIUSCV.js";
|
|
12
14
|
import {
|
|
13
15
|
DEFAULT_PROMPT_RIGHT_METRICS,
|
|
14
16
|
JsonlCaptureStore,
|
|
@@ -37,10 +39,11 @@ import {
|
|
|
37
39
|
renderResponseMetricsText,
|
|
38
40
|
renderSessionTokenUsage,
|
|
39
41
|
resolveCapturePath,
|
|
42
|
+
resolveCopilotToken,
|
|
40
43
|
resolveInsightsConfigPath,
|
|
41
44
|
resolveLegacyInsightsConfigPath,
|
|
42
45
|
resolveRetentionDays
|
|
43
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-ROQFQXIH.js";
|
|
44
47
|
|
|
45
48
|
// src/cli-shim.ts
|
|
46
49
|
import { existsSync } from "fs";
|
|
@@ -173,6 +176,7 @@ export {
|
|
|
173
176
|
readInsightsConfig,
|
|
174
177
|
recordAssistantDelta,
|
|
175
178
|
recordAssistantMessage,
|
|
179
|
+
recordSubagentFromSessionInfo,
|
|
176
180
|
recordToolActivity,
|
|
177
181
|
renderMetricsText,
|
|
178
182
|
renderPromptRightMetricsText,
|
|
@@ -182,9 +186,11 @@ export {
|
|
|
182
186
|
renderSubagentSidebar,
|
|
183
187
|
renderSubagentStatus,
|
|
184
188
|
resolveCapturePath,
|
|
189
|
+
resolveCopilotToken,
|
|
185
190
|
resolveInsightsConfigPath,
|
|
186
191
|
resolveLegacyInsightsConfigPath,
|
|
187
192
|
resolveRetentionDays,
|
|
188
193
|
server,
|
|
194
|
+
sumSubagentTokens,
|
|
189
195
|
rootTui as tui
|
|
190
196
|
};
|
package/dist/tui.js
CHANGED
|
@@ -10,10 +10,11 @@ import {
|
|
|
10
10
|
recordCompaction,
|
|
11
11
|
recordStep,
|
|
12
12
|
recordToolPart,
|
|
13
|
+
sumSubagentTokens,
|
|
13
14
|
treeActivity,
|
|
14
15
|
treeLoading,
|
|
15
16
|
treeSubagentCount
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-ODCIUSCV.js";
|
|
17
18
|
import {
|
|
18
19
|
createMetricsState,
|
|
19
20
|
readInsightsConfig,
|
|
@@ -21,8 +22,9 @@ import {
|
|
|
21
22
|
recordAssistantMessage,
|
|
22
23
|
recordToolActivity,
|
|
23
24
|
renderPromptRightMetricsText,
|
|
24
|
-
renderSessionTokenUsage
|
|
25
|
-
|
|
25
|
+
renderSessionTokenUsage,
|
|
26
|
+
resolveCopilotToken
|
|
27
|
+
} from "./chunk-ROQFQXIH.js";
|
|
26
28
|
|
|
27
29
|
// src/tui.tsx
|
|
28
30
|
import { createTextAttributes, StyledText } from "@opentui/core";
|
|
@@ -108,7 +110,8 @@ function formatUsageBar(usagePercent, width = 10) {
|
|
|
108
110
|
}
|
|
109
111
|
function formatGoUsageRow(row) {
|
|
110
112
|
const bar = formatUsageBar(row.usagePercent);
|
|
111
|
-
|
|
113
|
+
const pct = `${Math.round(row.usagePercent)}%`;
|
|
114
|
+
return `${row.label.padEnd(9)}${pct.padEnd(4)} ${bar} ${row.reset}`;
|
|
112
115
|
}
|
|
113
116
|
function goUsageSectionVisible(config, usesGoProvider) {
|
|
114
117
|
return usesGoProvider && config.goUsage.enabled && config.goUsage.cookie.length > 0 && config.goUsage.workspaceID.length > 0;
|
|
@@ -171,6 +174,87 @@ function createGoUsageRefresher(config, fetchImpl = fetch) {
|
|
|
171
174
|
return { state, refresh };
|
|
172
175
|
}
|
|
173
176
|
|
|
177
|
+
// src/copilot-usage.ts
|
|
178
|
+
var CopilotUsageError = class extends Error {
|
|
179
|
+
};
|
|
180
|
+
async function fetchCopilotUsage(token, fetchImpl = fetch) {
|
|
181
|
+
const response = await fetchImpl("https://api.github.com/copilot_internal/user", {
|
|
182
|
+
headers: {
|
|
183
|
+
Authorization: `Bearer ${token}`,
|
|
184
|
+
Accept: "application/json"
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
if (response.status === 401 || response.status === 403) {
|
|
188
|
+
throw new CopilotUsageError("token expired or invalid; update token in config or re-authenticate");
|
|
189
|
+
}
|
|
190
|
+
if (!response.ok) {
|
|
191
|
+
throw new CopilotUsageError(`copilot API request failed with status ${response.status}`);
|
|
192
|
+
}
|
|
193
|
+
let body;
|
|
194
|
+
try {
|
|
195
|
+
body = await response.json();
|
|
196
|
+
} catch {
|
|
197
|
+
throw new CopilotUsageError("could not parse copilot usage response");
|
|
198
|
+
}
|
|
199
|
+
return body;
|
|
200
|
+
}
|
|
201
|
+
function copilotUsageRow(data, now) {
|
|
202
|
+
const pi = data.quota_snapshots?.premium_interactions;
|
|
203
|
+
if (!pi || pi.unlimited) return void 0;
|
|
204
|
+
const used = pi.entitlement - pi.remaining;
|
|
205
|
+
const percentUsed = 100 - pi.percent_remaining;
|
|
206
|
+
const resetDate = Date.parse(data.quota_reset_date_utc);
|
|
207
|
+
const daysRemaining = Number.isFinite(resetDate) ? Math.max(0, Math.ceil((resetDate - now) / 864e5)) : 0;
|
|
208
|
+
return { used, total: pi.entitlement, percentUsed, daysRemaining, creditsUsed: pi.credits_used };
|
|
209
|
+
}
|
|
210
|
+
function formatCopilotUsageRow(row) {
|
|
211
|
+
const bar = formatUsageBar(row.percentUsed);
|
|
212
|
+
const pct = `${Math.round(row.percentUsed)}%`;
|
|
213
|
+
const main = `${"Premium".padEnd(9)}${pct.padEnd(4)} ${bar} ${row.daysRemaining}d`;
|
|
214
|
+
const detail = `${"".padEnd(9)}${String(row.used).padStart(4)} / ${row.total}`;
|
|
215
|
+
return `${main}
|
|
216
|
+
${detail}`;
|
|
217
|
+
}
|
|
218
|
+
function copilotUsageSectionVisible(config, token, usesCopilot) {
|
|
219
|
+
return usesCopilot && config.copilotUsage.enabled && token.length > 0;
|
|
220
|
+
}
|
|
221
|
+
function createCopilotProviderTracker() {
|
|
222
|
+
const providers = /* @__PURE__ */ new Map();
|
|
223
|
+
return {
|
|
224
|
+
record(sessionID, providerID) {
|
|
225
|
+
if (providerID) providers.set(sessionID, providerID);
|
|
226
|
+
},
|
|
227
|
+
usesCopilot(sessionID) {
|
|
228
|
+
return providers.get(sessionID) === "github-copilot";
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function createCopilotUsageRefresher(config, token, fetchImpl = fetch) {
|
|
233
|
+
const state = {};
|
|
234
|
+
let inflight;
|
|
235
|
+
async function refresh(now = Date.now()) {
|
|
236
|
+
if (inflight) {
|
|
237
|
+
await inflight;
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
if (state.lastFetchAt !== void 0 && now - state.lastFetchAt < config.refreshMs) return false;
|
|
241
|
+
inflight = (async () => {
|
|
242
|
+
try {
|
|
243
|
+
state.data = await fetchCopilotUsage(token, fetchImpl);
|
|
244
|
+
state.error = void 0;
|
|
245
|
+
} catch (error) {
|
|
246
|
+
state.error = error instanceof Error ? error.message : String(error);
|
|
247
|
+
} finally {
|
|
248
|
+
state.lastFetchAt = now;
|
|
249
|
+
inflight = void 0;
|
|
250
|
+
}
|
|
251
|
+
})();
|
|
252
|
+
await inflight;
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
return { state, refresh };
|
|
256
|
+
}
|
|
257
|
+
|
|
174
258
|
// src/activity-hydrate.ts
|
|
175
259
|
var CONCURRENCY_LIMIT = 4;
|
|
176
260
|
var LIST_LIMIT = 1e3;
|
|
@@ -312,7 +396,8 @@ function TokenUsageSidebar(props) {
|
|
|
312
396
|
};
|
|
313
397
|
const sync = () => {
|
|
314
398
|
if (!text) return;
|
|
315
|
-
const
|
|
399
|
+
const subagentTokens = sumSubagentTokens(props.subagentState, props.sessionID);
|
|
400
|
+
const content = renderSessionTokenUsage(props.state, props.sessionID, subagentTokens);
|
|
316
401
|
const next = {
|
|
317
402
|
content: `${collapsed()}|${content}`,
|
|
318
403
|
visible: content.length > 0,
|
|
@@ -409,6 +494,75 @@ function renderGoUsageSidebar(rows, error, api, titleAttributes, collapsed) {
|
|
|
409
494
|
}
|
|
410
495
|
return new StyledText(chunks);
|
|
411
496
|
}
|
|
497
|
+
function CopilotUsageSidebar(props) {
|
|
498
|
+
let text;
|
|
499
|
+
const [collapsed, setCollapsed] = createSignal(false);
|
|
500
|
+
const titleAttributes = createTextAttributes({ bold: true });
|
|
501
|
+
let previous;
|
|
502
|
+
const toggle = (event) => {
|
|
503
|
+
if (!text || event.y !== text.y) return;
|
|
504
|
+
setCollapsed((prev) => !prev);
|
|
505
|
+
sync();
|
|
506
|
+
};
|
|
507
|
+
const sync = () => {
|
|
508
|
+
if (!text) return;
|
|
509
|
+
const visible = copilotUsageSectionVisible(props.config, props.token, props.tracker.usesCopilot(props.sessionID));
|
|
510
|
+
if (visible) props.refresh();
|
|
511
|
+
const row = visible ? copilotUsageRow(props.state.data ?? {}, Date.now()) : void 0;
|
|
512
|
+
const error = props.state.error;
|
|
513
|
+
const showContent = visible && (row || error);
|
|
514
|
+
const signature = showContent ? JSON.stringify({ collapsed: collapsed(), row, error }) : "";
|
|
515
|
+
const next = {
|
|
516
|
+
content: signature,
|
|
517
|
+
visible: signature.length > 0,
|
|
518
|
+
height: signature.length > 0 ? "auto" : 0
|
|
519
|
+
};
|
|
520
|
+
if (!hasRenderStateChanged(previous, next)) return;
|
|
521
|
+
previous = next;
|
|
522
|
+
text.visible = next.visible;
|
|
523
|
+
text.height = next.height;
|
|
524
|
+
text.content = showContent ? renderCopilotUsageSidebar(row, error, props.api, titleAttributes, collapsed()) : "";
|
|
525
|
+
props.api.renderer.requestRender();
|
|
526
|
+
};
|
|
527
|
+
const unsubscribe = props.subscribe(sync);
|
|
528
|
+
const unsubscribeCopilot = props.copilotUsageSubscribe(sync);
|
|
529
|
+
const timer = setInterval(sync, 1e3);
|
|
530
|
+
onCleanup(() => {
|
|
531
|
+
unsubscribe();
|
|
532
|
+
unsubscribeCopilot();
|
|
533
|
+
clearInterval(timer);
|
|
534
|
+
});
|
|
535
|
+
return /* @__PURE__ */ jsx(
|
|
536
|
+
"text",
|
|
537
|
+
{
|
|
538
|
+
ref: (ref) => {
|
|
539
|
+
text = ref;
|
|
540
|
+
sync();
|
|
541
|
+
},
|
|
542
|
+
onMouseDown: toggle,
|
|
543
|
+
fg: props.api.theme.current.textMuted,
|
|
544
|
+
children: ""
|
|
545
|
+
}
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
function renderCopilotUsageSidebar(row, error, api, titleAttributes, collapsed) {
|
|
549
|
+
const chunks = [
|
|
550
|
+
textChunk(`${collapsed ? "\u25B6" : "\u25BC"} Copilot
|
|
551
|
+
`, api.theme.current.text, titleAttributes)
|
|
552
|
+
];
|
|
553
|
+
if (!collapsed) {
|
|
554
|
+
if (row) {
|
|
555
|
+
const lines = formatCopilotUsageRow(row).split("\n");
|
|
556
|
+
for (const [index, line] of lines.entries()) {
|
|
557
|
+
if (index > 0) chunks.push(textChunk("\n"));
|
|
558
|
+
chunks.push(textChunk(line, api.theme.current.textMuted));
|
|
559
|
+
}
|
|
560
|
+
} else if (error) {
|
|
561
|
+
chunks.push(textChunk(`Copilot: ${error}`, api.theme.current.error));
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return new StyledText(chunks);
|
|
565
|
+
}
|
|
412
566
|
function SubagentSidebar(props) {
|
|
413
567
|
let text;
|
|
414
568
|
const [collapsed, setCollapsed] = createSignal(false);
|
|
@@ -643,12 +797,19 @@ var tui = async (api, options) => {
|
|
|
643
797
|
const metricListeners = createListenerRegistry();
|
|
644
798
|
const subagentListeners = createListenerRegistry();
|
|
645
799
|
const goUsageListeners = createListenerRegistry();
|
|
800
|
+
const copilotUsageListeners = createListenerRegistry();
|
|
646
801
|
const hydratedSessions = /* @__PURE__ */ new Set();
|
|
647
802
|
const goProviderTracker = createGoProviderTracker();
|
|
803
|
+
const copilotProviderTracker = createCopilotProviderTracker();
|
|
648
804
|
const goUsage = createGoUsageRefresher(config.goUsage);
|
|
805
|
+
const copilotToken = resolveCopilotToken(config.copilotUsage);
|
|
806
|
+
const copilotUsage = createCopilotUsageRefresher(config.copilotUsage, copilotToken);
|
|
649
807
|
const refreshGoUsage = async () => {
|
|
650
808
|
if (await goUsage.refresh()) goUsageListeners.notify();
|
|
651
809
|
};
|
|
810
|
+
const refreshCopilotUsage = async () => {
|
|
811
|
+
if (await copilotUsage.refresh()) copilotUsageListeners.notify();
|
|
812
|
+
};
|
|
652
813
|
const hydrateSessionMetrics = async (sessionID) => {
|
|
653
814
|
if (!isSessionID2(sessionID) || hydratedSessions.has(sessionID)) return;
|
|
654
815
|
hydratedSessions.add(sessionID);
|
|
@@ -659,6 +820,7 @@ var tui = async (api, options) => {
|
|
|
659
820
|
const info = message.info;
|
|
660
821
|
const providerID = info.providerID;
|
|
661
822
|
goProviderTracker.record(sessionID, typeof providerID === "string" ? providerID : void 0);
|
|
823
|
+
copilotProviderTracker.record(sessionID, typeof providerID === "string" ? providerID : void 0);
|
|
662
824
|
if (info.role !== "assistant" || typeof info.time.completed !== "number") continue;
|
|
663
825
|
const input = {
|
|
664
826
|
sessionID: info.sessionID,
|
|
@@ -694,6 +856,7 @@ var tui = async (api, options) => {
|
|
|
694
856
|
const sessionID = info.sessionID ?? evt.properties.sessionID;
|
|
695
857
|
const providerID = info.providerID ?? info.model?.providerID;
|
|
696
858
|
goProviderTracker.record(sessionID, typeof providerID === "string" ? providerID : void 0);
|
|
859
|
+
copilotProviderTracker.record(sessionID, typeof providerID === "string" ? providerID : void 0);
|
|
697
860
|
if (info.role !== "assistant") return;
|
|
698
861
|
const messageInput = {
|
|
699
862
|
sessionID: info.sessionID ?? evt.properties.sessionID,
|
|
@@ -793,6 +956,7 @@ var tui = async (api, options) => {
|
|
|
793
956
|
api,
|
|
794
957
|
sessionID: props.session_id,
|
|
795
958
|
state: metrics,
|
|
959
|
+
subagentState: subagents,
|
|
796
960
|
subscribe: metricListeners.subscribe,
|
|
797
961
|
hydrate: () => void hydrateSessionMetrics(props.session_id)
|
|
798
962
|
}
|
|
@@ -810,6 +974,20 @@ var tui = async (api, options) => {
|
|
|
810
974
|
refresh: () => void refreshGoUsage()
|
|
811
975
|
}
|
|
812
976
|
),
|
|
977
|
+
/* @__PURE__ */ jsx(
|
|
978
|
+
CopilotUsageSidebar,
|
|
979
|
+
{
|
|
980
|
+
api,
|
|
981
|
+
state: copilotUsage.state,
|
|
982
|
+
config,
|
|
983
|
+
token: copilotToken,
|
|
984
|
+
tracker: copilotProviderTracker,
|
|
985
|
+
sessionID: props.session_id,
|
|
986
|
+
subscribe: metricListeners.subscribe,
|
|
987
|
+
copilotUsageSubscribe: copilotUsageListeners.subscribe,
|
|
988
|
+
refresh: () => void refreshCopilotUsage()
|
|
989
|
+
}
|
|
990
|
+
),
|
|
813
991
|
/* @__PURE__ */ jsx(
|
|
814
992
|
SubagentSidebar,
|
|
815
993
|
{
|
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.
|
|
4
|
+
"version": "0.4.0",
|
|
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",
|