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.
- package/bin/openusage +91 -0
- package/package.json +33 -0
- package/plugins/amp/icon.svg +6 -0
- package/plugins/amp/plugin.js +175 -0
- package/plugins/amp/plugin.json +20 -0
- package/plugins/amp/plugin.test.js +365 -0
- package/plugins/antigravity/icon.svg +3 -0
- package/plugins/antigravity/plugin.js +484 -0
- package/plugins/antigravity/plugin.json +17 -0
- package/plugins/antigravity/plugin.test.js +1356 -0
- package/plugins/claude/icon.svg +3 -0
- package/plugins/claude/plugin.js +565 -0
- package/plugins/claude/plugin.json +28 -0
- package/plugins/claude/plugin.test.js +1012 -0
- package/plugins/codex/icon.svg +3 -0
- package/plugins/codex/plugin.js +673 -0
- package/plugins/codex/plugin.json +30 -0
- package/plugins/codex/plugin.test.js +1071 -0
- package/plugins/copilot/icon.svg +3 -0
- package/plugins/copilot/plugin.js +264 -0
- package/plugins/copilot/plugin.json +20 -0
- package/plugins/copilot/plugin.test.js +529 -0
- package/plugins/cursor/icon.svg +3 -0
- package/plugins/cursor/plugin.js +526 -0
- package/plugins/cursor/plugin.json +24 -0
- package/plugins/cursor/plugin.test.js +1168 -0
- package/plugins/factory/icon.svg +1 -0
- package/plugins/factory/plugin.js +407 -0
- package/plugins/factory/plugin.json +19 -0
- package/plugins/factory/plugin.test.js +833 -0
- package/plugins/gemini/icon.svg +4 -0
- package/plugins/gemini/plugin.js +413 -0
- package/plugins/gemini/plugin.json +20 -0
- package/plugins/gemini/plugin.test.js +735 -0
- package/plugins/jetbrains-ai-assistant/icon.svg +3 -0
- package/plugins/jetbrains-ai-assistant/plugin.js +357 -0
- package/plugins/jetbrains-ai-assistant/plugin.json +17 -0
- package/plugins/jetbrains-ai-assistant/plugin.test.js +338 -0
- package/plugins/kimi/icon.svg +3 -0
- package/plugins/kimi/plugin.js +358 -0
- package/plugins/kimi/plugin.json +19 -0
- package/plugins/kimi/plugin.test.js +619 -0
- package/plugins/minimax/icon.svg +4 -0
- package/plugins/minimax/plugin.js +388 -0
- package/plugins/minimax/plugin.json +17 -0
- package/plugins/minimax/plugin.test.js +943 -0
- package/plugins/perplexity/icon.svg +1 -0
- package/plugins/perplexity/plugin.js +378 -0
- package/plugins/perplexity/plugin.json +15 -0
- package/plugins/perplexity/plugin.test.js +602 -0
- package/plugins/windsurf/icon.svg +3 -0
- package/plugins/windsurf/plugin.js +218 -0
- package/plugins/windsurf/plugin.json +16 -0
- package/plugins/windsurf/plugin.test.js +455 -0
- package/plugins/zai/icon.svg +5 -0
- package/plugins/zai/plugin.js +156 -0
- package/plugins/zai/plugin.json +18 -0
- package/plugins/zai/plugin.test.js +396 -0
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
var LS_SERVICE = "exa.language_server_pb.LanguageServerService"
|
|
3
|
+
var STATE_DB = "~/Library/Application Support/Antigravity/User/globalStorage/state.vscdb"
|
|
4
|
+
var CLOUD_CODE_URLS = [
|
|
5
|
+
"https://daily-cloudcode-pa.googleapis.com",
|
|
6
|
+
"https://cloudcode-pa.googleapis.com",
|
|
7
|
+
]
|
|
8
|
+
var FETCH_MODELS_PATH = "/v1internal:fetchAvailableModels"
|
|
9
|
+
var GOOGLE_OAUTH_URL = "https://oauth2.googleapis.com/token"
|
|
10
|
+
var GOOGLE_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com"
|
|
11
|
+
var GOOGLE_CLIENT_SECRET = "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"
|
|
12
|
+
var CC_MODEL_BLACKLIST = {
|
|
13
|
+
"MODEL_CHAT_20706": true,
|
|
14
|
+
"MODEL_CHAT_23310": true,
|
|
15
|
+
"MODEL_GOOGLE_GEMINI_2_5_FLASH": true,
|
|
16
|
+
"MODEL_GOOGLE_GEMINI_2_5_FLASH_THINKING": true,
|
|
17
|
+
"MODEL_GOOGLE_GEMINI_2_5_FLASH_LITE": true,
|
|
18
|
+
"MODEL_GOOGLE_GEMINI_2_5_PRO": true,
|
|
19
|
+
"MODEL_PLACEHOLDER_M19": true,
|
|
20
|
+
"MODEL_PLACEHOLDER_M9": true,
|
|
21
|
+
"MODEL_PLACEHOLDER_M12": true,
|
|
22
|
+
}
|
|
23
|
+
// --- Protobuf wire-format decoder ---
|
|
24
|
+
|
|
25
|
+
function readVarint(s, pos) {
|
|
26
|
+
var v = 0
|
|
27
|
+
var shift = 0
|
|
28
|
+
while (pos < s.length) {
|
|
29
|
+
var b = s.charCodeAt(pos++)
|
|
30
|
+
v += (b & 0x7f) * Math.pow(2, shift)
|
|
31
|
+
if ((b & 0x80) === 0) return { v: v, p: pos }
|
|
32
|
+
shift += 7
|
|
33
|
+
}
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function readFields(s) {
|
|
38
|
+
var fields = {}
|
|
39
|
+
var pos = 0
|
|
40
|
+
while (pos < s.length) {
|
|
41
|
+
var tag = readVarint(s, pos)
|
|
42
|
+
if (!tag) break
|
|
43
|
+
pos = tag.p
|
|
44
|
+
var fieldNum = Math.floor(tag.v / 8)
|
|
45
|
+
var wireType = tag.v % 8
|
|
46
|
+
if (wireType === 0) {
|
|
47
|
+
var val = readVarint(s, pos)
|
|
48
|
+
if (!val) break
|
|
49
|
+
fields[fieldNum] = { type: 0, value: val.v }
|
|
50
|
+
pos = val.p
|
|
51
|
+
} else if (wireType === 2) {
|
|
52
|
+
var len = readVarint(s, pos)
|
|
53
|
+
if (!len) break
|
|
54
|
+
pos = len.p
|
|
55
|
+
fields[fieldNum] = { type: 2, data: s.substring(pos, pos + len.v) }
|
|
56
|
+
pos += len.v
|
|
57
|
+
} else {
|
|
58
|
+
break
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return fields
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// --- SQLite credential reading ---
|
|
65
|
+
|
|
66
|
+
function loadApiKey(ctx) {
|
|
67
|
+
try {
|
|
68
|
+
var rows = ctx.host.sqlite.query(
|
|
69
|
+
STATE_DB,
|
|
70
|
+
"SELECT value FROM ItemTable WHERE key = 'antigravityAuthStatus' LIMIT 1"
|
|
71
|
+
)
|
|
72
|
+
var parsed = ctx.util.tryParseJson(rows)
|
|
73
|
+
if (!parsed || !parsed.length || !parsed[0].value) return null
|
|
74
|
+
var auth = ctx.util.tryParseJson(parsed[0].value)
|
|
75
|
+
if (!auth || !auth.apiKey) return null
|
|
76
|
+
return auth.apiKey
|
|
77
|
+
} catch (e) {
|
|
78
|
+
ctx.host.log.warn("failed to read auth from antigravity DB: " + String(e))
|
|
79
|
+
return null
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function loadProtoTokens(ctx) {
|
|
84
|
+
try {
|
|
85
|
+
var rows = ctx.host.sqlite.query(
|
|
86
|
+
STATE_DB,
|
|
87
|
+
"SELECT value FROM ItemTable WHERE key = 'jetskiStateSync.agentManagerInitState' LIMIT 1"
|
|
88
|
+
)
|
|
89
|
+
var parsed = ctx.util.tryParseJson(rows)
|
|
90
|
+
if (!parsed || !parsed.length || !parsed[0].value) return null
|
|
91
|
+
var raw = ctx.base64.decode(parsed[0].value)
|
|
92
|
+
var outer = readFields(raw)
|
|
93
|
+
if (!outer[6] || outer[6].type !== 2) return null
|
|
94
|
+
var inner = readFields(outer[6].data)
|
|
95
|
+
var accessToken = (inner[1] && inner[1].type === 2) ? inner[1].data : null
|
|
96
|
+
var refreshToken = (inner[3] && inner[3].type === 2) ? inner[3].data : null
|
|
97
|
+
var expirySeconds = null
|
|
98
|
+
if (inner[4] && inner[4].type === 2) {
|
|
99
|
+
var ts = readFields(inner[4].data)
|
|
100
|
+
if (ts[1] && ts[1].type === 0) expirySeconds = ts[1].value
|
|
101
|
+
}
|
|
102
|
+
if (!accessToken) return null
|
|
103
|
+
return { accessToken: accessToken, refreshToken: refreshToken, expirySeconds: expirySeconds }
|
|
104
|
+
} catch (e) {
|
|
105
|
+
ctx.host.log.warn("failed to read proto tokens from antigravity DB: " + String(e))
|
|
106
|
+
return null
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// --- Google OAuth token refresh ---
|
|
111
|
+
|
|
112
|
+
function refreshAccessToken(ctx, refreshTokenValue) {
|
|
113
|
+
if (!refreshTokenValue) {
|
|
114
|
+
ctx.host.log.warn("refresh skipped: no refresh token")
|
|
115
|
+
return null
|
|
116
|
+
}
|
|
117
|
+
ctx.host.log.info("attempting Google OAuth token refresh")
|
|
118
|
+
try {
|
|
119
|
+
var resp = ctx.host.http.request({
|
|
120
|
+
method: "POST",
|
|
121
|
+
url: GOOGLE_OAUTH_URL,
|
|
122
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
123
|
+
bodyText:
|
|
124
|
+
"client_id=" + encodeURIComponent(GOOGLE_CLIENT_ID) +
|
|
125
|
+
"&client_secret=" + encodeURIComponent(GOOGLE_CLIENT_SECRET) +
|
|
126
|
+
"&refresh_token=" + encodeURIComponent(refreshTokenValue) +
|
|
127
|
+
"&grant_type=refresh_token",
|
|
128
|
+
timeoutMs: 15000,
|
|
129
|
+
})
|
|
130
|
+
if (resp.status < 200 || resp.status >= 300) {
|
|
131
|
+
ctx.host.log.warn("Google OAuth refresh returned status: " + resp.status)
|
|
132
|
+
return null
|
|
133
|
+
}
|
|
134
|
+
var body = ctx.util.tryParseJson(resp.bodyText)
|
|
135
|
+
if (!body || !body.access_token) {
|
|
136
|
+
ctx.host.log.warn("Google OAuth refresh response missing access_token")
|
|
137
|
+
return null
|
|
138
|
+
}
|
|
139
|
+
var expiresIn = (typeof body.expires_in === "number") ? body.expires_in : 3600
|
|
140
|
+
cacheToken(ctx, body.access_token, expiresIn)
|
|
141
|
+
return body.access_token
|
|
142
|
+
} catch (e) {
|
|
143
|
+
ctx.host.log.warn("Google OAuth refresh failed: " + String(e))
|
|
144
|
+
return null
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// --- Token cache ---
|
|
149
|
+
|
|
150
|
+
function loadCachedToken(ctx) {
|
|
151
|
+
var path = ctx.app.pluginDataDir + "/auth.json"
|
|
152
|
+
try {
|
|
153
|
+
if (!ctx.host.fs.exists(path)) return null
|
|
154
|
+
var data = ctx.util.tryParseJson(ctx.host.fs.readText(path))
|
|
155
|
+
if (!data || !data.accessToken || !data.expiresAtMs) return null
|
|
156
|
+
if (data.expiresAtMs <= Date.now()) return null
|
|
157
|
+
return data.accessToken
|
|
158
|
+
} catch (e) {
|
|
159
|
+
ctx.host.log.warn("failed to read cached token: " + String(e))
|
|
160
|
+
return null
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function cacheToken(ctx, accessToken, expiresInSeconds) {
|
|
165
|
+
var path = ctx.app.pluginDataDir + "/auth.json"
|
|
166
|
+
try {
|
|
167
|
+
ctx.host.fs.writeText(path, JSON.stringify({
|
|
168
|
+
accessToken: accessToken,
|
|
169
|
+
expiresAtMs: Date.now() + (expiresInSeconds || 3600) * 1000,
|
|
170
|
+
}))
|
|
171
|
+
} catch (e) {
|
|
172
|
+
ctx.host.log.warn("failed to cache refreshed token: " + String(e))
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// --- LS discovery ---
|
|
177
|
+
|
|
178
|
+
function discoverLs(ctx) {
|
|
179
|
+
return ctx.host.ls.discover({
|
|
180
|
+
processName: "language_server_macos",
|
|
181
|
+
markers: ["antigravity"],
|
|
182
|
+
csrfFlag: "--csrf_token",
|
|
183
|
+
portFlag: "--extension_server_port",
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function probePort(ctx, scheme, port, csrf) {
|
|
188
|
+
ctx.host.http.request({
|
|
189
|
+
method: "POST",
|
|
190
|
+
url: scheme + "://127.0.0.1:" + port + "/" + LS_SERVICE + "/GetUnleashData",
|
|
191
|
+
headers: {
|
|
192
|
+
"Content-Type": "application/json",
|
|
193
|
+
"Connect-Protocol-Version": "1",
|
|
194
|
+
"x-codeium-csrf-token": csrf,
|
|
195
|
+
},
|
|
196
|
+
bodyText: JSON.stringify({
|
|
197
|
+
context: {
|
|
198
|
+
properties: {
|
|
199
|
+
devMode: "false",
|
|
200
|
+
extensionVersion: "unknown",
|
|
201
|
+
ide: "antigravity",
|
|
202
|
+
ideVersion: "unknown",
|
|
203
|
+
os: "macos",
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
}),
|
|
207
|
+
timeoutMs: 5000,
|
|
208
|
+
dangerouslyIgnoreTls: scheme === "https",
|
|
209
|
+
})
|
|
210
|
+
// Any HTTP response means this port is alive (even 400 validation errors).
|
|
211
|
+
return true
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function findWorkingPort(ctx, discovery) {
|
|
215
|
+
var ports = discovery.ports || []
|
|
216
|
+
for (var i = 0; i < ports.length; i++) {
|
|
217
|
+
var port = ports[i]
|
|
218
|
+
// Try HTTPS first (LS may use self-signed cert), then HTTP
|
|
219
|
+
try { if (probePort(ctx, "https", port, discovery.csrf)) return { port: port, scheme: "https" } } catch (e) { /* ignore */ }
|
|
220
|
+
try { if (probePort(ctx, "http", port, discovery.csrf)) return { port: port, scheme: "http" } } catch (e) { /* ignore */ }
|
|
221
|
+
ctx.host.log.info("port " + port + " probe failed on both schemes")
|
|
222
|
+
}
|
|
223
|
+
if (discovery.extensionPort) return { port: discovery.extensionPort, scheme: "http" }
|
|
224
|
+
return null
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function callLs(ctx, port, scheme, csrf, method, body) {
|
|
228
|
+
var resp = ctx.host.http.request({
|
|
229
|
+
method: "POST",
|
|
230
|
+
url: scheme + "://127.0.0.1:" + port + "/" + LS_SERVICE + "/" + method,
|
|
231
|
+
headers: {
|
|
232
|
+
"Content-Type": "application/json",
|
|
233
|
+
"Connect-Protocol-Version": "1",
|
|
234
|
+
"x-codeium-csrf-token": csrf,
|
|
235
|
+
},
|
|
236
|
+
bodyText: JSON.stringify(body || {}),
|
|
237
|
+
timeoutMs: 10000,
|
|
238
|
+
dangerouslyIgnoreTls: scheme === "https",
|
|
239
|
+
})
|
|
240
|
+
if (resp.status < 200 || resp.status >= 300) {
|
|
241
|
+
ctx.host.log.warn("callLs " + method + " returned " + resp.status)
|
|
242
|
+
return null
|
|
243
|
+
}
|
|
244
|
+
return ctx.util.tryParseJson(resp.bodyText)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// --- Line builders ---
|
|
248
|
+
|
|
249
|
+
function normalizeLabel(label) {
|
|
250
|
+
// "Gemini 3 Pro (High)" -> "Gemini 3 Pro"
|
|
251
|
+
return label.replace(/\s*\([^)]*\)\s*$/, "").trim()
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function poolLabel(normalizedLabel) {
|
|
255
|
+
var lower = normalizedLabel.toLowerCase()
|
|
256
|
+
if (lower.indexOf("gemini") !== -1 && lower.indexOf("pro") !== -1) return "Gemini Pro"
|
|
257
|
+
if (lower.indexOf("gemini") !== -1 && lower.indexOf("flash") !== -1) return "Gemini Flash"
|
|
258
|
+
// All non-Gemini models (Claude, GPT-OSS, etc.) share a single quota pool
|
|
259
|
+
return "Claude"
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function modelSortKey(label) {
|
|
263
|
+
var lower = label.toLowerCase()
|
|
264
|
+
// Gemini Pro variants first, then other Gemini, then Claude Opus, then other Claude, then rest
|
|
265
|
+
if (lower.indexOf("gemini") !== -1 && lower.indexOf("pro") !== -1) return "0a_" + label
|
|
266
|
+
if (lower.indexOf("gemini") !== -1) return "0b_" + label
|
|
267
|
+
if (lower.indexOf("claude") !== -1 && lower.indexOf("opus") !== -1) return "1a_" + label
|
|
268
|
+
if (lower.indexOf("claude") !== -1) return "1b_" + label
|
|
269
|
+
return "2_" + label
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
var QUOTA_PERIOD_MS = 5 * 60 * 60 * 1000 // 5 hours
|
|
273
|
+
|
|
274
|
+
function modelLine(ctx, label, remainingFraction, resetTime) {
|
|
275
|
+
var clamped = Math.max(0, Math.min(1, remainingFraction))
|
|
276
|
+
var used = Math.round((1 - clamped) * 100)
|
|
277
|
+
return ctx.line.progress({
|
|
278
|
+
label: label,
|
|
279
|
+
used: used,
|
|
280
|
+
limit: 100,
|
|
281
|
+
format: { kind: "percent" },
|
|
282
|
+
resetsAt: resetTime || undefined,
|
|
283
|
+
periodDurationMs: QUOTA_PERIOD_MS,
|
|
284
|
+
})
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function buildModelLines(ctx, configs) {
|
|
288
|
+
var deduped = {}
|
|
289
|
+
for (var i = 0; i < configs.length; i++) {
|
|
290
|
+
var c = configs[i]
|
|
291
|
+
var label = (typeof c.label === "string") ? c.label.trim() : ""
|
|
292
|
+
if (!label) continue
|
|
293
|
+
var qi = c.quotaInfo
|
|
294
|
+
var frac = (qi && typeof qi.remainingFraction === "number") ? qi.remainingFraction : 0
|
|
295
|
+
var rtime = (qi && qi.resetTime) || undefined
|
|
296
|
+
var pool = poolLabel(normalizeLabel(label))
|
|
297
|
+
if (!deduped[pool] || frac < deduped[pool].remainingFraction) {
|
|
298
|
+
deduped[pool] = {
|
|
299
|
+
label: pool,
|
|
300
|
+
remainingFraction: frac,
|
|
301
|
+
resetTime: rtime,
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
var models = []
|
|
307
|
+
var keys = Object.keys(deduped)
|
|
308
|
+
for (var i = 0; i < keys.length; i++) {
|
|
309
|
+
var m = deduped[keys[i]]
|
|
310
|
+
m.sortKey = modelSortKey(m.label)
|
|
311
|
+
models.push(m)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
models.sort(function (a, b) {
|
|
315
|
+
return a.sortKey < b.sortKey ? -1 : a.sortKey > b.sortKey ? 1 : 0
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
var lines = []
|
|
319
|
+
for (var i = 0; i < models.length; i++) {
|
|
320
|
+
lines.push(modelLine(ctx, models[i].label, models[i].remainingFraction, models[i].resetTime))
|
|
321
|
+
}
|
|
322
|
+
return lines
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// --- Cloud Code API ---
|
|
326
|
+
|
|
327
|
+
function probeCloudCode(ctx, token) {
|
|
328
|
+
for (var i = 0; i < CLOUD_CODE_URLS.length; i++) {
|
|
329
|
+
try {
|
|
330
|
+
var resp = ctx.host.http.request({
|
|
331
|
+
method: "POST",
|
|
332
|
+
url: CLOUD_CODE_URLS[i] + FETCH_MODELS_PATH,
|
|
333
|
+
headers: {
|
|
334
|
+
"Content-Type": "application/json",
|
|
335
|
+
Authorization: "Bearer " + token,
|
|
336
|
+
"User-Agent": "antigravity",
|
|
337
|
+
},
|
|
338
|
+
bodyText: "{}",
|
|
339
|
+
timeoutMs: 15000,
|
|
340
|
+
})
|
|
341
|
+
if (ctx.util.isAuthStatus(resp.status)) return { _authFailed: true }
|
|
342
|
+
if (resp.status >= 200 && resp.status < 300) {
|
|
343
|
+
return ctx.util.tryParseJson(resp.bodyText)
|
|
344
|
+
}
|
|
345
|
+
} catch (e) {
|
|
346
|
+
ctx.host.log.warn("Cloud Code request failed (" + CLOUD_CODE_URLS[i] + "): " + String(e))
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return null
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function parseCloudCodeModels(data) {
|
|
353
|
+
var modelsObj = data && data.models
|
|
354
|
+
if (!modelsObj || typeof modelsObj !== "object") return []
|
|
355
|
+
var keys = Object.keys(modelsObj)
|
|
356
|
+
var configs = []
|
|
357
|
+
for (var i = 0; i < keys.length; i++) {
|
|
358
|
+
var m = modelsObj[keys[i]]
|
|
359
|
+
if (!m || typeof m !== "object") continue
|
|
360
|
+
if (m.isInternal) continue
|
|
361
|
+
var modelId = m.model || keys[i]
|
|
362
|
+
if (CC_MODEL_BLACKLIST[modelId]) continue
|
|
363
|
+
var displayName = (typeof m.displayName === "string") ? m.displayName.trim() : ""
|
|
364
|
+
if (!displayName) continue
|
|
365
|
+
var qi = m.quotaInfo
|
|
366
|
+
var frac = (qi && typeof qi.remainingFraction === "number") ? qi.remainingFraction : 0
|
|
367
|
+
var rtime = (qi && qi.resetTime) || undefined
|
|
368
|
+
configs.push({
|
|
369
|
+
label: displayName,
|
|
370
|
+
quotaInfo: { remainingFraction: frac, resetTime: rtime },
|
|
371
|
+
})
|
|
372
|
+
}
|
|
373
|
+
return configs
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// --- LS probe ---
|
|
377
|
+
|
|
378
|
+
function probeLs(ctx, apiKey) {
|
|
379
|
+
var discovery = discoverLs(ctx)
|
|
380
|
+
if (!discovery) return null
|
|
381
|
+
|
|
382
|
+
var found = findWorkingPort(ctx, discovery)
|
|
383
|
+
if (!found) return null
|
|
384
|
+
|
|
385
|
+
ctx.host.log.info("using LS at " + found.scheme + "://127.0.0.1:" + found.port)
|
|
386
|
+
|
|
387
|
+
var metadata = {
|
|
388
|
+
ideName: "antigravity",
|
|
389
|
+
extensionName: "antigravity",
|
|
390
|
+
ideVersion: "unknown",
|
|
391
|
+
locale: "en",
|
|
392
|
+
}
|
|
393
|
+
if (apiKey) metadata.apiKey = apiKey
|
|
394
|
+
|
|
395
|
+
// Try GetUserStatus first, fall back to GetCommandModelConfigs
|
|
396
|
+
var data = null
|
|
397
|
+
try {
|
|
398
|
+
data = callLs(ctx, found.port, found.scheme, discovery.csrf, "GetUserStatus", { metadata: metadata })
|
|
399
|
+
} catch (e) {
|
|
400
|
+
ctx.host.log.warn("GetUserStatus threw: " + String(e))
|
|
401
|
+
}
|
|
402
|
+
var hasUserStatus = data && data.userStatus
|
|
403
|
+
|
|
404
|
+
if (!hasUserStatus) {
|
|
405
|
+
ctx.host.log.warn("GetUserStatus failed, trying GetCommandModelConfigs")
|
|
406
|
+
data = callLs(ctx, found.port, found.scheme, discovery.csrf, "GetCommandModelConfigs", { metadata: metadata })
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Parse model configs
|
|
410
|
+
var configs
|
|
411
|
+
if (hasUserStatus) {
|
|
412
|
+
configs = (data.userStatus.cascadeModelConfigData || {}).clientModelConfigs || []
|
|
413
|
+
} else if (data && data.clientModelConfigs) {
|
|
414
|
+
configs = data.clientModelConfigs
|
|
415
|
+
} else {
|
|
416
|
+
return null
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
var filtered = []
|
|
420
|
+
for (var j = 0; j < configs.length; j++) {
|
|
421
|
+
var mid = configs[j].modelOrAlias && configs[j].modelOrAlias.model
|
|
422
|
+
if (mid && CC_MODEL_BLACKLIST[mid]) continue
|
|
423
|
+
filtered.push(configs[j])
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
var lines = buildModelLines(ctx, filtered)
|
|
427
|
+
if (lines.length === 0) return null
|
|
428
|
+
|
|
429
|
+
var plan = null
|
|
430
|
+
if (hasUserStatus) {
|
|
431
|
+
var ps = data.userStatus.planStatus || {}
|
|
432
|
+
var pi = ps.planInfo || {}
|
|
433
|
+
plan = pi.planName || null
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return { plan: plan, lines: lines }
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// --- Probe ---
|
|
440
|
+
|
|
441
|
+
function probe(ctx) {
|
|
442
|
+
var apiKey = loadApiKey(ctx)
|
|
443
|
+
var proto = loadProtoTokens(ctx)
|
|
444
|
+
|
|
445
|
+
var lsResult = probeLs(ctx, apiKey)
|
|
446
|
+
if (lsResult) return lsResult
|
|
447
|
+
|
|
448
|
+
var tokens = []
|
|
449
|
+
if (proto && proto.accessToken) {
|
|
450
|
+
if (!proto.expirySeconds || proto.expirySeconds > Math.floor(Date.now() / 1000)) {
|
|
451
|
+
tokens.push(proto.accessToken)
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
var cached = loadCachedToken(ctx)
|
|
456
|
+
if (cached && cached !== (proto && proto.accessToken)) tokens.push(cached)
|
|
457
|
+
|
|
458
|
+
if (apiKey && apiKey !== (proto && proto.accessToken) && apiKey !== cached) tokens.push(apiKey)
|
|
459
|
+
|
|
460
|
+
if (tokens.length === 0) throw "Start Antigravity and try again."
|
|
461
|
+
|
|
462
|
+
var ccData = null
|
|
463
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
464
|
+
ccData = probeCloudCode(ctx, tokens[i])
|
|
465
|
+
if (ccData && !ccData._authFailed) break
|
|
466
|
+
ccData = null
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (!ccData && proto && proto.refreshToken) {
|
|
470
|
+
var refreshed = refreshAccessToken(ctx, proto.refreshToken)
|
|
471
|
+
if (refreshed) ccData = probeCloudCode(ctx, refreshed)
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (ccData && !ccData._authFailed) {
|
|
475
|
+
var configs = parseCloudCodeModels(ccData)
|
|
476
|
+
var lines = buildModelLines(ctx, configs)
|
|
477
|
+
if (lines.length > 0) return { plan: null, lines: lines }
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
throw "Start Antigravity and try again."
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
globalThis.__openusage_plugin = { id: "antigravity", probe: probe }
|
|
484
|
+
})()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "antigravity",
|
|
4
|
+
"name": "Antigravity",
|
|
5
|
+
"version": "0.0.1",
|
|
6
|
+
"entry": "plugin.js",
|
|
7
|
+
"icon": "icon.svg",
|
|
8
|
+
"brandColor": "#4285F4",
|
|
9
|
+
"cli": {
|
|
10
|
+
"category": "ide"
|
|
11
|
+
},
|
|
12
|
+
"lines": [
|
|
13
|
+
{ "type": "progress", "label": "Gemini Pro", "scope": "overview", "primaryOrder": 1 },
|
|
14
|
+
{ "type": "progress", "label": "Gemini Flash", "scope": "overview" },
|
|
15
|
+
{ "type": "progress", "label": "Claude", "scope": "overview" }
|
|
16
|
+
]
|
|
17
|
+
}
|