gitarsenal-cli 1.6.14 → 1.7.1
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/package.json +1 -1
- package/python/test_modalSandboxScript.py +145 -8
- package/test_modalSandboxScript.py +145 -8
package/package.json
CHANGED
@@ -327,6 +327,37 @@ def handle_huggingface_login(sandbox, current_dir):
|
|
327
327
|
return exit_code == 0, stdout_buffer, stderr_buffer
|
328
328
|
|
329
329
|
|
330
|
+
def get_stored_credentials():
|
331
|
+
"""Load stored credentials from ~/.gitarsenal/credentials.json"""
|
332
|
+
import json
|
333
|
+
from pathlib import Path
|
334
|
+
|
335
|
+
try:
|
336
|
+
credentials_file = Path.home() / ".gitarsenal" / "credentials.json"
|
337
|
+
if credentials_file.exists():
|
338
|
+
with open(credentials_file, 'r') as f:
|
339
|
+
credentials = json.load(f)
|
340
|
+
return credentials
|
341
|
+
else:
|
342
|
+
return {}
|
343
|
+
except Exception as e:
|
344
|
+
print(f"⚠️ Error loading stored credentials: {e}")
|
345
|
+
return {}
|
346
|
+
|
347
|
+
def generate_auth_context(stored_credentials):
|
348
|
+
"""Generate simple authentication context for the OpenAI prompt"""
|
349
|
+
if not stored_credentials:
|
350
|
+
return "No stored credentials available."
|
351
|
+
|
352
|
+
auth_context = "Available stored credentials (use actual values in commands):\n"
|
353
|
+
|
354
|
+
for key, value in stored_credentials.items():
|
355
|
+
# Mask the actual value for security in logs, but provide the real value
|
356
|
+
masked_value = value[:8] + "..." if len(value) > 8 else "***"
|
357
|
+
auth_context += f"- {key}: {masked_value} (actual value: {value})\n"
|
358
|
+
|
359
|
+
return auth_context
|
360
|
+
|
330
361
|
def call_openai_for_debug(command, error_output, api_key=None, current_dir=None, sandbox=None):
|
331
362
|
"""Call OpenAI to debug a failed command and suggest a fix"""
|
332
363
|
print("\n🔍 DEBUG: Starting LLM debugging...")
|
@@ -620,6 +651,9 @@ Directory contents:
|
|
620
651
|
"Content-Type": "application/json",
|
621
652
|
"Authorization": f"Bearer {api_key}"
|
622
653
|
}
|
654
|
+
|
655
|
+
stored_credentials = get_stored_credentials()
|
656
|
+
auth_context = generate_auth_context(stored_credentials)
|
623
657
|
|
624
658
|
# Create a prompt for the LLM
|
625
659
|
print("\n" + "="*60)
|
@@ -644,29 +678,41 @@ But it failed with this error:
|
|
644
678
|
{directory_context}
|
645
679
|
{file_context}
|
646
680
|
|
681
|
+
AVAILABLE CREDENTIALS:
|
682
|
+
{auth_context}
|
683
|
+
|
647
684
|
Please analyze the error and provide ONLY a single terminal command that would fix the issue.
|
648
|
-
Consider the current directory, system information,
|
685
|
+
Consider the current directory, system information, directory contents, and available credentials carefully before suggesting a solution.
|
649
686
|
|
650
687
|
IMPORTANT GUIDELINES:
|
651
688
|
1. For any commands that might ask for yes/no confirmation, use the appropriate non-interactive flag:
|
652
689
|
- For apt/apt-get: use -y or --yes
|
653
690
|
- For pip: use --no-input
|
654
691
|
- For rm: use -f or --force
|
655
|
-
- For other commands: check their documentation for the appropriate non-interactive flag
|
656
692
|
|
657
|
-
2. If the error indicates a file is not found
|
693
|
+
2. If the error indicates a file is not found:
|
658
694
|
- FIRST try to search for the file using: find . -name "filename" -type f 2>/dev/null
|
659
695
|
- If found, navigate to that directory using: cd /path/to/directory
|
660
696
|
- If not found, then consider creating the file or installing missing packages
|
661
697
|
|
662
698
|
3. For missing packages or dependencies:
|
663
699
|
- Use pip install for Python packages
|
664
|
-
- Use apt-get install for system packages
|
700
|
+
- Use apt-get install -y for system packages
|
665
701
|
- Use npm install for Node.js packages
|
666
702
|
|
667
703
|
4. For authentication issues:
|
668
|
-
-
|
669
|
-
-
|
704
|
+
- Analyze the error to determine what type of authentication is needed
|
705
|
+
- Use the actual credential values provided above (not placeholders)
|
706
|
+
- Common patterns:
|
707
|
+
* wandb errors: use wandb login with WANDB_API_KEY
|
708
|
+
* huggingface errors: use huggingface-cli login with HF_TOKEN or HUGGINGFACE_TOKEN
|
709
|
+
* github errors: configure git credentials with GITHUB_TOKEN
|
710
|
+
* kaggle errors: create ~/.kaggle/kaggle.json with KAGGLE_USERNAME and KAGGLE_KEY
|
711
|
+
* API errors: export the appropriate API key as environment variable
|
712
|
+
|
713
|
+
5. Environment variable exports:
|
714
|
+
- Use export commands for API keys that need to be in environment
|
715
|
+
- Use the actual credential values, not placeholders
|
670
716
|
|
671
717
|
Do not provide any explanations, just the exact command to run.
|
672
718
|
"""
|
@@ -2364,9 +2410,39 @@ def get_setup_commands_from_gitingest(repo_url):
|
|
2364
2410
|
api_keys = result.get("requiredApiKeys", [])
|
2365
2411
|
if api_keys:
|
2366
2412
|
print(f"\n🔑 Required API Keys ({len(api_keys)}):")
|
2413
|
+
# Load stored GitArsenal credentials
|
2414
|
+
stored_credentials = {}
|
2415
|
+
try:
|
2416
|
+
credentials_file = Path.home() / ".gitarsenal" / "credentials.json"
|
2417
|
+
if credentials_file.exists():
|
2418
|
+
with open(credentials_file, 'r') as f:
|
2419
|
+
stored_credentials = json.load(f)
|
2420
|
+
print(f"📋 Found {len(stored_credentials)} stored GitArsenal credentials")
|
2421
|
+
else:
|
2422
|
+
print("📋 No stored GitArsenal credentials found")
|
2423
|
+
except Exception as e:
|
2424
|
+
print(f"⚠️ Error loading stored credentials: {e}")
|
2425
|
+
|
2426
|
+
# Identify missing required API keys
|
2427
|
+
missing_required_keys = []
|
2428
|
+
available_keys = []
|
2429
|
+
|
2367
2430
|
for i, api_key in enumerate(api_keys, 1):
|
2368
|
-
|
2369
|
-
|
2431
|
+
key_name = api_key.get('name', 'Unknown')
|
2432
|
+
is_required = api_key.get("required", False)
|
2433
|
+
has_stored_key = key_name in stored_credentials
|
2434
|
+
|
2435
|
+
if is_required:
|
2436
|
+
if has_stored_key:
|
2437
|
+
status = "✅ Required (Available)"
|
2438
|
+
available_keys.append(key_name)
|
2439
|
+
else:
|
2440
|
+
status = "🔴 Required (Missing)"
|
2441
|
+
missing_required_keys.append(api_key)
|
2442
|
+
else:
|
2443
|
+
status = "🟡 Optional"
|
2444
|
+
|
2445
|
+
print(f" {i}. {key_name} - {status}")
|
2370
2446
|
print(f" Service: {api_key.get('service', 'Unknown')}")
|
2371
2447
|
print(f" Description: {api_key.get('description', 'No description')}")
|
2372
2448
|
if api_key.get('example'):
|
@@ -2374,6 +2450,67 @@ def get_setup_commands_from_gitingest(repo_url):
|
|
2374
2450
|
if api_key.get('documentation_url'):
|
2375
2451
|
print(f" Docs: {api_key.get('documentation_url')}")
|
2376
2452
|
print()
|
2453
|
+
|
2454
|
+
# Prompt for missing required API keys
|
2455
|
+
if missing_required_keys:
|
2456
|
+
print("🔧 Setting up missing required API keys...")
|
2457
|
+
print("Press Enter to continue or Ctrl+C to skip...")
|
2458
|
+
|
2459
|
+
for api_key in missing_required_keys:
|
2460
|
+
key_name = api_key.get('name', 'Unknown')
|
2461
|
+
service = api_key.get('service', 'Unknown')
|
2462
|
+
description = api_key.get('description', 'No description')
|
2463
|
+
example = api_key.get('example', '')
|
2464
|
+
docs_url = api_key.get('documentation_url', '')
|
2465
|
+
|
2466
|
+
print(f"\n📝 Setting up {key_name} for {service}:")
|
2467
|
+
print(f" Description: {description}")
|
2468
|
+
if example:
|
2469
|
+
print(f" Example: {example}")
|
2470
|
+
if docs_url:
|
2471
|
+
print(f" Documentation: {docs_url}")
|
2472
|
+
|
2473
|
+
# Prompt user for the API key
|
2474
|
+
try:
|
2475
|
+
import getpass
|
2476
|
+
print(f"\nPlease enter your {key_name}:")
|
2477
|
+
new_key = getpass.getpass("API Key (hidden): ").strip()
|
2478
|
+
|
2479
|
+
if new_key:
|
2480
|
+
# Save to credentials file
|
2481
|
+
credentials_file = Path.home() / ".gitarsenal" / "credentials.json"
|
2482
|
+
credentials_file.parent.mkdir(parents=True, exist_ok=True)
|
2483
|
+
|
2484
|
+
# Load existing credentials
|
2485
|
+
if credentials_file.exists():
|
2486
|
+
with open(credentials_file, 'r') as f:
|
2487
|
+
all_credentials = json.load(f)
|
2488
|
+
else:
|
2489
|
+
all_credentials = {}
|
2490
|
+
|
2491
|
+
# Add new key
|
2492
|
+
all_credentials[key_name] = new_key
|
2493
|
+
|
2494
|
+
# Save back to file
|
2495
|
+
with open(credentials_file, 'w') as f:
|
2496
|
+
json.dump(all_credentials, f, indent=2)
|
2497
|
+
|
2498
|
+
print(f"✅ {key_name} saved successfully!")
|
2499
|
+
available_keys.append(key_name)
|
2500
|
+
else:
|
2501
|
+
print(f"⚠️ Skipping {key_name} (no input provided)")
|
2502
|
+
except KeyboardInterrupt:
|
2503
|
+
print(f"\n⚠️ Skipping {key_name} (cancelled by user)")
|
2504
|
+
except Exception as e:
|
2505
|
+
print(f"❌ Error saving {key_name}: {e}")
|
2506
|
+
|
2507
|
+
# Show summary
|
2508
|
+
if available_keys:
|
2509
|
+
print(f"✅ Available API keys: {', '.join(available_keys)}")
|
2510
|
+
if missing_required_keys:
|
2511
|
+
print(f"⚠️ Missing required keys: {', '.join([k.get('name') for k in missing_required_keys])}")
|
2512
|
+
else:
|
2513
|
+
print("ℹ️ All required API keys are already available.")
|
2377
2514
|
|
2378
2515
|
# Display setup complexity if available
|
2379
2516
|
if "setupComplexity" in result:
|
@@ -327,6 +327,37 @@ def handle_huggingface_login(sandbox, current_dir):
|
|
327
327
|
return exit_code == 0, stdout_buffer, stderr_buffer
|
328
328
|
|
329
329
|
|
330
|
+
def get_stored_credentials():
|
331
|
+
"""Load stored credentials from ~/.gitarsenal/credentials.json"""
|
332
|
+
import json
|
333
|
+
from pathlib import Path
|
334
|
+
|
335
|
+
try:
|
336
|
+
credentials_file = Path.home() / ".gitarsenal" / "credentials.json"
|
337
|
+
if credentials_file.exists():
|
338
|
+
with open(credentials_file, 'r') as f:
|
339
|
+
credentials = json.load(f)
|
340
|
+
return credentials
|
341
|
+
else:
|
342
|
+
return {}
|
343
|
+
except Exception as e:
|
344
|
+
print(f"⚠️ Error loading stored credentials: {e}")
|
345
|
+
return {}
|
346
|
+
|
347
|
+
def generate_auth_context(stored_credentials):
|
348
|
+
"""Generate simple authentication context for the OpenAI prompt"""
|
349
|
+
if not stored_credentials:
|
350
|
+
return "No stored credentials available."
|
351
|
+
|
352
|
+
auth_context = "Available stored credentials (use actual values in commands):\n"
|
353
|
+
|
354
|
+
for key, value in stored_credentials.items():
|
355
|
+
# Mask the actual value for security in logs, but provide the real value
|
356
|
+
masked_value = value[:8] + "..." if len(value) > 8 else "***"
|
357
|
+
auth_context += f"- {key}: {masked_value} (actual value: {value})\n"
|
358
|
+
|
359
|
+
return auth_context
|
360
|
+
|
330
361
|
def call_openai_for_debug(command, error_output, api_key=None, current_dir=None, sandbox=None):
|
331
362
|
"""Call OpenAI to debug a failed command and suggest a fix"""
|
332
363
|
print("\n🔍 DEBUG: Starting LLM debugging...")
|
@@ -620,6 +651,9 @@ Directory contents:
|
|
620
651
|
"Content-Type": "application/json",
|
621
652
|
"Authorization": f"Bearer {api_key}"
|
622
653
|
}
|
654
|
+
|
655
|
+
stored_credentials = get_stored_credentials()
|
656
|
+
auth_context = generate_auth_context(stored_credentials)
|
623
657
|
|
624
658
|
# Create a prompt for the LLM
|
625
659
|
print("\n" + "="*60)
|
@@ -644,29 +678,41 @@ But it failed with this error:
|
|
644
678
|
{directory_context}
|
645
679
|
{file_context}
|
646
680
|
|
681
|
+
AVAILABLE CREDENTIALS:
|
682
|
+
{auth_context}
|
683
|
+
|
647
684
|
Please analyze the error and provide ONLY a single terminal command that would fix the issue.
|
648
|
-
Consider the current directory, system information,
|
685
|
+
Consider the current directory, system information, directory contents, and available credentials carefully before suggesting a solution.
|
649
686
|
|
650
687
|
IMPORTANT GUIDELINES:
|
651
688
|
1. For any commands that might ask for yes/no confirmation, use the appropriate non-interactive flag:
|
652
689
|
- For apt/apt-get: use -y or --yes
|
653
690
|
- For pip: use --no-input
|
654
691
|
- For rm: use -f or --force
|
655
|
-
- For other commands: check their documentation for the appropriate non-interactive flag
|
656
692
|
|
657
|
-
2. If the error indicates a file is not found
|
693
|
+
2. If the error indicates a file is not found:
|
658
694
|
- FIRST try to search for the file using: find . -name "filename" -type f 2>/dev/null
|
659
695
|
- If found, navigate to that directory using: cd /path/to/directory
|
660
696
|
- If not found, then consider creating the file or installing missing packages
|
661
697
|
|
662
698
|
3. For missing packages or dependencies:
|
663
699
|
- Use pip install for Python packages
|
664
|
-
- Use apt-get install for system packages
|
700
|
+
- Use apt-get install -y for system packages
|
665
701
|
- Use npm install for Node.js packages
|
666
702
|
|
667
703
|
4. For authentication issues:
|
668
|
-
-
|
669
|
-
-
|
704
|
+
- Analyze the error to determine what type of authentication is needed
|
705
|
+
- Use the actual credential values provided above (not placeholders)
|
706
|
+
- Common patterns:
|
707
|
+
* wandb errors: use wandb login with WANDB_API_KEY
|
708
|
+
* huggingface errors: use huggingface-cli login with HF_TOKEN or HUGGINGFACE_TOKEN
|
709
|
+
* github errors: configure git credentials with GITHUB_TOKEN
|
710
|
+
* kaggle errors: create ~/.kaggle/kaggle.json with KAGGLE_USERNAME and KAGGLE_KEY
|
711
|
+
* API errors: export the appropriate API key as environment variable
|
712
|
+
|
713
|
+
5. Environment variable exports:
|
714
|
+
- Use export commands for API keys that need to be in environment
|
715
|
+
- Use the actual credential values, not placeholders
|
670
716
|
|
671
717
|
Do not provide any explanations, just the exact command to run.
|
672
718
|
"""
|
@@ -2364,9 +2410,39 @@ def get_setup_commands_from_gitingest(repo_url):
|
|
2364
2410
|
api_keys = result.get("requiredApiKeys", [])
|
2365
2411
|
if api_keys:
|
2366
2412
|
print(f"\n🔑 Required API Keys ({len(api_keys)}):")
|
2413
|
+
# Load stored GitArsenal credentials
|
2414
|
+
stored_credentials = {}
|
2415
|
+
try:
|
2416
|
+
credentials_file = Path.home() / ".gitarsenal" / "credentials.json"
|
2417
|
+
if credentials_file.exists():
|
2418
|
+
with open(credentials_file, 'r') as f:
|
2419
|
+
stored_credentials = json.load(f)
|
2420
|
+
print(f"📋 Found {len(stored_credentials)} stored GitArsenal credentials")
|
2421
|
+
else:
|
2422
|
+
print("📋 No stored GitArsenal credentials found")
|
2423
|
+
except Exception as e:
|
2424
|
+
print(f"⚠️ Error loading stored credentials: {e}")
|
2425
|
+
|
2426
|
+
# Identify missing required API keys
|
2427
|
+
missing_required_keys = []
|
2428
|
+
available_keys = []
|
2429
|
+
|
2367
2430
|
for i, api_key in enumerate(api_keys, 1):
|
2368
|
-
|
2369
|
-
|
2431
|
+
key_name = api_key.get('name', 'Unknown')
|
2432
|
+
is_required = api_key.get("required", False)
|
2433
|
+
has_stored_key = key_name in stored_credentials
|
2434
|
+
|
2435
|
+
if is_required:
|
2436
|
+
if has_stored_key:
|
2437
|
+
status = "✅ Required (Available)"
|
2438
|
+
available_keys.append(key_name)
|
2439
|
+
else:
|
2440
|
+
status = "🔴 Required (Missing)"
|
2441
|
+
missing_required_keys.append(api_key)
|
2442
|
+
else:
|
2443
|
+
status = "🟡 Optional"
|
2444
|
+
|
2445
|
+
print(f" {i}. {key_name} - {status}")
|
2370
2446
|
print(f" Service: {api_key.get('service', 'Unknown')}")
|
2371
2447
|
print(f" Description: {api_key.get('description', 'No description')}")
|
2372
2448
|
if api_key.get('example'):
|
@@ -2374,6 +2450,67 @@ def get_setup_commands_from_gitingest(repo_url):
|
|
2374
2450
|
if api_key.get('documentation_url'):
|
2375
2451
|
print(f" Docs: {api_key.get('documentation_url')}")
|
2376
2452
|
print()
|
2453
|
+
|
2454
|
+
# Prompt for missing required API keys
|
2455
|
+
if missing_required_keys:
|
2456
|
+
print("🔧 Setting up missing required API keys...")
|
2457
|
+
print("Press Enter to continue or Ctrl+C to skip...")
|
2458
|
+
|
2459
|
+
for api_key in missing_required_keys:
|
2460
|
+
key_name = api_key.get('name', 'Unknown')
|
2461
|
+
service = api_key.get('service', 'Unknown')
|
2462
|
+
description = api_key.get('description', 'No description')
|
2463
|
+
example = api_key.get('example', '')
|
2464
|
+
docs_url = api_key.get('documentation_url', '')
|
2465
|
+
|
2466
|
+
print(f"\n📝 Setting up {key_name} for {service}:")
|
2467
|
+
print(f" Description: {description}")
|
2468
|
+
if example:
|
2469
|
+
print(f" Example: {example}")
|
2470
|
+
if docs_url:
|
2471
|
+
print(f" Documentation: {docs_url}")
|
2472
|
+
|
2473
|
+
# Prompt user for the API key
|
2474
|
+
try:
|
2475
|
+
import getpass
|
2476
|
+
print(f"\nPlease enter your {key_name}:")
|
2477
|
+
new_key = getpass.getpass("API Key (hidden): ").strip()
|
2478
|
+
|
2479
|
+
if new_key:
|
2480
|
+
# Save to credentials file
|
2481
|
+
credentials_file = Path.home() / ".gitarsenal" / "credentials.json"
|
2482
|
+
credentials_file.parent.mkdir(parents=True, exist_ok=True)
|
2483
|
+
|
2484
|
+
# Load existing credentials
|
2485
|
+
if credentials_file.exists():
|
2486
|
+
with open(credentials_file, 'r') as f:
|
2487
|
+
all_credentials = json.load(f)
|
2488
|
+
else:
|
2489
|
+
all_credentials = {}
|
2490
|
+
|
2491
|
+
# Add new key
|
2492
|
+
all_credentials[key_name] = new_key
|
2493
|
+
|
2494
|
+
# Save back to file
|
2495
|
+
with open(credentials_file, 'w') as f:
|
2496
|
+
json.dump(all_credentials, f, indent=2)
|
2497
|
+
|
2498
|
+
print(f"✅ {key_name} saved successfully!")
|
2499
|
+
available_keys.append(key_name)
|
2500
|
+
else:
|
2501
|
+
print(f"⚠️ Skipping {key_name} (no input provided)")
|
2502
|
+
except KeyboardInterrupt:
|
2503
|
+
print(f"\n⚠️ Skipping {key_name} (cancelled by user)")
|
2504
|
+
except Exception as e:
|
2505
|
+
print(f"❌ Error saving {key_name}: {e}")
|
2506
|
+
|
2507
|
+
# Show summary
|
2508
|
+
if available_keys:
|
2509
|
+
print(f"✅ Available API keys: {', '.join(available_keys)}")
|
2510
|
+
if missing_required_keys:
|
2511
|
+
print(f"⚠️ Missing required keys: {', '.join([k.get('name') for k in missing_required_keys])}")
|
2512
|
+
else:
|
2513
|
+
print("ℹ️ All required API keys are already available.")
|
2377
2514
|
|
2378
2515
|
# Display setup complexity if available
|
2379
2516
|
if "setupComplexity" in result:
|