vibecodingmachine-core 1.0.2 → 2025.11.2-7.1302

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 (49) hide show
  1. package/.babelrc +13 -13
  2. package/README.md +28 -28
  3. package/__tests__/applescript-manager-claude-fix.test.js +286 -286
  4. package/__tests__/requirement-2-auto-start-looping.test.js +69 -69
  5. package/__tests__/requirement-3-auto-start-looping.test.js +69 -69
  6. package/__tests__/requirement-4-auto-start-looping.test.js +69 -69
  7. package/__tests__/requirement-6-auto-start-looping.test.js +73 -73
  8. package/__tests__/requirement-7-status-tracking.test.js +332 -332
  9. package/jest.config.js +18 -18
  10. package/jest.setup.js +12 -12
  11. package/package.json +48 -48
  12. package/src/auth/access-denied.html +119 -119
  13. package/src/auth/shared-auth-storage.js +230 -230
  14. package/src/autonomous-mode/feature-implementer.cjs +70 -70
  15. package/src/autonomous-mode/feature-implementer.js +425 -425
  16. package/src/chat-management/chat-manager.cjs +71 -71
  17. package/src/chat-management/chat-manager.js +342 -342
  18. package/src/ide-integration/__tests__/applescript-manager-thread-closure.test.js +227 -227
  19. package/src/ide-integration/aider-cli-manager.cjs +850 -850
  20. package/src/ide-integration/applescript-manager.cjs +1088 -1088
  21. package/src/ide-integration/applescript-manager.js +2802 -2802
  22. package/src/ide-integration/applescript-utils.js +306 -306
  23. package/src/ide-integration/cdp-manager.cjs +221 -221
  24. package/src/ide-integration/cdp-manager.js +321 -321
  25. package/src/ide-integration/claude-code-cli-manager.cjs +301 -301
  26. package/src/ide-integration/cline-cli-manager.cjs +2252 -2252
  27. package/src/ide-integration/continue-cli-manager.js +431 -431
  28. package/src/ide-integration/provider-manager.cjs +354 -354
  29. package/src/ide-integration/quota-detector.cjs +34 -34
  30. package/src/ide-integration/quota-detector.js +349 -349
  31. package/src/ide-integration/windows-automation-manager.js +262 -262
  32. package/src/index.cjs +47 -43
  33. package/src/index.js +17 -17
  34. package/src/llm/direct-llm-manager.cjs +609 -609
  35. package/src/ui/ButtonComponents.js +247 -247
  36. package/src/ui/ChatInterface.js +499 -499
  37. package/src/ui/StateManager.js +259 -259
  38. package/src/utils/audit-logger.cjs +116 -116
  39. package/src/utils/config-helpers.cjs +94 -94
  40. package/src/utils/config-helpers.js +94 -94
  41. package/src/utils/electron-update-checker.js +113 -85
  42. package/src/utils/gcloud-auth.cjs +394 -394
  43. package/src/utils/logger.cjs +193 -193
  44. package/src/utils/logger.js +191 -191
  45. package/src/utils/repo-helpers.cjs +120 -120
  46. package/src/utils/repo-helpers.js +120 -120
  47. package/src/utils/requirement-helpers.js +432 -432
  48. package/src/utils/update-checker.js +227 -167
  49. 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 };