gitarsenal-cli 1.9.38 → 1.9.40
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/.venv_status.json +1 -1
- package/bin/gitarsenal.js +215 -85
- package/lib/sandbox.js +12 -1
- package/package.json +1 -1
- package/python/test_modalSandboxScript.py +11 -3
package/.venv_status.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"created":"2025-08-
|
|
1
|
+
{"created":"2025-08-11T12:44:14.984Z","packages":["modal","gitingest","requests","anthropic"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
|
package/bin/gitarsenal.js
CHANGED
|
@@ -105,19 +105,39 @@ function activateVirtualEnvironment() {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
// Lightweight preview of GPU/Torch/CUDA recommendations prior to GPU selection
|
|
108
|
-
async function previewRecommendations(repoUrl) {
|
|
109
|
-
const
|
|
108
|
+
async function previewRecommendations(repoUrl, optsOrShowSummary = true) {
|
|
109
|
+
const showSummary = typeof optsOrShowSummary === 'boolean' ? optsOrShowSummary : (optsOrShowSummary?.showSummary ?? true);
|
|
110
|
+
const externalSignal = typeof optsOrShowSummary === 'object' ? optsOrShowSummary.abortSignal : undefined;
|
|
111
|
+
const hideSpinner = typeof optsOrShowSummary === 'object' ? optsOrShowSummary.hideSpinner : false;
|
|
112
|
+
|
|
113
|
+
const spinner = hideSpinner ? null : ora('Analyzing repository for GPU/Torch/CUDA recommendations...').start();
|
|
114
|
+
const previewTimeoutMs = Number(process.env.GITARSENAL_PREVIEW_TIMEOUT_MS || 90000);
|
|
115
|
+
const controller = new AbortController();
|
|
116
|
+
const abortOnExternal = () => controller.abort();
|
|
117
|
+
const timeoutId = setTimeout(() => controller.abort(), previewTimeoutMs);
|
|
118
|
+
|
|
119
|
+
// Add periodic spinner updates to show progress (only if we have a spinner)
|
|
120
|
+
let elapsedTime = 0;
|
|
121
|
+
const progressInterval = spinner ? setInterval(() => {
|
|
122
|
+
elapsedTime += 10;
|
|
123
|
+
const minutes = Math.floor(elapsedTime / 60);
|
|
124
|
+
const seconds = elapsedTime % 60;
|
|
125
|
+
const timeStr = minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
|
|
126
|
+
spinner.text = `Analyzing repository for GPU/Torch/CUDA recommendations... (${timeStr})`;
|
|
127
|
+
}, 10000) : null; // Update every 10 seconds
|
|
128
|
+
|
|
110
129
|
try {
|
|
130
|
+
// Bridge external abort signal to our controller (for stopping spinner when full fetch returns)
|
|
131
|
+
if (externalSignal) {
|
|
132
|
+
if (externalSignal.aborted) controller.abort();
|
|
133
|
+
else externalSignal.addEventListener('abort', abortOnExternal, { once: true });
|
|
134
|
+
}
|
|
135
|
+
|
|
111
136
|
const envUrl = process.env.GITARSENAL_API_URL;
|
|
112
|
-
const endpoints = envUrl
|
|
113
|
-
? [envUrl]
|
|
114
|
-
: [
|
|
115
|
-
'https://www.gitarsenal.dev/api/best_gpu'
|
|
116
|
-
];
|
|
137
|
+
const endpoints = envUrl ? [envUrl] : ['https://www.gitarsenal.dev/api/best_gpu'];
|
|
117
138
|
|
|
118
139
|
const payload = {
|
|
119
140
|
repoUrl,
|
|
120
|
-
// Minimal GitIngest data to allow backend to run LLM analysis
|
|
121
141
|
gitingestData: {
|
|
122
142
|
system_info: {
|
|
123
143
|
platform: process.platform,
|
|
@@ -137,42 +157,22 @@ async function previewRecommendations(repoUrl) {
|
|
|
137
157
|
},
|
|
138
158
|
success: true
|
|
139
159
|
},
|
|
140
|
-
// Hint server to do lightweight preview if supported
|
|
141
160
|
preview: true
|
|
142
161
|
};
|
|
143
162
|
|
|
144
|
-
|
|
145
|
-
|
|
163
|
+
let data = null;
|
|
164
|
+
let lastErrorText = '';
|
|
146
165
|
|
|
147
|
-
const
|
|
148
|
-
const controller = new AbortController();
|
|
149
|
-
const id = setTimeout(() => controller.abort(), timeoutMs);
|
|
166
|
+
for (const url of endpoints) {
|
|
150
167
|
try {
|
|
168
|
+
if (spinner) spinner.text = `Analyzing (preview): ${url}`;
|
|
151
169
|
const res = await fetch(url, {
|
|
152
170
|
method: 'POST',
|
|
153
|
-
headers: {
|
|
154
|
-
|
|
155
|
-
'User-Agent': 'GitArsenal-CLI/1.0'
|
|
156
|
-
},
|
|
157
|
-
body: JSON.stringify(body),
|
|
171
|
+
headers: { 'Content-Type': 'application/json', 'User-Agent': 'GitArsenal-CLI/1.0' },
|
|
172
|
+
body: JSON.stringify(payload),
|
|
158
173
|
redirect: 'follow',
|
|
159
174
|
signal: controller.signal
|
|
160
175
|
});
|
|
161
|
-
clearTimeout(id);
|
|
162
|
-
return res;
|
|
163
|
-
} catch (e) {
|
|
164
|
-
clearTimeout(id);
|
|
165
|
-
throw e;
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
let data = null;
|
|
170
|
-
let lastErrorText = '';
|
|
171
|
-
|
|
172
|
-
for (const url of endpoints) {
|
|
173
|
-
try {
|
|
174
|
-
spinner.text = `Analyzing (preview): ${url}`;
|
|
175
|
-
const res = await fetchWithTimeout(url, payload, previewTimeoutMs);
|
|
176
176
|
if (!res.ok) {
|
|
177
177
|
const text = await res.text().catch(() => '');
|
|
178
178
|
lastErrorText = `${res.status} ${text.slice(0, 300)}`;
|
|
@@ -181,25 +181,37 @@ async function previewRecommendations(repoUrl) {
|
|
|
181
181
|
data = await res.json().catch(() => null);
|
|
182
182
|
if (data) break;
|
|
183
183
|
} catch (err) {
|
|
184
|
+
if (err && (err.name === 'AbortError' || err.code === 'ABORT_ERR')) {
|
|
185
|
+
// Silent stop on external abort (e.g., full fetch succeeded)
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
184
188
|
lastErrorText = err && err.message ? err.message : 'request failed';
|
|
185
189
|
continue;
|
|
186
190
|
}
|
|
187
191
|
}
|
|
188
192
|
|
|
189
|
-
spinner.stop();
|
|
190
|
-
|
|
191
193
|
if (!data) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
+
if (!hideSpinner) {
|
|
195
|
+
console.log(chalk.yellow('⚠️ Preview unavailable (timeout or server error).'));
|
|
196
|
+
if (lastErrorText) console.log(chalk.gray(`Reason: ${lastErrorText}`));
|
|
197
|
+
}
|
|
194
198
|
return null;
|
|
195
199
|
}
|
|
196
200
|
|
|
197
|
-
|
|
201
|
+
if (showSummary) {
|
|
202
|
+
printGpuTorchCudaSummary(data);
|
|
203
|
+
}
|
|
198
204
|
return data;
|
|
199
205
|
} catch (e) {
|
|
200
|
-
|
|
201
|
-
|
|
206
|
+
if (!(e && (e.name === 'AbortError' || e.code === 'ABORT_ERR')) && !hideSpinner) {
|
|
207
|
+
console.log(chalk.yellow(`⚠️ Preview failed: ${e.message}`));
|
|
208
|
+
}
|
|
202
209
|
return null;
|
|
210
|
+
} finally {
|
|
211
|
+
clearTimeout(timeoutId);
|
|
212
|
+
if (progressInterval) clearInterval(progressInterval);
|
|
213
|
+
if (spinner) spinner.stop();
|
|
214
|
+
if (externalSignal) externalSignal.removeEventListener('abort', abortOnExternal);
|
|
203
215
|
}
|
|
204
216
|
}
|
|
205
217
|
|
|
@@ -357,13 +369,14 @@ async function fetchFullSetupAndRecs(repoUrl) {
|
|
|
357
369
|
}
|
|
358
370
|
|
|
359
371
|
// Function to send user data to web application
|
|
360
|
-
async function sendUserData(userId, userName) {
|
|
372
|
+
async function sendUserData(userId, userName, userEmail) {
|
|
361
373
|
try {
|
|
362
|
-
console.log(chalk.blue(`🔗 Attempting to register user: ${userName} (${
|
|
374
|
+
console.log(chalk.blue(`🔗 Attempting to register user: ${userName} (${userEmail})`));
|
|
363
375
|
|
|
364
376
|
const userData = {
|
|
365
|
-
email:
|
|
366
|
-
name: userName
|
|
377
|
+
email: userEmail, // Use actual email address
|
|
378
|
+
name: userName,
|
|
379
|
+
username: userId
|
|
367
380
|
};
|
|
368
381
|
|
|
369
382
|
const data = JSON.stringify(userData);
|
|
@@ -453,70 +466,153 @@ async function sendUserData(userId, userName) {
|
|
|
453
466
|
async function collectUserCredentials(options) {
|
|
454
467
|
let userId = options.userId;
|
|
455
468
|
let userName = options.userName;
|
|
469
|
+
let userEmail = options.userEmail;
|
|
456
470
|
|
|
457
|
-
// Check for config file first
|
|
458
|
-
const
|
|
459
|
-
|
|
471
|
+
// Check for user-specific config file first (in user's home directory)
|
|
472
|
+
const os = require('os');
|
|
473
|
+
const userConfigDir = path.join(os.homedir(), '.gitarsenal');
|
|
474
|
+
const userConfigPath = path.join(userConfigDir, 'user-config.json');
|
|
475
|
+
|
|
476
|
+
if (fs.existsSync(userConfigPath)) {
|
|
460
477
|
try {
|
|
461
|
-
const config = JSON.parse(fs.readFileSync(
|
|
462
|
-
if (config.userId && config.userName) {
|
|
478
|
+
const config = JSON.parse(fs.readFileSync(userConfigPath, 'utf8'));
|
|
479
|
+
if (config.userId && config.userName && config.userEmail) {
|
|
463
480
|
userId = config.userId;
|
|
464
481
|
userName = config.userName;
|
|
482
|
+
userEmail = config.userEmail;
|
|
483
|
+
console.log(chalk.green(`✅ Welcome back, ${userName}!`));
|
|
484
|
+
return { userId, userName, userEmail };
|
|
465
485
|
}
|
|
466
486
|
} catch (error) {
|
|
467
|
-
console.log(chalk.yellow('⚠️ Could not read config file'));
|
|
487
|
+
console.log(chalk.yellow('⚠️ Could not read user config file'));
|
|
468
488
|
}
|
|
469
489
|
}
|
|
470
490
|
|
|
471
491
|
// If not provided via CLI or config, prompt for them
|
|
472
|
-
if (!userId || !userName) {
|
|
473
|
-
console.log(chalk.blue('\n🔐 GitArsenal
|
|
474
|
-
console.log(chalk.gray('
|
|
492
|
+
if (!userId || !userName || !userEmail) {
|
|
493
|
+
console.log(chalk.blue('\n🔐 GitArsenal Authentication'));
|
|
494
|
+
console.log(chalk.gray('Create an account or login to use GitArsenal'));
|
|
475
495
|
console.log(chalk.gray('Your credentials will be saved locally for future use.'));
|
|
476
496
|
|
|
497
|
+
const authChoice = await inquirer.prompt([
|
|
498
|
+
{
|
|
499
|
+
type: 'list',
|
|
500
|
+
name: 'action',
|
|
501
|
+
message: 'What would you like to do?',
|
|
502
|
+
choices: [
|
|
503
|
+
{ name: 'Create new account', value: 'register' },
|
|
504
|
+
{ name: 'Login with existing account', value: 'login' }
|
|
505
|
+
]
|
|
506
|
+
}
|
|
507
|
+
]);
|
|
508
|
+
|
|
509
|
+
if (authChoice.action === 'register') {
|
|
510
|
+
console.log(chalk.blue('\n📝 Create New Account'));
|
|
477
511
|
const credentials = await inquirer.prompt([
|
|
478
512
|
{
|
|
479
513
|
type: 'input',
|
|
480
514
|
name: 'userId',
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
515
|
+
message: 'Choose a username:',
|
|
516
|
+
validate: (input) => {
|
|
517
|
+
const username = input.trim();
|
|
518
|
+
if (username === '') return 'Username is required';
|
|
519
|
+
if (username.length < 3) return 'Username must be at least 3 characters';
|
|
520
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(username)) return 'Username can only contain letters, numbers, _ and -';
|
|
521
|
+
return true;
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
type: 'input',
|
|
526
|
+
name: 'userEmail',
|
|
527
|
+
message: 'Enter your email address:',
|
|
528
|
+
validate: (input) => {
|
|
529
|
+
const email = input.trim();
|
|
530
|
+
if (email === '') return 'Email address is required';
|
|
531
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
532
|
+
return 'Please enter a valid email address (e.g., user@example.com)';
|
|
533
|
+
}
|
|
534
|
+
return true;
|
|
535
|
+
}
|
|
484
536
|
},
|
|
485
537
|
{
|
|
486
538
|
type: 'input',
|
|
487
539
|
name: 'userName',
|
|
488
|
-
|
|
489
|
-
default: userName || 'Anonymous User',
|
|
540
|
+
message: 'Enter your full name:',
|
|
490
541
|
validate: (input) => input.trim() !== '' ? true : 'Name is required'
|
|
491
542
|
},
|
|
492
543
|
{
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
544
|
+
type: 'password',
|
|
545
|
+
name: 'password',
|
|
546
|
+
message: 'Create a password (min 8 characters):',
|
|
547
|
+
validate: (input) => {
|
|
548
|
+
if (input.length < 8) return 'Password must be at least 8 characters';
|
|
549
|
+
return true;
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
type: 'password',
|
|
554
|
+
name: 'confirmPassword',
|
|
555
|
+
message: 'Confirm your password:',
|
|
556
|
+
validate: (input, answers) => {
|
|
557
|
+
if (input !== answers.password) return 'Passwords do not match';
|
|
558
|
+
return true;
|
|
559
|
+
}
|
|
497
560
|
}
|
|
498
561
|
]);
|
|
499
562
|
|
|
500
563
|
userId = credentials.userId;
|
|
501
564
|
userName = credentials.userName;
|
|
565
|
+
userEmail = credentials.userEmail;
|
|
566
|
+
|
|
567
|
+
console.log(chalk.green('✅ Account created successfully!'));
|
|
568
|
+
} else {
|
|
569
|
+
console.log(chalk.blue('\n🔑 Login'));
|
|
570
|
+
const credentials = await inquirer.prompt([
|
|
571
|
+
{
|
|
572
|
+
type: 'input',
|
|
573
|
+
name: 'userIdentifier',
|
|
574
|
+
message: 'Enter your username or email:',
|
|
575
|
+
validate: (input) => input.trim() !== '' ? true : 'Username/email is required'
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
type: 'password',
|
|
579
|
+
name: 'password',
|
|
580
|
+
message: 'Enter your password:',
|
|
581
|
+
validate: (input) => input.trim() !== '' ? true : 'Password is required'
|
|
582
|
+
}
|
|
583
|
+
]);
|
|
584
|
+
|
|
585
|
+
// For now, we'll simulate successful login
|
|
586
|
+
// In a real implementation, you'd validate against a user database
|
|
587
|
+
const identifier = credentials.userIdentifier;
|
|
588
|
+
userId = identifier.includes('@') ? identifier.split('@')[0] : identifier;
|
|
589
|
+
userName = `User ${userId}`; // Would be fetched from database
|
|
590
|
+
userEmail = identifier.includes('@') ? identifier : `${identifier}@example.com`;
|
|
591
|
+
|
|
592
|
+
console.log(chalk.green('✅ Login successful!'));
|
|
593
|
+
}
|
|
502
594
|
|
|
503
|
-
// Save to config file
|
|
504
|
-
|
|
505
|
-
|
|
595
|
+
// Save credentials to user-specific config file
|
|
596
|
+
try {
|
|
597
|
+
// Ensure user config directory exists
|
|
598
|
+
if (!fs.existsSync(userConfigDir)) {
|
|
599
|
+
fs.mkdirSync(userConfigDir, { recursive: true });
|
|
600
|
+
}
|
|
601
|
+
|
|
506
602
|
const config = {
|
|
507
603
|
userId,
|
|
508
604
|
userName,
|
|
509
|
-
|
|
605
|
+
userEmail,
|
|
606
|
+
savedAt: new Date().toISOString()
|
|
510
607
|
};
|
|
511
|
-
|
|
512
|
-
|
|
608
|
+
fs.writeFileSync(userConfigPath, JSON.stringify(config, null, 2));
|
|
609
|
+
console.log(chalk.green('✅ Credentials saved locally'));
|
|
513
610
|
} catch (error) {
|
|
514
|
-
|
|
515
|
-
}
|
|
611
|
+
console.log(chalk.yellow('⚠️ Could not save credentials locally'));
|
|
516
612
|
}
|
|
517
613
|
}
|
|
518
614
|
|
|
519
|
-
return { userId, userName };
|
|
615
|
+
return { userId, userName, userEmail };
|
|
520
616
|
}
|
|
521
617
|
|
|
522
618
|
// Activate virtual environment
|
|
@@ -621,12 +717,12 @@ async function runContainerCommand(options) {
|
|
|
621
717
|
|
|
622
718
|
// Collect user credentials
|
|
623
719
|
const userCredentials = await collectUserCredentials(options);
|
|
624
|
-
const { userId, userName } = userCredentials;
|
|
720
|
+
const { userId, userName, userEmail } = userCredentials;
|
|
625
721
|
|
|
626
722
|
// Register user on dashboard immediately after collecting credentials
|
|
627
723
|
console.log(chalk.blue('\n📝 Registering user on GitArsenal dashboard...'));
|
|
628
724
|
// Send user data immediately so the dashboard records users
|
|
629
|
-
await sendUserData(userId, userName);
|
|
725
|
+
await sendUserData(userId, userName, userEmail);
|
|
630
726
|
|
|
631
727
|
// Check for required dependencies
|
|
632
728
|
const spinner = ora('Checking dependencies...').start();
|
|
@@ -658,18 +754,49 @@ async function runContainerCommand(options) {
|
|
|
658
754
|
repoUrl = answers.repoUrl;
|
|
659
755
|
}
|
|
660
756
|
|
|
661
|
-
// Attempt full fetch first to get both commands and recommendations;
|
|
757
|
+
// Attempt full fetch first to get both commands and recommendations; now start preview concurrently
|
|
662
758
|
if (useApi && repoUrl) {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
759
|
+
// Start a main spinner that will show overall progress
|
|
760
|
+
const mainSpinner = ora('Analyzing repository...').start();
|
|
761
|
+
|
|
762
|
+
try {
|
|
763
|
+
// Start preview immediately so we get early feedback; suppress summary here to avoid duplicates.
|
|
764
|
+
// Provide an AbortController so we can stop the preview spinner as soon as full fetch returns.
|
|
765
|
+
const previewAbort = new AbortController();
|
|
766
|
+
mainSpinner.text = 'Analyzing repository for GPU/Torch/CUDA recommendations...';
|
|
767
|
+
const previewPromise = previewRecommendations(repoUrl, { showSummary: false, abortSignal: previewAbort.signal, hideSpinner: true }).catch(() => null);
|
|
768
|
+
|
|
769
|
+
// Run full fetch in parallel; prefer its results if available.
|
|
770
|
+
mainSpinner.text = 'Finding the best machine for your code...';
|
|
771
|
+
const fullData = await fetchFullSetupAndRecs(repoUrl).catch(() => null);
|
|
772
|
+
|
|
773
|
+
if (fullData) {
|
|
774
|
+
// Stop preview spinner immediately since we have a response
|
|
775
|
+
previewAbort.abort();
|
|
776
|
+
mainSpinner.succeed('Analysis complete!');
|
|
777
|
+
printGpuTorchCudaSummary(fullData);
|
|
778
|
+
if (Array.isArray(fullData.commands) && fullData.commands.length) {
|
|
779
|
+
setupCommands = fullData.commands;
|
|
780
|
+
// Disable auto-detection since we already have commands
|
|
781
|
+
useApi = false;
|
|
782
|
+
}
|
|
783
|
+
} else {
|
|
784
|
+
// Full fetch failed, wait for preview and show its results
|
|
785
|
+
mainSpinner.text = 'Waiting for preview analysis to complete...';
|
|
786
|
+
const previewData = await previewPromise;
|
|
787
|
+
if (previewData) {
|
|
788
|
+
mainSpinner.succeed('Preview analysis complete!');
|
|
789
|
+
printGpuTorchCudaSummary(previewData);
|
|
790
|
+
} else {
|
|
791
|
+
mainSpinner.fail('Analysis failed - both preview and full analysis timed out or failed');
|
|
792
|
+
console.log(chalk.yellow('⚠️ Unable to analyze repository automatically.'));
|
|
793
|
+
console.log(chalk.gray('You can still proceed with manual setup commands.'));
|
|
794
|
+
}
|
|
670
795
|
}
|
|
671
|
-
}
|
|
672
|
-
|
|
796
|
+
} catch (error) {
|
|
797
|
+
mainSpinner.fail(`Analysis failed: ${error.message}`);
|
|
798
|
+
console.log(chalk.yellow('⚠️ Unable to analyze repository automatically.'));
|
|
799
|
+
console.log(chalk.gray('You can still proceed with manual setup commands.'));
|
|
673
800
|
}
|
|
674
801
|
}
|
|
675
802
|
|
|
@@ -799,7 +926,10 @@ async function runContainerCommand(options) {
|
|
|
799
926
|
volumeName,
|
|
800
927
|
setupCommands,
|
|
801
928
|
useApi,
|
|
802
|
-
yes: skipConfirmation
|
|
929
|
+
yes: skipConfirmation,
|
|
930
|
+
userId,
|
|
931
|
+
userName,
|
|
932
|
+
userEmail
|
|
803
933
|
});
|
|
804
934
|
|
|
805
935
|
} catch (containerError) {
|
package/lib/sandbox.js
CHANGED
|
@@ -44,7 +44,10 @@ async function runContainer(options) {
|
|
|
44
44
|
setupCommands = [],
|
|
45
45
|
useApi = true,
|
|
46
46
|
showExamples = false,
|
|
47
|
-
yes = false
|
|
47
|
+
yes = false,
|
|
48
|
+
userId,
|
|
49
|
+
userName,
|
|
50
|
+
userEmail
|
|
48
51
|
} = options;
|
|
49
52
|
|
|
50
53
|
// Get the path to the Python script
|
|
@@ -107,6 +110,14 @@ async function runContainer(options) {
|
|
|
107
110
|
console.log(chalk.gray(`🔍 Debug: Adding --yes flag to Python script`));
|
|
108
111
|
}
|
|
109
112
|
|
|
113
|
+
// Add user credentials if provided
|
|
114
|
+
if (userId && userEmail && userName) {
|
|
115
|
+
args.push('--user-id', userEmail);
|
|
116
|
+
args.push('--user-name', userId);
|
|
117
|
+
args.push('--display-name', userName);
|
|
118
|
+
console.log(chalk.gray(`🔍 Debug: Passing user credentials to Python script`));
|
|
119
|
+
}
|
|
120
|
+
|
|
110
121
|
// Handle manual setup commands if provided
|
|
111
122
|
if (setupCommands.length > 0) {
|
|
112
123
|
// Create a temporary file to store setup commands
|
package/package.json
CHANGED
|
@@ -1611,7 +1611,7 @@ def get_setup_commands_from_gitingest(repo_url):
|
|
|
1611
1611
|
url=api_url,
|
|
1612
1612
|
payload=payload,
|
|
1613
1613
|
max_retries=2,
|
|
1614
|
-
timeout=180 # 3 minute timeout
|
|
1614
|
+
timeout=180, # 3 minute timeout
|
|
1615
1615
|
)
|
|
1616
1616
|
|
|
1617
1617
|
if not response:
|
|
@@ -2115,6 +2115,11 @@ if __name__ == "__main__":
|
|
|
2115
2115
|
parser.add_argument('--store-api-key', type=str, help='Store API key for a service (e.g., openai, modal)')
|
|
2116
2116
|
parser.add_argument('--skip-auth', action='store_true', help='Skip authentication check (for development)')
|
|
2117
2117
|
|
|
2118
|
+
# User credential arguments (passed from JavaScript CLI)
|
|
2119
|
+
parser.add_argument('--user-id', type=str, help='User email address (passed from JavaScript CLI)')
|
|
2120
|
+
parser.add_argument('--user-name', type=str, help='Username (passed from JavaScript CLI)')
|
|
2121
|
+
parser.add_argument('--display-name', type=str, help='Display name (passed from JavaScript CLI)')
|
|
2122
|
+
|
|
2118
2123
|
args = parser.parse_args()
|
|
2119
2124
|
|
|
2120
2125
|
# Initialize authentication manager
|
|
@@ -2149,8 +2154,11 @@ if __name__ == "__main__":
|
|
|
2149
2154
|
show_usage_examples()
|
|
2150
2155
|
sys.exit(0)
|
|
2151
2156
|
|
|
2152
|
-
#
|
|
2153
|
-
if
|
|
2157
|
+
# Authentication is handled by the JavaScript CLI when credentials are passed
|
|
2158
|
+
if args.user_id and args.user_name and args.display_name:
|
|
2159
|
+
print(f"✅ Authenticated as: {args.display_name} ({args.user_id})")
|
|
2160
|
+
elif not args.skip_auth:
|
|
2161
|
+
# Only perform authentication check if running Python script directly (not from CLI)
|
|
2154
2162
|
if not _check_authentication(auth_manager):
|
|
2155
2163
|
print("\n❌ Authentication required. Please login or register first.")
|
|
2156
2164
|
print("Use --login to login or --register to create an account.")
|