free-antigravity-cli 1.0.0 → 1.0.2

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/README.md CHANGED
@@ -1,44 +1,59 @@
1
1
  # Free Antigravity CLI
2
2
 
3
- **Open Source Community Edition** - A free, open-source CLI for Antigravity that supports custom AI models.
3
+ **Open Source Community Edition** - Wraps the official [Antigravity CLI](https://antigravity.google/cli) (`agy`) with custom AI model support.
4
4
 
5
- Supports **OpenAI, Anthropic, Ollama, OpenRouter, Google AI Studio, and any OpenAI-compatible provider** alongside Gemini models.
5
+ Use **OpenAI, Anthropic, Ollama, OpenRouter, Google AI Studio, and any OpenAI-compatible provider** alongside Gemini models -- all through the native `agy` CLI experience.
6
+
7
+ ## How It Works
8
+
9
+ ```
10
+ antigravity
11
+ ├── Starts local proxy (port 50999)
12
+ ├── Auto-patches agy.exe to route through proxy
13
+ └── Delegates to agy CLI
14
+ ├── Google models → daily-cloudcode-pa.googleapis.com (transparent)
15
+ └── Custom models → injected by proxy into model list
16
+ ```
17
+
18
+ The CLI is a thin wrapper: it starts a local HTTP proxy that intercepts `fetchAvailableModels` API calls, injects your custom model definitions, then hands off to the official `agy` CLI. You get the full native Antigravity CLI experience plus custom models.
6
19
 
7
20
  ## Quick Start
8
21
 
9
22
  ```bash
10
- # Install globally
23
+ # 1. Install official Antigravity CLI first
24
+ curl -fsSL https://antigravity.google/cli/install.cmd -o install.cmd && install.cmd && del install.cmd
25
+
26
+ # 2. Install Free Antigravity CLI
11
27
  npm install -g free-antigravity-cli
12
28
 
13
- # Start interactive chat
14
- antigravity chat
29
+ # 3. Add your custom models
30
+ antigravity models add
15
31
 
16
- # Or use npx without installing
17
- npx free-antigravity-cli chat
32
+ # 4. Start chatting (all models appear in agy's model selector)
33
+ antigravity
18
34
  ```
19
35
 
20
- ## Features
36
+ ## Prerequisites
21
37
 
22
- - **Custom AI Models**: Use OpenAI, Anthropic, Ollama, OpenRouter, and custom providers
23
- - **Interactive Chat REPL**: Streaming AI chat right in your terminal
24
- - **Model Management**: Add, remove, list, and import models via CLI
25
- - **Local Proxy**: Built-in proxy server for IDE integration
26
- - **API Key Encryption**: AES-256-CBC encryption for stored API keys
27
- - **Community Owned**: Apache 2.0 license, fully open source
38
+ - **Node.js** >= 18
39
+ - **Official Antigravity CLI** (`agy`) installed at `%LOCALAPPDATA%\agy\bin\agy.exe`
28
40
 
29
41
  ## Commands
30
42
 
31
43
  ```
32
- antigravity chat # Interactive chat (default)
33
- antigravity chat "prompt" # One-shot prompt
34
- antigravity models list # List all models
35
- antigravity models add # Add a model (interactive)
36
- antigravity models remove <name> # Remove a model
37
- antigravity models import # Import from desktop Antigravity
38
- antigravity proxy # Start proxy server
39
- antigravity configure # Show config info
44
+ antigravity Start interactive chat (proxy + agy)
45
+ antigravity chat Same as above
46
+ antigravity models list List configured custom models
47
+ antigravity models add Add a new custom model (interactive wizard)
48
+ antigravity models remove <name> Remove a custom model
49
+ antigravity models import Import models from desktop Antigravity
50
+ antigravity configure Show configuration info
51
+ antigravity version Show version
52
+ antigravity help Show this help
40
53
  ```
41
54
 
55
+ Any arguments not listed above are passed directly to `agy` CLI.
56
+
42
57
  ## Supported Providers
43
58
 
44
59
  | Provider | CLI Value | Auth |
@@ -56,13 +71,7 @@ antigravity configure # Show config info
56
71
 
57
72
  ```bash
58
73
  npm install -g free-antigravity-cli
59
- antigravity chat
60
- ```
61
-
62
- ### npx (No Install)
63
-
64
- ```bash
65
- npx free-antigravity-cli chat
74
+ antigravity
66
75
  ```
67
76
 
68
77
  ### From Source
@@ -72,29 +81,10 @@ git clone https://github.com/vahapogut/free-antigravity-cli.git
72
81
  cd free-antigravity-cli
73
82
  npm install
74
83
  npm run build
75
- node dist/cli.js chat
76
- ```
77
-
78
- ## How It Works
79
-
80
- ```
81
- Terminal (antigravity chat)
82
- → CLI sends Gemini-format request
83
- → Local proxy (port 50999) intercepts
84
- ├── Google models → daily-cloudcode-pa.googleapis.com
85
- └── Custom models → OpenAI / Anthropic / Ollama / etc.
86
- → Response translated back to Gemini format
87
- → Streaming output to terminal
84
+ npm link
85
+ antigravity
88
86
  ```
89
87
 
90
- The CLI includes a **built-in proxy server** that translates between Gemini format and provider-native formats:
91
-
92
- - **OpenAI**: `Gemini ↔ OpenAI Chat Completions`
93
- - **Anthropic**: `Gemini ↔ Anthropic Messages`
94
- - **Ollama**: `Gemini ↔ OpenAI-compatible` (port 11434)
95
- - **Google AI Studio**: Passthrough with URL routing
96
- - **Custom**: OpenAI-compatible format
97
-
98
88
  ## Configuration
99
89
 
100
90
  Models are stored in `~/.free-antigravity/models.json`:
@@ -109,34 +99,91 @@ Models are stored in `~/.free-antigravity/models.json`:
109
99
  "apiKey": "sk-...",
110
100
  "apiUrl": "https://api.openai.com/v1/chat/completions",
111
101
  "externalModelName": "gpt-4o"
102
+ },
103
+ {
104
+ "name": "models/claude-opus-4-7",
105
+ "displayName": "Claude Opus 4.7",
106
+ "provider": "anthropic",
107
+ "apiKey": "sk-ant-...",
108
+ "apiUrl": "https://api.anthropic.com/v1/messages",
109
+ "externalModelName": "claude-opus-4-7"
110
+ },
111
+ {
112
+ "name": "models/llama3",
113
+ "displayName": "Llama 3 (Local)",
114
+ "provider": "ollama",
115
+ "apiKey": "none",
116
+ "apiUrl": "http://localhost:11434/v1/chat/completions",
117
+ "externalModelName": "llama3"
112
118
  }
113
119
  ]
114
120
  }
115
121
  ```
116
122
 
117
- ## Comparison with Google's Official CLI
123
+ ### Importing from Desktop Antigravity
124
+
125
+ ```bash
126
+ antigravity models import
127
+ ```
128
+
129
+ > **NOTE:** API keys from the desktop app are encrypted with Electron's `safeStorage` and cannot be decrypted by the CLI. After importing, re-enter your API keys via `antigravity models add`.
130
+
131
+ ## Technical Details
132
+
133
+ ### Binary Patching
134
+
135
+ On first run, the CLI automatically patches `agy.exe` to replace the hardcoded Google API URL:
136
+
137
+ ```
138
+ https://daily-cloudcode-pa.googleapis.com
139
+ → http://localhost:50999/v1internal/xxxxxxx
140
+ ```
141
+
142
+ This forces `agy` to route its `fetchAvailableModels` calls through the local proxy, where custom model definitions are injected.
143
+
144
+ The original binary is backed up at `agy.exe.bak`.
145
+
146
+ ### Proxy Server
147
+
148
+ The proxy runs on `http://127.0.0.1:50999` (falls back to dynamic port if busy) and:
149
+
150
+ 1. **Intercepts `fetchAvailableModels`**: Merges custom model definitions into the response
151
+ 2. **Intercepts `generateContent`/`streamGenerateContent`**: Routes custom model requests to external APIs
152
+ 3. **Translates formats**: Gemini ↔ OpenAI / Anthropic / Ollama / Google AI Studio
153
+ 4. **Transparent forwarding**: All other requests pass through to Google unchanged
154
+
155
+ ### Provider Translation
156
+
157
+ | Provider | Request Translation | Response Translation | Streaming |
158
+ |---|---|---|---|
159
+ | OpenAI | Gemini → Chat Completions | Chat Completions → Gemini | SSE delta → Gemini chunks |
160
+ | Anthropic | Gemini → Messages API | Messages → Gemini | SSE events → Gemini chunks |
161
+ | Ollama | Gemini → OpenAI-compatible | OpenAI → Gemini | Same as OpenAI |
162
+ | Google AI Studio | Passthrough (native Gemini) | Passthrough | SSE chunks |
163
+ | OpenRouter | Same as OpenAI | Same as OpenAI | Same as OpenAI |
164
+ | Custom | Same as OpenAI | Same as OpenAI | Same as OpenAI |
165
+
166
+ ## Comparison
118
167
 
119
168
  | Feature | Free Antigravity CLI | Google agy CLI |
120
169
  |---|---|---|
121
170
  | Open Source | Yes (Apache 2.0) | No |
122
171
  | Custom Models | Yes | No |
123
- | OpenAI | Yes | No |
124
- | Anthropic (Claude) | Yes | No |
125
- | Ollama (Local) | Yes | No |
172
+ | OpenAI / Anthropic / Ollama | Yes | No |
126
173
  | Gemini | Yes | Yes |
127
- | Size | ~200 KB | 151 MB |
174
+ | All agy Features | Yes (wraps agy) | Yes |
175
+ | Size | ~90 KB | 151 MB |
128
176
  | npm Install | Yes | No |
177
+ | Auto-updates | Via npm | Built-in |
129
178
 
130
179
  ## Contributing
131
180
 
132
- Pull requests welcome! See the [GitHub repo](https://github.com/vahapogut/free-antigravity-cli).
181
+ Pull requests welcome at [github.com/vahapogut/free-antigravity-cli](https://github.com/vahapogut/free-antigravity-cli).
133
182
 
134
183
  ## License
135
184
 
136
- Apache License 2.0 - see LICENSE file for details.
185
+ Apache License 2.0 - see [LICENSE](LICENSE).
137
186
 
138
187
  ## Author
139
188
 
140
- **Vahap Ogut**
141
-
142
- [GitHub](https://github.com/vahapogut)
189
+ **Vahap Ogut** - [GitHub](https://github.com/vahapogut)
package/dist/cli.js CHANGED
@@ -35,182 +35,186 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  })();
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
37
  /**
38
- * Free Antigravity CLI - Open Source Community Edition
39
- * Supports custom AI models alongside Gemini.
38
+ * Free Antigravity CLI - Community Edition
39
+ * Wraps the official agy CLI with custom model support via a local proxy.
40
40
  */
41
- const commander_1 = require("commander");
41
+ const child_process_1 = require("child_process");
42
42
  const path = __importStar(require("path"));
43
43
  const fs = __importStar(require("fs"));
44
+ const os = __importStar(require("os"));
44
45
  const config_1 = require("./config");
45
46
  const proxy_1 = require("./proxy");
46
- const chat_1 = require("./chat");
47
- const program = new commander_1.Command();
48
- program
49
- .name('antigravity')
50
- .description('Free Antigravity CLI - Open Source Community Edition\nSupports OpenAI, Anthropic, Ollama, OpenRouter, Google AI Studio, and custom providers.')
51
- .version('1.0.0');
52
- // --- Chat command ---
53
- program
54
- .command('chat')
55
- .description('Start interactive chat (default command)')
56
- .argument('[prompt]', 'One-shot prompt (non-interactive)')
57
- .option('-m, --model <name>', 'Model to use')
58
- .action(async (prompt, options) => {
59
- if (prompt) {
60
- // One-shot mode
61
- console.log(`Sending to ${options?.model || 'default model'}...`);
62
- await (0, chat_1.startChat)(options?.model);
63
- // In a full implementation, would send the prompt and exit
64
- console.log('One-shot mode: Use interactive chat for now.');
47
+ function getAgyBin() {
48
+ const locations = [
49
+ path.join(os.homedir(), 'AppData', 'Local', 'agy', 'bin', 'agy.exe'),
50
+ ];
51
+ for (const loc of locations) {
52
+ if (fs.existsSync(loc))
53
+ return loc;
65
54
  }
66
- else {
67
- await (0, chat_1.startChat)(options?.model);
68
- }
69
- });
70
- // --- Models command ---
71
- const modelsCmd = program.command('models').description('Manage custom AI models');
72
- modelsCmd
73
- .command('list')
74
- .description('List all configured models')
75
- .action(() => {
76
- const models = (0, config_1.listModels)();
77
- if (models.length === 0) {
78
- console.log('No models configured. Use "antigravity models add" to add one.');
79
- return;
80
- }
81
- console.log('\nConfigured Models:');
82
- console.log('─'.repeat(60));
83
- for (const m of models) {
84
- const keyStatus = m.apiKey && m.apiKey !== 'none' ? '🔑' : '🔓';
85
- console.log(` ${keyStatus} ${m.displayName || m.name}`);
86
- console.log(` Provider: ${m.provider} | Model: ${m.externalModelName}`);
87
- console.log(` URL: ${m.apiUrl}`);
88
- console.log();
89
- }
90
- console.log(`${models.length} model(s) configured.`);
91
- });
92
- modelsCmd
93
- .command('add')
94
- .description('Add a new custom model (interactive wizard)')
95
- .action(async () => {
96
- const inquirer = require('inquirer');
97
- console.log('\n Add Custom AI Model\n' + '─'.repeat(40));
98
- const answers = await inquirer.prompt([
99
- { type: 'list', name: 'provider', message: 'Provider:', choices: ['openai', 'anthropic', 'google', 'ollama', 'openrouter', 'custom'] },
100
- { type: 'input', name: 'modelId', message: 'Model ID (e.g. gpt-4o):', validate: (v) => v.length > 0 },
101
- { type: 'input', name: 'displayName', message: 'Display name (optional):' },
102
- { type: 'password', name: 'apiKey', message: 'API Key:', mask: '*' },
103
- { type: 'input', name: 'apiUrl', message: 'API URL:', default: (ans) => {
104
- const defaults = { openai: 'https://api.openai.com/v1/chat/completions', anthropic: 'https://api.anthropic.com/v1/messages', ollama: 'http://localhost:11434/v1/chat/completions', openrouter: 'https://openrouter.ai/api/v1/chat/completions', custom: 'https://api.together.xyz/v1' };
105
- return ans.provider === 'google' ? `https://generativelanguage.googleapis.com/v1beta/models/${ans.modelId}:generateContent` : (defaults[ans.provider] || '');
106
- } },
107
- ]);
108
- const entry = {
109
- name: 'models/' + answers.modelId,
110
- displayName: answers.displayName || answers.modelId,
111
- description: `${answers.displayName || answers.modelId} custom model via Free Antigravity CLI`,
112
- provider: answers.provider,
113
- apiKey: answers.apiKey || 'none',
114
- apiUrl: answers.apiUrl,
115
- externalModelName: answers.modelId,
116
- };
117
- const result = (0, config_1.addModel)(entry);
118
- if (result.success) {
119
- console.log(`\n Model "${entry.displayName}" added successfully!`);
120
- console.log(' Restart the proxy or chat to use it.\n');
55
+ return path.join(os.homedir(), 'AppData', 'Local', 'agy', 'bin', 'agy.exe');
56
+ }
57
+ async function ensureProxy() {
58
+ try {
59
+ return await (0, proxy_1.startProxy)();
121
60
  }
122
- else {
123
- console.error(`\n Failed: ${result.error}\n`);
61
+ catch {
62
+ return (0, proxy_1.getProxyPort)() || 50999;
124
63
  }
125
- });
126
- modelsCmd
127
- .command('remove')
128
- .description('Remove a model')
129
- .argument('<name>', 'Model name or display name')
130
- .action((name) => {
131
- const result = (0, config_1.removeModel)(name);
132
- if (result.success)
133
- console.log(`Model "${name}" removed.`);
134
- else
135
- console.error(`Failed: ${result.error}`);
136
- });
137
- modelsCmd
138
- .command('import')
139
- .description('Import models from Antigravity desktop custom_models.json')
140
- .action(() => {
141
- const desktopPath = path.join(require('os').homedir(), '.gemini', 'antigravity', 'custom_models.json');
142
- if (!fs.existsSync(desktopPath)) {
143
- console.log('Desktop custom_models.json not found at:', desktopPath);
64
+ }
65
+ function ensureAgyPatched(binPath) {
66
+ if (!fs.existsSync(binPath))
144
67
  return;
145
- }
146
68
  try {
147
- const content = fs.readFileSync(desktopPath, 'utf-8');
148
- const parsed = JSON.parse(content);
149
- const models = parsed.models || [];
150
- if (models.length === 0) {
151
- console.log('No models in desktop config.');
69
+ const buf = fs.readFileSync(binPath);
70
+ const original = Buffer.from('https://daily-cloudcode-pa.googleapis.com');
71
+ const replacement = Buffer.from('http://localhost:50999/v1internal/xxxxxxx');
72
+ if (buf.includes(replacement))
73
+ return;
74
+ const idx = buf.indexOf(original);
75
+ if (idx === -1)
76
+ return;
77
+ replacement.copy(buf, idx);
78
+ fs.writeFileSync(binPath, buf);
79
+ console.log('[ok] agy binary patched for custom model support.');
80
+ }
81
+ catch { /* ignore */ }
82
+ }
83
+ async function startAndDelegate(agyArgs) {
84
+ if (agyArgs.length === 0)
85
+ agyArgs.push('--prompt-interactive');
86
+ const agyBin = getAgyBin();
87
+ if (!fs.existsSync(agyBin)) {
88
+ console.error(`\nagy CLI not found at: ${agyBin}`);
89
+ console.error('Install: curl -fsSL https://antigravity.google/cli/install.cmd | cmd');
90
+ process.exit(1);
91
+ }
92
+ ensureAgyPatched(agyBin);
93
+ process.stdout.write('Starting proxy... ');
94
+ const port = await ensureProxy();
95
+ console.log(`ready (port ${port})\n`);
96
+ const child = (0, child_process_1.spawn)(agyBin, agyArgs, { stdio: 'inherit', shell: true });
97
+ child.on('exit', async (code) => { await (0, proxy_1.stopProxy)(); process.exit(code || 0); });
98
+ process.on('SIGINT', async () => { child.kill(); await (0, proxy_1.stopProxy)(); process.exit(0); });
99
+ }
100
+ async function main() {
101
+ const args = process.argv.slice(2);
102
+ const cmd = args[0];
103
+ // --- Model management ---
104
+ if (cmd === 'models') {
105
+ const sub = args[1];
106
+ if (sub === 'list') {
107
+ const models = (0, config_1.listModels)();
108
+ if (models.length === 0) {
109
+ console.log('No models. Use "antigravity models add".');
110
+ return;
111
+ }
112
+ console.log('\nCustom Models:\n' + '='.repeat(50));
113
+ for (const m of models) {
114
+ console.log(` ${m.displayName || m.name}`);
115
+ console.log(` Provider: ${m.provider} | Model: ${m.externalModelName}`);
116
+ console.log(` URL: ${m.apiUrl}\n`);
117
+ }
152
118
  return;
153
119
  }
154
- (0, config_1.ensureConfigDir)();
155
- // Decrypt desktop keys using the crypto module
156
- const { decryptString } = require('./crypto');
157
- const imported = [];
158
- for (const m of models) {
159
- let apiKey = m.apiKey || 'none';
160
- if (m.encrypted && apiKey !== 'none') {
161
- try {
162
- apiKey = decryptString(apiKey);
120
+ if (sub === 'add') {
121
+ const inquirer = require('inquirer');
122
+ console.log('\n Add Custom AI Model\n' + ''.repeat(40));
123
+ const answers = await inquirer.prompt([
124
+ { type: 'list', name: 'provider', message: 'Provider:', choices: ['openai', 'anthropic', 'google', 'ollama', 'openrouter', 'custom'] },
125
+ { type: 'input', name: 'modelId', message: 'Model ID (e.g. gpt-4o):', validate: (v) => v.length > 0 },
126
+ { type: 'input', name: 'displayName', message: 'Display name:' },
127
+ { type: 'password', name: 'apiKey', message: 'API Key:', mask: '*' },
128
+ { type: 'input', name: 'apiUrl', message: 'API URL:', default: (a) => {
129
+ const d = { openai: 'https://api.openai.com/v1/chat/completions', anthropic: 'https://api.anthropic.com/v1/messages', ollama: 'http://localhost:11434/v1/chat/completions', openrouter: 'https://openrouter.ai/api/v1/chat/completions', custom: 'https://api.together.xyz/v1', google: `https://generativelanguage.googleapis.com/v1beta/models/${a.modelId}:generateContent` };
130
+ return d[a.provider] || '';
131
+ } },
132
+ ]);
133
+ const r = (0, config_1.addModel)({ name: 'models/' + answers.modelId, displayName: answers.displayName || answers.modelId, description: '', provider: answers.provider, apiKey: answers.apiKey || 'none', apiUrl: answers.apiUrl, externalModelName: answers.modelId });
134
+ console.log(r.success ? `\nModel "${answers.displayName || answers.modelId}" added!\n` : `\nFailed: ${r.error}\n`);
135
+ return;
136
+ }
137
+ if (sub === 'remove') {
138
+ const name = args[2];
139
+ if (!name) {
140
+ console.log('Usage: antigravity models remove <name>');
141
+ return;
142
+ }
143
+ (0, config_1.removeModel)(name);
144
+ console.log(`Model "${name}" removed.`);
145
+ return;
146
+ }
147
+ if (sub === 'import') {
148
+ const desktopPath = path.join(os.homedir(), '.gemini', 'antigravity', 'custom_models.json');
149
+ if (!fs.existsSync(desktopPath)) {
150
+ console.log('Desktop Antigravity models not found.\nUse "antigravity models add" instead.');
151
+ return;
152
+ }
153
+ try {
154
+ const models = JSON.parse(fs.readFileSync(desktopPath, 'utf-8')).models || [];
155
+ if (models.length === 0) {
156
+ console.log('No models in desktop config.');
157
+ return;
163
158
  }
164
- catch { /* keep as-is */ }
159
+ (0, config_1.ensureConfigDir)();
160
+ const { decryptString } = require('./crypto');
161
+ const { saveModels } = require('./config');
162
+ const imported = [];
163
+ for (const m of models) {
164
+ let key = m.apiKey || 'none';
165
+ if (m.encrypted && key !== 'none') {
166
+ try {
167
+ key = decryptString(key);
168
+ }
169
+ catch { /* keep */ }
170
+ }
171
+ imported.push({ name: m.name, displayName: m.displayName, description: m.description, provider: m.provider, apiKey: key, apiUrl: m.apiUrl, externalModelName: m.externalModelName, allowUnauthorized: m.allowUnauthorized });
172
+ }
173
+ saveModels(imported);
174
+ console.log(`Imported ${imported.length} model(s). NOTE: API keys from desktop need to be re-entered via "antigravity models add".`);
175
+ }
176
+ catch (e) {
177
+ console.error('Import failed:', e);
165
178
  }
166
- imported.push({
167
- name: m.name, displayName: m.displayName, description: m.description,
168
- provider: m.provider, apiKey, apiUrl: m.apiUrl,
169
- externalModelName: m.externalModelName, allowUnauthorized: m.allowUnauthorized,
170
- });
179
+ return;
171
180
  }
172
- // Save all
173
- const { saveModels } = require('./config');
174
- saveModels(imported);
175
- console.log(`Imported ${imported.length} model(s) from desktop Antigravity.`);
176
- for (const m of imported)
177
- console.log(` - ${m.displayName} (${m.provider})`);
181
+ console.log('Usage: antigravity models <list|add|remove|import>');
182
+ return;
178
183
  }
179
- catch (e) {
180
- console.error('Import failed:', e);
184
+ // --- Info commands ---
185
+ if (cmd === 'configure') {
186
+ console.log(`Models file: ${path.join(os.homedir(), '.free-antigravity', 'models.json')}`);
187
+ console.log(`Models configured: ${(0, config_1.listModels)().length}`);
188
+ console.log(`Proxy: ${(0, proxy_1.getProxyPort)() ? `port ${(0, proxy_1.getProxyPort)()}` : 'not running'}`);
189
+ console.log(`agy binary: ${getAgyBin()}`);
190
+ return;
181
191
  }
182
- });
183
- // --- Proxy command ---
184
- program
185
- .command('proxy')
186
- .description('Start the proxy server (for IDE integration)')
187
- .action(async () => {
188
- try {
189
- const port = await (0, proxy_1.startProxy)();
190
- console.log(`Proxy running on http://127.0.0.1:${port}`);
191
- console.log('Press Ctrl+C to stop.');
192
- // Keep alive
193
- process.on('SIGINT', async () => { await (0, proxy_1.stopProxy)(); process.exit(0); });
192
+ if (cmd === 'version' || cmd === '--version' || cmd === '-V' || cmd === '-v') {
193
+ console.log('Free Antigravity CLI v1.0.0 (Community Edition)');
194
+ return;
194
195
  }
195
- catch (e) {
196
- console.error('Failed to start proxy:', e);
196
+ if (cmd === 'help' || cmd === '--help' || cmd === '-h') {
197
+ console.log(`Free Antigravity CLI v1.0.0 - Community Edition
198
+ Wraps the official agy CLI with custom model support.
199
+
200
+ Commands:
201
+ (no args) Start interactive chat with custom model support
202
+ chat Same as above
203
+ models list List custom models
204
+ models add Add a custom model
205
+ models remove <name> Remove a custom model
206
+ models import Import models from desktop Antigravity
207
+ configure Show configuration
208
+ version Show version
209
+ help This help
210
+
211
+ Any other arguments are passed directly to agy CLI.`);
212
+ return;
197
213
  }
198
- });
199
- // --- Configure command ---
200
- program
201
- .command('configure')
202
- .description('Show configuration info')
203
- .action(() => {
204
- const configPath = require('./config').getModelsPath();
205
- console.log('Free Antigravity CLI Configuration');
206
- console.log('─'.repeat(40));
207
- console.log(`Models file: ${configPath}`);
208
- console.log(`Models: ${(0, config_1.listModels)().length} configured`);
209
- console.log(`Proxy port: ${(0, proxy_1.getProxyPort)() || 'not running'}`);
210
- });
211
- // Default: chat if no command
212
- program.action(() => {
213
- (0, chat_1.startChat)();
214
- });
215
- program.parse(process.argv);
214
+ // --- Default: delegate to agy with proxy ---
215
+ if (cmd === 'chat')
216
+ args.shift();
217
+ await startAndDelegate(args);
218
+ }
219
+ main().catch(console.error);
216
220
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-antigravity-cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Open-source community CLI for Antigravity - supports custom AI models (OpenAI, Anthropic, Ollama, OpenRouter, Google AI Studio) alongside Gemini",
5
5
  "homepage": "https://github.com/vahapogut/free-antigravity-cli",
6
6
  "author": {
package/src/cli.ts CHANGED
@@ -1,184 +1,172 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Free Antigravity CLI - Open Source Community Edition
4
- * Supports custom AI models alongside Gemini.
3
+ * Free Antigravity CLI - Community Edition
4
+ * Wraps the official agy CLI with custom model support via a local proxy.
5
5
  */
6
- import { Command } from 'commander';
6
+ import { spawn } from 'child_process';
7
7
  import * as path from 'path';
8
8
  import * as fs from 'fs';
9
- import { loadModels, addModel, removeModel, listModels, getModel, ensureConfigDir, CustomModelEntry } from './config';
10
- import { startProxy, getProxyPort, loadCustomModels, stopProxy } from './proxy';
11
- import { startChat } from './chat';
12
-
13
- const program = new Command();
14
-
15
- program
16
- .name('antigravity')
17
- .description('Free Antigravity CLI - Open Source Community Edition\nSupports OpenAI, Anthropic, Ollama, OpenRouter, Google AI Studio, and custom providers.')
18
- .version('1.0.0');
19
-
20
- // --- Chat command ---
21
-
22
- program
23
- .command('chat')
24
- .description('Start interactive chat (default command)')
25
- .argument('[prompt]', 'One-shot prompt (non-interactive)')
26
- .option('-m, --model <name>', 'Model to use')
27
- .action(async (prompt?: string, options?: { model?: string }) => {
28
- if (prompt) {
29
- // One-shot mode
30
- console.log(`Sending to ${options?.model || 'default model'}...`);
31
- await startChat(options?.model);
32
- // In a full implementation, would send the prompt and exit
33
- console.log('One-shot mode: Use interactive chat for now.');
34
- } else {
35
- await startChat(options?.model);
9
+ import * as os from 'os';
10
+ import { addModel, removeModel, listModels, ensureConfigDir, CustomModelEntry } from './config';
11
+ import { startProxy, getProxyPort, stopProxy } from './proxy';
12
+
13
+ function getAgyBin(): string {
14
+ const locations = [
15
+ path.join(os.homedir(), 'AppData', 'Local', 'agy', 'bin', 'agy.exe'),
16
+ ];
17
+ for (const loc of locations) {
18
+ if (fs.existsSync(loc)) return loc;
19
+ }
20
+ return path.join(os.homedir(), 'AppData', 'Local', 'agy', 'bin', 'agy.exe');
21
+ }
22
+
23
+ async function ensureProxy(): Promise<number> {
24
+ try { return await startProxy(); }
25
+ catch { return getProxyPort() || 50999; }
26
+ }
27
+
28
+ function ensureAgyPatched(binPath: string): void {
29
+ if (!fs.existsSync(binPath)) return;
30
+ try {
31
+ const buf = fs.readFileSync(binPath);
32
+ const original = Buffer.from('https://daily-cloudcode-pa.googleapis.com');
33
+ const replacement = Buffer.from('http://localhost:50999/v1internal/xxxxxxx');
34
+ if (buf.includes(replacement)) return;
35
+ const idx = buf.indexOf(original);
36
+ if (idx === -1) return;
37
+ replacement.copy(buf, idx);
38
+ fs.writeFileSync(binPath, buf);
39
+ console.log('[ok] agy binary patched for custom model support.');
40
+ } catch { /* ignore */ }
41
+ }
42
+
43
+ async function startAndDelegate(agyArgs: string[]): Promise<void> {
44
+ if (agyArgs.length === 0) agyArgs.push('--prompt-interactive');
45
+ const agyBin = getAgyBin();
46
+
47
+ if (!fs.existsSync(agyBin)) {
48
+ console.error(`\nagy CLI not found at: ${agyBin}`);
49
+ console.error('Install: curl -fsSL https://antigravity.google/cli/install.cmd | cmd');
50
+ process.exit(1);
51
+ }
52
+
53
+ ensureAgyPatched(agyBin);
54
+ process.stdout.write('Starting proxy... ');
55
+ const port = await ensureProxy();
56
+ console.log(`ready (port ${port})\n`);
57
+
58
+ const child = spawn(agyBin, agyArgs, { stdio: 'inherit', shell: true });
59
+ child.on('exit', async (code) => { await stopProxy(); process.exit(code || 0); });
60
+ process.on('SIGINT', async () => { child.kill(); await stopProxy(); process.exit(0); });
61
+ }
62
+
63
+ async function main(): Promise<void> {
64
+ const args = process.argv.slice(2);
65
+ const cmd = args[0];
66
+
67
+ // --- Model management ---
68
+ if (cmd === 'models') {
69
+ const sub = args[1];
70
+
71
+ if (sub === 'list') {
72
+ const models = listModels();
73
+ if (models.length === 0) { console.log('No models. Use "antigravity models add".'); return; }
74
+ console.log('\nCustom Models:\n' + '='.repeat(50));
75
+ for (const m of models) {
76
+ console.log(` ${m.displayName || m.name}`);
77
+ console.log(` Provider: ${m.provider} | Model: ${m.externalModelName}`);
78
+ console.log(` URL: ${m.apiUrl}\n`);
79
+ }
80
+ return;
36
81
  }
37
- });
38
-
39
- // --- Models command ---
40
82
 
41
- const modelsCmd = program.command('models').description('Manage custom AI models');
42
-
43
- modelsCmd
44
- .command('list')
45
- .description('List all configured models')
46
- .action(() => {
47
- const models = listModels();
48
- if (models.length === 0) {
49
- console.log('No models configured. Use "antigravity models add" to add one.');
83
+ if (sub === 'add') {
84
+ const inquirer = require('inquirer');
85
+ console.log('\n Add Custom AI Model\n' + '─'.repeat(40));
86
+ const answers = await inquirer.prompt([
87
+ { type: 'list', name: 'provider', message: 'Provider:', choices: ['openai', 'anthropic', 'google', 'ollama', 'openrouter', 'custom'] },
88
+ { type: 'input', name: 'modelId', message: 'Model ID (e.g. gpt-4o):', validate: (v: string) => v.length > 0 },
89
+ { type: 'input', name: 'displayName', message: 'Display name:' },
90
+ { type: 'password', name: 'apiKey', message: 'API Key:', mask: '*' },
91
+ { type: 'input', name: 'apiUrl', message: 'API URL:', default: (a: any) => {
92
+ const d: Record<string, string> = { openai: 'https://api.openai.com/v1/chat/completions', anthropic: 'https://api.anthropic.com/v1/messages', ollama: 'http://localhost:11434/v1/chat/completions', openrouter: 'https://openrouter.ai/api/v1/chat/completions', custom: 'https://api.together.xyz/v1', google: `https://generativelanguage.googleapis.com/v1beta/models/${a.modelId}:generateContent` };
93
+ return d[a.provider] || '';
94
+ }},
95
+ ]);
96
+ const r = addModel({ name: 'models/' + answers.modelId, displayName: answers.displayName || answers.modelId, description: '', provider: answers.provider, apiKey: answers.apiKey || 'none', apiUrl: answers.apiUrl, externalModelName: answers.modelId });
97
+ console.log(r.success ? `\nModel "${answers.displayName || answers.modelId}" added!\n` : `\nFailed: ${r.error}\n`);
50
98
  return;
51
99
  }
52
- console.log('\nConfigured Models:');
53
- console.log(''.repeat(60));
54
- for (const m of models) {
55
- const keyStatus = m.apiKey && m.apiKey !== 'none' ? '🔑' : '🔓';
56
- console.log(` ${keyStatus} ${m.displayName || m.name}`);
57
- console.log(` Provider: ${m.provider} | Model: ${m.externalModelName}`);
58
- console.log(` URL: ${m.apiUrl}`);
59
- console.log();
60
- }
61
- console.log(`${models.length} model(s) configured.`);
62
- });
63
-
64
- modelsCmd
65
- .command('add')
66
- .description('Add a new custom model (interactive wizard)')
67
- .action(async () => {
68
- const inquirer = require('inquirer');
69
-
70
- console.log('\n Add Custom AI Model\n' + '─'.repeat(40));
71
-
72
- const answers = await inquirer.prompt([
73
- { type: 'list', name: 'provider', message: 'Provider:', choices: ['openai', 'anthropic', 'google', 'ollama', 'openrouter', 'custom'] },
74
- { type: 'input', name: 'modelId', message: 'Model ID (e.g. gpt-4o):', validate: (v: string) => v.length > 0 },
75
- { type: 'input', name: 'displayName', message: 'Display name (optional):' },
76
- { type: 'password', name: 'apiKey', message: 'API Key:', mask: '*' },
77
- { type: 'input', name: 'apiUrl', message: 'API URL:', default: (ans: any) => {
78
- const defaults: Record<string, string> = { openai: 'https://api.openai.com/v1/chat/completions', anthropic: 'https://api.anthropic.com/v1/messages', ollama: 'http://localhost:11434/v1/chat/completions', openrouter: 'https://openrouter.ai/api/v1/chat/completions', custom: 'https://api.together.xyz/v1' };
79
- return ans.provider === 'google' ? `https://generativelanguage.googleapis.com/v1beta/models/${ans.modelId}:generateContent` : (defaults[ans.provider] || '');
80
- }},
81
- ]);
82
-
83
- const entry: CustomModelEntry = {
84
- name: 'models/' + answers.modelId,
85
- displayName: answers.displayName || answers.modelId,
86
- description: `${answers.displayName || answers.modelId} custom model via Free Antigravity CLI`,
87
- provider: answers.provider,
88
- apiKey: answers.apiKey || 'none',
89
- apiUrl: answers.apiUrl,
90
- externalModelName: answers.modelId,
91
- };
92
-
93
- const result = addModel(entry);
94
- if (result.success) {
95
- console.log(`\n Model "${entry.displayName}" added successfully!`);
96
- console.log(' Restart the proxy or chat to use it.\n');
97
- } else {
98
- console.error(`\n Failed: ${result.error}\n`);
99
- }
100
- });
101
-
102
- modelsCmd
103
- .command('remove')
104
- .description('Remove a model')
105
- .argument('<name>', 'Model name or display name')
106
- .action((name: string) => {
107
- const result = removeModel(name);
108
- if (result.success) console.log(`Model "${name}" removed.`);
109
- else console.error(`Failed: ${result.error}`);
110
- });
111
-
112
- modelsCmd
113
- .command('import')
114
- .description('Import models from Antigravity desktop custom_models.json')
115
- .action(() => {
116
- const desktopPath = path.join(require('os').homedir(), '.gemini', 'antigravity', 'custom_models.json');
117
- if (!fs.existsSync(desktopPath)) {
118
- console.log('Desktop custom_models.json not found at:', desktopPath);
100
+
101
+ if (sub === 'remove') {
102
+ const name = args[2];
103
+ if (!name) { console.log('Usage: antigravity models remove <name>'); return; }
104
+ removeModel(name);
105
+ console.log(`Model "${name}" removed.`);
119
106
  return;
120
107
  }
121
- try {
122
- const content = fs.readFileSync(desktopPath, 'utf-8');
123
- const parsed = JSON.parse(content);
124
- const models = parsed.models || [];
125
- if (models.length === 0) { console.log('No models in desktop config.'); return; }
126
-
127
- ensureConfigDir();
128
- // Decrypt desktop keys using the crypto module
129
- const { decryptString } = require('./crypto');
130
- const imported: CustomModelEntry[] = [];
131
- for (const m of models) {
132
- let apiKey = m.apiKey || 'none';
133
- if (m.encrypted && apiKey !== 'none') {
134
- try { apiKey = decryptString(apiKey); } catch { /* keep as-is */ }
108
+
109
+ if (sub === 'import') {
110
+ const desktopPath = path.join(os.homedir(), '.gemini', 'antigravity', 'custom_models.json');
111
+ if (!fs.existsSync(desktopPath)) { console.log('Desktop Antigravity models not found.\nUse "antigravity models add" instead.'); return; }
112
+ try {
113
+ const models = (JSON.parse(fs.readFileSync(desktopPath, 'utf-8')) as { models?: any[] }).models || [];
114
+ if (models.length === 0) { console.log('No models in desktop config.'); return; }
115
+ ensureConfigDir();
116
+ const { decryptString } = require('./crypto');
117
+ const { saveModels } = require('./config');
118
+ const imported: CustomModelEntry[] = [];
119
+ for (const m of models) {
120
+ let key = m.apiKey || 'none';
121
+ if (m.encrypted && key !== 'none') { try { key = decryptString(key); } catch { /* keep */ } }
122
+ imported.push({ name: m.name, displayName: m.displayName, description: m.description, provider: m.provider, apiKey: key, apiUrl: m.apiUrl, externalModelName: m.externalModelName, allowUnauthorized: m.allowUnauthorized });
135
123
  }
136
- imported.push({
137
- name: m.name, displayName: m.displayName, description: m.description,
138
- provider: m.provider, apiKey, apiUrl: m.apiUrl,
139
- externalModelName: m.externalModelName, allowUnauthorized: m.allowUnauthorized,
140
- });
141
- }
142
- // Save all
143
- const { saveModels } = require('./config');
144
- saveModels(imported);
145
- console.log(`Imported ${imported.length} model(s) from desktop Antigravity.`);
146
- for (const m of imported) console.log(` - ${m.displayName} (${m.provider})`);
147
- } catch (e) { console.error('Import failed:', e); }
148
- });
149
-
150
- // --- Proxy command ---
151
-
152
- program
153
- .command('proxy')
154
- .description('Start the proxy server (for IDE integration)')
155
- .action(async () => {
156
- try {
157
- const port = await startProxy();
158
- console.log(`Proxy running on http://127.0.0.1:${port}`);
159
- console.log('Press Ctrl+C to stop.');
160
- // Keep alive
161
- process.on('SIGINT', async () => { await stopProxy(); process.exit(0); });
162
- } catch (e) { console.error('Failed to start proxy:', e); }
163
- });
164
-
165
- // --- Configure command ---
166
-
167
- program
168
- .command('configure')
169
- .description('Show configuration info')
170
- .action(() => {
171
- const configPath = (require('./config') as typeof import('./config')).getModelsPath();
172
- console.log('Free Antigravity CLI Configuration');
173
- console.log('─'.repeat(40));
174
- console.log(`Models file: ${configPath}`);
175
- console.log(`Models: ${listModels().length} configured`);
176
- console.log(`Proxy port: ${getProxyPort() || 'not running'}`);
177
- });
178
-
179
- // Default: chat if no command
180
- program.action(() => {
181
- startChat();
182
- });
183
-
184
- program.parse(process.argv);
124
+ saveModels(imported);
125
+ console.log(`Imported ${imported.length} model(s). NOTE: API keys from desktop need to be re-entered via "antigravity models add".`);
126
+ } catch (e) { console.error('Import failed:', e); }
127
+ return;
128
+ }
129
+
130
+ console.log('Usage: antigravity models <list|add|remove|import>');
131
+ return;
132
+ }
133
+
134
+ // --- Info commands ---
135
+ if (cmd === 'configure') {
136
+ console.log(`Models file: ${path.join(os.homedir(), '.free-antigravity', 'models.json')}`);
137
+ console.log(`Models configured: ${listModels().length}`);
138
+ console.log(`Proxy: ${getProxyPort() ? `port ${getProxyPort()}` : 'not running'}`);
139
+ console.log(`agy binary: ${getAgyBin()}`);
140
+ return;
141
+ }
142
+
143
+ if (cmd === 'version' || cmd === '--version' || cmd === '-V' || cmd === '-v') {
144
+ console.log('Free Antigravity CLI v1.0.0 (Community Edition)');
145
+ return;
146
+ }
147
+
148
+ if (cmd === 'help' || cmd === '--help' || cmd === '-h') {
149
+ console.log(`Free Antigravity CLI v1.0.0 - Community Edition
150
+ Wraps the official agy CLI with custom model support.
151
+
152
+ Commands:
153
+ (no args) Start interactive chat with custom model support
154
+ chat Same as above
155
+ models list List custom models
156
+ models add Add a custom model
157
+ models remove <name> Remove a custom model
158
+ models import Import models from desktop Antigravity
159
+ configure Show configuration
160
+ version Show version
161
+ help This help
162
+
163
+ Any other arguments are passed directly to agy CLI.`);
164
+ return;
165
+ }
166
+
167
+ // --- Default: delegate to agy with proxy ---
168
+ if (cmd === 'chat') args.shift();
169
+ await startAndDelegate(args);
170
+ }
171
+
172
+ main().catch(console.error);
package/src/chat.ts DELETED
@@ -1,184 +0,0 @@
1
- /**
2
- * Interactive chat REPL - streaming AI chat in the terminal.
3
- */
4
- import * as readline from 'readline';
5
- import * as http from 'http';
6
- import { startProxy, getProxyPort, loadCustomModels, generateModelPlaceholderId, toSlug, CustomModel } from './proxy';
7
- import { loadModels, CustomModelEntry } from './config';
8
-
9
- function toProxyModel(m: CustomModelEntry): CustomModel {
10
- return { ...m, displayName: m.displayName || m.name, description: m.description || '', _slug: undefined };
11
- }
12
-
13
- async function getModels(): Promise<string[]> {
14
- const custom = loadModels();
15
- return custom.map((m) => m.displayName || m.name);
16
- }
17
-
18
- async function selectModel(): Promise<string> {
19
- const models = await getModels();
20
- console.log('\nAvailable models:');
21
- models.forEach((m, i) => console.log(` ${i + 1}. ${m}`));
22
- console.log(' 0. Enter model name manually');
23
-
24
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
25
- return new Promise((resolve) => {
26
- rl.question('\nSelect model (number): ', (answer) => {
27
- rl.close();
28
- const idx = parseInt(answer, 10) - 1;
29
- if (idx >= 0 && idx < models.length) resolve(models[idx]);
30
- else resolve('');
31
- });
32
- });
33
- }
34
-
35
- export async function startChat(model?: string): Promise<void> {
36
- // Start proxy
37
- let proxyPort: number;
38
- try { proxyPort = await startProxy(); }
39
- catch { console.error('Failed to start proxy. Is port 50999 in use?'); process.exit(1); }
40
-
41
- console.log(`
42
- ╔══════════════════════════════════════╗
43
- ║ Free Antigravity CLI v1.0.0 ║
44
- ║ Community Edition ║
45
- ╚══════════════════════════════════════╝
46
- Proxy: http://127.0.0.1:${proxyPort}
47
- `);
48
-
49
- if (!model) model = await selectModel();
50
- if (!model) { console.log('No model selected. Exiting.'); process.exit(0); }
51
-
52
- const customModels = loadModels();
53
- const selectedEntry = customModels.find((m) => (m.displayName || m.name) === model);
54
- if (!selectedEntry) {
55
- console.log(`Model "${model}" not configured. Use "antigravity models add" first.`);
56
- process.exit(1);
57
- }
58
-
59
- const selectedModel = toProxyModel(selectedEntry);
60
- console.log(`Using: ${selectedModel.displayName} (${selectedModel.provider})`);
61
- console.log('Type /help for commands, /quit to exit.\n');
62
-
63
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: '\n> ' });
64
-
65
- let conversationHistory: { role: string; parts: { text?: string }[] }[] = [];
66
-
67
- rl.on('line', async (line) => {
68
- const input = line.trim();
69
-
70
- if (input === '/quit' || input === '/exit') {
71
- console.log('Goodbye!');
72
- rl.close();
73
- process.exit(0);
74
- }
75
-
76
- if (input === '/help') {
77
- console.log('Commands: /quit, /help, /clear (clear history), /model (switch model)');
78
- rl.prompt();
79
- return;
80
- }
81
-
82
- if (input === '/clear') {
83
- conversationHistory = [];
84
- console.log('Conversation cleared.');
85
- rl.prompt();
86
- return;
87
- }
88
-
89
- if (input === '/model') {
90
- const newModel = await selectModel();
91
- if (newModel) {
92
- const m = customModels.find((x) => (x.displayName || x.name) === newModel);
93
- if (m) { console.log(`Switched to ${m.displayName}`); }
94
- }
95
- rl.prompt();
96
- return;
97
- }
98
-
99
- if (!input) { rl.prompt(); return; }
100
-
101
- // Build Gemini request
102
- const geminiBody = {
103
- model: selectedModel.name,
104
- contents: [
105
- ...conversationHistory,
106
- { role: 'user', parts: [{ text: input }] },
107
- ],
108
- generationConfig: { temperature: 0.7, maxOutputTokens: 4096 },
109
- };
110
-
111
- // Send to proxy
112
- const placeholderId = generateModelPlaceholderId(selectedModel);
113
- const slug = toSlug(selectedModel);
114
-
115
- const postData = JSON.stringify({
116
- request: geminiBody,
117
- model: slug,
118
- project: 'free-antigravity-cli',
119
- requestId: Date.now().toString(),
120
- requestType: 'CHAT',
121
- });
122
-
123
- const options: http.RequestOptions = {
124
- hostname: '127.0.0.1',
125
- port: proxyPort,
126
- path: '/v1internal:streamGenerateContent?alt=sse',
127
- method: 'POST',
128
- headers: {
129
- 'Content-Type': 'application/json',
130
- 'Content-Length': Buffer.byteLength(postData),
131
- 'Accept': 'text/event-stream',
132
- },
133
- };
134
-
135
- const req = http.request(options, (res) => {
136
- let buffer = '';
137
- let fullResponse = '';
138
-
139
- res.on('data', (chunk: Buffer) => {
140
- buffer += chunk.toString('utf-8');
141
- const lines = buffer.split('\n');
142
- buffer = lines.pop() || '';
143
-
144
- for (const line of lines) {
145
- const trimmed = line.trim();
146
- if (!trimmed || !trimmed.startsWith('data: ')) continue;
147
- try {
148
- const data = JSON.parse(trimmed.substring(6));
149
- const candidates = data.response?.candidates || [];
150
- for (const c of candidates) {
151
- const parts = c.content?.parts || [];
152
- for (const p of parts) {
153
- if (p.text && !p.thought) {
154
- process.stdout.write(p.text);
155
- fullResponse += p.text;
156
- }
157
- }
158
- }
159
- } catch { /* partial chunk */ }
160
- }
161
- });
162
-
163
- res.on('end', () => {
164
- console.log();
165
- conversationHistory.push({ role: 'user', parts: [{ text: input }] });
166
- conversationHistory.push({ role: 'model', parts: [{ text: fullResponse }] });
167
- // Keep history manageable
168
- if (conversationHistory.length > 20) conversationHistory = conversationHistory.slice(-20);
169
- rl.prompt();
170
- });
171
- });
172
-
173
- req.on('error', (err) => {
174
- console.error(`\nConnection error: ${err.message}`);
175
- console.error('Is the proxy running? Try: antigravity proxy');
176
- rl.prompt();
177
- });
178
-
179
- req.write(postData);
180
- req.end();
181
- });
182
-
183
- rl.prompt();
184
- }