gitarsenal-cli 1.9.6 ā 1.9.8
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 +226 -11
- package/config.json +5 -0
- package/package.json +1 -1
- package/python/__pycache__/auth_manager.cpython-313.pyc +0 -0
- package/python/auth_manager.py +44 -0
package/.venv_status.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"created":"2025-08-
|
|
1
|
+
{"created":"2025-08-04T06:53:34.568Z","packages":["modal","gitingest","requests"],"uv_version":"uv 0.8.4 (e176e1714 2025-07-30)"}
|
package/bin/gitarsenal.js
CHANGED
|
@@ -13,6 +13,8 @@ const pkg = require('../package.json');
|
|
|
13
13
|
const boxen = require('boxen');
|
|
14
14
|
const { spawn } = require('child_process');
|
|
15
15
|
const fs = require('fs');
|
|
16
|
+
const https = require('https');
|
|
17
|
+
const http = require('http');
|
|
16
18
|
|
|
17
19
|
// Function to activate virtual environment
|
|
18
20
|
function activateVirtualEnvironment() {
|
|
@@ -102,6 +104,162 @@ function activateVirtualEnvironment() {
|
|
|
102
104
|
return true;
|
|
103
105
|
}
|
|
104
106
|
|
|
107
|
+
// Function to send user data to web application
|
|
108
|
+
async function sendUserData(userId, userName) {
|
|
109
|
+
try {
|
|
110
|
+
console.log(chalk.blue(`š Attempting to register user: ${userName} (${userId})`));
|
|
111
|
+
|
|
112
|
+
const userData = {
|
|
113
|
+
id: userId,
|
|
114
|
+
name: userName
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const data = JSON.stringify(userData);
|
|
118
|
+
|
|
119
|
+
// Get webhook URL from config or use default
|
|
120
|
+
let webhookUrl = 'https://www.gitarsenal.dev/api/users';
|
|
121
|
+
const configPath = path.join(__dirname, '..', 'config.json');
|
|
122
|
+
if (fs.existsSync(configPath)) {
|
|
123
|
+
try {
|
|
124
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
125
|
+
if (config.webhookUrl) {
|
|
126
|
+
webhookUrl = config.webhookUrl;
|
|
127
|
+
}
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.log(chalk.yellow('ā ļø Could not read config file, using default URL'));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
console.log(chalk.gray(`š” Sending to: ${webhookUrl}`));
|
|
134
|
+
console.log(chalk.gray(`š¦ Data: ${data}`));
|
|
135
|
+
|
|
136
|
+
const urlObj = new URL(webhookUrl);
|
|
137
|
+
const options = {
|
|
138
|
+
hostname: urlObj.hostname,
|
|
139
|
+
port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80),
|
|
140
|
+
path: urlObj.pathname,
|
|
141
|
+
method: 'POST',
|
|
142
|
+
headers: {
|
|
143
|
+
'Content-Type': 'application/json',
|
|
144
|
+
'Content-Length': Buffer.byteLength(data),
|
|
145
|
+
'User-Agent': 'GitArsenal-CLI/1.0'
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
return new Promise((resolve, reject) => {
|
|
150
|
+
const client = urlObj.protocol === 'https:' ? https : http;
|
|
151
|
+
const req = client.request(options, (res) => {
|
|
152
|
+
let responseData = '';
|
|
153
|
+
res.on('data', (chunk) => {
|
|
154
|
+
responseData += chunk;
|
|
155
|
+
});
|
|
156
|
+
res.on('end', () => {
|
|
157
|
+
console.log(chalk.gray(`š Response status: ${res.statusCode}`));
|
|
158
|
+
console.log(chalk.gray(`š Response: ${responseData}`));
|
|
159
|
+
|
|
160
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
161
|
+
console.log(chalk.green('ā
User registered on GitArsenal dashboard'));
|
|
162
|
+
resolve(responseData);
|
|
163
|
+
} else if (res.statusCode === 409) {
|
|
164
|
+
console.log(chalk.green('ā
User already exists on GitArsenal dashboard'));
|
|
165
|
+
resolve(responseData);
|
|
166
|
+
} else {
|
|
167
|
+
console.log(chalk.yellow(`ā ļø Failed to register user (status: ${res.statusCode})`));
|
|
168
|
+
console.log(chalk.gray(`Response: ${responseData}`));
|
|
169
|
+
resolve(responseData);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
req.on('error', (err) => {
|
|
175
|
+
console.log(chalk.red(`ā Could not connect to GitArsenal dashboard: ${err.message}`));
|
|
176
|
+
resolve();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
req.setTimeout(10000, () => {
|
|
180
|
+
console.log(chalk.red('ā Request timeout - could not connect to dashboard'));
|
|
181
|
+
req.destroy();
|
|
182
|
+
resolve();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
req.write(data);
|
|
186
|
+
req.end();
|
|
187
|
+
});
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.log(chalk.red(`ā Error registering user: ${error.message}`));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Function to collect user credentials
|
|
194
|
+
async function collectUserCredentials(options) {
|
|
195
|
+
let userId = options.userId;
|
|
196
|
+
let userName = options.userName;
|
|
197
|
+
|
|
198
|
+
// Check for config file first
|
|
199
|
+
const configPath = path.join(__dirname, '..', 'config.json');
|
|
200
|
+
if (fs.existsSync(configPath)) {
|
|
201
|
+
try {
|
|
202
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
203
|
+
if (config.userId && config.userName) {
|
|
204
|
+
userId = config.userId;
|
|
205
|
+
userName = config.userName;
|
|
206
|
+
}
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.log(chalk.yellow('ā ļø Could not read config file'));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// If not provided via CLI or config, prompt for them
|
|
213
|
+
if (!userId || !userName) {
|
|
214
|
+
console.log(chalk.blue('\nš GitArsenal User Identification'));
|
|
215
|
+
console.log(chalk.gray('Help us track your usage and improve GitArsenal!'));
|
|
216
|
+
console.log(chalk.gray('Your credentials will be saved locally for future use.'));
|
|
217
|
+
|
|
218
|
+
const credentials = await inquirer.prompt([
|
|
219
|
+
{
|
|
220
|
+
type: 'input',
|
|
221
|
+
name: 'userId',
|
|
222
|
+
message: 'Enter your user ID (or email):',
|
|
223
|
+
default: userId || 'anonymous',
|
|
224
|
+
validate: (input) => input.trim() !== '' ? true : 'User ID is required'
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
type: 'input',
|
|
228
|
+
name: 'userName',
|
|
229
|
+
message: 'Enter your name:',
|
|
230
|
+
default: userName || 'Anonymous User',
|
|
231
|
+
validate: (input) => input.trim() !== '' ? true : 'Name is required'
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
type: 'confirm',
|
|
235
|
+
name: 'saveConfig',
|
|
236
|
+
message: 'Save these credentials for future use?',
|
|
237
|
+
default: true
|
|
238
|
+
}
|
|
239
|
+
]);
|
|
240
|
+
|
|
241
|
+
userId = credentials.userId;
|
|
242
|
+
userName = credentials.userName;
|
|
243
|
+
|
|
244
|
+
// Save to config file if requested
|
|
245
|
+
if (credentials.saveConfig) {
|
|
246
|
+
try {
|
|
247
|
+
const config = {
|
|
248
|
+
userId,
|
|
249
|
+
userName,
|
|
250
|
+
webhookUrl: 'https://www.gitarsenal.dev/api/users'
|
|
251
|
+
};
|
|
252
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
253
|
+
console.log(chalk.green('ā
Credentials saved to config file'));
|
|
254
|
+
} catch (error) {
|
|
255
|
+
console.log(chalk.yellow('ā ļø Could not save config file'));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return { userId, userName };
|
|
261
|
+
}
|
|
262
|
+
|
|
105
263
|
// Activate virtual environment
|
|
106
264
|
activateVirtualEnvironment();
|
|
107
265
|
|
|
@@ -140,6 +298,8 @@ const containerCmd = program
|
|
|
140
298
|
.option('-y, --yes', 'Skip confirmation prompts')
|
|
141
299
|
.option('-m, --manual', 'Disable automatic setup command detection')
|
|
142
300
|
.option('--show-examples', 'Show usage examples')
|
|
301
|
+
.option('--user-id <id>', 'User ID for tracking')
|
|
302
|
+
.option('--user-name <name>', 'User name for tracking')
|
|
143
303
|
.action(async (options) => {
|
|
144
304
|
await runContainerCommand(options);
|
|
145
305
|
});
|
|
@@ -189,6 +349,8 @@ program
|
|
|
189
349
|
.option('-y, --yes', 'Skip confirmation prompts')
|
|
190
350
|
.option('-m, --manual', 'Disable automatic setup command detection')
|
|
191
351
|
.option('--show-examples', 'Show usage examples')
|
|
352
|
+
.option('--user-id <id>', 'User ID for tracking')
|
|
353
|
+
.option('--user-name <name>', 'User name for tracking')
|
|
192
354
|
.action(async (options) => {
|
|
193
355
|
// If options are provided directly, run the container command
|
|
194
356
|
if (options.repo || options.showExamples || process.argv.length <= 3) {
|
|
@@ -208,6 +370,15 @@ async function runContainerCommand(options) {
|
|
|
208
370
|
return;
|
|
209
371
|
}
|
|
210
372
|
|
|
373
|
+
// Collect user credentials
|
|
374
|
+
const userCredentials = await collectUserCredentials(options);
|
|
375
|
+
const { userId, userName } = userCredentials;
|
|
376
|
+
|
|
377
|
+
// Register user on dashboard immediately after collecting credentials
|
|
378
|
+
console.log(chalk.blue('\nš Registering user on GitArsenal dashboard...'));
|
|
379
|
+
// Note: User data will be sent by the Python script after authentication
|
|
380
|
+
// await sendUserData(userId, userName);
|
|
381
|
+
|
|
211
382
|
// Check for required dependencies
|
|
212
383
|
const spinner = ora('Checking dependencies...').start();
|
|
213
384
|
const dependenciesOk = await checkDependencies();
|
|
@@ -345,14 +516,22 @@ async function runContainerCommand(options) {
|
|
|
345
516
|
}
|
|
346
517
|
}
|
|
347
518
|
|
|
519
|
+
// Log command start
|
|
520
|
+
const commandString = `gitarsenal container ${repoUrl ? `--repo ${repoUrl}` : ''} ${gpuType ? `--gpu ${gpuType}` : ''}`;
|
|
521
|
+
|
|
348
522
|
// Run the container
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
523
|
+
try {
|
|
524
|
+
await runContainer({
|
|
525
|
+
repoUrl,
|
|
526
|
+
gpuType,
|
|
527
|
+
volumeName,
|
|
528
|
+
setupCommands,
|
|
529
|
+
useApi
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
} catch (containerError) {
|
|
533
|
+
throw containerError;
|
|
534
|
+
}
|
|
356
535
|
|
|
357
536
|
} catch (error) {
|
|
358
537
|
console.error(chalk.red(`Error: ${error.message}`));
|
|
@@ -362,6 +541,15 @@ async function runContainerCommand(options) {
|
|
|
362
541
|
|
|
363
542
|
async function handleKeysAdd(options) {
|
|
364
543
|
try {
|
|
544
|
+
// Collect user credentials for keys operations
|
|
545
|
+
const userCredentials = await collectUserCredentials(options);
|
|
546
|
+
const { userId, userName } = userCredentials;
|
|
547
|
+
|
|
548
|
+
// Register user on dashboard
|
|
549
|
+
console.log(chalk.blue('\nš Registering user on GitArsenal dashboard...'));
|
|
550
|
+
// Note: User data will be sent by the Python script after authentication
|
|
551
|
+
// await sendUserData(userId, userName);
|
|
552
|
+
|
|
365
553
|
const spinner = ora('Adding API key...').start();
|
|
366
554
|
|
|
367
555
|
let service = options.service;
|
|
@@ -413,7 +601,7 @@ async function handleKeysAdd(options) {
|
|
|
413
601
|
output += data.toString();
|
|
414
602
|
});
|
|
415
603
|
|
|
416
|
-
pythonProcess.on('close', (code) => {
|
|
604
|
+
pythonProcess.on('close', async (code) => {
|
|
417
605
|
if (code === 0) {
|
|
418
606
|
spinner.succeed(`API key for ${service} added successfully`);
|
|
419
607
|
} else {
|
|
@@ -429,6 +617,15 @@ async function handleKeysAdd(options) {
|
|
|
429
617
|
|
|
430
618
|
async function handleKeysList() {
|
|
431
619
|
try {
|
|
620
|
+
// Collect user credentials for keys operations
|
|
621
|
+
const userCredentials = await collectUserCredentials({});
|
|
622
|
+
const { userId, userName } = userCredentials;
|
|
623
|
+
|
|
624
|
+
// Register user on dashboard
|
|
625
|
+
console.log(chalk.blue('\nš Registering user on GitArsenal dashboard...'));
|
|
626
|
+
// Note: User data will be sent by the Python script after authentication
|
|
627
|
+
// await sendUserData(userId, userName);
|
|
628
|
+
|
|
432
629
|
const spinner = ora('Fetching API keys...').start();
|
|
433
630
|
|
|
434
631
|
// Call Python script to list keys
|
|
@@ -440,7 +637,7 @@ async function handleKeysList() {
|
|
|
440
637
|
'list'
|
|
441
638
|
], { stdio: 'inherit' });
|
|
442
639
|
|
|
443
|
-
pythonProcess.on('close', (code) => {
|
|
640
|
+
pythonProcess.on('close', async (code) => {
|
|
444
641
|
if (code !== 0) {
|
|
445
642
|
spinner.fail('Failed to list API keys');
|
|
446
643
|
} else {
|
|
@@ -456,6 +653,15 @@ async function handleKeysList() {
|
|
|
456
653
|
|
|
457
654
|
async function handleKeysView(options) {
|
|
458
655
|
try {
|
|
656
|
+
// Collect user credentials for keys operations
|
|
657
|
+
const userCredentials = await collectUserCredentials(options);
|
|
658
|
+
const { userId, userName } = userCredentials;
|
|
659
|
+
|
|
660
|
+
// Register user on dashboard
|
|
661
|
+
console.log(chalk.blue('\nš Registering user on GitArsenal dashboard...'));
|
|
662
|
+
// Note: User data will be sent by the Python script after authentication
|
|
663
|
+
// await sendUserData(userId, userName);
|
|
664
|
+
|
|
459
665
|
const spinner = ora('Viewing API key...').start();
|
|
460
666
|
|
|
461
667
|
let service = options.service;
|
|
@@ -483,7 +689,7 @@ async function handleKeysView(options) {
|
|
|
483
689
|
'--service', service
|
|
484
690
|
], { stdio: 'inherit' });
|
|
485
691
|
|
|
486
|
-
pythonProcess.on('close', (code) => {
|
|
692
|
+
pythonProcess.on('close', async (code) => {
|
|
487
693
|
if (code !== 0) {
|
|
488
694
|
spinner.fail(`Failed to view API key for ${service}`);
|
|
489
695
|
} else {
|
|
@@ -499,6 +705,15 @@ async function handleKeysView(options) {
|
|
|
499
705
|
|
|
500
706
|
async function handleKeysDelete(options) {
|
|
501
707
|
try {
|
|
708
|
+
// Collect user credentials for keys operations
|
|
709
|
+
const userCredentials = await collectUserCredentials(options);
|
|
710
|
+
const { userId, userName } = userCredentials;
|
|
711
|
+
|
|
712
|
+
// Register user on dashboard
|
|
713
|
+
console.log(chalk.blue('\nš Registering user on GitArsenal dashboard...'));
|
|
714
|
+
// Note: User data will be sent by the Python script after authentication
|
|
715
|
+
// await sendUserData(userId, userName);
|
|
716
|
+
|
|
502
717
|
const spinner = ora('Deleting API key...').start();
|
|
503
718
|
|
|
504
719
|
let service = options.service;
|
|
@@ -553,7 +768,7 @@ async function handleKeysDelete(options) {
|
|
|
553
768
|
output += data.toString();
|
|
554
769
|
});
|
|
555
770
|
|
|
556
|
-
pythonProcess.on('close', (code) => {
|
|
771
|
+
pythonProcess.on('close', async (code) => {
|
|
557
772
|
if (code === 0) {
|
|
558
773
|
spinner.succeed(`API key for ${service} deleted successfully`);
|
|
559
774
|
} else {
|
package/config.json
ADDED
package/package.json
CHANGED
|
Binary file
|
package/python/auth_manager.py
CHANGED
|
@@ -203,11 +203,51 @@ class AuthManager:
|
|
|
203
203
|
print(f"Username: {username}")
|
|
204
204
|
print(f"Email: {email}")
|
|
205
205
|
print("\nYou can now login with your credentials.")
|
|
206
|
+
|
|
207
|
+
# Send user data to web application
|
|
208
|
+
self.send_user_data_to_webapp(username, email)
|
|
209
|
+
|
|
206
210
|
return True
|
|
207
211
|
else:
|
|
208
212
|
print("ā Failed to save registration data.")
|
|
209
213
|
return False
|
|
210
214
|
|
|
215
|
+
def send_user_data_to_webapp(self, username: str, email: str):
|
|
216
|
+
"""Send user data to the web application for tracking"""
|
|
217
|
+
try:
|
|
218
|
+
# Get webhook URL from environment or use default
|
|
219
|
+
webhook_url = os.getenv("GITARSENAL_WEBHOOK_URL", "https://www.gitarsenal.dev/api/users")
|
|
220
|
+
|
|
221
|
+
user_data = {
|
|
222
|
+
"id": username, # Use username as ID for consistency
|
|
223
|
+
"name": username # Use username as name for now
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
print(f"š Sending user data to web application: {username}")
|
|
227
|
+
|
|
228
|
+
response = requests.post(
|
|
229
|
+
webhook_url,
|
|
230
|
+
json=user_data,
|
|
231
|
+
headers={
|
|
232
|
+
'Content-Type': 'application/json',
|
|
233
|
+
'User-Agent': 'GitArsenal-CLI/1.0'
|
|
234
|
+
},
|
|
235
|
+
timeout=10
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
if response.status_code >= 200 and response.status_code < 300:
|
|
239
|
+
print("ā
User data sent to web application successfully")
|
|
240
|
+
elif response.status_code == 409:
|
|
241
|
+
print("ā
User already exists in web application")
|
|
242
|
+
else:
|
|
243
|
+
print(f"ā ļø Failed to send user data (status: {response.status_code})")
|
|
244
|
+
print(f"Response: {response.text}")
|
|
245
|
+
|
|
246
|
+
except requests.exceptions.RequestException as e:
|
|
247
|
+
print(f"ā ļø Failed to send user data to web application: {e}")
|
|
248
|
+
except Exception as e:
|
|
249
|
+
print(f"ā ļø Error sending user data: {e}")
|
|
250
|
+
|
|
211
251
|
def login_user(self, username: str, password: str) -> bool:
|
|
212
252
|
"""Login a user"""
|
|
213
253
|
print("\n" + "="*60)
|
|
@@ -249,6 +289,10 @@ class AuthManager:
|
|
|
249
289
|
if self.save_session(session_data):
|
|
250
290
|
print("ā
Login successful!")
|
|
251
291
|
print(f"Welcome back, {username}!")
|
|
292
|
+
|
|
293
|
+
# Send user data to web application
|
|
294
|
+
self.send_user_data_to_webapp(username, user_data.get('email', ''))
|
|
295
|
+
|
|
252
296
|
return True
|
|
253
297
|
else:
|
|
254
298
|
print("ā Failed to create session.")
|