vibecodingmachine-core 1.0.1 → 2025.11.2-7.1239
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/.babelrc +13 -13
- package/README.md +28 -28
- package/__tests__/applescript-manager-claude-fix.test.js +286 -286
- package/__tests__/requirement-2-auto-start-looping.test.js +69 -69
- package/__tests__/requirement-3-auto-start-looping.test.js +69 -69
- package/__tests__/requirement-4-auto-start-looping.test.js +69 -69
- package/__tests__/requirement-6-auto-start-looping.test.js +73 -73
- package/__tests__/requirement-7-status-tracking.test.js +332 -332
- package/jest.config.js +18 -18
- package/jest.setup.js +12 -12
- package/package.json +48 -48
- package/src/auth/access-denied.html +119 -119
- package/src/auth/shared-auth-storage.js +230 -230
- package/src/autonomous-mode/feature-implementer.cjs +70 -70
- package/src/autonomous-mode/feature-implementer.js +425 -425
- package/src/chat-management/chat-manager.cjs +71 -71
- package/src/chat-management/chat-manager.js +342 -342
- package/src/ide-integration/__tests__/applescript-manager-thread-closure.test.js +227 -227
- package/src/ide-integration/aider-cli-manager.cjs +850 -850
- package/src/ide-integration/applescript-manager.cjs +1088 -1088
- package/src/ide-integration/applescript-manager.js +2802 -2802
- package/src/ide-integration/applescript-utils.js +306 -306
- package/src/ide-integration/cdp-manager.cjs +221 -221
- package/src/ide-integration/cdp-manager.js +321 -321
- package/src/ide-integration/claude-code-cli-manager.cjs +301 -301
- package/src/ide-integration/cline-cli-manager.cjs +2252 -2252
- package/src/ide-integration/continue-cli-manager.js +431 -431
- package/src/ide-integration/provider-manager.cjs +354 -354
- package/src/ide-integration/quota-detector.cjs +34 -34
- package/src/ide-integration/quota-detector.js +349 -349
- package/src/ide-integration/windows-automation-manager.js +262 -262
- package/src/index.cjs +47 -43
- package/src/index.js +17 -17
- package/src/llm/direct-llm-manager.cjs +609 -609
- package/src/ui/ButtonComponents.js +247 -247
- package/src/ui/ChatInterface.js +499 -499
- package/src/ui/StateManager.js +259 -259
- package/src/utils/audit-logger.cjs +116 -116
- package/src/utils/config-helpers.cjs +94 -94
- package/src/utils/config-helpers.js +94 -94
- package/src/utils/electron-update-checker.js +113 -85
- package/src/utils/gcloud-auth.cjs +394 -394
- package/src/utils/logger.cjs +193 -193
- package/src/utils/logger.js +191 -191
- package/src/utils/repo-helpers.cjs +120 -120
- package/src/utils/repo-helpers.js +120 -120
- package/src/utils/requirement-helpers.js +432 -432
- package/src/utils/update-checker.js +227 -167
- package/src/utils/version-checker.js +169 -0
|
@@ -1,394 +1,394 @@
|
|
|
1
|
-
// Google Cloud Authentication Helper
|
|
2
|
-
// Handles gcloud installation, authentication, and API key generation
|
|
3
|
-
const { execSync, spawn } = require('child_process');
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
const os = require('os');
|
|
7
|
-
|
|
8
|
-
class GCloudAuth {
|
|
9
|
-
constructor() {
|
|
10
|
-
this.logger = console;
|
|
11
|
-
this.configDir = path.join(os.homedir(), '.allnightai');
|
|
12
|
-
this.apiKeyFile = path.join(this.configDir, 'gcloud-api-key.json');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Check if gcloud CLI is installed
|
|
17
|
-
*/
|
|
18
|
-
isGCloudInstalled() {
|
|
19
|
-
try {
|
|
20
|
-
execSync('which gcloud', { stdio: 'pipe' });
|
|
21
|
-
return true;
|
|
22
|
-
} catch {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Install gcloud CLI
|
|
29
|
-
*/
|
|
30
|
-
async installGCloud() {
|
|
31
|
-
this.logger.log('Installing Google Cloud CLI...');
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
const platform = os.platform();
|
|
35
|
-
|
|
36
|
-
if (platform === 'darwin') {
|
|
37
|
-
// macOS - use Homebrew
|
|
38
|
-
this.logger.log('Installing via Homebrew...');
|
|
39
|
-
execSync('brew install --cask google-cloud-sdk', {
|
|
40
|
-
stdio: 'inherit',
|
|
41
|
-
timeout: 300000 // 5 minute timeout
|
|
42
|
-
});
|
|
43
|
-
} else if (platform === 'linux') {
|
|
44
|
-
// Linux - use curl installer
|
|
45
|
-
this.logger.log('Installing via curl...');
|
|
46
|
-
execSync('curl https://sdk.cloud.google.com | bash', {
|
|
47
|
-
stdio: 'inherit',
|
|
48
|
-
shell: true,
|
|
49
|
-
timeout: 300000
|
|
50
|
-
});
|
|
51
|
-
// Source the completion script
|
|
52
|
-
execSync('exec -l $SHELL', { stdio: 'inherit', shell: true });
|
|
53
|
-
} else {
|
|
54
|
-
return {
|
|
55
|
-
success: false,
|
|
56
|
-
error: 'Unsupported platform. Please install gcloud CLI manually: https://cloud.google.com/sdk/docs/install'
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
this.logger.log('Google Cloud CLI installed successfully');
|
|
61
|
-
return { success: true };
|
|
62
|
-
} catch (error) {
|
|
63
|
-
this.logger.error('Failed to install gcloud CLI:', error.message);
|
|
64
|
-
return {
|
|
65
|
-
success: false,
|
|
66
|
-
error: error.message
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Check if user is authenticated with gcloud
|
|
73
|
-
*/
|
|
74
|
-
isAuthenticated() {
|
|
75
|
-
try {
|
|
76
|
-
const result = execSync('gcloud auth list --filter=status:ACTIVE --format="value(account)"', {
|
|
77
|
-
encoding: 'utf8',
|
|
78
|
-
stdio: 'pipe'
|
|
79
|
-
});
|
|
80
|
-
return result.trim().length > 0;
|
|
81
|
-
} catch {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Authenticate with Google Cloud (opens browser)
|
|
88
|
-
*/
|
|
89
|
-
async authenticate() {
|
|
90
|
-
this.logger.log('Opening browser for Google Cloud authentication...');
|
|
91
|
-
|
|
92
|
-
try {
|
|
93
|
-
// This will open the browser automatically
|
|
94
|
-
execSync('gcloud auth login', {
|
|
95
|
-
stdio: 'inherit',
|
|
96
|
-
timeout: 180000 // 3 minute timeout
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
this.logger.log('Successfully authenticated with Google Cloud');
|
|
100
|
-
return { success: true };
|
|
101
|
-
} catch (error) {
|
|
102
|
-
this.logger.error('Failed to authenticate:', error.message);
|
|
103
|
-
return {
|
|
104
|
-
success: false,
|
|
105
|
-
error: error.message
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Get or create project
|
|
112
|
-
*/
|
|
113
|
-
async ensureProject() {
|
|
114
|
-
try {
|
|
115
|
-
// Get current project
|
|
116
|
-
let project = execSync('gcloud config get-value project', {
|
|
117
|
-
encoding: 'utf8',
|
|
118
|
-
stdio: 'pipe'
|
|
119
|
-
}).trim();
|
|
120
|
-
|
|
121
|
-
if (!project || project === '(unset)') {
|
|
122
|
-
// Create a new project
|
|
123
|
-
const projectId = `vibecodingmachine-${Date.now()}`;
|
|
124
|
-
this.logger.log(`Creating new project: ${projectId}`);
|
|
125
|
-
|
|
126
|
-
execSync(`gcloud projects create ${projectId} --name="VibeCodingMachine"`, {
|
|
127
|
-
stdio: 'inherit'
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
execSync(`gcloud config set project ${projectId}`, {
|
|
131
|
-
stdio: 'inherit'
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
project = projectId;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return { success: true, project };
|
|
138
|
-
} catch (error) {
|
|
139
|
-
return {
|
|
140
|
-
success: false,
|
|
141
|
-
error: error.message
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Enable required APIs
|
|
148
|
-
*/
|
|
149
|
-
async enableAPIs() {
|
|
150
|
-
try {
|
|
151
|
-
this.logger.log('Enabling Vertex AI API...');
|
|
152
|
-
|
|
153
|
-
execSync('gcloud services enable aiplatform.googleapis.com', {
|
|
154
|
-
stdio: 'inherit',
|
|
155
|
-
timeout: 120000
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
this.logger.log('APIs enabled successfully');
|
|
159
|
-
return { success: true };
|
|
160
|
-
} catch (error) {
|
|
161
|
-
return {
|
|
162
|
-
success: false,
|
|
163
|
-
error: error.message
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Set up gcloud PATH
|
|
170
|
-
*/
|
|
171
|
-
setupGCloudPath() {
|
|
172
|
-
const gcloudPaths = [
|
|
173
|
-
'/opt/homebrew/share/google-cloud-sdk/bin',
|
|
174
|
-
'/usr/local/share/google-cloud-sdk/bin',
|
|
175
|
-
path.join(os.homedir(), 'google-cloud-sdk', 'bin')
|
|
176
|
-
];
|
|
177
|
-
|
|
178
|
-
for (const gcloudPath of gcloudPaths) {
|
|
179
|
-
if (fs.existsSync(gcloudPath)) {
|
|
180
|
-
if (!process.env.PATH.includes(gcloudPath)) {
|
|
181
|
-
process.env.PATH = `${gcloudPath}:${process.env.PATH}`;
|
|
182
|
-
this.logger.log(`Added ${gcloudPath} to PATH`);
|
|
183
|
-
}
|
|
184
|
-
return gcloudPath;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Generate API key using Application Default Credentials
|
|
192
|
-
*/
|
|
193
|
-
async generateAPIKey() {
|
|
194
|
-
try {
|
|
195
|
-
this.logger.log('Generating API credentials...');
|
|
196
|
-
|
|
197
|
-
// Ensure gcloud is in PATH
|
|
198
|
-
this.setupGCloudPath();
|
|
199
|
-
|
|
200
|
-
// Get current project
|
|
201
|
-
const project = await this.getCurrentProject();
|
|
202
|
-
|
|
203
|
-
// Display prominent warning about selecting all permissions
|
|
204
|
-
console.log('\n╔══════════════════════════════════════════════════════════════════╗');
|
|
205
|
-
console.log('║ ║');
|
|
206
|
-
console.log('║ ⚠️ IMPORTANT INSTRUCTIONS ⚠️ ║');
|
|
207
|
-
console.log('║ ║');
|
|
208
|
-
console.log('║ Your browser will open for Google Cloud authentication. ║');
|
|
209
|
-
console.log('║ ║');
|
|
210
|
-
console.log('║ ╔════════════════════════════════════════════════════════╗ ║');
|
|
211
|
-
console.log('║ ║ ✓ CLICK "SELECT ALL" TO SELECT ALL PERMISSIONS ║ ║');
|
|
212
|
-
console.log('║ ╚════════════════════════════════════════════════════════╝ ║');
|
|
213
|
-
console.log('║ ║');
|
|
214
|
-
console.log('║ Then click "Continue" or "Allow" to consent. ║');
|
|
215
|
-
console.log('║ ║');
|
|
216
|
-
console.log('║ If you don\'t select all permissions, authentication will fail. ║');
|
|
217
|
-
console.log('║ ║');
|
|
218
|
-
console.log('╚══════════════════════════════════════════════════════════════════╝');
|
|
219
|
-
console.log('\nProject: ' + project);
|
|
220
|
-
console.log('Opening browser in 3 seconds...\n');
|
|
221
|
-
|
|
222
|
-
// Give user time to read the warning
|
|
223
|
-
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
224
|
-
|
|
225
|
-
// Use Application Default Credentials with browser
|
|
226
|
-
execSync(`gcloud auth application-default login --project=${project}`, {
|
|
227
|
-
stdio: 'inherit',
|
|
228
|
-
timeout: 300000, // 5 minutes
|
|
229
|
-
env: { ...process.env, PATH: process.env.PATH }
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
// Get the credentials file location
|
|
233
|
-
const credsPath = path.join(
|
|
234
|
-
os.homedir(),
|
|
235
|
-
'.config',
|
|
236
|
-
'gcloud',
|
|
237
|
-
'application_default_credentials.json'
|
|
238
|
-
);
|
|
239
|
-
|
|
240
|
-
if (!fs.existsSync(credsPath)) {
|
|
241
|
-
throw new Error('Credentials file not found');
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Copy credentials to our config directory
|
|
245
|
-
fs.mkdirSync(this.configDir, { recursive: true });
|
|
246
|
-
const creds = JSON.parse(fs.readFileSync(credsPath, 'utf8'));
|
|
247
|
-
|
|
248
|
-
// Save API key info
|
|
249
|
-
const apiKeyInfo = {
|
|
250
|
-
type: 'gcloud_application_default',
|
|
251
|
-
credentials_path: credsPath,
|
|
252
|
-
project: creds.quota_project_id || project,
|
|
253
|
-
created_at: new Date().toISOString()
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
fs.writeFileSync(this.apiKeyFile, JSON.stringify(apiKeyInfo, null, 2));
|
|
257
|
-
|
|
258
|
-
this.logger.log('API credentials generated and saved');
|
|
259
|
-
return {
|
|
260
|
-
success: true,
|
|
261
|
-
keyFile: this.apiKeyFile,
|
|
262
|
-
credsPath
|
|
263
|
-
};
|
|
264
|
-
} catch (error) {
|
|
265
|
-
return {
|
|
266
|
-
success: false,
|
|
267
|
-
error: error.message
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Get current project ID
|
|
274
|
-
*/
|
|
275
|
-
async getCurrentProject() {
|
|
276
|
-
try {
|
|
277
|
-
const project = execSync('gcloud config get-value project', {
|
|
278
|
-
encoding: 'utf8',
|
|
279
|
-
stdio: 'pipe'
|
|
280
|
-
}).trim();
|
|
281
|
-
return project;
|
|
282
|
-
} catch {
|
|
283
|
-
return null;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Get saved API key info
|
|
289
|
-
*/
|
|
290
|
-
getSavedAPIKey() {
|
|
291
|
-
try {
|
|
292
|
-
if (!fs.existsSync(this.apiKeyFile)) {
|
|
293
|
-
return null;
|
|
294
|
-
}
|
|
295
|
-
return JSON.parse(fs.readFileSync(this.apiKeyFile, 'utf8'));
|
|
296
|
-
} catch {
|
|
297
|
-
return null;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Check if Application Default Credentials already exist
|
|
303
|
-
*/
|
|
304
|
-
hasApplicationDefaultCredentials() {
|
|
305
|
-
const credsPath = path.join(
|
|
306
|
-
os.homedir(),
|
|
307
|
-
'.config',
|
|
308
|
-
'gcloud',
|
|
309
|
-
'application_default_credentials.json'
|
|
310
|
-
);
|
|
311
|
-
return fs.existsSync(credsPath);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Full authentication flow
|
|
316
|
-
*/
|
|
317
|
-
async fullAuthFlow() {
|
|
318
|
-
// 1. Check/install gcloud
|
|
319
|
-
if (!this.isGCloudInstalled()) {
|
|
320
|
-
this.logger.log('Google Cloud CLI not found. Installing...');
|
|
321
|
-
const installResult = await this.installGCloud();
|
|
322
|
-
if (!installResult.success) {
|
|
323
|
-
return installResult;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Ensure gcloud is in PATH
|
|
328
|
-
this.setupGCloudPath();
|
|
329
|
-
|
|
330
|
-
// 2. Authenticate
|
|
331
|
-
if (!this.isAuthenticated()) {
|
|
332
|
-
this.logger.log('Not authenticated. Starting authentication...');
|
|
333
|
-
const authResult = await this.authenticate();
|
|
334
|
-
if (!authResult.success) {
|
|
335
|
-
return authResult;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// 3. Ensure project
|
|
340
|
-
const projectResult = await this.ensureProject();
|
|
341
|
-
if (!projectResult.success) {
|
|
342
|
-
return projectResult;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// 4. Enable APIs
|
|
346
|
-
const apiResult = await this.enableAPIs();
|
|
347
|
-
if (!apiResult.success) {
|
|
348
|
-
return apiResult;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// 5. Generate API key (or use existing)
|
|
352
|
-
if (this.hasApplicationDefaultCredentials()) {
|
|
353
|
-
this.logger.log('Application Default Credentials already exist');
|
|
354
|
-
|
|
355
|
-
const credsPath = path.join(
|
|
356
|
-
os.homedir(),
|
|
357
|
-
'.config',
|
|
358
|
-
'gcloud',
|
|
359
|
-
'application_default_credentials.json'
|
|
360
|
-
);
|
|
361
|
-
|
|
362
|
-
// Save API key info
|
|
363
|
-
fs.mkdirSync(this.configDir, { recursive: true });
|
|
364
|
-
const apiKeyInfo = {
|
|
365
|
-
type: 'gcloud_application_default',
|
|
366
|
-
credentials_path: credsPath,
|
|
367
|
-
project: projectResult.project,
|
|
368
|
-
created_at: new Date().toISOString()
|
|
369
|
-
};
|
|
370
|
-
fs.writeFileSync(this.apiKeyFile, JSON.stringify(apiKeyInfo, null, 2));
|
|
371
|
-
|
|
372
|
-
return {
|
|
373
|
-
success: true,
|
|
374
|
-
keyFile: this.apiKeyFile,
|
|
375
|
-
credsPath: credsPath,
|
|
376
|
-
project: projectResult.project
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
const keyResult = await this.generateAPIKey();
|
|
381
|
-
if (!keyResult.success) {
|
|
382
|
-
return keyResult;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
return {
|
|
386
|
-
success: true,
|
|
387
|
-
keyFile: keyResult.keyFile,
|
|
388
|
-
credsPath: keyResult.credsPath,
|
|
389
|
-
project: projectResult.project
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
module.exports = { GCloudAuth };
|
|
1
|
+
// Google Cloud Authentication Helper
|
|
2
|
+
// Handles gcloud installation, authentication, and API key generation
|
|
3
|
+
const { execSync, spawn } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
|
|
8
|
+
class GCloudAuth {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.logger = console;
|
|
11
|
+
this.configDir = path.join(os.homedir(), '.allnightai');
|
|
12
|
+
this.apiKeyFile = path.join(this.configDir, 'gcloud-api-key.json');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check if gcloud CLI is installed
|
|
17
|
+
*/
|
|
18
|
+
isGCloudInstalled() {
|
|
19
|
+
try {
|
|
20
|
+
execSync('which gcloud', { stdio: 'pipe' });
|
|
21
|
+
return true;
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Install gcloud CLI
|
|
29
|
+
*/
|
|
30
|
+
async installGCloud() {
|
|
31
|
+
this.logger.log('Installing Google Cloud CLI...');
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const platform = os.platform();
|
|
35
|
+
|
|
36
|
+
if (platform === 'darwin') {
|
|
37
|
+
// macOS - use Homebrew
|
|
38
|
+
this.logger.log('Installing via Homebrew...');
|
|
39
|
+
execSync('brew install --cask google-cloud-sdk', {
|
|
40
|
+
stdio: 'inherit',
|
|
41
|
+
timeout: 300000 // 5 minute timeout
|
|
42
|
+
});
|
|
43
|
+
} else if (platform === 'linux') {
|
|
44
|
+
// Linux - use curl installer
|
|
45
|
+
this.logger.log('Installing via curl...');
|
|
46
|
+
execSync('curl https://sdk.cloud.google.com | bash', {
|
|
47
|
+
stdio: 'inherit',
|
|
48
|
+
shell: true,
|
|
49
|
+
timeout: 300000
|
|
50
|
+
});
|
|
51
|
+
// Source the completion script
|
|
52
|
+
execSync('exec -l $SHELL', { stdio: 'inherit', shell: true });
|
|
53
|
+
} else {
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
error: 'Unsupported platform. Please install gcloud CLI manually: https://cloud.google.com/sdk/docs/install'
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.logger.log('Google Cloud CLI installed successfully');
|
|
61
|
+
return { success: true };
|
|
62
|
+
} catch (error) {
|
|
63
|
+
this.logger.error('Failed to install gcloud CLI:', error.message);
|
|
64
|
+
return {
|
|
65
|
+
success: false,
|
|
66
|
+
error: error.message
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Check if user is authenticated with gcloud
|
|
73
|
+
*/
|
|
74
|
+
isAuthenticated() {
|
|
75
|
+
try {
|
|
76
|
+
const result = execSync('gcloud auth list --filter=status:ACTIVE --format="value(account)"', {
|
|
77
|
+
encoding: 'utf8',
|
|
78
|
+
stdio: 'pipe'
|
|
79
|
+
});
|
|
80
|
+
return result.trim().length > 0;
|
|
81
|
+
} catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Authenticate with Google Cloud (opens browser)
|
|
88
|
+
*/
|
|
89
|
+
async authenticate() {
|
|
90
|
+
this.logger.log('Opening browser for Google Cloud authentication...');
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
// This will open the browser automatically
|
|
94
|
+
execSync('gcloud auth login', {
|
|
95
|
+
stdio: 'inherit',
|
|
96
|
+
timeout: 180000 // 3 minute timeout
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
this.logger.log('Successfully authenticated with Google Cloud');
|
|
100
|
+
return { success: true };
|
|
101
|
+
} catch (error) {
|
|
102
|
+
this.logger.error('Failed to authenticate:', error.message);
|
|
103
|
+
return {
|
|
104
|
+
success: false,
|
|
105
|
+
error: error.message
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get or create project
|
|
112
|
+
*/
|
|
113
|
+
async ensureProject() {
|
|
114
|
+
try {
|
|
115
|
+
// Get current project
|
|
116
|
+
let project = execSync('gcloud config get-value project', {
|
|
117
|
+
encoding: 'utf8',
|
|
118
|
+
stdio: 'pipe'
|
|
119
|
+
}).trim();
|
|
120
|
+
|
|
121
|
+
if (!project || project === '(unset)') {
|
|
122
|
+
// Create a new project
|
|
123
|
+
const projectId = `vibecodingmachine-${Date.now()}`;
|
|
124
|
+
this.logger.log(`Creating new project: ${projectId}`);
|
|
125
|
+
|
|
126
|
+
execSync(`gcloud projects create ${projectId} --name="VibeCodingMachine"`, {
|
|
127
|
+
stdio: 'inherit'
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
execSync(`gcloud config set project ${projectId}`, {
|
|
131
|
+
stdio: 'inherit'
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
project = projectId;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return { success: true, project };
|
|
138
|
+
} catch (error) {
|
|
139
|
+
return {
|
|
140
|
+
success: false,
|
|
141
|
+
error: error.message
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Enable required APIs
|
|
148
|
+
*/
|
|
149
|
+
async enableAPIs() {
|
|
150
|
+
try {
|
|
151
|
+
this.logger.log('Enabling Vertex AI API...');
|
|
152
|
+
|
|
153
|
+
execSync('gcloud services enable aiplatform.googleapis.com', {
|
|
154
|
+
stdio: 'inherit',
|
|
155
|
+
timeout: 120000
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
this.logger.log('APIs enabled successfully');
|
|
159
|
+
return { success: true };
|
|
160
|
+
} catch (error) {
|
|
161
|
+
return {
|
|
162
|
+
success: false,
|
|
163
|
+
error: error.message
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Set up gcloud PATH
|
|
170
|
+
*/
|
|
171
|
+
setupGCloudPath() {
|
|
172
|
+
const gcloudPaths = [
|
|
173
|
+
'/opt/homebrew/share/google-cloud-sdk/bin',
|
|
174
|
+
'/usr/local/share/google-cloud-sdk/bin',
|
|
175
|
+
path.join(os.homedir(), 'google-cloud-sdk', 'bin')
|
|
176
|
+
];
|
|
177
|
+
|
|
178
|
+
for (const gcloudPath of gcloudPaths) {
|
|
179
|
+
if (fs.existsSync(gcloudPath)) {
|
|
180
|
+
if (!process.env.PATH.includes(gcloudPath)) {
|
|
181
|
+
process.env.PATH = `${gcloudPath}:${process.env.PATH}`;
|
|
182
|
+
this.logger.log(`Added ${gcloudPath} to PATH`);
|
|
183
|
+
}
|
|
184
|
+
return gcloudPath;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Generate API key using Application Default Credentials
|
|
192
|
+
*/
|
|
193
|
+
async generateAPIKey() {
|
|
194
|
+
try {
|
|
195
|
+
this.logger.log('Generating API credentials...');
|
|
196
|
+
|
|
197
|
+
// Ensure gcloud is in PATH
|
|
198
|
+
this.setupGCloudPath();
|
|
199
|
+
|
|
200
|
+
// Get current project
|
|
201
|
+
const project = await this.getCurrentProject();
|
|
202
|
+
|
|
203
|
+
// Display prominent warning about selecting all permissions
|
|
204
|
+
console.log('\n╔══════════════════════════════════════════════════════════════════╗');
|
|
205
|
+
console.log('║ ║');
|
|
206
|
+
console.log('║ ⚠️ IMPORTANT INSTRUCTIONS ⚠️ ║');
|
|
207
|
+
console.log('║ ║');
|
|
208
|
+
console.log('║ Your browser will open for Google Cloud authentication. ║');
|
|
209
|
+
console.log('║ ║');
|
|
210
|
+
console.log('║ ╔════════════════════════════════════════════════════════╗ ║');
|
|
211
|
+
console.log('║ ║ ✓ CLICK "SELECT ALL" TO SELECT ALL PERMISSIONS ║ ║');
|
|
212
|
+
console.log('║ ╚════════════════════════════════════════════════════════╝ ║');
|
|
213
|
+
console.log('║ ║');
|
|
214
|
+
console.log('║ Then click "Continue" or "Allow" to consent. ║');
|
|
215
|
+
console.log('║ ║');
|
|
216
|
+
console.log('║ If you don\'t select all permissions, authentication will fail. ║');
|
|
217
|
+
console.log('║ ║');
|
|
218
|
+
console.log('╚══════════════════════════════════════════════════════════════════╝');
|
|
219
|
+
console.log('\nProject: ' + project);
|
|
220
|
+
console.log('Opening browser in 3 seconds...\n');
|
|
221
|
+
|
|
222
|
+
// Give user time to read the warning
|
|
223
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
224
|
+
|
|
225
|
+
// Use Application Default Credentials with browser
|
|
226
|
+
execSync(`gcloud auth application-default login --project=${project}`, {
|
|
227
|
+
stdio: 'inherit',
|
|
228
|
+
timeout: 300000, // 5 minutes
|
|
229
|
+
env: { ...process.env, PATH: process.env.PATH }
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Get the credentials file location
|
|
233
|
+
const credsPath = path.join(
|
|
234
|
+
os.homedir(),
|
|
235
|
+
'.config',
|
|
236
|
+
'gcloud',
|
|
237
|
+
'application_default_credentials.json'
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
if (!fs.existsSync(credsPath)) {
|
|
241
|
+
throw new Error('Credentials file not found');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Copy credentials to our config directory
|
|
245
|
+
fs.mkdirSync(this.configDir, { recursive: true });
|
|
246
|
+
const creds = JSON.parse(fs.readFileSync(credsPath, 'utf8'));
|
|
247
|
+
|
|
248
|
+
// Save API key info
|
|
249
|
+
const apiKeyInfo = {
|
|
250
|
+
type: 'gcloud_application_default',
|
|
251
|
+
credentials_path: credsPath,
|
|
252
|
+
project: creds.quota_project_id || project,
|
|
253
|
+
created_at: new Date().toISOString()
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
fs.writeFileSync(this.apiKeyFile, JSON.stringify(apiKeyInfo, null, 2));
|
|
257
|
+
|
|
258
|
+
this.logger.log('API credentials generated and saved');
|
|
259
|
+
return {
|
|
260
|
+
success: true,
|
|
261
|
+
keyFile: this.apiKeyFile,
|
|
262
|
+
credsPath
|
|
263
|
+
};
|
|
264
|
+
} catch (error) {
|
|
265
|
+
return {
|
|
266
|
+
success: false,
|
|
267
|
+
error: error.message
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Get current project ID
|
|
274
|
+
*/
|
|
275
|
+
async getCurrentProject() {
|
|
276
|
+
try {
|
|
277
|
+
const project = execSync('gcloud config get-value project', {
|
|
278
|
+
encoding: 'utf8',
|
|
279
|
+
stdio: 'pipe'
|
|
280
|
+
}).trim();
|
|
281
|
+
return project;
|
|
282
|
+
} catch {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Get saved API key info
|
|
289
|
+
*/
|
|
290
|
+
getSavedAPIKey() {
|
|
291
|
+
try {
|
|
292
|
+
if (!fs.existsSync(this.apiKeyFile)) {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
return JSON.parse(fs.readFileSync(this.apiKeyFile, 'utf8'));
|
|
296
|
+
} catch {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Check if Application Default Credentials already exist
|
|
303
|
+
*/
|
|
304
|
+
hasApplicationDefaultCredentials() {
|
|
305
|
+
const credsPath = path.join(
|
|
306
|
+
os.homedir(),
|
|
307
|
+
'.config',
|
|
308
|
+
'gcloud',
|
|
309
|
+
'application_default_credentials.json'
|
|
310
|
+
);
|
|
311
|
+
return fs.existsSync(credsPath);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Full authentication flow
|
|
316
|
+
*/
|
|
317
|
+
async fullAuthFlow() {
|
|
318
|
+
// 1. Check/install gcloud
|
|
319
|
+
if (!this.isGCloudInstalled()) {
|
|
320
|
+
this.logger.log('Google Cloud CLI not found. Installing...');
|
|
321
|
+
const installResult = await this.installGCloud();
|
|
322
|
+
if (!installResult.success) {
|
|
323
|
+
return installResult;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Ensure gcloud is in PATH
|
|
328
|
+
this.setupGCloudPath();
|
|
329
|
+
|
|
330
|
+
// 2. Authenticate
|
|
331
|
+
if (!this.isAuthenticated()) {
|
|
332
|
+
this.logger.log('Not authenticated. Starting authentication...');
|
|
333
|
+
const authResult = await this.authenticate();
|
|
334
|
+
if (!authResult.success) {
|
|
335
|
+
return authResult;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// 3. Ensure project
|
|
340
|
+
const projectResult = await this.ensureProject();
|
|
341
|
+
if (!projectResult.success) {
|
|
342
|
+
return projectResult;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// 4. Enable APIs
|
|
346
|
+
const apiResult = await this.enableAPIs();
|
|
347
|
+
if (!apiResult.success) {
|
|
348
|
+
return apiResult;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// 5. Generate API key (or use existing)
|
|
352
|
+
if (this.hasApplicationDefaultCredentials()) {
|
|
353
|
+
this.logger.log('Application Default Credentials already exist');
|
|
354
|
+
|
|
355
|
+
const credsPath = path.join(
|
|
356
|
+
os.homedir(),
|
|
357
|
+
'.config',
|
|
358
|
+
'gcloud',
|
|
359
|
+
'application_default_credentials.json'
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
// Save API key info
|
|
363
|
+
fs.mkdirSync(this.configDir, { recursive: true });
|
|
364
|
+
const apiKeyInfo = {
|
|
365
|
+
type: 'gcloud_application_default',
|
|
366
|
+
credentials_path: credsPath,
|
|
367
|
+
project: projectResult.project,
|
|
368
|
+
created_at: new Date().toISOString()
|
|
369
|
+
};
|
|
370
|
+
fs.writeFileSync(this.apiKeyFile, JSON.stringify(apiKeyInfo, null, 2));
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
success: true,
|
|
374
|
+
keyFile: this.apiKeyFile,
|
|
375
|
+
credsPath: credsPath,
|
|
376
|
+
project: projectResult.project
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const keyResult = await this.generateAPIKey();
|
|
381
|
+
if (!keyResult.success) {
|
|
382
|
+
return keyResult;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return {
|
|
386
|
+
success: true,
|
|
387
|
+
keyFile: keyResult.keyFile,
|
|
388
|
+
credsPath: keyResult.credsPath,
|
|
389
|
+
project: projectResult.project
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
module.exports = { GCloudAuth };
|