opencode-antigravity-autopilot 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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +205 -0
  3. package/dist/auth/AccountRotator.d.ts +9 -0
  4. package/dist/auth/AccountRotator.d.ts.map +1 -0
  5. package/dist/auth/AccountRotator.js +47 -0
  6. package/dist/auth/AccountRotator.js.map +1 -0
  7. package/dist/auth/TokenStorageReader.d.ts +22 -0
  8. package/dist/auth/TokenStorageReader.d.ts.map +1 -0
  9. package/dist/auth/TokenStorageReader.js +46 -0
  10. package/dist/auth/TokenStorageReader.js.map +1 -0
  11. package/dist/index.d.ts +11 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +10 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/manager.d.ts +31 -0
  16. package/dist/manager.d.ts.map +1 -0
  17. package/dist/manager.js +95 -0
  18. package/dist/manager.js.map +1 -0
  19. package/dist/oh-my-opencode.d.ts +17 -0
  20. package/dist/oh-my-opencode.d.ts.map +1 -0
  21. package/dist/oh-my-opencode.js +59 -0
  22. package/dist/oh-my-opencode.js.map +1 -0
  23. package/dist/plugin.d.ts +19 -0
  24. package/dist/plugin.d.ts.map +1 -0
  25. package/dist/plugin.js +26 -0
  26. package/dist/plugin.js.map +1 -0
  27. package/dist/quota/LSPFinder.d.ts +8 -0
  28. package/dist/quota/LSPFinder.d.ts.map +1 -0
  29. package/dist/quota/LSPFinder.js +43 -0
  30. package/dist/quota/LSPFinder.js.map +1 -0
  31. package/dist/quota/QuotaPoller.d.ts +8 -0
  32. package/dist/quota/QuotaPoller.d.ts.map +1 -0
  33. package/dist/quota/QuotaPoller.js +26 -0
  34. package/dist/quota/QuotaPoller.js.map +1 -0
  35. package/dist/rotation/ModelSelector.d.ts +12 -0
  36. package/dist/rotation/ModelSelector.d.ts.map +1 -0
  37. package/dist/rotation/ModelSelector.js +26 -0
  38. package/dist/rotation/ModelSelector.js.map +1 -0
  39. package/dist/rotation/QuotaTracker.d.ts +13 -0
  40. package/dist/rotation/QuotaTracker.d.ts.map +1 -0
  41. package/dist/rotation/QuotaTracker.js +54 -0
  42. package/dist/rotation/QuotaTracker.js.map +1 -0
  43. package/dist/types.d.ts +42 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +2 -0
  46. package/dist/types.js.map +1 -0
  47. package/package.json +59 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gooseware
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,205 @@
1
+ # OpenCode Antigravity Autopilot
2
+
3
+ [![npm version](https://img.shields.io/npm/v/opencode-antigravity-autopilot.svg)](https://www.npmjs.com/package/opencode-antigravity-autopilot)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5
+
6
+ Intelligent quota management and model rotation for [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth). Automatically switches models when quota runs low, tracks usage across accounts, and works with both **OpenCode** and **oh-my-opencode**.
7
+
8
+ ## Quick Install
9
+
10
+ **New to the Antigravity ecosystem? Start here:**
11
+
12
+ 👉 **[Complete Installation Guide](INSTALL.md)** - Step-by-step setup for auth + quota + oh-my-opencode
13
+
14
+ **Let an LLM set it up:**
15
+
16
+ ```
17
+ Set up opencode-antigravity-autopilot for me. Follow:
18
+ https://raw.githubusercontent.com/gooseware/opencode-antigravity-autopilot/main/INSTALL.md
19
+
20
+ Ask me:
21
+ 1. Am I using oh-my-opencode or vanilla OpenCode?
22
+ 2. What models do I prefer? (e.g., gemini-3-pro, claude-sonnet-4-5-thinking)
23
+ 3. Should quota rotation be automatic?
24
+
25
+ Then configure everything for me.
26
+ ```
27
+
28
+ ## Manual Install
29
+
30
+ ### Prerequisites
31
+
32
+ - [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) installed and authenticated
33
+ - Node.js >= 20
34
+
35
+ ### Installation
36
+
37
+ ```bash
38
+ npm install opencode-antigravity-autopilot
39
+ ```
40
+
41
+ ## Configuration
42
+
43
+ ### For OpenCode
44
+
45
+ Add to `~/.config/opencode/opencode.json`:
46
+
47
+ ```json
48
+ {
49
+ "plugin": [
50
+ "opencode-antigravity-auth@beta",
51
+ "opencode-antigravity-autopilot"
52
+ ]
53
+ }
54
+ ```
55
+
56
+ ### For oh-my-opencode
57
+
58
+ Add to `~/.config/opencode/oh-my-opencode.json`:
59
+
60
+ ```json
61
+ {
62
+ "google_auth": false,
63
+ "quota_rotation": true,
64
+ "agents": {
65
+ "Sisyphus": { "model": "google/antigravity-claude-sonnet-4-5" },
66
+ "librarian": { "model": "google/antigravity-gemini-3-flash" },
67
+ "explore": { "model": "google/antigravity-gemini-3-flash" },
68
+ "oracle": { "model": "google/antigravity-claude-opus-4-5-thinking" }
69
+ }
70
+ }
71
+ ```
72
+
73
+ ## Usage
74
+
75
+ ### Basic Usage
76
+
77
+ ```typescript
78
+ import { QuotaManager } from 'opencode-antigravity-autopilot';
79
+
80
+ const manager = new QuotaManager({
81
+ quotaThreshold: 0.2,
82
+ preferredModels: [
83
+ 'google/antigravity-gemini-3-pro',
84
+ 'google/antigravity-claude-sonnet-4-5'
85
+ ]
86
+ });
87
+
88
+ await manager.initialize();
89
+
90
+ const bestModel = manager.selectBestModel();
91
+ console.log(`Using model: ${bestModel}`);
92
+
93
+ const quota = await manager.getQuota();
94
+ console.log(`Remaining quota: ${quota?.remainingFraction * 100}%`);
95
+ ```
96
+
97
+ ### oh-my-opencode Integration
98
+
99
+ ```typescript
100
+ import { createOhMyOpenCodeIntegration, QuotaManager } from 'opencode-antigravity-autopilot';
101
+
102
+ const manager = new QuotaManager();
103
+ await manager.initialize();
104
+
105
+ const integration = createOhMyOpenCodeIntegration(manager, {
106
+ defaultModel: 'google/antigravity-gemini-3-flash'
107
+ });
108
+
109
+ const modelForAgent = await integration.getModelForAgent('oracle');
110
+ console.log(`Oracle will use: ${modelForAgent}`);
111
+ ```
112
+
113
+ ### Model Rotation Strategy
114
+
115
+ ```typescript
116
+ manager.setModelRotationStrategy({
117
+ preferredModels: [
118
+ 'google/antigravity-gemini-3-pro-high',
119
+ 'google/antigravity-claude-sonnet-4-5-thinking'
120
+ ],
121
+ fallbackModels: [
122
+ 'google/antigravity-gemini-3-flash',
123
+ 'google/gemini-2.5-flash'
124
+ ],
125
+ quotaThreshold: 0.15
126
+ });
127
+ ```
128
+
129
+ ## Features
130
+
131
+ - **Automatic Model Rotation**: Switches to fallback models when quota drops below threshold
132
+ - **Multi-Account Support**: Leverages opencode-antigravity-auth's account pool
133
+ - **Quota Tracking**: Real-time monitoring via LSP process
134
+ - **oh-my-opencode Compatible**: Dynamic agent model assignment
135
+ - **Zero Config**: Works out-of-box with sensible defaults
136
+
137
+ ## How It Works
138
+
139
+ 1. Reads authenticated accounts from opencode-antigravity-auth storage
140
+ 2. Monitors quota via Antigravity LSP process (passive monitoring)
141
+ 3. Tracks quota per model and selects best available option
142
+ 4. Auto-rotates accounts when current account is exhausted
143
+ 5. Integrates with oh-my-opencode for agent-level model management
144
+
145
+ ## API
146
+
147
+ ### `QuotaManager`
148
+
149
+ ```typescript
150
+ const manager = new QuotaManager(config?: PluginConfig);
151
+ await manager.initialize();
152
+
153
+ manager.getQuota(): Promise<QuotaInfo | null>
154
+ manager.selectBestModel(): string | null
155
+ manager.rotateAccount(): Promise<void>
156
+ manager.updateQuotaForModel(model: string, quota: QuotaInfo): void
157
+ manager.setModelRotationStrategy(strategy: ModelRotationStrategy): void
158
+ ```
159
+
160
+ ### `createOhMyOpenCodeIntegration`
161
+
162
+ ```typescript
163
+ const integration = createOhMyOpenCodeIntegration(manager, config);
164
+
165
+ integration.getModelForAgent(agentName: string, preferredModel?: string): Promise<string>
166
+ integration.updateAgentConfig(config: OhMyOpenCodeConfig, strategy: ModelRotationStrategy): OhMyOpenCodeConfig
167
+ integration.pollQuotaAndRotate(models: string[]): Promise<void>
168
+ ```
169
+
170
+ ## Configuration Options
171
+
172
+ ```typescript
173
+ interface PluginConfig {
174
+ quotaThreshold?: number; // Default: 0.2 (20%)
175
+ pollIntervalMs?: number; // Default: 60000 (1 min)
176
+ enableRotation?: boolean; // Default: true
177
+ preferredModels?: string[]; // Models to prefer
178
+ }
179
+ ```
180
+
181
+ ## Troubleshooting
182
+
183
+ **LSP Process Not Found**
184
+ - Ensure Antigravity IDE is running
185
+ - Check `ps aux | grep language_server_antigravity`
186
+
187
+ **Quota Always Shows Null**
188
+ - Verify opencode-antigravity-auth is authenticated
189
+ - Restart Antigravity IDE
190
+
191
+ **Models Not Rotating**
192
+ - Check `quotaThreshold` setting
193
+ - Verify preferred models are configured correctly
194
+
195
+ ## Credits
196
+
197
+ Built on [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) by [@NoeFabris](https://github.com/NoeFabris). This plugin extends its authentication system with intelligent quota management.
198
+
199
+ ## License
200
+
201
+ MIT
202
+
203
+ ## Contributing
204
+
205
+ Issues and PRs welcome at [github.com/gooseware/opencode-antigravity-autopilot](https://github.com/gooseware/opencode-antigravity-autopilot)
@@ -0,0 +1,9 @@
1
+ import { AccountMetadataV3 } from './TokenStorageReader';
2
+ export declare class AccountRotator {
3
+ private accounts;
4
+ private activeIndex;
5
+ constructor(accounts: AccountMetadataV3[], initialIndex: number);
6
+ getCurrentAccount(): AccountMetadataV3 | null;
7
+ markCurrentExhausted(cooldownMs?: number): number;
8
+ }
9
+ //# sourceMappingURL=AccountRotator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccountRotator.d.ts","sourceRoot":"","sources":["../../src/auth/AccountRotator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,WAAW,CAAS;gBAEhB,QAAQ,EAAE,iBAAiB,EAAE,EAAE,YAAY,EAAE,MAAM;IAKxD,iBAAiB,IAAI,iBAAiB,GAAG,IAAI;IAqC7C,oBAAoB,CAAC,UAAU,GAAE,MAAuB,GAAG,MAAM;CAYzE"}
@@ -0,0 +1,47 @@
1
+ export class AccountRotator {
2
+ accounts;
3
+ activeIndex;
4
+ constructor(accounts, initialIndex) {
5
+ this.accounts = [...accounts];
6
+ this.activeIndex = initialIndex;
7
+ }
8
+ getCurrentAccount() {
9
+ if (this.accounts.length === 0) {
10
+ return null;
11
+ }
12
+ const count = this.accounts.length;
13
+ const now = Date.now();
14
+ for (let i = 0; i < count; i++) {
15
+ const index = (this.activeIndex + i) % count;
16
+ const account = this.accounts[index];
17
+ if (!account.coolingDownUntil || account.coolingDownUntil <= now) {
18
+ this.activeIndex = index;
19
+ return account;
20
+ }
21
+ }
22
+ let minCooldown = Infinity;
23
+ let minIndex = -1;
24
+ for (let i = 0; i < count; i++) {
25
+ const account = this.accounts[i];
26
+ if (account.coolingDownUntil && account.coolingDownUntil < minCooldown) {
27
+ minCooldown = account.coolingDownUntil;
28
+ minIndex = i;
29
+ }
30
+ }
31
+ if (minIndex !== -1) {
32
+ this.activeIndex = minIndex;
33
+ return this.accounts[minIndex];
34
+ }
35
+ return this.accounts[this.activeIndex];
36
+ }
37
+ markCurrentExhausted(cooldownMs = 30 * 60 * 1000) {
38
+ if (this.accounts.length === 0) {
39
+ return -1;
40
+ }
41
+ const currentAccount = this.accounts[this.activeIndex];
42
+ currentAccount.coolingDownUntil = Date.now() + cooldownMs;
43
+ this.activeIndex = (this.activeIndex + 1) % this.accounts.length;
44
+ return this.activeIndex;
45
+ }
46
+ }
47
+ //# sourceMappingURL=AccountRotator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccountRotator.js","sourceRoot":"","sources":["../../src/auth/AccountRotator.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,cAAc;IACjB,QAAQ,CAAsB;IAC9B,WAAW,CAAS;IAE5B,YAAY,QAA6B,EAAE,YAAoB;QAC7D,IAAI,CAAC,QAAQ,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAG,YAAY,CAAC;IAClC,CAAC;IAEM,iBAAiB;QACtB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;YAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAErC,IAAI,CAAC,OAAO,CAAC,gBAAgB,IAAI,OAAO,CAAC,gBAAgB,IAAI,GAAG,EAAE,CAAC;gBACjE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;gBACzB,OAAO,OAAO,CAAC;YACjB,CAAC;QACH,CAAC;QAED,IAAI,WAAW,GAAG,QAAQ,CAAC;QAC3B,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC;QAElB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YACjC,IAAI,OAAO,CAAC,gBAAgB,IAAI,OAAO,CAAC,gBAAgB,GAAG,WAAW,EAAE,CAAC;gBACvE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC;gBACvC,QAAQ,GAAG,CAAC,CAAC;YACf,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC;YAC5B,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAED,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACzC,CAAC;IAEM,oBAAoB,CAAC,aAAqB,EAAE,GAAG,EAAE,GAAG,IAAI;QAC7D,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,CAAC,CAAC;QACd,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACvD,cAAc,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC;QAE1D,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAEjE,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ export interface AccountMetadataV3 {
2
+ refreshToken: string;
3
+ email: string;
4
+ addedAt?: number;
5
+ lastUsed?: number;
6
+ coolingDownUntil?: number;
7
+ }
8
+ export interface AccountStorageV3 {
9
+ version: number;
10
+ accounts: AccountMetadataV3[];
11
+ activeIndex: number;
12
+ }
13
+ export declare class TokenStorageReader {
14
+ private accounts;
15
+ private activeIndex;
16
+ constructor();
17
+ getAccounts(): AccountMetadataV3[];
18
+ getActiveIndex(): number;
19
+ private load;
20
+ private getStoragePath;
21
+ }
22
+ //# sourceMappingURL=TokenStorageReader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenStorageReader.d.ts","sourceRoot":"","sources":["../../src/auth/TokenStorageReader.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,WAAW,CAAc;;IAM1B,WAAW,IAAI,iBAAiB,EAAE;IAIlC,cAAc,IAAI,MAAM;IAI/B,OAAO,CAAC,IAAI;IA0BZ,OAAO,CAAC,cAAc;CASvB"}
@@ -0,0 +1,46 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ export class TokenStorageReader {
5
+ accounts = [];
6
+ activeIndex = -1;
7
+ constructor() {
8
+ this.load();
9
+ }
10
+ getAccounts() {
11
+ return this.accounts;
12
+ }
13
+ getActiveIndex() {
14
+ return this.activeIndex;
15
+ }
16
+ load() {
17
+ const storagePath = this.getStoragePath();
18
+ if (!fs.existsSync(storagePath)) {
19
+ console.warn(`Token storage file not found at ${storagePath}`);
20
+ return;
21
+ }
22
+ try {
23
+ const content = fs.readFileSync(storagePath, 'utf-8');
24
+ const data = JSON.parse(content);
25
+ if (data.version !== 3) {
26
+ console.warn(`Unsupported storage version: ${data.version}. Expected version 3.`);
27
+ return;
28
+ }
29
+ const storage = data;
30
+ this.accounts = storage.accounts || [];
31
+ this.activeIndex = storage.activeIndex ?? -1;
32
+ }
33
+ catch (error) {
34
+ console.error('Failed to parse token storage file:', error);
35
+ }
36
+ }
37
+ getStoragePath() {
38
+ const xdgConfigHome = process.env.XDG_CONFIG_HOME;
39
+ if (xdgConfigHome) {
40
+ return path.join(xdgConfigHome, 'opencode', 'antigravity-accounts.json');
41
+ }
42
+ const homeDir = os.homedir();
43
+ return path.join(homeDir, '.config', 'opencode', 'antigravity-accounts.json');
44
+ }
45
+ }
46
+ //# sourceMappingURL=TokenStorageReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenStorageReader.js","sourceRoot":"","sources":["../../src/auth/TokenStorageReader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAgBzB,MAAM,OAAO,kBAAkB;IACrB,QAAQ,GAAwB,EAAE,CAAC;IACnC,WAAW,GAAW,CAAC,CAAC,CAAC;IAEjC;QACE,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAEM,WAAW;QAChB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAEM,cAAc;QACnB,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAEO,IAAI;QACV,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QAE1C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,mCAAmC,WAAW,EAAE,CAAC,CAAC;YAC/D,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YACtD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAEjC,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,IAAI,CAAC,gCAAgC,IAAI,CAAC,OAAO,uBAAuB,CAAC,CAAC;gBAClF,OAAO;YACT,CAAC;YAED,MAAM,OAAO,GAAG,IAAwB,CAAC;YACzC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;YACvC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;QAE/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAEO,cAAc;QACpB,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QAClD,IAAI,aAAa,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,2BAA2B,CAAC,CAAC;QAC7E,CAAC;QAED,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,2BAA2B,CAAC,CAAC;IAChF,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ export { AntigravityQuotaPlugin } from './plugin';
2
+ export { QuotaManager, activate } from './manager';
3
+ export { createOhMyOpenCodeIntegration, generateOhMyOpenCodeConfig } from './oh-my-opencode';
4
+ export type { PluginConfig, ModelRotationStrategy, QuotaInfo, ModelQuotaState, AccountMetadataV3, AccountStorageV3, ModelFamily, } from './types';
5
+ export { TokenStorageReader } from './auth/TokenStorageReader';
6
+ export { AccountRotator } from './auth/AccountRotator';
7
+ export { LSPFinder } from './quota/LSPFinder';
8
+ export { QuotaPoller } from './quota/QuotaPoller';
9
+ export { QuotaTracker } from './rotation/QuotaTracker';
10
+ export { ModelSelector } from './rotation/ModelSelector';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,6BAA6B,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC7F,YAAY,EACV,YAAY,EACZ,qBAAqB,EACrB,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,GACZ,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export { AntigravityQuotaPlugin } from './plugin';
2
+ export { QuotaManager, activate } from './manager';
3
+ export { createOhMyOpenCodeIntegration, generateOhMyOpenCodeConfig } from './oh-my-opencode';
4
+ export { TokenStorageReader } from './auth/TokenStorageReader';
5
+ export { AccountRotator } from './auth/AccountRotator';
6
+ export { LSPFinder } from './quota/LSPFinder';
7
+ export { QuotaPoller } from './quota/QuotaPoller';
8
+ export { QuotaTracker } from './rotation/QuotaTracker';
9
+ export { ModelSelector } from './rotation/ModelSelector';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,6BAA6B,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAU7F,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { QuotaInfo } from './quota/QuotaPoller';
2
+ import { QuotaTracker } from './rotation/QuotaTracker';
3
+ import { PluginConfig, ModelRotationStrategy } from './types';
4
+ export declare class QuotaManager {
5
+ private tokenReader;
6
+ private rotator;
7
+ private lspFinder;
8
+ private poller;
9
+ private quotaTracker;
10
+ private modelSelector;
11
+ private lspProcess;
12
+ constructor(config?: PluginConfig);
13
+ initialize(): Promise<void>;
14
+ getToken(): Promise<string | null>;
15
+ getQuota(): Promise<QuotaInfo | null>;
16
+ rotateAccount(): Promise<void>;
17
+ selectBestModel(): string | null;
18
+ updateQuotaForModel(model: string, quota: QuotaInfo): void;
19
+ getQuotaTracker(): QuotaTracker;
20
+ setModelRotationStrategy(strategy: ModelRotationStrategy): void;
21
+ }
22
+ export declare function activate(config?: PluginConfig): Promise<{
23
+ getToken(): Promise<string | null>;
24
+ getQuota(): Promise<QuotaInfo | null>;
25
+ rotateAccount(): Promise<void>;
26
+ selectBestModel(): string | null;
27
+ updateQuotaForModel(model: string, quota: QuotaInfo): void;
28
+ getQuotaTracker(): QuotaTracker;
29
+ setModelRotationStrategy(strategy: ModelRotationStrategy): void;
30
+ }>;
31
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAe,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAE9D,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,UAAU,CAAiE;gBAEvE,MAAM,CAAC,EAAE,YAAY;IAoB3B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAKlC,QAAQ,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAqBrC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI;IAI1D,eAAe,IAAI,YAAY;IAI/B,wBAAwB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,IAAI;CAGhE;AAED,wBAAsB,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY;gBAK9B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;gBAItB,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;qBAIpB,OAAO,CAAC,IAAI,CAAC;uBAIjB,MAAM,GAAG,IAAI;+BAIL,MAAM,SAAS,SAAS,GAAG,IAAI;uBAIvC,YAAY;uCAII,qBAAqB,GAAG,IAAI;GAIlE"}
@@ -0,0 +1,95 @@
1
+ import { TokenStorageReader } from './auth/TokenStorageReader';
2
+ import { AccountRotator } from './auth/AccountRotator';
3
+ import { LSPFinder } from './quota/LSPFinder';
4
+ import { QuotaPoller } from './quota/QuotaPoller';
5
+ import { QuotaTracker } from './rotation/QuotaTracker';
6
+ import { ModelSelector } from './rotation/ModelSelector';
7
+ export class QuotaManager {
8
+ tokenReader;
9
+ rotator;
10
+ lspFinder;
11
+ poller;
12
+ quotaTracker;
13
+ modelSelector = null;
14
+ lspProcess = null;
15
+ constructor(config) {
16
+ this.tokenReader = new TokenStorageReader();
17
+ const accounts = this.tokenReader.getAccounts();
18
+ const activeIndex = this.tokenReader.getActiveIndex();
19
+ this.rotator = new AccountRotator(accounts, activeIndex);
20
+ this.lspFinder = new LSPFinder();
21
+ this.poller = new QuotaPoller();
22
+ this.quotaTracker = new QuotaTracker(config?.quotaThreshold || 0.2);
23
+ if (config?.preferredModels) {
24
+ const strategy = {
25
+ preferredModels: config.preferredModels,
26
+ fallbackModels: [],
27
+ quotaThreshold: config.quotaThreshold || 0.2,
28
+ };
29
+ this.modelSelector = new ModelSelector(this.quotaTracker, strategy);
30
+ }
31
+ }
32
+ async initialize() {
33
+ this.lspProcess = await this.lspFinder.findProcess();
34
+ }
35
+ async getToken() {
36
+ const account = this.rotator.getCurrentAccount();
37
+ return account ? account.refreshToken : null;
38
+ }
39
+ async getQuota() {
40
+ if (!this.lspProcess) {
41
+ this.lspProcess = await this.lspFinder.findProcess();
42
+ }
43
+ if (!this.lspProcess) {
44
+ return null;
45
+ }
46
+ const quota = await this.poller.checkQuota(this.lspProcess.port, this.lspProcess.csrfToken);
47
+ if (!quota) {
48
+ this.lspProcess = null;
49
+ }
50
+ return quota;
51
+ }
52
+ async rotateAccount() {
53
+ this.rotator.markCurrentExhausted();
54
+ }
55
+ selectBestModel() {
56
+ return this.modelSelector?.selectModel() || null;
57
+ }
58
+ updateQuotaForModel(model, quota) {
59
+ this.quotaTracker.updateQuota(model, quota);
60
+ }
61
+ getQuotaTracker() {
62
+ return this.quotaTracker;
63
+ }
64
+ setModelRotationStrategy(strategy) {
65
+ this.modelSelector = new ModelSelector(this.quotaTracker, strategy);
66
+ }
67
+ }
68
+ export async function activate(config) {
69
+ const manager = new QuotaManager(config);
70
+ await manager.initialize();
71
+ return {
72
+ async getToken() {
73
+ return manager.getToken();
74
+ },
75
+ async getQuota() {
76
+ return manager.getQuota();
77
+ },
78
+ async rotateAccount() {
79
+ return manager.rotateAccount();
80
+ },
81
+ selectBestModel() {
82
+ return manager.selectBestModel();
83
+ },
84
+ updateQuotaForModel(model, quota) {
85
+ manager.updateQuotaForModel(model, quota);
86
+ },
87
+ getQuotaTracker() {
88
+ return manager.getQuotaTracker();
89
+ },
90
+ setModelRotationStrategy(strategy) {
91
+ manager.setModelRotationStrategy(strategy);
92
+ },
93
+ };
94
+ }
95
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { QuotaManager } from './manager';
2
+ import { ModelRotationStrategy } from './types';
3
+ interface OhMyOpenCodeConfig {
4
+ agents: Record<string, {
5
+ model: string;
6
+ }>;
7
+ }
8
+ export declare function createOhMyOpenCodeIntegration(quotaManager: QuotaManager, config?: {
9
+ defaultModel?: string;
10
+ }): {
11
+ getModelForAgent(agentName: string, preferredModel?: string): Promise<string>;
12
+ updateAgentConfig(existingConfig: OhMyOpenCodeConfig, modelRotationStrategy: ModelRotationStrategy): OhMyOpenCodeConfig;
13
+ pollQuotaAndRotate(models: string[]): Promise<void>;
14
+ };
15
+ export declare function generateOhMyOpenCodeConfig(preferredModels: string[]): OhMyOpenCodeConfig;
16
+ export {};
17
+ //# sourceMappingURL=oh-my-opencode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oh-my-opencode.d.ts","sourceRoot":"","sources":["../src/oh-my-opencode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAgB,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAE9D,UAAU,kBAAkB;IAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3C;AAED,wBAAgB,6BAA6B,CAC3C,YAAY,EAAE,YAAY,EAC1B,MAAM,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE;gCAGE,MAAM,mBAAmB,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;sCAmBjE,kBAAkB,yBACX,qBAAqB,GAC3C,kBAAkB;+BAkBY,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;EAS5D;AAED,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,MAAM,EAAE,GACxB,kBAAkB,CAqBpB"}
@@ -0,0 +1,59 @@
1
+ export function createOhMyOpenCodeIntegration(quotaManager, config) {
2
+ return {
3
+ async getModelForAgent(agentName, preferredModel) {
4
+ const targetModel = preferredModel || config?.defaultModel;
5
+ if (!targetModel) {
6
+ const selected = quotaManager.selectBestModel();
7
+ return selected || 'google/antigravity-gemini-3-flash';
8
+ }
9
+ const quotaState = quotaManager.getQuotaTracker().getQuotaForModel(targetModel);
10
+ if (quotaState && quotaState.quotaFraction < 0.2) {
11
+ const fallback = quotaManager.selectBestModel();
12
+ return fallback || targetModel;
13
+ }
14
+ return targetModel;
15
+ },
16
+ updateAgentConfig(existingConfig, modelRotationStrategy) {
17
+ quotaManager.setModelRotationStrategy(modelRotationStrategy);
18
+ const updatedAgents = {};
19
+ for (const [agentName, agentConfig] of Object.entries(existingConfig.agents)) {
20
+ const bestModel = quotaManager.selectBestModel();
21
+ updatedAgents[agentName] = {
22
+ model: bestModel || agentConfig.model,
23
+ };
24
+ }
25
+ return {
26
+ ...existingConfig,
27
+ agents: updatedAgents,
28
+ };
29
+ },
30
+ async pollQuotaAndRotate(models) {
31
+ for (const model of models) {
32
+ const quota = await quotaManager.getQuota();
33
+ if (quota) {
34
+ quotaManager.updateQuotaForModel(model, quota);
35
+ }
36
+ }
37
+ },
38
+ };
39
+ }
40
+ export function generateOhMyOpenCodeConfig(preferredModels) {
41
+ const defaultAgents = [
42
+ 'Sisyphus',
43
+ 'librarian',
44
+ 'explore',
45
+ 'oracle',
46
+ 'frontend-ui-ux-engineer',
47
+ 'document-writer',
48
+ 'multimodal-looker',
49
+ ];
50
+ const agents = {};
51
+ defaultAgents.forEach((agent, index) => {
52
+ const modelIndex = index % preferredModels.length;
53
+ agents[agent] = {
54
+ model: preferredModels[modelIndex] || 'google/antigravity-gemini-3-flash',
55
+ };
56
+ });
57
+ return { agents };
58
+ }
59
+ //# sourceMappingURL=oh-my-opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oh-my-opencode.js","sourceRoot":"","sources":["../src/oh-my-opencode.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,6BAA6B,CAC3C,YAA0B,EAC1B,MAAkC;IAElC,OAAO;QACL,KAAK,CAAC,gBAAgB,CAAC,SAAiB,EAAE,cAAuB;YAC/D,MAAM,WAAW,GAAG,cAAc,IAAI,MAAM,EAAE,YAAY,CAAC;YAE3D,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,QAAQ,GAAG,YAAY,CAAC,eAAe,EAAE,CAAC;gBAChD,OAAO,QAAQ,IAAI,mCAAmC,CAAC;YACzD,CAAC;YAED,MAAM,UAAU,GAAG,YAAY,CAAC,eAAe,EAAE,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;YAEhF,IAAI,UAAU,IAAI,UAAU,CAAC,aAAa,GAAG,GAAG,EAAE,CAAC;gBACjD,MAAM,QAAQ,GAAG,YAAY,CAAC,eAAe,EAAE,CAAC;gBAChD,OAAO,QAAQ,IAAI,WAAW,CAAC;YACjC,CAAC;YAED,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,iBAAiB,CACf,cAAkC,EAClC,qBAA4C;YAE5C,YAAY,CAAC,wBAAwB,CAAC,qBAAqB,CAAC,CAAC;YAE7D,MAAM,aAAa,GAAsC,EAAE,CAAC;YAE5D,KAAK,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC7E,MAAM,SAAS,GAAG,YAAY,CAAC,eAAe,EAAE,CAAC;gBACjD,aAAa,CAAC,SAAS,CAAC,GAAG;oBACzB,KAAK,EAAE,SAAS,IAAI,WAAW,CAAC,KAAK;iBACtC,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,GAAG,cAAc;gBACjB,MAAM,EAAE,aAAa;aACtB,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,kBAAkB,CAAC,MAAgB;YACvC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,CAAC;gBAC5C,IAAI,KAAK,EAAE,CAAC;oBACV,YAAY,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;gBACjD,CAAC;YACH,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,eAAyB;IAEzB,MAAM,aAAa,GAAG;QACpB,UAAU;QACV,WAAW;QACX,SAAS;QACT,QAAQ;QACR,yBAAyB;QACzB,iBAAiB;QACjB,mBAAmB;KACpB,CAAC;IAEF,MAAM,MAAM,GAAsC,EAAE,CAAC;IAErD,aAAa,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QACrC,MAAM,UAAU,GAAG,KAAK,GAAG,eAAe,CAAC,MAAM,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,GAAG;YACd,KAAK,EAAE,eAAe,CAAC,UAAU,CAAC,IAAI,mCAAmC;SAC1E,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { PluginConfig } from './types';
2
+ interface PluginContext {
3
+ client: any;
4
+ directory: string;
5
+ }
6
+ interface PluginResult {
7
+ loader?: () => Promise<any>;
8
+ }
9
+ export declare const AntigravityQuotaPlugin: ({ client, directory }: PluginContext, config?: PluginConfig) => Promise<PluginResult>;
10
+ export { QuotaManager } from './manager';
11
+ export { createOhMyOpenCodeIntegration, generateOhMyOpenCodeConfig } from './oh-my-opencode';
12
+ export type { PluginConfig, ModelRotationStrategy, QuotaInfo, ModelQuotaState } from './types';
13
+ export { TokenStorageReader } from './auth/TokenStorageReader';
14
+ export { AccountRotator } from './auth/AccountRotator';
15
+ export { LSPFinder } from './quota/LSPFinder';
16
+ export { QuotaPoller } from './quota/QuotaPoller';
17
+ export { QuotaTracker } from './rotation/QuotaTracker';
18
+ export { ModelSelector } from './rotation/ModelSelector';
19
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,UAAU,aAAa;IACrB,MAAM,EAAE,GAAG,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,YAAY;IACpB,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7B;AAED,eAAO,MAAM,sBAAsB,GACjC,uBAAuB,aAAa,EACpC,SAAS,YAAY,KACpB,OAAO,CAAC,YAAY,CAkBtB,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,6BAA6B,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC7F,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/F,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/plugin.js ADDED
@@ -0,0 +1,26 @@
1
+ import { QuotaManager } from './manager';
2
+ export const AntigravityQuotaPlugin = async ({ client, directory }, config) => {
3
+ const manager = new QuotaManager(config);
4
+ await manager.initialize();
5
+ return {
6
+ loader: async () => {
7
+ return {
8
+ getQuota: async () => manager.getQuota(),
9
+ rotateAccount: async () => manager.rotateAccount(),
10
+ selectBestModel: () => manager.selectBestModel(),
11
+ updateQuotaForModel: (model, quota) => manager.updateQuotaForModel(model, quota),
12
+ getQuotaTracker: () => manager.getQuotaTracker(),
13
+ setModelRotationStrategy: (strategy) => manager.setModelRotationStrategy(strategy),
14
+ };
15
+ },
16
+ };
17
+ };
18
+ export { QuotaManager } from './manager';
19
+ export { createOhMyOpenCodeIntegration, generateOhMyOpenCodeConfig } from './oh-my-opencode';
20
+ export { TokenStorageReader } from './auth/TokenStorageReader';
21
+ export { AccountRotator } from './auth/AccountRotator';
22
+ export { LSPFinder } from './quota/LSPFinder';
23
+ export { QuotaPoller } from './quota/QuotaPoller';
24
+ export { QuotaTracker } from './rotation/QuotaTracker';
25
+ export { ModelSelector } from './rotation/ModelSelector';
26
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAYzC,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,EACzC,EAAE,MAAM,EAAE,SAAS,EAAiB,EACpC,MAAqB,EACE,EAAE;IACzB,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;IAE3B,OAAO;QACL,MAAM,EAAE,KAAK,IAAI,EAAE;YACjB,OAAO;gBACL,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE;gBACxC,aAAa,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE;gBAClD,eAAe,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,eAAe,EAAE;gBAChD,mBAAmB,EAAE,CAAC,KAAa,EAAE,KAAU,EAAE,EAAE,CACjD,OAAO,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC;gBAC3C,eAAe,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,eAAe,EAAE;gBAChD,wBAAwB,EAAE,CAAC,QAAa,EAAE,EAAE,CAC1C,OAAO,CAAC,wBAAwB,CAAC,QAAQ,CAAC;aAC7C,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,6BAA6B,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAE7F,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare class LSPFinder {
2
+ findProcess(): Promise<{
3
+ pid: number;
4
+ csrfToken: string;
5
+ port: number;
6
+ } | null>;
7
+ }
8
+ //# sourceMappingURL=LSPFinder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LSPFinder.d.ts","sourceRoot":"","sources":["../../src/quota/LSPFinder.ts"],"names":[],"mappings":"AAGA,qBAAa,SAAS;IACpB,WAAW,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CA2ChF"}
@@ -0,0 +1,43 @@
1
+ import { spawn } from 'child_process';
2
+ import * as readline from 'readline';
3
+ export class LSPFinder {
4
+ findProcess() {
5
+ return new Promise((resolve) => {
6
+ const ps = spawn('ps', ['aux']);
7
+ const rl = readline.createInterface({
8
+ input: ps.stdout,
9
+ crlfDelay: Infinity,
10
+ });
11
+ ps.on('error', () => {
12
+ rl.close();
13
+ resolve(null);
14
+ });
15
+ let found = false;
16
+ rl.on('line', (line) => {
17
+ if (found)
18
+ return;
19
+ if (line.includes('language_server_antigravity')) {
20
+ const pidMatch = line.trim().split(/\s+/)[1];
21
+ const csrfMatch = line.match(/--csrf_token=([a-zA-Z0-9_\-]+)/);
22
+ const portMatch = line.match(/--extension_server_port=(\d+)/);
23
+ if (pidMatch && csrfMatch && portMatch) {
24
+ found = true;
25
+ resolve({
26
+ pid: parseInt(pidMatch, 10),
27
+ csrfToken: csrfMatch[1],
28
+ port: parseInt(portMatch[1], 10),
29
+ });
30
+ ps.kill();
31
+ rl.close();
32
+ }
33
+ }
34
+ });
35
+ ps.on('close', () => {
36
+ if (!found) {
37
+ resolve(null);
38
+ }
39
+ });
40
+ });
41
+ }
42
+ }
43
+ //# sourceMappingURL=LSPFinder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LSPFinder.js","sourceRoot":"","sources":["../../src/quota/LSPFinder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AAErC,MAAM,OAAO,SAAS;IACpB,WAAW;QACT,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YAChC,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;gBAClC,KAAK,EAAE,EAAE,CAAC,MAAM;gBAChB,SAAS,EAAE,QAAQ;aACpB,CAAC,CAAC;YAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBAClB,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;YAEH,IAAI,KAAK,GAAG,KAAK,CAAC;YAElB,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBACrB,IAAI,KAAK;oBAAE,OAAO;gBAElB,IAAI,IAAI,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EAAE,CAAC;oBACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;oBAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;oBAE9D,IAAI,QAAQ,IAAI,SAAS,IAAI,SAAS,EAAE,CAAC;wBACvC,KAAK,GAAG,IAAI,CAAC;wBACb,OAAO,CAAC;4BACN,GAAG,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC;4BAC3B,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;4BACvB,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;yBACjC,CAAC,CAAC;wBACH,EAAE,CAAC,IAAI,EAAE,CAAC;wBACV,EAAE,CAAC,KAAK,EAAE,CAAC;oBACb,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBAClB,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,OAAO,CAAC,IAAI,CAAC,CAAC;gBAChB,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ export interface QuotaInfo {
2
+ remainingFraction: number;
3
+ resetTime: string;
4
+ }
5
+ export declare class QuotaPoller {
6
+ checkQuota(port: number, csrfToken: string): Promise<QuotaInfo | null>;
7
+ }
8
+ //# sourceMappingURL=QuotaPoller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QuotaPoller.d.ts","sourceRoot":"","sources":["../../src/quota/QuotaPoller.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,WAAW;IACd,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;CA0B/E"}
@@ -0,0 +1,26 @@
1
+ import axios from 'axios';
2
+ export class QuotaPoller {
3
+ async checkQuota(port, csrfToken) {
4
+ try {
5
+ const url = `http://127.0.0.1:${port}/exa.language_server_pb.LanguageServerService/GetUserStatus`;
6
+ const response = await axios.post(url, { ideName: "antigravity", ideVersion: "unknown" }, {
7
+ headers: {
8
+ 'Content-Type': 'application/json',
9
+ 'X-Codeium-Csrf-Token': csrfToken
10
+ }
11
+ });
12
+ const quotaInfo = response.data?.clientModelConfigs?.quotaInfo;
13
+ if (!quotaInfo) {
14
+ return null;
15
+ }
16
+ return {
17
+ remainingFraction: quotaInfo.remainingFraction,
18
+ resetTime: quotaInfo.resetTime
19
+ };
20
+ }
21
+ catch (error) {
22
+ return null;
23
+ }
24
+ }
25
+ }
26
+ //# sourceMappingURL=QuotaPoller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QuotaPoller.js","sourceRoot":"","sources":["../../src/quota/QuotaPoller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,MAAM,OAAO,WAAW;IACpB,KAAK,CAAC,UAAU,CAAC,IAAY,EAAE,SAAiB;QAC5C,IAAI,CAAC;YACD,MAAM,GAAG,GAAG,oBAAoB,IAAI,6DAA6D,CAAC;YAClG,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EACjC,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,EACjD;gBACI,OAAO,EAAE;oBACL,cAAc,EAAE,kBAAkB;oBAClC,sBAAsB,EAAE,SAAS;iBACpC;aACJ,CACJ,CAAC;YAEF,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,EAAE,kBAAkB,EAAE,SAAS,CAAC;YAC/D,IAAI,CAAC,SAAS,EAAE,CAAC;gBACb,OAAO,IAAI,CAAC;YAChB,CAAC;YAED,OAAO;gBACH,iBAAiB,EAAE,SAAS,CAAC,iBAAiB;gBAC9C,SAAS,EAAE,SAAS,CAAC,SAAS;aACjC,CAAC;QACN,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;CACJ"}
@@ -0,0 +1,12 @@
1
+ import { QuotaTracker } from './QuotaTracker';
2
+ import { ModelRotationStrategy } from '../types';
3
+ export declare class ModelSelector {
4
+ private quotaTracker;
5
+ private strategy;
6
+ constructor(quotaTracker: QuotaTracker, strategy: ModelRotationStrategy);
7
+ selectModel(): string | null;
8
+ updateStrategy(strategy: Partial<ModelRotationStrategy>): void;
9
+ getStrategy(): ModelRotationStrategy;
10
+ getQuotaStates(): import("../types").ModelQuotaState[];
11
+ }
12
+ //# sourceMappingURL=ModelSelector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ModelSelector.d.ts","sourceRoot":"","sources":["../../src/rotation/ModelSelector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEjD,qBAAa,aAAa;IACxB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAwB;gBAE5B,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,qBAAqB;IAKvE,WAAW,IAAI,MAAM,GAAG,IAAI;IAgB5B,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,IAAI;IAI9D,WAAW,IAAI,qBAAqB;IAIpC,cAAc;CAGf"}
@@ -0,0 +1,26 @@
1
+ export class ModelSelector {
2
+ quotaTracker;
3
+ strategy;
4
+ constructor(quotaTracker, strategy) {
5
+ this.quotaTracker = quotaTracker;
6
+ this.strategy = strategy;
7
+ }
8
+ selectModel() {
9
+ const preferredModel = this.quotaTracker.getBestAvailableModel(this.strategy.preferredModels);
10
+ if (preferredModel) {
11
+ return preferredModel;
12
+ }
13
+ const fallbackModel = this.quotaTracker.getBestAvailableModel(this.strategy.fallbackModels);
14
+ return fallbackModel;
15
+ }
16
+ updateStrategy(strategy) {
17
+ this.strategy = { ...this.strategy, ...strategy };
18
+ }
19
+ getStrategy() {
20
+ return { ...this.strategy };
21
+ }
22
+ getQuotaStates() {
23
+ return this.quotaTracker.getAllQuotaStates();
24
+ }
25
+ }
26
+ //# sourceMappingURL=ModelSelector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ModelSelector.js","sourceRoot":"","sources":["../../src/rotation/ModelSelector.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,aAAa;IAChB,YAAY,CAAe;IAC3B,QAAQ,CAAwB;IAExC,YAAY,YAA0B,EAAE,QAA+B;QACrE,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,WAAW;QACT,MAAM,cAAc,GAAG,IAAI,CAAC,YAAY,CAAC,qBAAqB,CAC5D,IAAI,CAAC,QAAQ,CAAC,eAAe,CAC9B,CAAC;QAEF,IAAI,cAAc,EAAE,CAAC;YACnB,OAAO,cAAc,CAAC;QACxB,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC,qBAAqB,CAC3D,IAAI,CAAC,QAAQ,CAAC,cAAc,CAC7B,CAAC;QAEF,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,cAAc,CAAC,QAAwC;QACrD,IAAI,CAAC,QAAQ,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAAC;IACpD,CAAC;IAED,WAAW;QACT,OAAO,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC9B,CAAC;IAED,cAAc;QACZ,OAAO,IAAI,CAAC,YAAY,CAAC,iBAAiB,EAAE,CAAC;IAC/C,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import { QuotaInfo, ModelQuotaState } from '../types';
2
+ export declare class QuotaTracker {
3
+ private quotaState;
4
+ private readonly quotaThreshold;
5
+ constructor(quotaThreshold?: number);
6
+ updateQuota(model: string, quota: QuotaInfo): void;
7
+ getQuotaForModel(model: string): ModelQuotaState | null;
8
+ isModelAvailable(model: string): boolean;
9
+ getBestAvailableModel(candidates: string[]): string | null;
10
+ getAllQuotaStates(): ModelQuotaState[];
11
+ clearStaleData(maxAgeMs?: number): void;
12
+ }
13
+ //# sourceMappingURL=QuotaTracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QuotaTracker.d.ts","sourceRoot":"","sources":["../../src/rotation/QuotaTracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEtD,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAA2C;IAC7D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,cAAc,GAAE,MAAY;IAIxC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI;IASlD,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;IAIvD,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAWxC,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI;IAmB1D,iBAAiB,IAAI,eAAe,EAAE;IAItC,cAAc,CAAC,QAAQ,GAAE,MAAe,GAAG,IAAI;CAQhD"}
@@ -0,0 +1,54 @@
1
+ export class QuotaTracker {
2
+ quotaState = new Map();
3
+ quotaThreshold;
4
+ constructor(quotaThreshold = 0.2) {
5
+ this.quotaThreshold = quotaThreshold;
6
+ }
7
+ updateQuota(model, quota) {
8
+ this.quotaState.set(model, {
9
+ model,
10
+ quotaFraction: quota.remainingFraction,
11
+ lastChecked: Date.now(),
12
+ resetTime: quota.resetTime,
13
+ });
14
+ }
15
+ getQuotaForModel(model) {
16
+ return this.quotaState.get(model) || null;
17
+ }
18
+ isModelAvailable(model) {
19
+ const state = this.quotaState.get(model);
20
+ if (!state)
21
+ return true;
22
+ if (state.quotaFraction < this.quotaThreshold) {
23
+ return false;
24
+ }
25
+ return true;
26
+ }
27
+ getBestAvailableModel(candidates) {
28
+ let bestModel = null;
29
+ let bestQuota = -1;
30
+ for (const model of candidates) {
31
+ if (!this.isModelAvailable(model))
32
+ continue;
33
+ const state = this.quotaState.get(model);
34
+ const quota = state?.quotaFraction ?? 1.0;
35
+ if (quota > bestQuota) {
36
+ bestQuota = quota;
37
+ bestModel = model;
38
+ }
39
+ }
40
+ return bestModel;
41
+ }
42
+ getAllQuotaStates() {
43
+ return Array.from(this.quotaState.values());
44
+ }
45
+ clearStaleData(maxAgeMs = 300000) {
46
+ const now = Date.now();
47
+ for (const [model, state] of this.quotaState.entries()) {
48
+ if (now - state.lastChecked > maxAgeMs) {
49
+ this.quotaState.delete(model);
50
+ }
51
+ }
52
+ }
53
+ }
54
+ //# sourceMappingURL=QuotaTracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QuotaTracker.js","sourceRoot":"","sources":["../../src/rotation/QuotaTracker.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,YAAY;IACf,UAAU,GAAiC,IAAI,GAAG,EAAE,CAAC;IAC5C,cAAc,CAAS;IAExC,YAAY,iBAAyB,GAAG;QACtC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACvC,CAAC;IAED,WAAW,CAAC,KAAa,EAAE,KAAgB;QACzC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE;YACzB,KAAK;YACL,aAAa,EAAE,KAAK,CAAC,iBAAiB;YACtC,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;YACvB,SAAS,EAAE,KAAK,CAAC,SAAS;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,gBAAgB,CAAC,KAAa;QAC5B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;IAC5C,CAAC;IAED,gBAAgB,CAAC,KAAa;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,IAAI,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;YAC9C,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qBAAqB,CAAC,UAAoB;QACxC,IAAI,SAAS,GAAkB,IAAI,CAAC;QACpC,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC;QAEnB,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC;gBAAE,SAAS;YAE5C,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACzC,MAAM,KAAK,GAAG,KAAK,EAAE,aAAa,IAAI,GAAG,CAAC;YAE1C,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;gBACtB,SAAS,GAAG,KAAK,CAAC;gBAClB,SAAS,GAAG,KAAK,CAAC;YACpB,CAAC;QACH,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,iBAAiB;QACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,cAAc,CAAC,WAAmB,MAAM;QACtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;YACvD,IAAI,GAAG,GAAG,KAAK,CAAC,WAAW,GAAG,QAAQ,EAAE,CAAC;gBACvC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,42 @@
1
+ export interface QuotaInfo {
2
+ remainingFraction: number;
3
+ resetTime?: string;
4
+ model?: string;
5
+ }
6
+ export interface AccountMetadataV3 {
7
+ refreshToken: string;
8
+ email?: string;
9
+ addedAt?: number;
10
+ lastUsed?: number;
11
+ coolingDownUntil?: number;
12
+ projectId?: string;
13
+ managedProjectId?: string;
14
+ }
15
+ export interface AccountStorageV3 {
16
+ version: number;
17
+ accounts: AccountMetadataV3[];
18
+ activeIndex: number;
19
+ activeIndexByFamily?: {
20
+ claude?: number;
21
+ gemini?: number;
22
+ };
23
+ }
24
+ export interface ModelQuotaState {
25
+ model: string;
26
+ quotaFraction: number;
27
+ lastChecked: number;
28
+ resetTime?: string;
29
+ }
30
+ export type ModelFamily = 'claude' | 'gemini';
31
+ export interface ModelRotationStrategy {
32
+ preferredModels: string[];
33
+ fallbackModels: string[];
34
+ quotaThreshold: number;
35
+ }
36
+ export interface PluginConfig {
37
+ quotaThreshold?: number;
38
+ pollIntervalMs?: number;
39
+ enableRotation?: boolean;
40
+ preferredModels?: string[];
41
+ }
42
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9C,MAAM,WAAW,qBAAqB;IACpC,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "opencode-antigravity-autopilot",
3
+ "version": "1.0.0",
4
+ "description": "Intelligent model rotation and quota orchestration for opencode-antigravity-auth",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "type": "module",
8
+ "license": "MIT",
9
+ "author": "gooseware",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/gooseware/opencode-antigravity-autopilot.git"
13
+ },
14
+ "homepage": "https://github.com/gooseware/opencode-antigravity-autopilot#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/gooseware/opencode-antigravity-autopilot/issues"
17
+ },
18
+ "keywords": [
19
+ "opencode",
20
+ "antigravity",
21
+ "autopilot",
22
+ "quota",
23
+ "model-rotation",
24
+ "orchestration",
25
+ "oh-my-opencode",
26
+ "gemini",
27
+ "claude",
28
+ "ai-models"
29
+ ],
30
+ "engines": {
31
+ "node": ">=20.0.0"
32
+ },
33
+ "files": [
34
+ "dist/",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "scripts": {
39
+ "build": "tsc -p tsconfig.build.json",
40
+ "typecheck": "tsc --noEmit",
41
+ "test": "jest",
42
+ "test:watch": "jest --watch",
43
+ "prepublishOnly": "npm run build"
44
+ },
45
+ "dependencies": {
46
+ "axios": "^1.13.2"
47
+ },
48
+ "devDependencies": {
49
+ "@types/express": "^5.0.6",
50
+ "@types/jest": "^30.0.0",
51
+ "@types/node": "^25.0.8",
52
+ "jest": "^30.2.0",
53
+ "ts-jest": "^29.4.6",
54
+ "typescript": "^5.9.3"
55
+ },
56
+ "peerDependencies": {
57
+ "opencode-antigravity-auth": "^1.2.8"
58
+ }
59
+ }