openusage 0.1.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.
Files changed (58) hide show
  1. package/bin/openusage +91 -0
  2. package/package.json +33 -0
  3. package/plugins/amp/icon.svg +6 -0
  4. package/plugins/amp/plugin.js +175 -0
  5. package/plugins/amp/plugin.json +20 -0
  6. package/plugins/amp/plugin.test.js +365 -0
  7. package/plugins/antigravity/icon.svg +3 -0
  8. package/plugins/antigravity/plugin.js +484 -0
  9. package/plugins/antigravity/plugin.json +17 -0
  10. package/plugins/antigravity/plugin.test.js +1356 -0
  11. package/plugins/claude/icon.svg +3 -0
  12. package/plugins/claude/plugin.js +565 -0
  13. package/plugins/claude/plugin.json +28 -0
  14. package/plugins/claude/plugin.test.js +1012 -0
  15. package/plugins/codex/icon.svg +3 -0
  16. package/plugins/codex/plugin.js +673 -0
  17. package/plugins/codex/plugin.json +30 -0
  18. package/plugins/codex/plugin.test.js +1071 -0
  19. package/plugins/copilot/icon.svg +3 -0
  20. package/plugins/copilot/plugin.js +264 -0
  21. package/plugins/copilot/plugin.json +20 -0
  22. package/plugins/copilot/plugin.test.js +529 -0
  23. package/plugins/cursor/icon.svg +3 -0
  24. package/plugins/cursor/plugin.js +526 -0
  25. package/plugins/cursor/plugin.json +24 -0
  26. package/plugins/cursor/plugin.test.js +1168 -0
  27. package/plugins/factory/icon.svg +1 -0
  28. package/plugins/factory/plugin.js +407 -0
  29. package/plugins/factory/plugin.json +19 -0
  30. package/plugins/factory/plugin.test.js +833 -0
  31. package/plugins/gemini/icon.svg +4 -0
  32. package/plugins/gemini/plugin.js +413 -0
  33. package/plugins/gemini/plugin.json +20 -0
  34. package/plugins/gemini/plugin.test.js +735 -0
  35. package/plugins/jetbrains-ai-assistant/icon.svg +3 -0
  36. package/plugins/jetbrains-ai-assistant/plugin.js +357 -0
  37. package/plugins/jetbrains-ai-assistant/plugin.json +17 -0
  38. package/plugins/jetbrains-ai-assistant/plugin.test.js +338 -0
  39. package/plugins/kimi/icon.svg +3 -0
  40. package/plugins/kimi/plugin.js +358 -0
  41. package/plugins/kimi/plugin.json +19 -0
  42. package/plugins/kimi/plugin.test.js +619 -0
  43. package/plugins/minimax/icon.svg +4 -0
  44. package/plugins/minimax/plugin.js +388 -0
  45. package/plugins/minimax/plugin.json +17 -0
  46. package/plugins/minimax/plugin.test.js +943 -0
  47. package/plugins/perplexity/icon.svg +1 -0
  48. package/plugins/perplexity/plugin.js +378 -0
  49. package/plugins/perplexity/plugin.json +15 -0
  50. package/plugins/perplexity/plugin.test.js +602 -0
  51. package/plugins/windsurf/icon.svg +3 -0
  52. package/plugins/windsurf/plugin.js +218 -0
  53. package/plugins/windsurf/plugin.json +16 -0
  54. package/plugins/windsurf/plugin.test.js +455 -0
  55. package/plugins/zai/icon.svg +5 -0
  56. package/plugins/zai/plugin.js +156 -0
  57. package/plugins/zai/plugin.json +18 -0
  58. package/plugins/zai/plugin.test.js +396 -0
@@ -0,0 +1,3 @@
1
+ <svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M79.7057 21.6044C85.0857 27.2967 87.3915 35.1429 88.3522 46.0659C90.8885 46.0659 93.2711 46.6428 94.8851 48.8352L97.8826 52.9121C98.728 54.0659 99.1892 55.4505 99.1892 56.9121V67.9505C99.1833 68.6605 99.0137 69.3596 98.6938 69.9934C98.3739 70.6271 97.9122 71.1784 97.3446 71.6044C83.7791 81.5275 67.0241 89.5275 50 89.5275C31.1698 89.5275 12.2627 78.6428 2.65542 71.6044C2.08785 71.1784 1.62614 70.6271 1.30621 69.9934C0.986278 69.3596 0.816752 68.6605 0.810822 67.9505L0.810822 56.9121C0.810822 55.4505 1.27197 54.0659 2.11741 52.8736L5.11488 48.8352C6.7289 46.6428 9.1115 46.0659 11.6478 46.0659C12.6085 35.1429 14.8759 27.2967 20.2944 21.6044C30.5165 10.7582 44.0819 9.52747 49.8463 9.52747H50C55.6491 9.52747 69.3683 10.6429 79.7057 21.6044ZM50 39.7967C48.8471 39.7967 47.5021 39.8736 46.0418 40.0275C45.678 41.7486 44.8848 43.3496 43.7361 44.6813C42.1163 46.2842 40.1962 47.5511 38.0858 48.4092C35.9755 49.2672 33.7165 49.6995 31.4388 49.6813C28.8256 49.6813 26.0971 49.1044 23.8683 47.6813C21.7547 48.4121 19.7179 49.4121 19.5642 51.9121C19.3721 56.6044 19.3336 61.3352 19.3336 66.0659C19.3336 68.4121 19.3336 70.7967 19.2568 73.1813C19.2568 74.5659 20.1022 75.8352 21.3704 76.4121C31.5156 81.0275 41.1613 83.3736 50 83.3736C58.8387 83.3736 68.446 81.0659 78.6297 76.4121C79.2511 76.1286 79.7794 75.6746 80.1535 75.1028C80.5276 74.531 80.7321 73.8647 80.7432 73.1813C80.8585 66.1044 80.7432 58.9505 80.4358 51.9121C80.2821 49.3736 78.2454 48.4121 76.1318 47.6813C73.9029 49.1044 71.136 49.6429 68.5612 49.6429C66.2861 49.6662 64.0288 49.2399 61.9186 48.3885C59.8084 47.5371 57.8868 46.2773 56.2639 44.6813C55.1153 43.3496 54.322 41.7486 53.9582 40.0275C52.6516 39.8736 51.3066 39.8352 50 39.7967ZM39.6242 56.7198C41.853 56.7198 43.6592 58.489 43.6592 60.7198V68.1044C43.6592 69.1653 43.2381 70.1827 42.4886 70.9328C41.7391 71.683 40.7226 72.1044 39.6626 72.1044C38.6026 72.1044 37.5861 71.683 36.8366 70.9328C36.087 70.1827 35.666 69.1653 35.666 68.1044V60.6813C35.666 58.4505 37.4337 56.6813 39.6626 56.6813L39.6242 56.7198ZM60.1453 56.7198C62.3742 56.7198 64.1419 58.489 64.1419 60.7198V68.1044C64.1419 69.1653 63.7208 70.1827 62.9713 70.9328C62.2218 71.683 61.2052 72.1044 60.1453 72.1044C59.0853 72.1044 58.0688 71.683 57.3192 70.9328C56.5697 70.1827 56.1487 69.1653 56.1487 68.1044V60.6813C56.1487 58.4505 57.9548 56.6813 60.1453 56.6813V56.7198ZM32.0921 20.4121C27.788 20.8352 24.1757 22.2582 22.3311 24.2582C18.3345 28.6044 19.1799 39.6813 21.4857 42.0275C23.7655 43.9275 26.6682 44.9142 29.6326 44.7967C32.2458 44.7967 37.1647 44.2198 41.1998 40.1044C43.0059 38.3736 44.0819 34.0659 43.9666 29.7198C43.8514 26.2198 42.8522 23.2967 41.3919 22.0659C39.7779 20.6813 36.1655 20.0659 32.0921 20.4121ZM58.6081 22.0659C57.1478 23.2967 56.1487 26.2198 56.0334 29.7198C55.9181 34.0659 56.9941 38.3736 58.8003 40.1044C60.3121 41.6165 62.111 42.8106 64.0909 43.6164C66.0708 44.4223 68.1918 44.8236 70.329 44.7967C73.7492 44.7967 76.8619 43.6813 78.5144 42.0275C80.8201 39.6813 81.6655 28.6044 77.6689 24.2198C75.8243 22.2967 72.212 20.8352 67.9079 20.4121C63.8345 20.0275 60.2221 20.6813 58.6081 22.0659ZM50 31.0659C49.0009 31.0659 47.848 31.1429 46.5414 31.2582C46.6951 31.9121 46.7335 32.6813 46.8104 33.4505C46.8104 34.0275 46.8104 34.6044 46.7335 35.1813C47.9633 35.0659 49.0393 35.0659 50 35.0659C50.9992 35.0659 52.0367 35.0659 53.2665 35.1813C53.1896 34.5659 53.1896 34.0275 53.1896 33.4505C53.2665 32.6813 53.3049 31.9121 53.4586 31.2582C52.152 31.1429 50.9992 31.0659 50 31.0659Z" fill="white"/>
3
+ </svg>
@@ -0,0 +1,264 @@
1
+ (function () {
2
+ const KEYCHAIN_SERVICE = "OpenUsage-copilot";
3
+ const GH_KEYCHAIN_SERVICE = "gh:github.com";
4
+ const USAGE_URL = "https://api.github.com/copilot_internal/user";
5
+
6
+ function readJson(ctx, path) {
7
+ try {
8
+ if (!ctx.host.fs.exists(path)) return null;
9
+ const text = ctx.host.fs.readText(path);
10
+ return ctx.util.tryParseJson(text);
11
+ } catch (e) {
12
+ ctx.host.log.warn("readJson failed for " + path + ": " + String(e));
13
+ return null;
14
+ }
15
+ }
16
+
17
+ function writeJson(ctx, path, value) {
18
+ try {
19
+ ctx.host.fs.writeText(path, JSON.stringify(value));
20
+ } catch (e) {
21
+ ctx.host.log.warn("writeJson failed for " + path + ": " + String(e));
22
+ }
23
+ }
24
+
25
+ function saveToken(ctx, token) {
26
+ try {
27
+ ctx.host.keychain.writeGenericPassword(
28
+ KEYCHAIN_SERVICE,
29
+ JSON.stringify({ token: token }),
30
+ );
31
+ } catch (e) {
32
+ ctx.host.log.warn("keychain write failed: " + String(e));
33
+ }
34
+ writeJson(ctx, ctx.app.pluginDataDir + "/auth.json", { token: token });
35
+ }
36
+
37
+ function clearCachedToken(ctx) {
38
+ try {
39
+ ctx.host.keychain.deleteGenericPassword(KEYCHAIN_SERVICE);
40
+ } catch (e) {
41
+ ctx.host.log.info("keychain delete failed: " + String(e));
42
+ }
43
+ writeJson(ctx, ctx.app.pluginDataDir + "/auth.json", null);
44
+ }
45
+
46
+ function loadTokenFromKeychain(ctx) {
47
+ try {
48
+ const raw = ctx.host.keychain.readGenericPassword(KEYCHAIN_SERVICE);
49
+ if (raw) {
50
+ const parsed = ctx.util.tryParseJson(raw);
51
+ if (parsed && parsed.token) {
52
+ ctx.host.log.info("token loaded from OpenUsage keychain");
53
+ return { token: parsed.token, source: "keychain" };
54
+ }
55
+ }
56
+ } catch (e) {
57
+ ctx.host.log.info("OpenUsage keychain read failed: " + String(e));
58
+ }
59
+ return null;
60
+ }
61
+
62
+ function loadTokenFromGhCli(ctx) {
63
+ try {
64
+ const raw = ctx.host.keychain.readGenericPassword(GH_KEYCHAIN_SERVICE);
65
+ if (raw) {
66
+ let token = raw;
67
+ if (
68
+ typeof token === "string" &&
69
+ token.indexOf("go-keyring-base64:") === 0
70
+ ) {
71
+ token = ctx.base64.decode(token.slice("go-keyring-base64:".length));
72
+ }
73
+ if (token) {
74
+ ctx.host.log.info("token loaded from gh CLI keychain");
75
+ return { token: token, source: "gh-cli" };
76
+ }
77
+ }
78
+ } catch (e) {
79
+ ctx.host.log.info("gh CLI keychain read failed: " + String(e));
80
+ }
81
+ return null;
82
+ }
83
+
84
+ function loadTokenFromStateFile(ctx) {
85
+ const data = readJson(ctx, ctx.app.pluginDataDir + "/auth.json");
86
+ if (data && data.token) {
87
+ ctx.host.log.info("token loaded from state file");
88
+ return { token: data.token, source: "state" };
89
+ }
90
+ return null;
91
+ }
92
+
93
+ function loadToken(ctx) {
94
+ return (
95
+ loadTokenFromKeychain(ctx) ||
96
+ loadTokenFromGhCli(ctx) ||
97
+ loadTokenFromStateFile(ctx)
98
+ );
99
+ }
100
+
101
+ function fetchUsage(ctx, token) {
102
+ return ctx.util.request({
103
+ method: "GET",
104
+ url: USAGE_URL,
105
+ headers: {
106
+ Authorization: "token " + token,
107
+ Accept: "application/json",
108
+ "Editor-Version": "vscode/1.96.2",
109
+ "Editor-Plugin-Version": "copilot-chat/0.26.7",
110
+ "User-Agent": "GitHubCopilotChat/0.26.7",
111
+ "X-Github-Api-Version": "2025-04-01",
112
+ },
113
+ timeoutMs: 10000,
114
+ });
115
+ }
116
+
117
+ function makeProgressLine(ctx, label, snapshot, resetDate) {
118
+ if (!snapshot || typeof snapshot.percent_remaining !== "number")
119
+ return null;
120
+ const usedPercent = Math.min(100, Math.max(0, 100 - snapshot.percent_remaining));
121
+ return ctx.line.progress({
122
+ label: label,
123
+ used: usedPercent,
124
+ limit: 100,
125
+ format: { kind: "percent" },
126
+ resetsAt: ctx.util.toIso(resetDate),
127
+ periodDurationMs: 30 * 24 * 60 * 60 * 1000,
128
+ });
129
+ }
130
+
131
+ function makeLimitedProgressLine(ctx, label, remaining, total, resetDate) {
132
+ if (typeof remaining !== "number" || typeof total !== "number" || total <= 0)
133
+ return null;
134
+ const used = total - remaining;
135
+ const usedPercent = Math.min(100, Math.max(0, Math.round((used / total) * 100)));
136
+ return ctx.line.progress({
137
+ label: label,
138
+ used: usedPercent,
139
+ limit: 100,
140
+ format: { kind: "percent" },
141
+ resetsAt: ctx.util.toIso(resetDate),
142
+ periodDurationMs: 30 * 24 * 60 * 60 * 1000,
143
+ });
144
+ }
145
+
146
+ function probe(ctx) {
147
+ const cred = loadToken(ctx);
148
+ if (!cred) {
149
+ throw "Not logged in. Run `gh auth login` first.";
150
+ }
151
+
152
+ let token = cred.token;
153
+ let source = cred.source;
154
+
155
+ let resp;
156
+ try {
157
+ resp = fetchUsage(ctx, token);
158
+ } catch (e) {
159
+ ctx.host.log.error("usage request exception: " + String(e));
160
+ throw "Usage request failed. Check your connection.";
161
+ }
162
+
163
+ if (resp.status === 401 || resp.status === 403) {
164
+ // If cached token is stale, clear it and try fallback sources
165
+ if (source === "keychain") {
166
+ ctx.host.log.info("cached token invalid, trying fallback sources");
167
+ clearCachedToken(ctx);
168
+ const fallback = loadTokenFromGhCli(ctx);
169
+ if (fallback) {
170
+ try {
171
+ resp = fetchUsage(ctx, fallback.token);
172
+ } catch (e) {
173
+ ctx.host.log.error("fallback usage request exception: " + String(e));
174
+ throw "Usage request failed. Check your connection.";
175
+ }
176
+ if (resp.status >= 200 && resp.status < 300) {
177
+ // Fallback worked, persist the new token
178
+ saveToken(ctx, fallback.token);
179
+ token = fallback.token;
180
+ source = fallback.source;
181
+ }
182
+ }
183
+ }
184
+ // Still failing after retry
185
+ if (resp.status === 401 || resp.status === 403) {
186
+ throw "Token invalid. Run `gh auth login` to re-authenticate.";
187
+ }
188
+ }
189
+
190
+ if (resp.status < 200 || resp.status >= 300) {
191
+ ctx.host.log.error("usage returned error: status=" + resp.status);
192
+ throw (
193
+ "Usage request failed (HTTP " +
194
+ String(resp.status) +
195
+ "). Try again later."
196
+ );
197
+ }
198
+
199
+ // Persist gh-cli token to OpenUsage keychain for future use
200
+ if (source === "gh-cli") {
201
+ saveToken(ctx, token);
202
+ }
203
+
204
+ const data = ctx.util.tryParseJson(resp.bodyText);
205
+ if (data === null) {
206
+ throw "Usage response invalid. Try again later.";
207
+ }
208
+
209
+ ctx.host.log.info("usage fetch succeeded");
210
+
211
+ const lines = [];
212
+ let plan = null;
213
+ if (data.copilot_plan) {
214
+ plan = ctx.fmt.planLabel(data.copilot_plan);
215
+ }
216
+
217
+ // Paid tier: quota_snapshots
218
+ const snapshots = data.quota_snapshots;
219
+ if (snapshots) {
220
+ const premiumLine = makeProgressLine(
221
+ ctx,
222
+ "Premium",
223
+ snapshots.premium_interactions,
224
+ data.quota_reset_date,
225
+ );
226
+ if (premiumLine) lines.push(premiumLine);
227
+
228
+ const chatLine = makeProgressLine(
229
+ ctx,
230
+ "Chat",
231
+ snapshots.chat,
232
+ data.quota_reset_date,
233
+ );
234
+ if (chatLine) lines.push(chatLine);
235
+ }
236
+
237
+ // Free tier: limited_user_quotas
238
+ if (data.limited_user_quotas && data.monthly_quotas) {
239
+ const lq = data.limited_user_quotas;
240
+ const mq = data.monthly_quotas;
241
+ const resetDate = data.limited_user_reset_date;
242
+
243
+ const chatLine = makeLimitedProgressLine(ctx, "Chat", lq.chat, mq.chat, resetDate);
244
+ if (chatLine) lines.push(chatLine);
245
+
246
+ const completionsLine = makeLimitedProgressLine(ctx, "Completions", lq.completions, mq.completions, resetDate);
247
+ if (completionsLine) lines.push(completionsLine);
248
+ }
249
+
250
+ if (lines.length === 0) {
251
+ lines.push(
252
+ ctx.line.badge({
253
+ label: "Status",
254
+ text: "No usage data",
255
+ color: "#a3a3a3",
256
+ }),
257
+ );
258
+ }
259
+
260
+ return { plan: plan, lines: lines };
261
+ }
262
+
263
+ globalThis.__openusage_plugin = { id: "copilot", probe };
264
+ })();
@@ -0,0 +1,20 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "copilot",
4
+ "name": "Copilot",
5
+ "version": "0.0.1",
6
+ "entry": "plugin.js",
7
+ "icon": "icon.svg",
8
+ "brandColor": "#A855F7",
9
+ "cli": {
10
+ "category": "cli",
11
+ "binaryName": "gh",
12
+ "installCmd": "sudo apt install gh",
13
+ "loginCmd": "gh auth login"
14
+ },
15
+ "lines": [
16
+ { "type": "progress", "label": "Premium", "scope": "overview", "primaryOrder": 1 },
17
+ { "type": "progress", "label": "Chat", "scope": "overview", "primaryOrder": 2 },
18
+ { "type": "progress", "label": "Completions", "scope": "overview" }
19
+ ]
20
+ }