@yinxe/opencode-tui-usage 0.0.7 → 0.0.8
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/context-usage.d.ts +9 -0
- package/dist/context-usage.d.ts.map +1 -0
- package/dist/context-usage.jsx +54 -0
- package/dist/formatters.d.ts +5 -0
- package/dist/formatters.d.ts.map +1 -0
- package/dist/formatters.js +30 -0
- package/dist/quota/service.d.ts.map +1 -1
- package/dist/quota/service.js +1 -2
- package/dist/tokens-usage.d.ts +11 -0
- package/dist/tokens-usage.d.ts.map +1 -1
- package/dist/tokens-usage.jsx +2 -14
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.jsx +2 -0
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.jsx +4 -27
- package/package.json +1 -1
- package/dist/quota/providers/minimax-io.d.ts +0 -2
- package/dist/quota/providers/minimax-io.d.ts.map +0 -1
- package/dist/quota/providers/minimax-io.js +0 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** @jsxImportSource @opentui/solid */
|
|
2
|
+
import type { JSX } from "solid-js";
|
|
3
|
+
import type { TuiPluginApi } from "@opencode-ai/plugin/tui";
|
|
4
|
+
export interface ContextUsageViewProps {
|
|
5
|
+
api: TuiPluginApi;
|
|
6
|
+
sessionId: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function ContextUsageView(props: ContextUsageViewProps): JSX.Element;
|
|
9
|
+
//# sourceMappingURL=context-usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-usage.d.ts","sourceRoot":"","sources":["../src/context-usage.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAKpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,YAAY,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,GAAG,CAAC,OAAO,CAiE1E"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { createSignal, createEffect } from "solid-js";
|
|
2
|
+
import { Show } from "solid-js";
|
|
3
|
+
import { ProgressBar } from "./components.jsx";
|
|
4
|
+
import { formatNumber, formatPercent } from "./formatters.js";
|
|
5
|
+
export function ContextUsageView(props) {
|
|
6
|
+
const [contextData, setContextData] = createSignal(null);
|
|
7
|
+
createEffect(() => {
|
|
8
|
+
const sessionId = props.sessionId;
|
|
9
|
+
const messages = props.api.state.session.messages(sessionId);
|
|
10
|
+
if (!messages || messages.length === 0) {
|
|
11
|
+
setContextData(null);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
let latestTokens = 0;
|
|
15
|
+
let latestTime = -Infinity;
|
|
16
|
+
let limit = 0;
|
|
17
|
+
for (const msg of messages) {
|
|
18
|
+
if (msg.role !== "assistant" || !msg.tokens)
|
|
19
|
+
continue;
|
|
20
|
+
const tokens = msg.tokens.input +
|
|
21
|
+
msg.tokens.output +
|
|
22
|
+
msg.tokens.reasoning +
|
|
23
|
+
msg.tokens.cache.read +
|
|
24
|
+
msg.tokens.cache.write;
|
|
25
|
+
if (tokens <= 0)
|
|
26
|
+
continue;
|
|
27
|
+
const time = msg.time.completed ?? msg.time.created;
|
|
28
|
+
if (time > latestTime) {
|
|
29
|
+
latestTime = time;
|
|
30
|
+
latestTokens = tokens;
|
|
31
|
+
const provider = props.api.state.provider.find((p) => p.id === msg.providerID);
|
|
32
|
+
const model = provider?.models[msg.modelID];
|
|
33
|
+
limit = model?.limit?.context ?? 0;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (latestTokens === 0 || limit === 0) {
|
|
37
|
+
setContextData(null);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const percent = Math.min(100, (latestTokens / limit) * 100);
|
|
41
|
+
setContextData({ tokens: latestTokens, limit, percent });
|
|
42
|
+
});
|
|
43
|
+
return (<Show when={contextData()} fallback={<></>}>
|
|
44
|
+
<box flexDirection="column" gap={0}>
|
|
45
|
+
<box flexDirection="row" gap={2}>
|
|
46
|
+
<text fg="#a29bfe">Context:</text>
|
|
47
|
+
<text>
|
|
48
|
+
{formatNumber(contextData().tokens)} / {formatNumber(contextData().limit)} ({formatPercent(contextData().percent)})
|
|
49
|
+
</text>
|
|
50
|
+
</box>
|
|
51
|
+
<ProgressBar value={contextData().percent} color="#a29bfe" width={20}/>
|
|
52
|
+
</box>
|
|
53
|
+
</Show>);
|
|
54
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function formatNumber(n: number): string;
|
|
2
|
+
export declare function formatCost(cost: number): string;
|
|
3
|
+
export declare function formatDuration(totalSeconds: number): string;
|
|
4
|
+
export declare function formatPercent(value: number): string;
|
|
5
|
+
//# sourceMappingURL=formatters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI9C;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAa3D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function formatNumber(n) {
|
|
2
|
+
if (n >= 1000000)
|
|
3
|
+
return (n / 1000000).toFixed(1) + "M";
|
|
4
|
+
if (n >= 1000)
|
|
5
|
+
return (n / 1000).toFixed(1) + "K";
|
|
6
|
+
return n.toString();
|
|
7
|
+
}
|
|
8
|
+
export function formatCost(cost) {
|
|
9
|
+
if (cost === 0)
|
|
10
|
+
return "$0";
|
|
11
|
+
const formatted = cost.toFixed(6).replace(/\.?0+$/, "");
|
|
12
|
+
return "$" + formatted;
|
|
13
|
+
}
|
|
14
|
+
export function formatDuration(totalSeconds) {
|
|
15
|
+
if (totalSeconds < 60) {
|
|
16
|
+
return `${totalSeconds}s`;
|
|
17
|
+
}
|
|
18
|
+
if (totalSeconds < 3600) {
|
|
19
|
+
const m = Math.floor(totalSeconds / 60);
|
|
20
|
+
const s = totalSeconds % 60;
|
|
21
|
+
return `${m}:${s.toString().padStart(2, "0")}`;
|
|
22
|
+
}
|
|
23
|
+
const h = Math.floor(totalSeconds / 3600);
|
|
24
|
+
const m = Math.floor((totalSeconds % 3600) / 60);
|
|
25
|
+
const s = totalSeconds % 60;
|
|
26
|
+
return `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
|
|
27
|
+
}
|
|
28
|
+
export function formatPercent(value) {
|
|
29
|
+
return `${Math.round(value)}%`;
|
|
30
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/quota/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/quota/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAKnD,qBAAa,YAAY;IACvB,OAAO,CAAC,SAAS,CAAyC;IAC1D,OAAO,CAAC,gBAAgB,CAAwB;IAChD,OAAO,CAAC,kBAAkB,CAAuB;IACjD,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,YAAY,CAAK;;IAQzB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IAI/C,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAmBhD,qBAAqB,IAAI,MAAM,GAAG,IAAI;IAItC,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIlD,0BAA0B,IAAI,MAAM,EAAE;IAItC,0BAA0B,IAAI,MAAM,EAAE;IAIhC,UAAU,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;CAahD"}
|
package/dist/quota/service.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { readProviderConfig, getProviderConfig } from "./config.js";
|
|
2
|
-
import { MiniMaxCNQuotaProvider } from "./providers/minimax.js";
|
|
3
|
-
import { MiniMaxIOQuotaProvider } from "./providers/minimax-io.js";
|
|
2
|
+
import { MiniMaxCNQuotaProvider, MiniMaxIOQuotaProvider } from "./providers/minimax.js";
|
|
4
3
|
import { OpenCodeGoQuotaProvider } from "./providers/opencode-go.js";
|
|
5
4
|
export class QuotaService {
|
|
6
5
|
providers = new Map();
|
package/dist/tokens-usage.d.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
2
|
import type { JSX } from "solid-js";
|
|
3
3
|
import type { TuiPluginApi } from "@opencode-ai/plugin/tui";
|
|
4
|
+
export interface TokenStats {
|
|
5
|
+
providerID: string;
|
|
6
|
+
modelID: string;
|
|
7
|
+
totalCost: number;
|
|
8
|
+
input: number;
|
|
9
|
+
output: number;
|
|
10
|
+
reasoning: number;
|
|
11
|
+
cacheRead: number;
|
|
12
|
+
cacheWrite: number;
|
|
13
|
+
messageCount: number;
|
|
14
|
+
}
|
|
4
15
|
export interface TokensUsageViewProps {
|
|
5
16
|
api: TuiPluginApi;
|
|
6
17
|
sessionId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens-usage.d.ts","sourceRoot":"","sources":["../src/tokens-usage.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"tokens-usage.d.ts","sourceRoot":"","sources":["../src/tokens-usage.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAIpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,YAAY,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAYD,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,GAAG,CAAC,OAAO,CAsIxE"}
|
package/dist/tokens-usage.jsx
CHANGED
|
@@ -1,18 +1,6 @@
|
|
|
1
1
|
import { createSignal, createEffect, Show, For } from "solid-js";
|
|
2
2
|
import { Title } from "./components.jsx";
|
|
3
|
-
|
|
4
|
-
if (n >= 1000000)
|
|
5
|
-
return (n / 1000000).toFixed(1) + "M";
|
|
6
|
-
if (n >= 1000)
|
|
7
|
-
return (n / 1000).toFixed(1) + "K";
|
|
8
|
-
return n.toString();
|
|
9
|
-
}
|
|
10
|
-
function formatCost(cost) {
|
|
11
|
-
if (cost === 0)
|
|
12
|
-
return "$0";
|
|
13
|
-
const formatted = cost.toFixed(6).replace(/\.?0+$/, "");
|
|
14
|
-
return "$" + formatted;
|
|
15
|
-
}
|
|
3
|
+
import { formatNumber, formatCost } from "./formatters.js";
|
|
16
4
|
function InlineMetric(props) {
|
|
17
5
|
return (<box flexDirection="row" gap={0}>
|
|
18
6
|
<text fg={props.color}>{props.label}</text>
|
|
@@ -114,7 +102,7 @@ export function TokensUsageView(props) {
|
|
|
114
102
|
</box>
|
|
115
103
|
</Show>
|
|
116
104
|
|
|
117
|
-
<Show when={!isLoading() && stats().length >
|
|
105
|
+
<Show when={!isLoading() && stats().length > 0}>
|
|
118
106
|
<For each={stats()}>
|
|
119
107
|
{(stat) => (<box flexDirection="column" gap={0}>
|
|
120
108
|
<box flexDirection="row" gap={1}>
|
package/dist/tui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,KAAK,EAAa,eAAe,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,KAAK,EAAa,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAyC1E,QAAA,MAAM,MAAM,EAAE,eAAe,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAG3C,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/tui.jsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { UsageView } from "./usage.jsx";
|
|
2
2
|
import { SessionInfoView } from "./session-info.jsx";
|
|
3
3
|
import { TokensUsageView } from "./tokens-usage.jsx";
|
|
4
|
+
import { ContextUsageView } from "./context-usage.jsx";
|
|
4
5
|
import { QuotaService } from "./quota/service.js";
|
|
5
6
|
const id = "opencode-tui-usage-plugin";
|
|
6
7
|
const tui = async (api) => {
|
|
@@ -12,6 +13,7 @@ const tui = async (api) => {
|
|
|
12
13
|
return (<box gap={0}>
|
|
13
14
|
<UsageView quotaService={quotaService} api={api} sessionId={_props.session_id}/>
|
|
14
15
|
<SessionInfoView api={api} sessionId={_props.session_id}/>
|
|
16
|
+
<ContextUsageView api={api} sessionId={_props.session_id}/>
|
|
15
17
|
<TokensUsageView api={api} sessionId={_props.session_id}/>
|
|
16
18
|
</box>);
|
|
17
19
|
},
|
package/dist/usage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAIpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAIpD,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE;QACZ,UAAU,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;QAC1C,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QACjD,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QACnD,0BAA0B,IAAI,MAAM,EAAE,CAAC;QACvC,0BAA0B,IAAI,MAAM,EAAE,CAAC;KACxC,CAAC;IACF,GAAG,EAAE,YAAY,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAoCD,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,GAAG,CAAC,OAAO,CA2N5D"}
|
package/dist/usage.jsx
CHANGED
|
@@ -1,38 +1,15 @@
|
|
|
1
1
|
import { createSignal, createEffect, onCleanup } from "solid-js";
|
|
2
2
|
import { Title, ProgressBar } from "./components.jsx";
|
|
3
|
+
import { formatDuration } from "./formatters.js";
|
|
3
4
|
const REFRESH_INTERVAL = 60;
|
|
4
|
-
function formatDuration(totalSeconds) {
|
|
5
|
-
if (totalSeconds < 60) {
|
|
6
|
-
return `${totalSeconds}s`;
|
|
7
|
-
}
|
|
8
|
-
if (totalSeconds < 3600) {
|
|
9
|
-
const m = Math.floor(totalSeconds / 60);
|
|
10
|
-
const s = totalSeconds % 60;
|
|
11
|
-
return `${m}:${s.toString().padStart(2, "0")}`;
|
|
12
|
-
}
|
|
13
|
-
const h = Math.floor(totalSeconds / 3600);
|
|
14
|
-
const m = Math.floor((totalSeconds % 3600) / 60);
|
|
15
|
-
const s = totalSeconds % 60;
|
|
16
|
-
return `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
|
|
17
|
-
}
|
|
18
5
|
function EmptyState(props) {
|
|
19
6
|
if (!props.provider) {
|
|
20
7
|
return <text fg="#888">No LLM activity detected</text>;
|
|
21
8
|
}
|
|
22
9
|
if (!props.supported) {
|
|
23
10
|
return (<box flexDirection="column" gap={0}>
|
|
24
|
-
<text fg="#
|
|
25
|
-
<text fg="#
|
|
26
|
-
Adapter for "{props.provider}" not found.
|
|
27
|
-
</text>
|
|
28
|
-
{props.registeredProviders.length > 0 ? (<text fg="#888">
|
|
29
|
-
Registered: {props.registeredProviders.join(", ")}
|
|
30
|
-
</text>) : null}
|
|
31
|
-
{props.configuredProviders.length > 0 ? (<text fg="#888">
|
|
32
|
-
Configured: {props.configuredProviders.join(", ")}
|
|
33
|
-
</text>) : (<text fg="#888">
|
|
34
|
-
Configure provider in usage.provider.json
|
|
35
|
-
</text>)}
|
|
11
|
+
<text fg="#ff6b6b">not support provider: {props.provider}</text>
|
|
12
|
+
<text fg="#74b9ff">github.com/Yinxe/opencode-tui-usage</text>
|
|
36
13
|
</box>);
|
|
37
14
|
}
|
|
38
15
|
if (props.error) {
|
|
@@ -157,7 +134,7 @@ export function UsageView(props) {
|
|
|
157
134
|
onCleanup(() => clearInterval(id));
|
|
158
135
|
});
|
|
159
136
|
return (<box flexDirection="column" gap={0}>
|
|
160
|
-
<Title text="Usage" color="#6bcf7f"/>
|
|
137
|
+
<Title text="Usage Quota" color="#6bcf7f"/>
|
|
161
138
|
<text fg="#888">Provider: {currentProvider() ?? "Unknown"}</text>
|
|
162
139
|
{loading() ? (<>
|
|
163
140
|
<box flexDirection="column" gap={0}>
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"minimax-io.d.ts","sourceRoot":"","sources":["../../../src/quota/providers/minimax-io.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { MiniMaxIOQuotaProvider } from "./minimax.js";
|