opencode-antigravity-autopilot 2.2.1 → 2.2.3

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 (33) hide show
  1. package/README.md +13 -12
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/oh-my-opencode.d.ts.map +1 -1
  7. package/dist/oh-my-opencode.js +3 -2
  8. package/dist/oh-my-opencode.js.map +1 -1
  9. package/dist/plugin.d.ts.map +1 -1
  10. package/dist/plugin.js +7 -5
  11. package/dist/plugin.js.map +1 -1
  12. package/dist/rotation/QuotaTracker.d.ts +1 -0
  13. package/dist/rotation/QuotaTracker.d.ts.map +1 -1
  14. package/dist/rotation/QuotaTracker.js +3 -0
  15. package/dist/rotation/QuotaTracker.js.map +1 -1
  16. package/dist/scripts/scripts/test-agent-quota.js +154 -0
  17. package/dist/scripts/src/auth/AccountRotator.js +143 -0
  18. package/dist/scripts/src/auth/TokenStorageReader.js +88 -0
  19. package/dist/scripts/src/manager.js +360 -0
  20. package/dist/scripts/src/oh-my-opencode.js +145 -0
  21. package/dist/scripts/src/quota/ApiQuotaPoller.js +340 -0
  22. package/dist/scripts/src/quota/LSPFinder.js +86 -0
  23. package/dist/scripts/src/quota/QuotaCacheUpdater.js +212 -0
  24. package/dist/scripts/src/quota/QuotaPoller.js +86 -0
  25. package/dist/scripts/src/rotation/ModelSelector.js +63 -0
  26. package/dist/scripts/src/rotation/QuotaTracker.js +105 -0
  27. package/dist/scripts/src/types.js +2 -0
  28. package/dist/scripts/src/utils/logger.js +130 -0
  29. package/dist/utils/model-name-translator.d.ts +5 -0
  30. package/dist/utils/model-name-translator.d.ts.map +1 -0
  31. package/dist/utils/model-name-translator.js +119 -0
  32. package/dist/utils/model-name-translator.js.map +1 -0
  33. package/package.json +1 -1
@@ -0,0 +1,340 @@
1
+ "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
17
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
+ return new (P || (P = Promise))(function (resolve, reject) {
20
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
23
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
24
+ });
25
+ };
26
+ var __generator = (this && this.__generator) || function (thisArg, body) {
27
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
28
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
29
+ function verb(n) { return function (v) { return step([n, v]); }; }
30
+ function step(op) {
31
+ if (f) throw new TypeError("Generator is already executing.");
32
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
33
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
34
+ if (y = 0, t) op = [op[0] & 2, t.value];
35
+ switch (op[0]) {
36
+ case 0: case 1: t = op; break;
37
+ case 4: _.label++; return { value: op[1], done: false };
38
+ case 5: _.label++; y = op[1]; op = [0]; continue;
39
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
40
+ default:
41
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
42
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
43
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
44
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
45
+ if (t[2]) _.ops.pop();
46
+ _.trys.pop(); continue;
47
+ }
48
+ op = body.call(thisArg, _);
49
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
50
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
+ }
52
+ };
53
+ var __importDefault = (this && this.__importDefault) || function (mod) {
54
+ return (mod && mod.__esModule) ? mod : { "default": mod };
55
+ };
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ exports.ApiQuotaPoller = exports.AuthenticationError = void 0;
58
+ var fs_1 = __importDefault(require("fs"));
59
+ var LOG_FILE = '/tmp/autopilot.log';
60
+ function logToFile(message) {
61
+ var timestamp = new Date().toISOString();
62
+ fs_1.default.appendFileSync(LOG_FILE, "[".concat(timestamp, "] ").concat(message, "\n"));
63
+ }
64
+ var ANTIGRAVITY_CLIENT_ID = '1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com';
65
+ var ANTIGRAVITY_CLIENT_SECRET = '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';
66
+ var GOOGLE_TOKEN_URL = 'https://oauth2.googleapis.com/token';
67
+ var CLOUDCODE_BASE_URL = 'https://cloudcode-pa.googleapis.com';
68
+ var CLOUDCODE_METADATA = {
69
+ ideType: 'ANTIGRAVITY',
70
+ platform: 'PLATFORM_UNSPECIFIED',
71
+ pluginType: 'GEMINI',
72
+ };
73
+ var AuthenticationError = /** @class */ (function (_super) {
74
+ __extends(AuthenticationError, _super);
75
+ function AuthenticationError(message) {
76
+ var _this = _super.call(this, message) || this;
77
+ _this.name = 'AuthenticationError';
78
+ return _this;
79
+ }
80
+ return AuthenticationError;
81
+ }(Error));
82
+ exports.AuthenticationError = AuthenticationError;
83
+ var ApiQuotaPoller = /** @class */ (function () {
84
+ function ApiQuotaPoller() {
85
+ if (!(this instanceof ApiQuotaPoller)) {
86
+ // @ts-ignore
87
+ return new ApiQuotaPoller();
88
+ }
89
+ }
90
+ ApiQuotaPoller.prototype.refreshAccessToken = function (refreshToken) {
91
+ return __awaiter(this, void 0, void 0, function () {
92
+ var params, controller, timeout, response, data, e_1;
93
+ return __generator(this, function (_a) {
94
+ switch (_a.label) {
95
+ case 0:
96
+ params = new URLSearchParams({
97
+ client_id: ANTIGRAVITY_CLIENT_ID,
98
+ client_secret: ANTIGRAVITY_CLIENT_SECRET,
99
+ refresh_token: refreshToken,
100
+ grant_type: 'refresh_token',
101
+ });
102
+ controller = new AbortController();
103
+ timeout = setTimeout(function () { return controller.abort(); }, 10000);
104
+ _a.label = 1;
105
+ case 1:
106
+ _a.trys.push([1, 4, 5, 6]);
107
+ return [4 /*yield*/, fetch(GOOGLE_TOKEN_URL, {
108
+ method: 'POST',
109
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
110
+ body: params.toString(),
111
+ signal: controller.signal,
112
+ })];
113
+ case 2:
114
+ response = _a.sent();
115
+ if (!response.ok) {
116
+ logToFile("Token refresh failed: ".concat(response.status));
117
+ if (response.status === 401 || response.status === 403) {
118
+ throw new AuthenticationError("Token refresh failed (".concat(response.status, ")"));
119
+ }
120
+ throw new Error("Token refresh failed (".concat(response.status, ")"));
121
+ }
122
+ return [4 /*yield*/, response.json()];
123
+ case 3:
124
+ data = (_a.sent());
125
+ return [2 /*return*/, data.access_token];
126
+ case 4:
127
+ e_1 = _a.sent();
128
+ logToFile("Token refresh error: ".concat(e_1.message));
129
+ throw e_1;
130
+ case 5:
131
+ clearTimeout(timeout);
132
+ return [7 /*endfinally*/];
133
+ case 6: return [2 /*return*/];
134
+ }
135
+ });
136
+ });
137
+ };
138
+ ApiQuotaPoller.prototype.loadCodeAssist = function (accessToken) {
139
+ return __awaiter(this, void 0, void 0, function () {
140
+ var controller, timeout, response;
141
+ return __generator(this, function (_a) {
142
+ switch (_a.label) {
143
+ case 0:
144
+ controller = new AbortController();
145
+ timeout = setTimeout(function () { return controller.abort(); }, 10000);
146
+ _a.label = 1;
147
+ case 1:
148
+ _a.trys.push([1, , 4, 5]);
149
+ return [4 /*yield*/, fetch("".concat(CLOUDCODE_BASE_URL, "/v1internal:loadCodeAssist"), {
150
+ method: 'POST',
151
+ headers: {
152
+ Authorization: "Bearer ".concat(accessToken),
153
+ 'Content-Type': 'application/json',
154
+ 'User-Agent': 'antigravity',
155
+ },
156
+ body: JSON.stringify({ metadata: CLOUDCODE_METADATA }),
157
+ signal: controller.signal,
158
+ })];
159
+ case 2:
160
+ response = _a.sent();
161
+ if (!response.ok) {
162
+ logToFile("loadCodeAssist failed: ".concat(response.status));
163
+ throw new Error("loadCodeAssist failed (".concat(response.status, ")"));
164
+ }
165
+ return [4 /*yield*/, response.json()];
166
+ case 3: return [2 /*return*/, (_a.sent())];
167
+ case 4:
168
+ clearTimeout(timeout);
169
+ return [7 /*endfinally*/];
170
+ case 5: return [2 /*return*/];
171
+ }
172
+ });
173
+ });
174
+ };
175
+ ApiQuotaPoller.prototype.extractProjectId = function (cloudaicompanionProject) {
176
+ if (!cloudaicompanionProject)
177
+ return undefined;
178
+ if (typeof cloudaicompanionProject === 'string') {
179
+ var match = cloudaicompanionProject.match(/projects\/([^/]+)/);
180
+ return match ? match[1] : undefined;
181
+ }
182
+ return undefined;
183
+ };
184
+ ApiQuotaPoller.prototype.fetchAvailableModels = function (accessToken, projectId) {
185
+ return __awaiter(this, void 0, void 0, function () {
186
+ var payload, controller, timeout, response;
187
+ return __generator(this, function (_a) {
188
+ switch (_a.label) {
189
+ case 0:
190
+ payload = projectId ? { project: projectId } : {};
191
+ controller = new AbortController();
192
+ timeout = setTimeout(function () { return controller.abort(); }, 10000);
193
+ _a.label = 1;
194
+ case 1:
195
+ _a.trys.push([1, , 4, 5]);
196
+ return [4 /*yield*/, fetch("".concat(CLOUDCODE_BASE_URL, "/v1internal:fetchAvailableModels"), {
197
+ method: 'POST',
198
+ headers: {
199
+ Authorization: "Bearer ".concat(accessToken),
200
+ 'Content-Type': 'application/json',
201
+ 'User-Agent': 'antigravity',
202
+ },
203
+ body: JSON.stringify(payload),
204
+ signal: controller.signal,
205
+ })];
206
+ case 2:
207
+ response = _a.sent();
208
+ if (!response.ok) {
209
+ logToFile("fetchAvailableModels failed: ".concat(response.status));
210
+ throw new Error("fetchModels failed (".concat(response.status, ")"));
211
+ }
212
+ return [4 /*yield*/, response.json()];
213
+ case 3: return [2 /*return*/, (_a.sent())];
214
+ case 4:
215
+ clearTimeout(timeout);
216
+ return [7 /*endfinally*/];
217
+ case 5: return [2 /*return*/];
218
+ }
219
+ });
220
+ });
221
+ };
222
+ ApiQuotaPoller.prototype.checkQuota = function (account) {
223
+ return __awaiter(this, void 0, void 0, function () {
224
+ var accessToken, projectId, codeAssist, quotaResponse, models, _i, _a, _b, modelKey, info, quotaInfo, label, lowerLabel, remainingFraction, error_1;
225
+ var _c;
226
+ return __generator(this, function (_d) {
227
+ switch (_d.label) {
228
+ case 0:
229
+ _d.trys.push([0, 5, , 6]);
230
+ return [4 /*yield*/, this.refreshAccessToken(account.refreshToken)];
231
+ case 1:
232
+ accessToken = _d.sent();
233
+ projectId = account.projectId || account.managedProjectId;
234
+ if (!!projectId) return [3 /*break*/, 3];
235
+ return [4 /*yield*/, this.loadCodeAssist(accessToken)];
236
+ case 2:
237
+ codeAssist = _d.sent();
238
+ projectId = this.extractProjectId(codeAssist.cloudaicompanionProject);
239
+ _d.label = 3;
240
+ case 3: return [4 /*yield*/, this.fetchAvailableModels(accessToken, projectId)];
241
+ case 4:
242
+ quotaResponse = _d.sent();
243
+ if (!quotaResponse.models)
244
+ return [2 /*return*/, []];
245
+ models = [];
246
+ for (_i = 0, _a = Object.entries(quotaResponse.models); _i < _a.length; _i++) {
247
+ _b = _a[_i], modelKey = _b[0], info = _b[1];
248
+ quotaInfo = info.quotaInfo;
249
+ if (!quotaInfo)
250
+ continue;
251
+ label = info.displayName || modelKey;
252
+ lowerLabel = label.toLowerCase();
253
+ // Filter out unwanted models
254
+ if (lowerLabel.startsWith('chat_') ||
255
+ lowerLabel.startsWith('rev19') ||
256
+ lowerLabel.includes('gemini 2.5') ||
257
+ lowerLabel.includes('gemini 3 pro image')) {
258
+ continue;
259
+ }
260
+ remainingFraction = Math.min(1, Math.max(0, (_c = quotaInfo.remainingFraction) !== null && _c !== void 0 ? _c : 0));
261
+ models.push({
262
+ model: info.model || modelKey,
263
+ displayName: label,
264
+ remainingFraction: remainingFraction,
265
+ isExhausted: remainingFraction <= 0,
266
+ resetTime: quotaInfo.resetTime,
267
+ });
268
+ }
269
+ return [2 /*return*/, models];
270
+ case 5:
271
+ error_1 = _d.sent();
272
+ if (error_1 instanceof AuthenticationError) {
273
+ throw error_1;
274
+ }
275
+ logToFile("Failed to check quota via API: ".concat(error_1));
276
+ return [2 /*return*/, []];
277
+ case 6: return [2 /*return*/];
278
+ }
279
+ });
280
+ });
281
+ };
282
+ ApiQuotaPoller.prototype.checkQuotaForModel = function (account, modelName) {
283
+ return __awaiter(this, void 0, void 0, function () {
284
+ var models, model, normalizedSearch_1;
285
+ return __generator(this, function (_a) {
286
+ switch (_a.label) {
287
+ case 0: return [4 /*yield*/, this.checkQuota(account)];
288
+ case 1:
289
+ models = _a.sent();
290
+ model = models.find(function (m) { return m.model === modelName || m.displayName === modelName; });
291
+ // Try partial match (e.g., "gemini-3-pro" matches "Gemini 3 Pro")
292
+ if (!model) {
293
+ normalizedSearch_1 = modelName.toLowerCase().replace(/[-_]/g, ' ');
294
+ model = models.find(function (m) {
295
+ return m.model.toLowerCase().includes(normalizedSearch_1) ||
296
+ m.displayName.toLowerCase().includes(normalizedSearch_1);
297
+ });
298
+ }
299
+ if (!model)
300
+ return [2 /*return*/, null];
301
+ return [2 /*return*/, {
302
+ remainingFraction: model.remainingFraction,
303
+ resetTime: model.resetTime,
304
+ model: model.model,
305
+ }];
306
+ }
307
+ });
308
+ });
309
+ };
310
+ ApiQuotaPoller.prototype.getAllQuotas = function (account) {
311
+ return __awaiter(this, void 0, void 0, function () {
312
+ var models, quotaMap, _i, models_1, model;
313
+ return __generator(this, function (_a) {
314
+ switch (_a.label) {
315
+ case 0: return [4 /*yield*/, this.checkQuota(account)];
316
+ case 1:
317
+ models = _a.sent();
318
+ quotaMap = new Map();
319
+ for (_i = 0, models_1 = models; _i < models_1.length; _i++) {
320
+ model = models_1[_i];
321
+ quotaMap.set(model.model, {
322
+ remainingFraction: model.remainingFraction,
323
+ resetTime: model.resetTime,
324
+ model: model.model,
325
+ });
326
+ // Also add by display name for easier lookup
327
+ quotaMap.set(model.displayName, {
328
+ remainingFraction: model.remainingFraction,
329
+ resetTime: model.resetTime,
330
+ model: model.model,
331
+ });
332
+ }
333
+ return [2 /*return*/, quotaMap];
334
+ }
335
+ });
336
+ });
337
+ };
338
+ return ApiQuotaPoller;
339
+ }());
340
+ exports.ApiQuotaPoller = ApiQuotaPoller;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.LSPFinder = void 0;
37
+ var child_process_1 = require("child_process");
38
+ var readline = __importStar(require("readline"));
39
+ var LSPFinder = /** @class */ (function () {
40
+ function LSPFinder() {
41
+ if (!(this instanceof LSPFinder)) {
42
+ // @ts-ignore
43
+ return new LSPFinder();
44
+ }
45
+ }
46
+ LSPFinder.prototype.findProcess = function () {
47
+ return new Promise(function (resolve) {
48
+ var ps = (0, child_process_1.spawn)('ps', ['aux']);
49
+ var rl = readline.createInterface({
50
+ input: ps.stdout,
51
+ crlfDelay: Infinity,
52
+ });
53
+ ps.on('error', function () {
54
+ rl.close();
55
+ resolve(null);
56
+ });
57
+ var found = false;
58
+ rl.on('line', function (line) {
59
+ if (found)
60
+ return;
61
+ if (line.includes('language_server_antigravity')) {
62
+ var pidMatch = line.trim().split(/\s+/)[1];
63
+ var csrfMatch = line.match(/--csrf_token=([a-zA-Z0-9_\-]+)/);
64
+ var portMatch = line.match(/--extension_server_port=(\d+)/);
65
+ if (pidMatch && csrfMatch && portMatch) {
66
+ found = true;
67
+ resolve({
68
+ pid: parseInt(pidMatch, 10),
69
+ csrfToken: csrfMatch[1],
70
+ port: parseInt(portMatch[1], 10),
71
+ });
72
+ ps.kill();
73
+ rl.close();
74
+ }
75
+ }
76
+ });
77
+ ps.on('close', function () {
78
+ if (!found) {
79
+ resolve(null);
80
+ }
81
+ });
82
+ });
83
+ };
84
+ return LSPFinder;
85
+ }());
86
+ exports.LSPFinder = LSPFinder;
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.QuotaCacheUpdater = void 0;
43
+ exports.writeQuotaToCache = writeQuotaToCache;
44
+ exports.startQuotaCacheService = startQuotaCacheService;
45
+ var manager_1 = require("../manager");
46
+ var fs_1 = __importDefault(require("fs"));
47
+ var path_1 = __importDefault(require("path"));
48
+ var os_1 = __importDefault(require("os"));
49
+ var LOG_FILE = '/tmp/autopilot.log';
50
+ function logToFile(message) {
51
+ var timestamp = new Date().toISOString();
52
+ fs_1.default.appendFileSync(LOG_FILE, "[".concat(timestamp, "] [QuotaCacheUpdater] ").concat(message, "\n"));
53
+ }
54
+ function getQuotaCachePath() {
55
+ var xdgConfigHome = process.env.XDG_CONFIG_HOME;
56
+ if (xdgConfigHome) {
57
+ return path_1.default.join(xdgConfigHome, 'opencode', 'quota-cache.json');
58
+ }
59
+ var homeDir = os_1.default.homedir();
60
+ return path_1.default.join(homeDir, '.config', 'opencode', 'quota-cache.json');
61
+ }
62
+ function writeQuotaToCache(quota) {
63
+ return __awaiter(this, void 0, void 0, function () {
64
+ var cache, cachePath, cacheDir;
65
+ return __generator(this, function (_a) {
66
+ try {
67
+ cache = {
68
+ percentage: Math.round(quota.remainingFraction * 100),
69
+ model: quota.model || 'unknown',
70
+ timestamp: Date.now(),
71
+ };
72
+ cachePath = getQuotaCachePath();
73
+ cacheDir = path_1.default.dirname(cachePath);
74
+ if (!fs_1.default.existsSync(cacheDir)) {
75
+ fs_1.default.mkdirSync(cacheDir, { recursive: true });
76
+ }
77
+ fs_1.default.writeFileSync(cachePath, JSON.stringify(cache, null, 2), 'utf-8');
78
+ }
79
+ catch (error) {
80
+ logToFile("Failed to write quota cache: ".concat(error));
81
+ }
82
+ return [2 /*return*/];
83
+ });
84
+ });
85
+ }
86
+ var DEFAULT_IDLE_POLL_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
87
+ var QuotaCacheUpdater = /** @class */ (function () {
88
+ function QuotaCacheUpdater(manager, idlePollIntervalMs) {
89
+ if (idlePollIntervalMs === void 0) { idlePollIntervalMs = DEFAULT_IDLE_POLL_INTERVAL_MS; }
90
+ if (!(this instanceof QuotaCacheUpdater)) {
91
+ // @ts-ignore
92
+ return new QuotaCacheUpdater(manager, idlePollIntervalMs);
93
+ }
94
+ this.idleTimeoutId = null;
95
+ this.manager = manager;
96
+ this.idlePollIntervalMs = idlePollIntervalMs;
97
+ this.lastQueryTime = 0;
98
+ }
99
+ QuotaCacheUpdater.prototype.updateCache = function () {
100
+ return __awaiter(this, void 0, void 0, function () {
101
+ var quota, cache, cachePath, cacheDir, error_1;
102
+ return __generator(this, function (_a) {
103
+ switch (_a.label) {
104
+ case 0:
105
+ _a.trys.push([0, 2, , 3]);
106
+ return [4 /*yield*/, this.manager.getQuotaViaApi()];
107
+ case 1:
108
+ quota = _a.sent();
109
+ if (!quota) {
110
+ return [2 /*return*/];
111
+ }
112
+ cache = {
113
+ percentage: Math.round(quota.remainingFraction * 100),
114
+ model: quota.model || 'unknown',
115
+ timestamp: Date.now(),
116
+ };
117
+ cachePath = getQuotaCachePath();
118
+ cacheDir = path_1.default.dirname(cachePath);
119
+ if (!fs_1.default.existsSync(cacheDir)) {
120
+ fs_1.default.mkdirSync(cacheDir, { recursive: true });
121
+ }
122
+ fs_1.default.writeFileSync(cachePath, JSON.stringify(cache, null, 2), 'utf-8');
123
+ logToFile("Cache updated: ".concat(cache.percentage, "% remaining for ").concat(cache.model));
124
+ return [3 /*break*/, 3];
125
+ case 2:
126
+ error_1 = _a.sent();
127
+ logToFile("Failed to update quota cache: ".concat(error_1));
128
+ return [3 /*break*/, 3];
129
+ case 3: return [2 /*return*/];
130
+ }
131
+ });
132
+ });
133
+ };
134
+ /**
135
+ * Called after a query is made to refresh quota and reset idle timer.
136
+ */
137
+ QuotaCacheUpdater.prototype.onQueryCompleted = function () {
138
+ return __awaiter(this, void 0, void 0, function () {
139
+ return __generator(this, function (_a) {
140
+ switch (_a.label) {
141
+ case 0:
142
+ this.lastQueryTime = Date.now();
143
+ return [4 /*yield*/, this.updateCache()];
144
+ case 1:
145
+ _a.sent();
146
+ this.resetIdleTimer();
147
+ return [2 /*return*/];
148
+ }
149
+ });
150
+ });
151
+ };
152
+ /**
153
+ * Start the updater - polls immediately and sets up idle polling.
154
+ */
155
+ QuotaCacheUpdater.prototype.start = function () {
156
+ logToFile('Starting QuotaCacheUpdater');
157
+ this.lastQueryTime = Date.now();
158
+ this.updateCache();
159
+ this.resetIdleTimer();
160
+ };
161
+ /**
162
+ * Reset the idle timer. Called after each query.
163
+ */
164
+ QuotaCacheUpdater.prototype.resetIdleTimer = function () {
165
+ var _this = this;
166
+ if (this.idleTimeoutId) {
167
+ clearTimeout(this.idleTimeoutId);
168
+ }
169
+ this.idleTimeoutId = setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
170
+ var timeSinceLastQuery;
171
+ return __generator(this, function (_a) {
172
+ switch (_a.label) {
173
+ case 0:
174
+ timeSinceLastQuery = Date.now() - this.lastQueryTime;
175
+ logToFile("Idle poll triggered. Time since last query: ".concat(Math.round(timeSinceLastQuery / 1000), "s"));
176
+ return [4 /*yield*/, this.updateCache()];
177
+ case 1:
178
+ _a.sent();
179
+ this.resetIdleTimer(); // Schedule next idle poll
180
+ return [2 /*return*/];
181
+ }
182
+ });
183
+ }); }, this.idlePollIntervalMs);
184
+ };
185
+ QuotaCacheUpdater.prototype.stop = function () {
186
+ if (this.idleTimeoutId) {
187
+ clearTimeout(this.idleTimeoutId);
188
+ this.idleTimeoutId = null;
189
+ }
190
+ logToFile('QuotaCacheUpdater stopped');
191
+ };
192
+ return QuotaCacheUpdater;
193
+ }());
194
+ exports.QuotaCacheUpdater = QuotaCacheUpdater;
195
+ function startQuotaCacheService() {
196
+ return __awaiter(this, arguments, void 0, function (idlePollIntervalMs) {
197
+ var manager, updater;
198
+ if (idlePollIntervalMs === void 0) { idlePollIntervalMs = DEFAULT_IDLE_POLL_INTERVAL_MS; }
199
+ return __generator(this, function (_a) {
200
+ switch (_a.label) {
201
+ case 0:
202
+ manager = new manager_1.QuotaManager();
203
+ return [4 /*yield*/, manager.initialize()];
204
+ case 1:
205
+ _a.sent();
206
+ updater = new QuotaCacheUpdater(manager, idlePollIntervalMs);
207
+ updater.start();
208
+ return [2 /*return*/, updater];
209
+ }
210
+ });
211
+ });
212
+ }