@juspay/neurolink 7.33.4 → 7.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +101 -7
- package/dist/cli/commands/setup-anthropic.d.ts +16 -0
- package/dist/cli/commands/setup-anthropic.js +414 -0
- package/dist/cli/commands/setup-azure.d.ts +17 -0
- package/dist/cli/commands/setup-azure.js +415 -0
- package/dist/cli/commands/setup-bedrock.d.ts +13 -0
- package/dist/cli/commands/setup-bedrock.js +487 -0
- package/dist/cli/commands/setup-gcp.d.ts +18 -0
- package/dist/cli/commands/setup-gcp.js +569 -0
- package/dist/cli/commands/setup-google-ai.d.ts +16 -0
- package/dist/cli/commands/setup-google-ai.js +369 -0
- package/dist/cli/commands/setup-huggingface.d.ts +8 -0
- package/dist/cli/commands/setup-huggingface.js +200 -0
- package/dist/cli/commands/setup-mistral.d.ts +8 -0
- package/dist/cli/commands/setup-mistral.js +233 -0
- package/dist/cli/commands/setup-openai.d.ts +16 -0
- package/dist/cli/commands/setup-openai.js +402 -0
- package/dist/cli/commands/setup.d.ts +19 -0
- package/dist/cli/commands/setup.js +539 -0
- package/dist/cli/errorHandler.d.ts +1 -0
- package/dist/cli/errorHandler.js +28 -0
- package/dist/cli/factories/commandFactory.d.ts +27 -0
- package/dist/cli/factories/commandFactory.js +416 -60
- package/dist/cli/factories/ollamaCommandFactory.js +7 -1
- package/dist/cli/factories/setupCommandFactory.d.ts +18 -0
- package/dist/cli/factories/setupCommandFactory.js +137 -0
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +9 -164
- package/dist/cli/loop/optionsSchema.d.ts +15 -0
- package/dist/cli/loop/optionsSchema.js +59 -0
- package/dist/cli/loop/session.d.ts +15 -0
- package/dist/cli/loop/session.js +252 -0
- package/dist/cli/parser.d.ts +1 -0
- package/dist/cli/parser.js +161 -0
- package/dist/cli/utils/envManager.d.ts +3 -2
- package/dist/cli/utils/envManager.js +18 -4
- package/dist/cli/utils/ollamaUtils.js +6 -0
- package/dist/config/{conversationMemoryConfig.d.ts → conversationMemory.d.ts} +1 -1
- package/dist/core/baseProvider.js +17 -3
- package/dist/core/conversationMemoryFactory.d.ts +23 -0
- package/dist/core/conversationMemoryFactory.js +144 -0
- package/dist/core/conversationMemoryInitializer.d.ts +14 -0
- package/dist/core/conversationMemoryInitializer.js +127 -0
- package/dist/core/conversationMemoryManager.d.ts +3 -2
- package/dist/core/conversationMemoryManager.js +4 -3
- package/dist/core/redisConversationMemoryManager.d.ts +73 -0
- package/dist/core/redisConversationMemoryManager.js +483 -0
- package/dist/core/types.d.ts +1 -1
- package/dist/lib/config/{conversationMemoryConfig.d.ts → conversationMemory.d.ts} +1 -1
- package/dist/lib/core/baseProvider.js +17 -3
- package/dist/lib/core/conversationMemoryFactory.d.ts +23 -0
- package/dist/lib/core/conversationMemoryFactory.js +144 -0
- package/dist/lib/core/conversationMemoryInitializer.d.ts +14 -0
- package/dist/lib/core/conversationMemoryInitializer.js +127 -0
- package/dist/lib/core/conversationMemoryManager.d.ts +3 -2
- package/dist/lib/core/conversationMemoryManager.js +4 -3
- package/dist/lib/core/redisConversationMemoryManager.d.ts +73 -0
- package/dist/lib/core/redisConversationMemoryManager.js +483 -0
- package/dist/lib/core/types.d.ts +1 -1
- package/dist/lib/neurolink.d.ts +15 -9
- package/dist/lib/neurolink.js +218 -67
- package/dist/lib/providers/amazonBedrock.d.ts +4 -4
- package/dist/lib/providers/anthropic.d.ts +4 -4
- package/dist/lib/providers/azureOpenai.d.ts +4 -4
- package/dist/lib/providers/googleAiStudio.d.ts +4 -4
- package/dist/lib/providers/googleAiStudio.js +1 -1
- package/dist/lib/providers/huggingFace.d.ts +4 -4
- package/dist/lib/providers/litellm.d.ts +1 -1
- package/dist/lib/providers/mistral.d.ts +4 -4
- package/dist/lib/providers/mistral.js +2 -2
- package/dist/lib/providers/openAI.d.ts +4 -4
- package/dist/lib/session/globalSessionState.d.ts +27 -0
- package/dist/lib/session/globalSessionState.js +77 -0
- package/dist/lib/types/{conversationTypes.d.ts → conversation.d.ts} +32 -0
- package/dist/lib/types/generateTypes.d.ts +1 -1
- package/dist/lib/types/streamTypes.d.ts +1 -1
- package/dist/lib/utils/conversationMemory.d.ts +22 -0
- package/dist/lib/utils/conversationMemory.js +121 -0
- package/dist/lib/utils/conversationMemoryUtils.d.ts +1 -1
- package/dist/lib/utils/conversationMemoryUtils.js +2 -2
- package/dist/lib/utils/messageBuilder.d.ts +1 -1
- package/dist/lib/utils/messageBuilder.js +1 -1
- package/dist/lib/utils/redis.d.ts +42 -0
- package/dist/lib/utils/redis.js +263 -0
- package/dist/neurolink.d.ts +15 -9
- package/dist/neurolink.js +218 -67
- package/dist/providers/amazonBedrock.d.ts +4 -4
- package/dist/providers/anthropic.d.ts +4 -4
- package/dist/providers/azureOpenai.d.ts +4 -4
- package/dist/providers/googleAiStudio.d.ts +4 -4
- package/dist/providers/googleAiStudio.js +1 -1
- package/dist/providers/huggingFace.d.ts +4 -4
- package/dist/providers/litellm.d.ts +1 -1
- package/dist/providers/mistral.d.ts +4 -4
- package/dist/providers/mistral.js +2 -2
- package/dist/providers/openAI.d.ts +4 -4
- package/dist/session/globalSessionState.d.ts +27 -0
- package/dist/session/globalSessionState.js +77 -0
- package/dist/types/{conversationTypes.d.ts → conversation.d.ts} +32 -0
- package/dist/types/generateTypes.d.ts +1 -1
- package/dist/types/streamTypes.d.ts +1 -1
- package/dist/utils/conversationMemory.d.ts +22 -0
- package/dist/utils/conversationMemory.js +121 -0
- package/dist/utils/conversationMemoryUtils.d.ts +1 -1
- package/dist/utils/conversationMemoryUtils.js +2 -2
- package/dist/utils/messageBuilder.d.ts +1 -1
- package/dist/utils/messageBuilder.js +1 -1
- package/dist/utils/redis.d.ts +42 -0
- package/dist/utils/redis.js +263 -0
- package/package.json +3 -1
- /package/dist/config/{conversationMemoryConfig.js → conversationMemory.js} +0 -0
- /package/dist/lib/config/{conversationMemoryConfig.js → conversationMemory.js} +0 -0
- /package/dist/lib/types/{conversationTypes.js → conversation.js} +0 -0
- /package/dist/types/{conversationTypes.js → conversation.js} +0 -0
@@ -0,0 +1,569 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
/**
|
3
|
+
* Google Vertex AI Setup Command
|
4
|
+
*
|
5
|
+
* Supports three authentication methods:
|
6
|
+
* - Method 1: File Path (GOOGLE_APPLICATION_CREDENTIALS)
|
7
|
+
* - Method 2: JSON String (GOOGLE_SERVICE_ACCOUNT_KEY)
|
8
|
+
* - Method 3: Individual Vars (GOOGLE_AUTH_CLIENT_EMAIL + GOOGLE_AUTH_PRIVATE_KEY)
|
9
|
+
*
|
10
|
+
* All methods require GOOGLE_VERTEX_PROJECT
|
11
|
+
* Optional: GOOGLE_VERTEX_LOCATION (defaults to 'us-east5')
|
12
|
+
*/
|
13
|
+
import fs from "fs";
|
14
|
+
import path from "path";
|
15
|
+
import os from "os";
|
16
|
+
import inquirer from "inquirer";
|
17
|
+
import chalk from "chalk";
|
18
|
+
import ora from "ora";
|
19
|
+
import { logger } from "../../lib/utils/logger.js";
|
20
|
+
var AuthMethod;
|
21
|
+
(function (AuthMethod) {
|
22
|
+
AuthMethod["FILE_PATH"] = "file-path";
|
23
|
+
AuthMethod["JSON_STRING"] = "json-string";
|
24
|
+
AuthMethod["INDIVIDUAL_VARS"] = "individual-vars";
|
25
|
+
})(AuthMethod || (AuthMethod = {}));
|
26
|
+
const AUTH_METHOD_NAMES = {
|
27
|
+
[AuthMethod.FILE_PATH]: "Method 1: File Path",
|
28
|
+
[AuthMethod.JSON_STRING]: "Method 2: JSON String",
|
29
|
+
[AuthMethod.INDIVIDUAL_VARS]: "Method 3: Individual Vars",
|
30
|
+
};
|
31
|
+
export async function handleGCPSetup(argv) {
|
32
|
+
try {
|
33
|
+
const options = {
|
34
|
+
checkOnly: argv.check || false,
|
35
|
+
interactive: !argv.nonInteractive,
|
36
|
+
};
|
37
|
+
logger.always(chalk.blue("🔍 Checking environment..."));
|
38
|
+
// Step 1: Detect current authentication method status
|
39
|
+
const status = detectAuthMethodStatus();
|
40
|
+
// Step 2: Display current status
|
41
|
+
displayAuthStatus(status);
|
42
|
+
// Check-only mode - show status and exit
|
43
|
+
if (options.checkOnly) {
|
44
|
+
const completeMethod = getCompleteMethod(status);
|
45
|
+
if (completeMethod) {
|
46
|
+
logger.always(chalk.green("✅ Google Vertex setup complete with " +
|
47
|
+
AUTH_METHOD_NAMES[completeMethod]));
|
48
|
+
if (status.common.hasProject) {
|
49
|
+
logger.always(` Project: ${process.env.GOOGLE_VERTEX_PROJECT}`);
|
50
|
+
}
|
51
|
+
if (status.common.hasLocation) {
|
52
|
+
logger.always(` Location: ${process.env.GOOGLE_VERTEX_LOCATION}`);
|
53
|
+
}
|
54
|
+
else {
|
55
|
+
logger.always(` Location: us-east5 (default)`);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
return;
|
59
|
+
}
|
60
|
+
// Step 3: Check if any method is complete and offer to reconfigure
|
61
|
+
const completeMethod = getCompleteMethod(status);
|
62
|
+
if (completeMethod) {
|
63
|
+
logger.always(chalk.green("✅ Current setup: " +
|
64
|
+
AUTH_METHOD_NAMES[completeMethod] +
|
65
|
+
" (Complete)"));
|
66
|
+
if (status.common.hasProject) {
|
67
|
+
logger.always(` Project: ${process.env.GOOGLE_VERTEX_PROJECT}`);
|
68
|
+
}
|
69
|
+
if (status.common.hasLocation) {
|
70
|
+
logger.always(` Location: ${process.env.GOOGLE_VERTEX_LOCATION}`);
|
71
|
+
}
|
72
|
+
else {
|
73
|
+
logger.always(` Location: us-east5 (default)`);
|
74
|
+
}
|
75
|
+
const { reconfigure } = await inquirer.prompt([
|
76
|
+
{
|
77
|
+
type: "confirm",
|
78
|
+
name: "reconfigure",
|
79
|
+
message: "Setup is already complete. Do you want to reconfigure or switch methods?",
|
80
|
+
default: false,
|
81
|
+
},
|
82
|
+
]);
|
83
|
+
if (!reconfigure) {
|
84
|
+
logger.always(chalk.blue("👍 Keeping existing configuration."));
|
85
|
+
return;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
// Step 4: Interactive setup
|
89
|
+
if (!options.interactive) {
|
90
|
+
logger.always(chalk.yellow("⚠️ Non-interactive mode: setup incomplete"));
|
91
|
+
return;
|
92
|
+
}
|
93
|
+
// Step 5: Method selection
|
94
|
+
const selectedMethod = await selectAuthMethod(status);
|
95
|
+
logger.always(chalk.blue(`👉 You selected ${AUTH_METHOD_NAMES[selectedMethod]}. Completing setup...`));
|
96
|
+
// Step 6: Prompt for missing values
|
97
|
+
const config = await promptForMissingValues(selectedMethod, status);
|
98
|
+
// Step 7: Update .env file
|
99
|
+
await updateEnvFile(selectedMethod, config);
|
100
|
+
// Step 8: Success message
|
101
|
+
logger.always(chalk.green(`✅ Google Vertex setup complete with ${AUTH_METHOD_NAMES[selectedMethod]}`));
|
102
|
+
logger.always(` Project: ${config.project}`);
|
103
|
+
logger.always(` Location: ${config.location || "us-east5"}`);
|
104
|
+
}
|
105
|
+
catch (error) {
|
106
|
+
logger.error(chalk.red("❌ GCP setup failed:"));
|
107
|
+
logger.error(chalk.red(error instanceof Error ? error.message : "Unknown error"));
|
108
|
+
process.exit(1);
|
109
|
+
}
|
110
|
+
}
|
111
|
+
/**
|
112
|
+
* Detect the current status of all authentication methods
|
113
|
+
*/
|
114
|
+
function detectAuthMethodStatus() {
|
115
|
+
const hasCredentials = !!process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
116
|
+
const hasServiceAccountKey = !!process.env.GOOGLE_SERVICE_ACCOUNT_KEY;
|
117
|
+
const hasClientEmail = !!process.env.GOOGLE_AUTH_CLIENT_EMAIL;
|
118
|
+
const hasPrivateKey = !!process.env.GOOGLE_AUTH_PRIVATE_KEY;
|
119
|
+
const hasProject = !!process.env.GOOGLE_VERTEX_PROJECT;
|
120
|
+
const hasLocation = !!process.env.GOOGLE_VERTEX_LOCATION;
|
121
|
+
const status = {
|
122
|
+
method1: {
|
123
|
+
complete: hasCredentials && hasProject,
|
124
|
+
hasCredentials,
|
125
|
+
missingVars: [],
|
126
|
+
},
|
127
|
+
method2: {
|
128
|
+
complete: hasServiceAccountKey && hasProject,
|
129
|
+
hasServiceAccountKey,
|
130
|
+
missingVars: [],
|
131
|
+
},
|
132
|
+
method3: {
|
133
|
+
complete: hasClientEmail && hasPrivateKey && hasProject,
|
134
|
+
hasClientEmail,
|
135
|
+
hasPrivateKey,
|
136
|
+
missingVars: [],
|
137
|
+
},
|
138
|
+
common: {
|
139
|
+
hasProject,
|
140
|
+
hasLocation,
|
141
|
+
missingVars: [],
|
142
|
+
},
|
143
|
+
};
|
144
|
+
// Calculate missing variables for each method
|
145
|
+
if (!hasCredentials) {
|
146
|
+
status.method1.missingVars.push("GOOGLE_APPLICATION_CREDENTIALS");
|
147
|
+
}
|
148
|
+
if (!hasProject) {
|
149
|
+
status.method1.missingVars.push("GOOGLE_VERTEX_PROJECT");
|
150
|
+
}
|
151
|
+
if (!hasServiceAccountKey) {
|
152
|
+
status.method2.missingVars.push("GOOGLE_SERVICE_ACCOUNT_KEY");
|
153
|
+
}
|
154
|
+
if (!hasProject) {
|
155
|
+
status.method2.missingVars.push("GOOGLE_VERTEX_PROJECT");
|
156
|
+
}
|
157
|
+
if (!hasClientEmail) {
|
158
|
+
status.method3.missingVars.push("GOOGLE_AUTH_CLIENT_EMAIL");
|
159
|
+
}
|
160
|
+
if (!hasPrivateKey) {
|
161
|
+
status.method3.missingVars.push("GOOGLE_AUTH_PRIVATE_KEY");
|
162
|
+
}
|
163
|
+
if (!hasProject) {
|
164
|
+
status.method3.missingVars.push("GOOGLE_VERTEX_PROJECT");
|
165
|
+
}
|
166
|
+
if (!hasProject) {
|
167
|
+
status.common.missingVars.push("GOOGLE_VERTEX_PROJECT");
|
168
|
+
}
|
169
|
+
return status;
|
170
|
+
}
|
171
|
+
/**
|
172
|
+
* Display the current authentication status
|
173
|
+
*/
|
174
|
+
function displayAuthStatus(status) {
|
175
|
+
if (status.method1.complete) {
|
176
|
+
logger.always(chalk.green("✔ Method 1: Complete"));
|
177
|
+
}
|
178
|
+
else if (status.method1.hasCredentials) {
|
179
|
+
logger.always(chalk.yellow(`⚠ Method 1: Partially set (missing ${status.method1.missingVars.join(", ")})`));
|
180
|
+
}
|
181
|
+
else {
|
182
|
+
logger.always(chalk.red("✘ Method 1: Not set"));
|
183
|
+
}
|
184
|
+
if (status.method2.complete) {
|
185
|
+
logger.always(chalk.green("✔ Method 2: Complete"));
|
186
|
+
}
|
187
|
+
else if (status.method2.hasServiceAccountKey) {
|
188
|
+
logger.always(chalk.yellow(`⚠ Method 2: Partially set (missing ${status.method2.missingVars.join(", ")})`));
|
189
|
+
}
|
190
|
+
else {
|
191
|
+
logger.always(chalk.red("✘ Method 2: Not set"));
|
192
|
+
}
|
193
|
+
if (status.method3.complete) {
|
194
|
+
logger.always(chalk.green("✔ Method 3: Complete"));
|
195
|
+
}
|
196
|
+
else if (status.method3.hasClientEmail || status.method3.hasPrivateKey) {
|
197
|
+
logger.always(chalk.yellow(`⚠ Method 3: Partially set (missing ${status.method3.missingVars.join(", ")})`));
|
198
|
+
}
|
199
|
+
else {
|
200
|
+
logger.always(chalk.red("✘ Method 3: Not set"));
|
201
|
+
}
|
202
|
+
}
|
203
|
+
/**
|
204
|
+
* Check if any authentication method is complete
|
205
|
+
*/
|
206
|
+
function getCompleteMethod(status) {
|
207
|
+
if (status.method1.complete) {
|
208
|
+
return AuthMethod.FILE_PATH;
|
209
|
+
}
|
210
|
+
if (status.method2.complete) {
|
211
|
+
return AuthMethod.JSON_STRING;
|
212
|
+
}
|
213
|
+
if (status.method3.complete) {
|
214
|
+
return AuthMethod.INDIVIDUAL_VARS;
|
215
|
+
}
|
216
|
+
return null;
|
217
|
+
}
|
218
|
+
/**
|
219
|
+
* Let user select authentication method
|
220
|
+
*/
|
221
|
+
async function selectAuthMethod(status) {
|
222
|
+
// Check for partially filled methods
|
223
|
+
const partiallyFilledMethods = [];
|
224
|
+
if (status.method1.hasCredentials && !status.method1.complete) {
|
225
|
+
partiallyFilledMethods.push({
|
226
|
+
method: AuthMethod.FILE_PATH,
|
227
|
+
name: "Method 1",
|
228
|
+
count: 1,
|
229
|
+
});
|
230
|
+
}
|
231
|
+
if (status.method2.hasServiceAccountKey && !status.method2.complete) {
|
232
|
+
partiallyFilledMethods.push({
|
233
|
+
method: AuthMethod.JSON_STRING,
|
234
|
+
name: "Method 2",
|
235
|
+
count: 1,
|
236
|
+
});
|
237
|
+
}
|
238
|
+
if ((status.method3.hasClientEmail || status.method3.hasPrivateKey) &&
|
239
|
+
!status.method3.complete) {
|
240
|
+
const count = (status.method3.hasClientEmail ? 1 : 0) +
|
241
|
+
(status.method3.hasPrivateKey ? 1 : 0);
|
242
|
+
partiallyFilledMethods.push({
|
243
|
+
method: AuthMethod.INDIVIDUAL_VARS,
|
244
|
+
name: "Method 3",
|
245
|
+
count,
|
246
|
+
});
|
247
|
+
}
|
248
|
+
// If there's a partially filled method, suggest continuing with it
|
249
|
+
if (partiallyFilledMethods.length > 0) {
|
250
|
+
const partial = partiallyFilledMethods[0];
|
251
|
+
const totalVars = partial.method === AuthMethod.INDIVIDUAL_VARS ? 2 : 1;
|
252
|
+
logger.always(chalk.yellow(`\nYou already have ${partial.count}/${totalVars} values set for ${partial.name}.`));
|
253
|
+
const { continueWithPartial } = await inquirer.prompt([
|
254
|
+
{
|
255
|
+
type: "confirm",
|
256
|
+
name: "continueWithPartial",
|
257
|
+
message: `Do you want to continue with ${partial.name} or pick another method?`,
|
258
|
+
default: true,
|
259
|
+
},
|
260
|
+
]);
|
261
|
+
if (continueWithPartial) {
|
262
|
+
return partial.method;
|
263
|
+
}
|
264
|
+
}
|
265
|
+
// Present method selection
|
266
|
+
const { method } = await inquirer.prompt([
|
267
|
+
{
|
268
|
+
type: "list",
|
269
|
+
name: "method",
|
270
|
+
message: "Which authentication method would you like to use?",
|
271
|
+
choices: [
|
272
|
+
{
|
273
|
+
name: "File Path (Recommended for local development)",
|
274
|
+
value: AuthMethod.FILE_PATH,
|
275
|
+
},
|
276
|
+
{
|
277
|
+
name: "JSON String (Good for containers/cloud)",
|
278
|
+
value: AuthMethod.JSON_STRING,
|
279
|
+
},
|
280
|
+
{
|
281
|
+
name: "Individual Vars (Good for CI/CD)",
|
282
|
+
value: AuthMethod.INDIVIDUAL_VARS,
|
283
|
+
},
|
284
|
+
],
|
285
|
+
},
|
286
|
+
]);
|
287
|
+
return method;
|
288
|
+
}
|
289
|
+
/**
|
290
|
+
* Prompt user for missing values based on selected method
|
291
|
+
*/
|
292
|
+
async function promptForMissingValues(method, status) {
|
293
|
+
const config = {};
|
294
|
+
switch (method) {
|
295
|
+
case AuthMethod.FILE_PATH:
|
296
|
+
if (!status.method1.hasCredentials) {
|
297
|
+
// Try to auto-detect ADC file first
|
298
|
+
const adcPath = path.join(os.homedir(), ".config", "gcloud", "application_default_credentials.json");
|
299
|
+
if (fs.existsSync(adcPath)) {
|
300
|
+
logger.always(chalk.green("✔ Found Application Default Credentials"));
|
301
|
+
logger.always(chalk.blue(` Location: ${adcPath}`));
|
302
|
+
config.credentialsPath = adcPath;
|
303
|
+
}
|
304
|
+
else {
|
305
|
+
const { credentialsPath } = await inquirer.prompt([
|
306
|
+
{
|
307
|
+
type: "input",
|
308
|
+
name: "credentialsPath",
|
309
|
+
message: "Enter the path to your Google Cloud credentials JSON file:",
|
310
|
+
validate: validateCredentialsFile,
|
311
|
+
transformer: (input) => input.replace(/^~/, os.homedir()),
|
312
|
+
},
|
313
|
+
]);
|
314
|
+
config.credentialsPath = credentialsPath.replace(/^~/, os.homedir());
|
315
|
+
}
|
316
|
+
}
|
317
|
+
break;
|
318
|
+
case AuthMethod.JSON_STRING:
|
319
|
+
if (!status.method2.hasServiceAccountKey) {
|
320
|
+
const { serviceAccountKey } = await inquirer.prompt([
|
321
|
+
{
|
322
|
+
type: "password",
|
323
|
+
mask: "*",
|
324
|
+
name: "serviceAccountKey",
|
325
|
+
message: "Enter your service account JSON as a string:",
|
326
|
+
validate: validateServiceAccountJSON,
|
327
|
+
},
|
328
|
+
]);
|
329
|
+
config.serviceAccountKey = serviceAccountKey;
|
330
|
+
}
|
331
|
+
break;
|
332
|
+
case AuthMethod.INDIVIDUAL_VARS:
|
333
|
+
if (!status.method3.hasClientEmail) {
|
334
|
+
const { clientEmail } = await inquirer.prompt([
|
335
|
+
{
|
336
|
+
type: "input",
|
337
|
+
name: "clientEmail",
|
338
|
+
message: "Enter your service account client email (format: name@project.iam.gserviceaccount.com):",
|
339
|
+
validate: (input) => {
|
340
|
+
if (!input.trim()) {
|
341
|
+
return "Client email is required";
|
342
|
+
}
|
343
|
+
// Check for basic email format
|
344
|
+
if (!input.includes("@")) {
|
345
|
+
return "Invalid email format. Expected: service-account@project-id.iam.gserviceaccount.com";
|
346
|
+
}
|
347
|
+
// Check for Google service account domain
|
348
|
+
if (!input.endsWith(".iam.gserviceaccount.com")) {
|
349
|
+
return "Invalid service account email. Must end with '.iam.gserviceaccount.com'\nExample: my-service-account@my-project.iam.gserviceaccount.com";
|
350
|
+
}
|
351
|
+
// Validate the structure: name@project.iam.gserviceaccount.com
|
352
|
+
const emailPattern = /^[a-z0-9-]+@[a-z0-9-]+\.iam\.gserviceaccount\.com$/;
|
353
|
+
if (!emailPattern.test(input.trim())) {
|
354
|
+
return "Invalid format. Expected: service-account-name@project-id.iam.gserviceaccount.com\nExample: my-service-account@my-project-123.iam.gserviceaccount.com";
|
355
|
+
}
|
356
|
+
return true;
|
357
|
+
},
|
358
|
+
},
|
359
|
+
]);
|
360
|
+
config.clientEmail = clientEmail.trim();
|
361
|
+
}
|
362
|
+
if (!status.method3.hasPrivateKey) {
|
363
|
+
const { privateKey } = await inquirer.prompt([
|
364
|
+
{
|
365
|
+
type: "password",
|
366
|
+
mask: "*",
|
367
|
+
name: "privateKey",
|
368
|
+
message: "Enter your service account private key:",
|
369
|
+
validate: (input) => {
|
370
|
+
if (!input.trim()) {
|
371
|
+
return "Private key is required";
|
372
|
+
}
|
373
|
+
if (!input.includes("BEGIN PRIVATE KEY") ||
|
374
|
+
!input.includes("END PRIVATE KEY")) {
|
375
|
+
return "Invalid private key format. Should include BEGIN and END markers.";
|
376
|
+
}
|
377
|
+
return true;
|
378
|
+
},
|
379
|
+
},
|
380
|
+
]);
|
381
|
+
config.privateKey = privateKey.trim();
|
382
|
+
}
|
383
|
+
break;
|
384
|
+
}
|
385
|
+
// Always prompt for project if missing
|
386
|
+
if (!status.common.hasProject) {
|
387
|
+
const { project } = await inquirer.prompt([
|
388
|
+
{
|
389
|
+
type: "input",
|
390
|
+
name: "project",
|
391
|
+
message: "Enter your Google Cloud Project ID:",
|
392
|
+
validate: (input) => {
|
393
|
+
if (!input.trim()) {
|
394
|
+
return "Project ID is required";
|
395
|
+
}
|
396
|
+
if (!/^[a-z][a-z0-9-]{4,28}[a-z0-9]$/.test(input.trim())) {
|
397
|
+
return "Invalid project ID format. Must be 6-30 characters, start with lowercase letter, contain only lowercase letters, numbers, and hyphens.";
|
398
|
+
}
|
399
|
+
return true;
|
400
|
+
},
|
401
|
+
},
|
402
|
+
]);
|
403
|
+
config.project = project.trim();
|
404
|
+
}
|
405
|
+
else {
|
406
|
+
config.project = process.env.GOOGLE_VERTEX_PROJECT;
|
407
|
+
}
|
408
|
+
// Always prompt for location if missing, with default
|
409
|
+
if (!status.common.hasLocation) {
|
410
|
+
const { location } = await inquirer.prompt([
|
411
|
+
{
|
412
|
+
type: "input",
|
413
|
+
name: "location",
|
414
|
+
message: "Enter your Google Vertex AI location:",
|
415
|
+
default: "us-east5",
|
416
|
+
validate: (input) => {
|
417
|
+
if (!input.trim()) {
|
418
|
+
return "Location is required";
|
419
|
+
}
|
420
|
+
return true;
|
421
|
+
},
|
422
|
+
},
|
423
|
+
]);
|
424
|
+
config.location = location.trim();
|
425
|
+
}
|
426
|
+
else {
|
427
|
+
config.location = process.env.GOOGLE_VERTEX_LOCATION;
|
428
|
+
}
|
429
|
+
return config;
|
430
|
+
}
|
431
|
+
/**
|
432
|
+
* Validate credentials file path
|
433
|
+
*/
|
434
|
+
function validateCredentialsFile(input) {
|
435
|
+
if (!input.trim()) {
|
436
|
+
return "Credentials path is required";
|
437
|
+
}
|
438
|
+
const expandedPath = input.replace(/^~/, os.homedir());
|
439
|
+
if (!fs.existsSync(expandedPath)) {
|
440
|
+
return `File not found: ${expandedPath}`;
|
441
|
+
}
|
442
|
+
try {
|
443
|
+
const content = fs.readFileSync(expandedPath, "utf8");
|
444
|
+
const parsed = JSON.parse(content);
|
445
|
+
if (!parsed.client_email || !parsed.private_key) {
|
446
|
+
return "Invalid service account file: missing client_email or private_key";
|
447
|
+
}
|
448
|
+
return true;
|
449
|
+
}
|
450
|
+
catch {
|
451
|
+
return "Invalid JSON file";
|
452
|
+
}
|
453
|
+
}
|
454
|
+
/**
|
455
|
+
* Validate service account JSON string
|
456
|
+
*/
|
457
|
+
function validateServiceAccountJSON(input) {
|
458
|
+
if (!input.trim()) {
|
459
|
+
return "Service account JSON is required";
|
460
|
+
}
|
461
|
+
try {
|
462
|
+
const parsed = JSON.parse(input.trim());
|
463
|
+
if (!parsed.client_email || !parsed.private_key) {
|
464
|
+
return "Invalid service account JSON: missing client_email or private_key";
|
465
|
+
}
|
466
|
+
return true;
|
467
|
+
}
|
468
|
+
catch {
|
469
|
+
return "Invalid JSON format";
|
470
|
+
}
|
471
|
+
}
|
472
|
+
/**
|
473
|
+
* Update .env file with selected authentication method
|
474
|
+
*/
|
475
|
+
async function updateEnvFile(method, config) {
|
476
|
+
const envPath = path.join(process.cwd(), ".env");
|
477
|
+
const spinner = ora("💾 Updating .env file...").start();
|
478
|
+
try {
|
479
|
+
let envContent = "";
|
480
|
+
// Read existing .env file if it exists
|
481
|
+
if (fs.existsSync(envPath)) {
|
482
|
+
envContent = fs.readFileSync(envPath, "utf8");
|
483
|
+
}
|
484
|
+
// Parse existing environment variables
|
485
|
+
const envLines = envContent.split("\n");
|
486
|
+
const existingVars = new Map();
|
487
|
+
const otherLines = [];
|
488
|
+
for (const line of envLines) {
|
489
|
+
const trimmed = line.trim();
|
490
|
+
if (trimmed && !trimmed.startsWith("#")) {
|
491
|
+
const equalsIndex = trimmed.indexOf("=");
|
492
|
+
if (equalsIndex > 0) {
|
493
|
+
const key = trimmed.substring(0, equalsIndex);
|
494
|
+
const value = trimmed.substring(equalsIndex + 1);
|
495
|
+
existingVars.set(key, value);
|
496
|
+
}
|
497
|
+
else {
|
498
|
+
otherLines.push(line);
|
499
|
+
}
|
500
|
+
}
|
501
|
+
else {
|
502
|
+
otherLines.push(line);
|
503
|
+
}
|
504
|
+
}
|
505
|
+
// Remove all Google Vertex auth variables first (clean slate)
|
506
|
+
existingVars.delete("GOOGLE_APPLICATION_CREDENTIALS");
|
507
|
+
existingVars.delete("GOOGLE_SERVICE_ACCOUNT_KEY");
|
508
|
+
existingVars.delete("GOOGLE_AUTH_CLIENT_EMAIL");
|
509
|
+
existingVars.delete("GOOGLE_AUTH_PRIVATE_KEY");
|
510
|
+
// Set variables for selected method
|
511
|
+
switch (method) {
|
512
|
+
case AuthMethod.FILE_PATH:
|
513
|
+
if (config.credentialsPath) {
|
514
|
+
existingVars.set("GOOGLE_APPLICATION_CREDENTIALS", config.credentialsPath);
|
515
|
+
}
|
516
|
+
break;
|
517
|
+
case AuthMethod.JSON_STRING:
|
518
|
+
if (config.serviceAccountKey) {
|
519
|
+
existingVars.set("GOOGLE_SERVICE_ACCOUNT_KEY", config.serviceAccountKey);
|
520
|
+
}
|
521
|
+
break;
|
522
|
+
case AuthMethod.INDIVIDUAL_VARS:
|
523
|
+
if (config.clientEmail) {
|
524
|
+
existingVars.set("GOOGLE_AUTH_CLIENT_EMAIL", config.clientEmail);
|
525
|
+
}
|
526
|
+
if (config.privateKey) {
|
527
|
+
const escaped = config.privateKey
|
528
|
+
.replace(/\r?\n/g, "\\n")
|
529
|
+
.replace(/"/g, '\\"');
|
530
|
+
existingVars.set("GOOGLE_AUTH_PRIVATE_KEY", `"${escaped}"`);
|
531
|
+
}
|
532
|
+
break;
|
533
|
+
}
|
534
|
+
// Always set project and location
|
535
|
+
if (config.project) {
|
536
|
+
existingVars.set("GOOGLE_VERTEX_PROJECT", config.project);
|
537
|
+
}
|
538
|
+
if (config.location) {
|
539
|
+
existingVars.set("GOOGLE_VERTEX_LOCATION", config.location);
|
540
|
+
}
|
541
|
+
// Reconstruct .env content preserving structure
|
542
|
+
const newEnvLines = [];
|
543
|
+
// Add non-variable lines first (comments, empty lines)
|
544
|
+
for (const line of otherLines) {
|
545
|
+
newEnvLines.push(line);
|
546
|
+
}
|
547
|
+
// Add separator comment for Google Vertex if needed
|
548
|
+
if (!envContent.includes("GOOGLE VERTEX AI CONFIGURATION")) {
|
549
|
+
if (newEnvLines.length > 0 &&
|
550
|
+
newEnvLines[newEnvLines.length - 1].trim()) {
|
551
|
+
newEnvLines.push("");
|
552
|
+
}
|
553
|
+
newEnvLines.push("# GOOGLE VERTEX AI CONFIGURATION");
|
554
|
+
}
|
555
|
+
// Add all environment variables
|
556
|
+
for (const [key, value] of existingVars.entries()) {
|
557
|
+
newEnvLines.push(`${key}=${value}`);
|
558
|
+
}
|
559
|
+
// Write updated content
|
560
|
+
const finalContent = newEnvLines.join("\n") + (newEnvLines.length > 0 ? "\n" : "");
|
561
|
+
fs.writeFileSync(envPath, finalContent, "utf8");
|
562
|
+
spinner.succeed(chalk.green("✔ .env file updated successfully"));
|
563
|
+
}
|
564
|
+
catch (error) {
|
565
|
+
spinner.fail(chalk.red("❌ Failed to update .env file"));
|
566
|
+
logger.error(chalk.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
567
|
+
throw error;
|
568
|
+
}
|
569
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
/**
|
3
|
+
* Google AI Studio Setup Command
|
4
|
+
*
|
5
|
+
* Simple setup for Google AI Studio (Google AI) integration:
|
6
|
+
* - GOOGLE_AI_API_KEY (required)
|
7
|
+
* - GOOGLE_AI_MODEL (optional, with recommended choices)
|
8
|
+
*
|
9
|
+
* Follows the same UX patterns as setup-openai and setup-gcp
|
10
|
+
*/
|
11
|
+
interface GoogleAISetupArgv {
|
12
|
+
check?: boolean;
|
13
|
+
nonInteractive?: boolean;
|
14
|
+
}
|
15
|
+
export declare function handleGoogleAISetup(argv: GoogleAISetupArgv): Promise<void>;
|
16
|
+
export {};
|