@a-r-m-i-n/opencode-openai-usage 0.1.0 → 0.1.1
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/tui.js +131 -61
- package/package.json +3 -2
package/dist/tui.js
CHANGED
|
@@ -8,18 +8,25 @@ import {
|
|
|
8
8
|
} from "./chunk-SR64YZVV.js";
|
|
9
9
|
|
|
10
10
|
// src/tui.tsx
|
|
11
|
+
import { memo as _$memo } from "@opentui/solid";
|
|
12
|
+
import { createTextNode as _$createTextNode } from "@opentui/solid";
|
|
13
|
+
import { insertNode as _$insertNode } from "@opentui/solid";
|
|
14
|
+
import { effect as _$effect } from "@opentui/solid";
|
|
15
|
+
import { insert as _$insert } from "@opentui/solid";
|
|
16
|
+
import { setProp as _$setProp } from "@opentui/solid";
|
|
17
|
+
import { createElement as _$createElement } from "@opentui/solid";
|
|
11
18
|
import { createRequire } from "module";
|
|
12
19
|
import { createTextAttributes } from "@opentui/core";
|
|
13
20
|
import { createSignal } from "solid-js";
|
|
14
|
-
import { jsx, jsxs } from "@opentui/solid/jsx-runtime";
|
|
15
21
|
var id = "openai-usage-tui";
|
|
16
22
|
var CACHE_SYNC_MS = 5e3;
|
|
17
|
-
var DIM_ATTRIBUTES = createTextAttributes({
|
|
23
|
+
var DIM_ATTRIBUTES = createTextAttributes({
|
|
24
|
+
dim: true
|
|
25
|
+
});
|
|
18
26
|
var BAR_WIDTH = 20;
|
|
19
27
|
var BAR_EMPTY_COLOR = "#6b7280";
|
|
20
28
|
var BAR_LABEL_DARK_COLOR = "#111827";
|
|
21
29
|
var BAR_LABEL_LIGHT_COLOR = "#f9fafb";
|
|
22
|
-
var SIDEBAR_VERSION_COLOR = "#9ca3af";
|
|
23
30
|
var SIDEBAR_INVERT_KV_KEY = "openai-usage.sidebar.invert";
|
|
24
31
|
var SIDEBAR_VISIBLE_KV_KEY = "openai-usage.sidebar.visible";
|
|
25
32
|
var require2 = createRequire(import.meta.url);
|
|
@@ -37,7 +44,11 @@ function readPluginManifest() {
|
|
|
37
44
|
homepage
|
|
38
45
|
};
|
|
39
46
|
} catch {
|
|
40
|
-
return {
|
|
47
|
+
return {
|
|
48
|
+
name: null,
|
|
49
|
+
version: null,
|
|
50
|
+
homepage: null
|
|
51
|
+
};
|
|
41
52
|
}
|
|
42
53
|
}
|
|
43
54
|
function formatPercent(percent) {
|
|
@@ -78,14 +89,32 @@ function renderProgressBar(percent, labelSuffix) {
|
|
|
78
89
|
const label = `${formatPercent(percent)} ${labelSuffix}`;
|
|
79
90
|
const labelStart = Math.max(0, Math.floor((BAR_WIDTH - label.length) / 2));
|
|
80
91
|
const labelEnd = labelStart + label.length;
|
|
81
|
-
return Array.from({
|
|
92
|
+
return Array.from({
|
|
93
|
+
length: BAR_WIDTH
|
|
94
|
+
}, (_, index) => {
|
|
82
95
|
const isFilled = index < barSegments.filled;
|
|
83
96
|
const isLabelCell = index >= labelStart && index < labelEnd;
|
|
84
97
|
const underlyingColor = isFilled ? barFillColor : BAR_EMPTY_COLOR;
|
|
85
98
|
if (isLabelCell) {
|
|
86
|
-
return
|
|
99
|
+
return (() => {
|
|
100
|
+
var _el$ = _$createElement("text");
|
|
101
|
+
_$setProp(_el$, "bg", underlyingColor);
|
|
102
|
+
_$insert(_el$, () => label[index - labelStart]);
|
|
103
|
+
_$effect((_$p) => _$setProp(_el$, "fg", isFilled ? getBarLabelColor(barFillColor) : BAR_LABEL_LIGHT_COLOR, _$p));
|
|
104
|
+
return _el$;
|
|
105
|
+
})();
|
|
87
106
|
}
|
|
88
|
-
return isFilled ?
|
|
107
|
+
return isFilled ? (() => {
|
|
108
|
+
var _el$2 = _$createElement("text");
|
|
109
|
+
_$insertNode(_el$2, _$createTextNode(`\u2588`));
|
|
110
|
+
_$setProp(_el$2, "fg", underlyingColor);
|
|
111
|
+
return _el$2;
|
|
112
|
+
})() : (() => {
|
|
113
|
+
var _el$4 = _$createElement("text");
|
|
114
|
+
_$insertNode(_el$4, _$createTextNode(` `));
|
|
115
|
+
_$setProp(_el$4, "bg", "#6b7280");
|
|
116
|
+
return _el$4;
|
|
117
|
+
})();
|
|
89
118
|
});
|
|
90
119
|
}
|
|
91
120
|
var module = {
|
|
@@ -93,9 +122,7 @@ var module = {
|
|
|
93
122
|
tui: async (api, rawOptions) => {
|
|
94
123
|
const stateDir = getOpenCodeStateDir();
|
|
95
124
|
const options = rawOptions ?? {};
|
|
96
|
-
const [sidebarVisible, setSidebarVisible] = createSignal(
|
|
97
|
-
api.kv.get(SIDEBAR_VISIBLE_KV_KEY, true) !== false
|
|
98
|
-
);
|
|
125
|
+
const [sidebarVisible, setSidebarVisible] = createSignal(api.kv.get(SIDEBAR_VISIBLE_KV_KEY, true) !== false);
|
|
99
126
|
const [invert, setInvert] = createSignal(api.kv.get(SIDEBAR_INVERT_KV_KEY, options.invert === true) === true);
|
|
100
127
|
const [state, setState] = createSignal(await readUsageState(stateDir));
|
|
101
128
|
const [open, setOpen] = createSignal(true);
|
|
@@ -118,12 +145,10 @@ var module = {
|
|
|
118
145
|
await syncState();
|
|
119
146
|
const latestState = state();
|
|
120
147
|
setState(latestState);
|
|
121
|
-
api.ui.dialog.replace(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
})
|
|
126
|
-
);
|
|
148
|
+
api.ui.dialog.replace(() => api.ui.DialogAlert({
|
|
149
|
+
title: "OpenAI Usage",
|
|
150
|
+
message: formatCommandSummary(latestState, PACKAGE_NAME, PLUGIN_VERSION, PACKAGE_HOMEPAGE)
|
|
151
|
+
}));
|
|
127
152
|
};
|
|
128
153
|
const toggleSidebarInvert = () => {
|
|
129
154
|
const nextInvert = !invert();
|
|
@@ -168,39 +193,90 @@ var module = {
|
|
|
168
193
|
return null;
|
|
169
194
|
}
|
|
170
195
|
const usageDisplay = getUsageDisplay(window.usedPercent, invert());
|
|
171
|
-
return
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
196
|
+
return (() => {
|
|
197
|
+
var _el$6 = _$createElement("box"), _el$7 = _$createElement("box"), _el$8 = _$createElement("text"), _el$9 = _$createElement("text");
|
|
198
|
+
_$insertNode(_el$6, _el$7);
|
|
199
|
+
_$setProp(_el$6, "flexDirection", "column");
|
|
200
|
+
_$setProp(_el$6, "gap", 0);
|
|
201
|
+
_$setProp(_el$6, "padding", 0);
|
|
202
|
+
_$setProp(_el$6, "margin", 0);
|
|
203
|
+
_$insertNode(_el$7, _el$8);
|
|
204
|
+
_$insertNode(_el$7, _el$9);
|
|
205
|
+
_$setProp(_el$7, "flexDirection", "row");
|
|
206
|
+
_$setProp(_el$7, "gap", 0);
|
|
207
|
+
_$setProp(_el$7, "padding", 0);
|
|
208
|
+
_$setProp(_el$7, "margin", 0);
|
|
209
|
+
_$insert(_el$8, () => `${formatWindowLabel(window.windowDurationMins)} `);
|
|
210
|
+
_$insert(_el$7, () => renderProgressBar(usageDisplay.percent, usageDisplay.label), _el$9);
|
|
211
|
+
_$setProp(_el$9, "attributes", DIM_ATTRIBUTES);
|
|
212
|
+
_$insert(_el$9, () => ` Reset: ${formatRelativeDuration(window.resetsAt)}`);
|
|
213
|
+
return _el$6;
|
|
214
|
+
})();
|
|
176
215
|
};
|
|
177
|
-
const renderSidebarHeader = () =>
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
216
|
+
const renderSidebarHeader = () => (() => {
|
|
217
|
+
var _el$0 = _$createElement("box"), _el$1 = _$createElement("text");
|
|
218
|
+
_$insertNode(_el$0, _el$1);
|
|
219
|
+
_$setProp(_el$0, "flexDirection", "row");
|
|
220
|
+
_$setProp(_el$0, "gap", 0);
|
|
221
|
+
_$setProp(_el$0, "padding", 0);
|
|
222
|
+
_$setProp(_el$0, "margin", 0);
|
|
223
|
+
_$setProp(_el$0, "onMouseDown", () => setOpen(!open()));
|
|
224
|
+
_$insert(_el$1, () => open() ? "\u25BC OpenAI Usage" : "\u25B6 OpenAI Usage");
|
|
225
|
+
_$insert(_el$0, PLUGIN_VERSION ? (() => {
|
|
226
|
+
var _el$10 = _$createElement("text");
|
|
227
|
+
_$setProp(_el$10, "fg", "#9ca3af");
|
|
228
|
+
_$setProp(_el$10, "attributes", DIM_ATTRIBUTES);
|
|
229
|
+
_$insert(_el$10, ` ${PLUGIN_VERSION}`);
|
|
230
|
+
return _el$10;
|
|
231
|
+
})() : null, null);
|
|
232
|
+
return _el$0;
|
|
233
|
+
})();
|
|
181
234
|
const renderSidebarBody = () => {
|
|
182
235
|
const currentState = state();
|
|
183
236
|
if (currentState.error && !currentState.primary && !currentState.secondary) {
|
|
184
|
-
return
|
|
185
|
-
|
|
237
|
+
return (() => {
|
|
238
|
+
var _el$11 = _$createElement("text");
|
|
239
|
+
_$insert(_el$11, () => `Status: unavailable
|
|
240
|
+
Error: ${currentState.error}`);
|
|
241
|
+
return _el$11;
|
|
242
|
+
})();
|
|
186
243
|
}
|
|
187
244
|
if (!currentState.primary && !currentState.secondary) {
|
|
188
|
-
return
|
|
245
|
+
return (() => {
|
|
246
|
+
var _el$12 = _$createElement("text");
|
|
247
|
+
_$insertNode(_el$12, _$createTextNode(`Status: waiting for usage data`));
|
|
248
|
+
return _el$12;
|
|
249
|
+
})();
|
|
189
250
|
}
|
|
190
|
-
return
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
251
|
+
return (() => {
|
|
252
|
+
var _el$14 = _$createElement("box");
|
|
253
|
+
_$setProp(_el$14, "flexDirection", "column");
|
|
254
|
+
_$setProp(_el$14, "gap", 0);
|
|
255
|
+
_$setProp(_el$14, "padding", 0);
|
|
256
|
+
_$setProp(_el$14, "margin", 0);
|
|
257
|
+
_$insert(_el$14, () => renderSidebarWindow(currentState.primary), null);
|
|
258
|
+
_$insert(_el$14, () => renderSidebarWindow(currentState.secondary), null);
|
|
259
|
+
return _el$14;
|
|
260
|
+
})();
|
|
194
261
|
};
|
|
195
262
|
const renderSidebarContent = () => {
|
|
196
263
|
const currentState = state();
|
|
197
264
|
if (!sidebarVisible() || currentState.configured === false) {
|
|
198
265
|
return null;
|
|
199
266
|
}
|
|
200
|
-
return
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
267
|
+
return (() => {
|
|
268
|
+
var _el$15 = _$createElement("box");
|
|
269
|
+
_$setProp(_el$15, "flexDirection", "column");
|
|
270
|
+
_$setProp(_el$15, "gap", 0);
|
|
271
|
+
_$setProp(_el$15, "padding", 0);
|
|
272
|
+
_$setProp(_el$15, "margin", 0);
|
|
273
|
+
_$insert(_el$15, renderSidebarHeader, null);
|
|
274
|
+
_$insert(_el$15, (() => {
|
|
275
|
+
var _c$ = _$memo(() => !!open());
|
|
276
|
+
return () => _c$() ? renderSidebarBody() : null;
|
|
277
|
+
})(), null);
|
|
278
|
+
return _el$15;
|
|
279
|
+
})();
|
|
204
280
|
};
|
|
205
281
|
api.slots.register({
|
|
206
282
|
order: -100,
|
|
@@ -208,31 +284,25 @@ Error: ${currentState.error}` });
|
|
|
208
284
|
sidebar_content: renderSidebarContent
|
|
209
285
|
}
|
|
210
286
|
});
|
|
211
|
-
const unregisterCommand = api.command?.register(() => [
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
description: "between used/left quota",
|
|
231
|
-
category: "OpenAI Usage",
|
|
232
|
-
onSelect: toggleSidebarInvert
|
|
233
|
-
}
|
|
234
|
-
]
|
|
235
|
-
]);
|
|
287
|
+
const unregisterCommand = api.command?.register(() => [{
|
|
288
|
+
title: sidebarVisible() ? "Hide Sidebar Section" : "Show Sidebar Section",
|
|
289
|
+
value: "openai-usage.toggle-sidebar-visibility",
|
|
290
|
+
description: "show/hide sidebar entry",
|
|
291
|
+
category: "OpenAI Usage",
|
|
292
|
+
onSelect: toggleSidebarVisibility
|
|
293
|
+
}, ...state().configured === false ? [] : [{
|
|
294
|
+
title: "View status",
|
|
295
|
+
value: "openai-usage.show",
|
|
296
|
+
description: "from OpenAI's backend API",
|
|
297
|
+
category: "OpenAI Usage",
|
|
298
|
+
onSelect: showUsageDialog
|
|
299
|
+
}, {
|
|
300
|
+
title: "Toggle Display Mode",
|
|
301
|
+
value: "openai-usage.toggle-sidebar-invert",
|
|
302
|
+
description: "between used/left quota",
|
|
303
|
+
category: "OpenAI Usage",
|
|
304
|
+
onSelect: toggleSidebarInvert
|
|
305
|
+
}]]);
|
|
236
306
|
api.lifecycle.onDispose(() => {
|
|
237
307
|
unregisterCommand?.();
|
|
238
308
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a-r-m-i-n/opencode-openai-usage",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "OpenCode plugin that shows ChatGPT/OpenAI usage in the sidebar and command palette.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"./tui": "./dist/tui.js"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
|
-
"build": "tsup
|
|
32
|
+
"build": "tsup",
|
|
33
33
|
"test": "node --import tsx --test ./src/lib/openai-usage.test.ts",
|
|
34
34
|
"prepublishOnly": "npm run build"
|
|
35
35
|
},
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"solid-js": "1.9.12"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
+
"esbuild-plugin-solid": "^0.6.0",
|
|
44
45
|
"tsup": "^8.3.6",
|
|
45
46
|
"tsx": "^4.19.2",
|
|
46
47
|
"typescript": "^5.8.3"
|