@marckrenn/pi-sub-bar 1.0.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/src/paths.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Shared path helpers for sub-bar settings storage.
3
+ */
4
+
5
+ import { dirname, join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ export function getExtensionDir(): string {
9
+ return join(dirname(fileURLToPath(import.meta.url)), "..");
10
+ }
11
+
12
+ export function getSettingsPath(): string {
13
+ return join(getExtensionDir(), "settings.json");
14
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Provider-specific extra usage lines (non-window info).
3
+ */
4
+
5
+ import type { UsageSnapshot } from "../types.js";
6
+ import type { Settings } from "../settings-types.js";
7
+ import { PROVIDER_METADATA, type UsageExtra } from "./metadata.js";
8
+
9
+ export type { UsageExtra } from "./metadata.js";
10
+
11
+ export function getUsageExtras(
12
+ usage: UsageSnapshot,
13
+ settings?: Settings,
14
+ modelId?: string
15
+ ): UsageExtra[] {
16
+ const handler = PROVIDER_METADATA[usage.provider]?.getExtras;
17
+ if (handler) {
18
+ return handler(usage, settings, modelId);
19
+ }
20
+ return [];
21
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Provider metadata shared across the extension.
3
+ */
4
+
5
+ import type { RateWindow, UsageSnapshot, ProviderName } from "../types.js";
6
+ import type { Settings } from "../settings-types.js";
7
+ import { getModelMultiplier } from "../utils.js";
8
+ import { PROVIDER_METADATA as BASE_METADATA, type ProviderMetadata as BaseProviderMetadata } from "@marckrenn/pi-sub-shared";
9
+
10
+ export { PROVIDERS, PROVIDER_DISPLAY_NAMES } from "@marckrenn/pi-sub-shared";
11
+ export type { ProviderStatusConfig, ProviderDetectionConfig } from "@marckrenn/pi-sub-shared";
12
+
13
+ export interface UsageExtra {
14
+ label: string;
15
+ }
16
+
17
+ export interface ProviderMetadata extends BaseProviderMetadata {
18
+ isWindowVisible?: (usage: UsageSnapshot, window: RateWindow, settings?: Settings) => boolean;
19
+ getExtras?: (usage: UsageSnapshot, settings?: Settings, modelId?: string) => UsageExtra[];
20
+ }
21
+
22
+ const anthropicWindowVisible: ProviderMetadata["isWindowVisible"] = (_usage, window, settings) => {
23
+ if (!settings) return true;
24
+ const ps = settings.providers.anthropic;
25
+ if (window.label === "5h") return ps.windows.show5h;
26
+ if (window.label === "7d") return ps.windows.show7d;
27
+ if (window.label.startsWith("Extra [")) return ps.windows.showExtra;
28
+ return true;
29
+ };
30
+
31
+ const copilotWindowVisible: ProviderMetadata["isWindowVisible"] = (_usage, window, settings) => {
32
+ if (!settings) return true;
33
+ const ps = settings.providers.copilot;
34
+ if (window.label === "Month") return ps.windows.showMonth;
35
+ return true;
36
+ };
37
+
38
+ const geminiWindowVisible: ProviderMetadata["isWindowVisible"] = (_usage, window, settings) => {
39
+ if (!settings) return true;
40
+ const ps = settings.providers.gemini;
41
+ if (window.label === "Pro") return ps.windows.showPro;
42
+ if (window.label === "Flash") return ps.windows.showFlash;
43
+ return true;
44
+ };
45
+
46
+ const antigravityWindowVisible: ProviderMetadata["isWindowVisible"] = (_usage, window, settings) => {
47
+ if (!settings) return true;
48
+ const ps = settings.providers.antigravity;
49
+ if (window.label === "Claude") return ps.windows.showClaude;
50
+ if (window.label === "Pro") return ps.windows.showPro;
51
+ if (window.label === "Flash") return ps.windows.showFlash;
52
+ return true;
53
+ };
54
+
55
+ const codexWindowVisible: ProviderMetadata["isWindowVisible"] = (_usage, window, settings) => {
56
+ if (!settings) return true;
57
+ const ps = settings.providers.codex;
58
+ if (window.label.match(/^\d+h$/)) return ps.windows.showPrimary;
59
+ if (window.label === "Day" || window.label === "Week") return ps.windows.showSecondary;
60
+ return true;
61
+ };
62
+
63
+ const kiroWindowVisible: ProviderMetadata["isWindowVisible"] = (_usage, window, settings) => {
64
+ if (!settings) return true;
65
+ const ps = settings.providers.kiro;
66
+ if (window.label === "Credits") return ps.windows.showCredits;
67
+ return true;
68
+ };
69
+
70
+ const zaiWindowVisible: ProviderMetadata["isWindowVisible"] = (_usage, window, settings) => {
71
+ if (!settings) return true;
72
+ const ps = settings.providers.zai;
73
+ if (window.label === "Tokens") return ps.windows.showTokens;
74
+ if (window.label === "Monthly") return ps.windows.showMonthly;
75
+ return true;
76
+ };
77
+
78
+ const anthropicExtras: ProviderMetadata["getExtras"] = (usage, settings) => {
79
+ const extras: UsageExtra[] = [];
80
+ const showExtraWindow = settings?.providers.anthropic.windows.showExtra ?? true;
81
+ if (showExtraWindow && usage.extraUsageEnabled === false) {
82
+ extras.push({ label: "Extra [off]" });
83
+ }
84
+ return extras;
85
+ };
86
+
87
+ const copilotExtras: ProviderMetadata["getExtras"] = (usage, settings, modelId) => {
88
+ const extras: UsageExtra[] = [];
89
+ const showMultiplier = settings?.providers.copilot.showMultiplier ?? true;
90
+ const showRequestsLeft = settings?.providers.copilot.showRequestsLeft ?? true;
91
+ if (!showMultiplier) return extras;
92
+
93
+ const multiplier = getModelMultiplier(modelId);
94
+ const remaining = usage.requestsRemaining;
95
+ if (multiplier !== undefined) {
96
+ let multiplierStr = `Model multiplier: ${multiplier}x`;
97
+ if (showRequestsLeft && remaining !== undefined) {
98
+ const leftCount = Math.floor(remaining / Math.max(multiplier, 0.0001));
99
+ multiplierStr += ` (${leftCount} req. left)`;
100
+ }
101
+ extras.push({ label: multiplierStr });
102
+ }
103
+ return extras;
104
+ };
105
+
106
+ export const PROVIDER_METADATA: Record<ProviderName, ProviderMetadata> = {
107
+ anthropic: {
108
+ ...BASE_METADATA.anthropic,
109
+ isWindowVisible: anthropicWindowVisible,
110
+ getExtras: anthropicExtras,
111
+ },
112
+ copilot: {
113
+ ...BASE_METADATA.copilot,
114
+ isWindowVisible: copilotWindowVisible,
115
+ getExtras: copilotExtras,
116
+ },
117
+ gemini: {
118
+ ...BASE_METADATA.gemini,
119
+ isWindowVisible: geminiWindowVisible,
120
+ },
121
+ antigravity: {
122
+ ...BASE_METADATA.antigravity,
123
+ isWindowVisible: antigravityWindowVisible,
124
+ },
125
+ codex: {
126
+ ...BASE_METADATA.codex,
127
+ isWindowVisible: codexWindowVisible,
128
+ },
129
+ kiro: {
130
+ ...BASE_METADATA.kiro,
131
+ isWindowVisible: kiroWindowVisible,
132
+ },
133
+ zai: {
134
+ ...BASE_METADATA.zai,
135
+ isWindowVisible: zaiWindowVisible,
136
+ },
137
+ };
@@ -0,0 +1,328 @@
1
+ /**
2
+ * Provider-specific settings helpers.
3
+ */
4
+
5
+ import type { SettingItem } from "@mariozechner/pi-tui";
6
+ import type { ProviderName } from "../types.js";
7
+ import type {
8
+ Settings,
9
+ BaseProviderSettings,
10
+ AnthropicProviderSettings,
11
+ CopilotProviderSettings,
12
+ GeminiProviderSettings,
13
+ AntigravityProviderSettings,
14
+ CodexProviderSettings,
15
+ KiroProviderSettings,
16
+ ZaiProviderSettings,
17
+ } from "../settings-types.js";
18
+
19
+ function buildBaseProviderItems(ps: BaseProviderSettings): SettingItem[] {
20
+ return [
21
+ {
22
+ id: "showStatus",
23
+ label: "Show Status Indicator",
24
+ currentValue: ps.showStatus ? "on" : "off",
25
+ values: ["on", "off"],
26
+ description: "Show status indicator for this provider.",
27
+ },
28
+ ];
29
+ }
30
+
31
+ function applyBaseProviderSetting(ps: BaseProviderSettings, id: string, value: string): boolean {
32
+ switch (id) {
33
+ case "showStatus":
34
+ ps.showStatus = value === "on";
35
+ return true;
36
+ default:
37
+ return false;
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Build settings items for a specific provider.
43
+ */
44
+ export function buildProviderSettingsItems(settings: Settings, provider: ProviderName): SettingItem[] {
45
+ const ps = settings.providers[provider];
46
+ const items: SettingItem[] = [...buildBaseProviderItems(ps)];
47
+
48
+ if (provider === "anthropic") {
49
+ const anthroSettings = ps as AnthropicProviderSettings;
50
+ items.push(
51
+ {
52
+ id: "show5h",
53
+ label: "Show 5h Window",
54
+ currentValue: anthroSettings.windows.show5h ? "on" : "off",
55
+ values: ["on", "off"],
56
+ description: "Show the 5-hour usage window.",
57
+ },
58
+ {
59
+ id: "show7d",
60
+ label: "Show 7d Window",
61
+ currentValue: anthroSettings.windows.show7d ? "on" : "off",
62
+ values: ["on", "off"],
63
+ description: "Show the 7-day usage window.",
64
+ },
65
+ {
66
+ id: "showExtra",
67
+ label: "Show Extra Window",
68
+ currentValue: anthroSettings.windows.showExtra ? "on" : "off",
69
+ values: ["on", "off"],
70
+ description: "Show the extra usage window.",
71
+ },
72
+ );
73
+ }
74
+
75
+ if (provider === "copilot") {
76
+ const copilotSettings = ps as CopilotProviderSettings;
77
+ items.push(
78
+ {
79
+ id: "showMultiplier",
80
+ label: "Show Model Multiplier",
81
+ currentValue: copilotSettings.showMultiplier ? "on" : "off",
82
+ values: ["on", "off"],
83
+ description: "Show request cost multiplier for the current model.",
84
+ },
85
+ {
86
+ id: "showRequestsLeft",
87
+ label: "Show Requests Remaining",
88
+ currentValue: copilotSettings.showRequestsLeft ? "on" : "off",
89
+ values: ["on", "off"],
90
+ description: "Estimate requests remaining based on the multiplier.",
91
+ },
92
+ {
93
+ id: "quotaDisplay",
94
+ label: "Show Quota in",
95
+ currentValue: copilotSettings.quotaDisplay,
96
+ values: ["percentage", "requests"],
97
+ description: "Display Copilot usage as percentage or requests.",
98
+ },
99
+ {
100
+ id: "showMonth",
101
+ label: "Show Month Window",
102
+ currentValue: copilotSettings.windows.showMonth ? "on" : "off",
103
+ values: ["on", "off"],
104
+ description: "Show the monthly usage window.",
105
+ },
106
+ );
107
+ }
108
+
109
+ if (provider === "gemini") {
110
+ const geminiSettings = ps as GeminiProviderSettings;
111
+ items.push(
112
+ {
113
+ id: "showPro",
114
+ label: "Show Pro Window",
115
+ currentValue: geminiSettings.windows.showPro ? "on" : "off",
116
+ values: ["on", "off"],
117
+ description: "Show the Pro quota window.",
118
+ },
119
+ {
120
+ id: "showFlash",
121
+ label: "Show Flash Window",
122
+ currentValue: geminiSettings.windows.showFlash ? "on" : "off",
123
+ values: ["on", "off"],
124
+ description: "Show the Flash quota window.",
125
+ },
126
+ );
127
+ }
128
+
129
+ if (provider === "antigravity") {
130
+ const antigravitySettings = ps as AntigravityProviderSettings;
131
+ items.push(
132
+ {
133
+ id: "showClaude",
134
+ label: "Show Claude Window",
135
+ currentValue: antigravitySettings.windows.showClaude ? "on" : "off",
136
+ values: ["on", "off"],
137
+ description: "Show the Claude quota window.",
138
+ },
139
+ {
140
+ id: "showPro",
141
+ label: "Show Pro Window",
142
+ currentValue: antigravitySettings.windows.showPro ? "on" : "off",
143
+ values: ["on", "off"],
144
+ description: "Show the Gemini Pro quota window.",
145
+ },
146
+ {
147
+ id: "showFlash",
148
+ label: "Show Flash Window",
149
+ currentValue: antigravitySettings.windows.showFlash ? "on" : "off",
150
+ values: ["on", "off"],
151
+ description: "Show the Gemini Flash quota window.",
152
+ },
153
+ );
154
+ }
155
+
156
+ if (provider === "codex") {
157
+ const codexSettings = ps as CodexProviderSettings;
158
+ items.push(
159
+ {
160
+ id: "invertUsage",
161
+ label: "Invert Usage",
162
+ currentValue: codexSettings.invertUsage ? "on" : "off",
163
+ values: ["on", "off"],
164
+ description: "Show remaining-style usage for Codex.",
165
+ },
166
+ {
167
+ id: "showPrimary",
168
+ label: "Show Primary Window",
169
+ currentValue: codexSettings.windows.showPrimary ? "on" : "off",
170
+ values: ["on", "off"],
171
+ description: "Show the primary usage window.",
172
+ },
173
+ {
174
+ id: "showSecondary",
175
+ label: "Show Secondary Window",
176
+ currentValue: codexSettings.windows.showSecondary ? "on" : "off",
177
+ values: ["on", "off"],
178
+ description: "Show secondary windows (day/week).",
179
+ },
180
+ );
181
+ }
182
+
183
+ if (provider === "kiro") {
184
+ const kiroSettings = ps as KiroProviderSettings;
185
+ items.push({
186
+ id: "showCredits",
187
+ label: "Show Credits Window",
188
+ currentValue: kiroSettings.windows.showCredits ? "on" : "off",
189
+ values: ["on", "off"],
190
+ description: "Show the credits usage window.",
191
+ });
192
+ }
193
+
194
+ if (provider === "zai") {
195
+ const zaiSettings = ps as ZaiProviderSettings;
196
+ items.push(
197
+ {
198
+ id: "showTokens",
199
+ label: "Show Tokens Window",
200
+ currentValue: zaiSettings.windows.showTokens ? "on" : "off",
201
+ values: ["on", "off"],
202
+ description: "Show the tokens usage window.",
203
+ },
204
+ {
205
+ id: "showMonthly",
206
+ label: "Show Monthly Window",
207
+ currentValue: zaiSettings.windows.showMonthly ? "on" : "off",
208
+ values: ["on", "off"],
209
+ description: "Show the monthly usage window.",
210
+ },
211
+ );
212
+ }
213
+
214
+ return items;
215
+ }
216
+
217
+ /**
218
+ * Apply a provider settings change in-place.
219
+ */
220
+ export function applyProviderSettingsChange(
221
+ settings: Settings,
222
+ provider: ProviderName,
223
+ id: string,
224
+ value: string
225
+ ): Settings {
226
+ const ps = settings.providers[provider];
227
+ if (applyBaseProviderSetting(ps, id, value)) {
228
+ return settings;
229
+ }
230
+
231
+ if (provider === "anthropic") {
232
+ const anthroSettings = ps as AnthropicProviderSettings;
233
+ switch (id) {
234
+ case "show5h":
235
+ anthroSettings.windows.show5h = value === "on";
236
+ break;
237
+ case "show7d":
238
+ anthroSettings.windows.show7d = value === "on";
239
+ break;
240
+ case "showExtra":
241
+ anthroSettings.windows.showExtra = value === "on";
242
+ break;
243
+ }
244
+ }
245
+
246
+ if (provider === "copilot") {
247
+ const copilotSettings = ps as CopilotProviderSettings;
248
+ switch (id) {
249
+ case "showMultiplier":
250
+ copilotSettings.showMultiplier = value === "on";
251
+ break;
252
+ case "showRequestsLeft":
253
+ copilotSettings.showRequestsLeft = value === "on";
254
+ break;
255
+ case "quotaDisplay":
256
+ copilotSettings.quotaDisplay = value as "percentage" | "requests";
257
+ break;
258
+ case "showMonth":
259
+ copilotSettings.windows.showMonth = value === "on";
260
+ break;
261
+ }
262
+ }
263
+
264
+ if (provider === "gemini") {
265
+ const geminiSettings = ps as GeminiProviderSettings;
266
+ switch (id) {
267
+ case "showPro":
268
+ geminiSettings.windows.showPro = value === "on";
269
+ break;
270
+ case "showFlash":
271
+ geminiSettings.windows.showFlash = value === "on";
272
+ break;
273
+ }
274
+ }
275
+
276
+ if (provider === "antigravity") {
277
+ const antigravitySettings = ps as AntigravityProviderSettings;
278
+ switch (id) {
279
+ case "showClaude":
280
+ antigravitySettings.windows.showClaude = value === "on";
281
+ break;
282
+ case "showPro":
283
+ antigravitySettings.windows.showPro = value === "on";
284
+ break;
285
+ case "showFlash":
286
+ antigravitySettings.windows.showFlash = value === "on";
287
+ break;
288
+ }
289
+ }
290
+
291
+ if (provider === "codex") {
292
+ const codexSettings = ps as CodexProviderSettings;
293
+ switch (id) {
294
+ case "invertUsage":
295
+ codexSettings.invertUsage = value === "on";
296
+ break;
297
+ case "showPrimary":
298
+ codexSettings.windows.showPrimary = value === "on";
299
+ break;
300
+ case "showSecondary":
301
+ codexSettings.windows.showSecondary = value === "on";
302
+ break;
303
+ }
304
+ }
305
+
306
+ if (provider === "kiro") {
307
+ const kiroSettings = ps as KiroProviderSettings;
308
+ switch (id) {
309
+ case "showCredits":
310
+ kiroSettings.windows.showCredits = value === "on";
311
+ break;
312
+ }
313
+ }
314
+
315
+ if (provider === "zai") {
316
+ const zaiSettings = ps as ZaiProviderSettings;
317
+ switch (id) {
318
+ case "showTokens":
319
+ zaiSettings.windows.showTokens = value === "on";
320
+ break;
321
+ case "showMonthly":
322
+ zaiSettings.windows.showMonthly = value === "on";
323
+ break;
324
+ }
325
+ }
326
+
327
+ return settings;
328
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Provider-specific window visibility rules.
3
+ */
4
+
5
+ import type { RateWindow, UsageSnapshot } from "../types.js";
6
+ import type { Settings } from "../settings-types.js";
7
+ import { PROVIDER_METADATA } from "./metadata.js";
8
+
9
+ /**
10
+ * Check if a window should be shown based on settings.
11
+ */
12
+ export function shouldShowWindow(usage: UsageSnapshot, window: RateWindow, settings?: Settings): boolean {
13
+ const handler = PROVIDER_METADATA[usage.provider]?.isWindowVisible;
14
+ if (handler) {
15
+ return handler(usage, window, settings);
16
+ }
17
+ return true;
18
+ }