gitarsenal-cli 1.6.11 ā 1.6.13
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/bin/gitarsenal.js +10 -25
- package/package.json +1 -1
- package/python/gitarsenal_keys.py +64 -31
- package/python/test_modalSandboxScript.py +57 -13
- package/test_modalSandboxScript.py +23 -0
package/bin/gitarsenal.js
CHANGED
@@ -60,7 +60,7 @@ const keysCmd = program
|
|
60
60
|
keysCmd
|
61
61
|
.command('add')
|
62
62
|
.description('Add an API key')
|
63
|
-
.option('-s, --service <service>', 'Service name (
|
63
|
+
.option('-s, --service <service>', 'Service name (any service supported)')
|
64
64
|
.option('-k, --key <key>', 'API key (if not provided, will prompt)')
|
65
65
|
.action(async (options) => {
|
66
66
|
await handleKeysAdd(options);
|
@@ -277,15 +277,10 @@ async function handleKeysAdd(options) {
|
|
277
277
|
spinner.stop();
|
278
278
|
const serviceAnswer = await inquirer.prompt([
|
279
279
|
{
|
280
|
-
type: '
|
280
|
+
type: 'input',
|
281
281
|
name: 'service',
|
282
|
-
message: '
|
283
|
-
|
284
|
-
{ name: 'OpenAI', value: 'openai' },
|
285
|
-
{ name: 'Weights & Biases', value: 'wandb' },
|
286
|
-
{ name: 'Hugging Face', value: 'huggingface' },
|
287
|
-
{ name: 'GitArsenal OpenAI (for debugging)', value: 'gitarsenal-openai' }
|
288
|
-
]
|
282
|
+
message: 'Enter service name:',
|
283
|
+
validate: (input) => input.trim() !== '' ? true : 'Service name is required'
|
289
284
|
}
|
290
285
|
]);
|
291
286
|
service = serviceAnswer.service;
|
@@ -377,15 +372,10 @@ async function handleKeysView(options) {
|
|
377
372
|
spinner.stop();
|
378
373
|
const serviceAnswer = await inquirer.prompt([
|
379
374
|
{
|
380
|
-
type: '
|
375
|
+
type: 'input',
|
381
376
|
name: 'service',
|
382
|
-
message: '
|
383
|
-
|
384
|
-
{ name: 'OpenAI', value: 'openai' },
|
385
|
-
{ name: 'Weights & Biases', value: 'wandb' },
|
386
|
-
{ name: 'Hugging Face', value: 'huggingface' },
|
387
|
-
{ name: 'GitArsenal OpenAI (for debugging)', value: 'gitarsenal-openai' }
|
388
|
-
]
|
377
|
+
message: 'Enter service name:',
|
378
|
+
validate: (input) => input.trim() !== '' ? true : 'Service name is required'
|
389
379
|
}
|
390
380
|
]);
|
391
381
|
service = serviceAnswer.service;
|
@@ -426,15 +416,10 @@ async function handleKeysDelete(options) {
|
|
426
416
|
spinner.stop();
|
427
417
|
const serviceAnswer = await inquirer.prompt([
|
428
418
|
{
|
429
|
-
type: '
|
419
|
+
type: 'input',
|
430
420
|
name: 'service',
|
431
|
-
message: '
|
432
|
-
|
433
|
-
{ name: 'OpenAI', value: 'openai' },
|
434
|
-
{ name: 'Weights & Biases', value: 'wandb' },
|
435
|
-
{ name: 'Hugging Face', value: 'huggingface' },
|
436
|
-
{ name: 'GitArsenal OpenAI (for debugging)', value: 'gitarsenal-openai' }
|
437
|
-
]
|
421
|
+
message: 'Enter service name:',
|
422
|
+
validate: (input) => input.trim() !== '' ? true : 'Service name is required'
|
438
423
|
}
|
439
424
|
]);
|
440
425
|
service = serviceAnswer.service;
|
package/package.json
CHANGED
@@ -41,23 +41,51 @@ def handle_add(credentials_manager, args):
|
|
41
41
|
sys.exit(1)
|
42
42
|
|
43
43
|
if not key:
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
# Prompt for the API key interactively
|
45
|
+
print(f"\nš {service.upper()} API KEY REQUIRED")
|
46
|
+
print("=" * 50)
|
47
|
+
|
48
|
+
# Get appropriate prompt based on service
|
49
|
+
prompts = {
|
50
|
+
'openai': "Please enter your OpenAI API key:\nYou can get your API key from: https://platform.openai.com/api-keys",
|
51
|
+
'wandb': "Please enter your Weights & Biases API key:\nYou can get your API key from: https://wandb.ai/authorize",
|
52
|
+
'huggingface': "Please enter your Hugging Face token:\nYou can get your token from: https://huggingface.co/settings/tokens",
|
53
|
+
'gitarsenal-openai': "Please enter GitArsenal's OpenAI API key for debugging:",
|
54
|
+
'claude': "Please enter your Claude API key:\nYou can get your API key from: https://console.anthropic.com/"
|
55
|
+
}
|
56
|
+
|
57
|
+
prompt = prompts.get(service, f"Please enter your {service} API key:")
|
58
|
+
print(prompt)
|
59
|
+
print("-" * 50)
|
60
|
+
|
61
|
+
try:
|
62
|
+
import getpass
|
63
|
+
key = getpass.getpass("API Key (hidden): ").strip()
|
64
|
+
if not key:
|
65
|
+
print("ā No API key provided.")
|
66
|
+
sys.exit(1)
|
67
|
+
print("ā
API key received successfully!")
|
68
|
+
except KeyboardInterrupt:
|
69
|
+
print("\nā API key input cancelled by user.")
|
70
|
+
sys.exit(1)
|
71
|
+
except Exception as e:
|
72
|
+
print(f"ā Error getting API key: {e}")
|
73
|
+
sys.exit(1)
|
74
|
+
|
75
|
+
# Generate credential key from service name
|
76
|
+
# Convert service name to a standardized key format
|
77
|
+
credential_key = f"{service.replace('-', '_')}_api_key"
|
78
|
+
|
79
|
+
# Special mappings for backward compatibility
|
80
|
+
special_mappings = {
|
49
81
|
'openai': 'openai_api_key',
|
50
82
|
'wandb': 'wandb_api_key',
|
51
83
|
'huggingface': 'huggingface_token',
|
52
84
|
'gitarsenal-openai': 'gitarsenal_openai_api_key'
|
53
85
|
}
|
54
86
|
|
55
|
-
if
|
56
|
-
|
57
|
-
print("Supported services: openai, wandb, huggingface, gitarsenal-openai")
|
58
|
-
sys.exit(1)
|
59
|
-
|
60
|
-
credential_key = service_mapping[service]
|
87
|
+
# Use special mapping if it exists, otherwise use generated key
|
88
|
+
credential_key = special_mappings.get(service, credential_key)
|
61
89
|
|
62
90
|
# Save the credential
|
63
91
|
credentials = credentials_manager.load_credentials()
|
@@ -82,19 +110,26 @@ def handle_list(credentials_manager):
|
|
82
110
|
print("š Stored API Keys:")
|
83
111
|
print("=" * 50)
|
84
112
|
|
85
|
-
# Map credential keys to display names
|
113
|
+
# Map credential keys to display names (for known services)
|
86
114
|
key_mapping = {
|
87
115
|
'openai_api_key': 'OpenAI',
|
88
116
|
'wandb_api_key': 'Weights & Biases',
|
89
117
|
'huggingface_token': 'Hugging Face',
|
90
|
-
'gitarsenal_openai_api_key': 'GitArsenal OpenAI'
|
118
|
+
'gitarsenal_openai_api_key': 'GitArsenal OpenAI',
|
119
|
+
'claude_api_key': 'Claude'
|
91
120
|
}
|
92
121
|
|
93
122
|
for key, value in credentials.items():
|
123
|
+
# Generate display name from key if not in mapping
|
94
124
|
if key in key_mapping:
|
95
125
|
display_name = key_mapping[key]
|
96
|
-
|
97
|
-
|
126
|
+
else:
|
127
|
+
# Convert key back to service name for display
|
128
|
+
service_name = key.replace('_api_key', '').replace('_token', '').replace('_', '-')
|
129
|
+
display_name = service_name.title()
|
130
|
+
|
131
|
+
masked_value = value[:8] + "*" * (len(value) - 12) + value[-4:] if len(value) > 12 else "*" * len(value)
|
132
|
+
print(f" {display_name}: {masked_value}")
|
98
133
|
|
99
134
|
print(f"\nš Storage location: {credentials_manager.credentials_file}")
|
100
135
|
|
@@ -106,20 +141,19 @@ def handle_view(credentials_manager, args):
|
|
106
141
|
print("ā Service name is required. Use --service option.")
|
107
142
|
sys.exit(1)
|
108
143
|
|
109
|
-
#
|
110
|
-
|
144
|
+
# Generate credential key from service name
|
145
|
+
credential_key = f"{service.replace('-', '_')}_api_key"
|
146
|
+
|
147
|
+
# Special mappings for backward compatibility
|
148
|
+
special_mappings = {
|
111
149
|
'openai': 'openai_api_key',
|
112
150
|
'wandb': 'wandb_api_key',
|
113
151
|
'huggingface': 'huggingface_token',
|
114
152
|
'gitarsenal-openai': 'gitarsenal_openai_api_key'
|
115
153
|
}
|
116
154
|
|
117
|
-
if
|
118
|
-
|
119
|
-
print("Supported services: openai, wandb, huggingface, gitarsenal-openai")
|
120
|
-
sys.exit(1)
|
121
|
-
|
122
|
-
credential_key = service_mapping[service]
|
155
|
+
# Use special mapping if it exists, otherwise use generated key
|
156
|
+
credential_key = special_mappings.get(service, credential_key)
|
123
157
|
credentials = credentials_manager.load_credentials()
|
124
158
|
|
125
159
|
if credential_key not in credentials:
|
@@ -141,20 +175,19 @@ def handle_delete(credentials_manager, args):
|
|
141
175
|
print("ā Service name is required. Use --service option.")
|
142
176
|
sys.exit(1)
|
143
177
|
|
144
|
-
#
|
145
|
-
|
178
|
+
# Generate credential key from service name
|
179
|
+
credential_key = f"{service.replace('-', '_')}_api_key"
|
180
|
+
|
181
|
+
# Special mappings for backward compatibility
|
182
|
+
special_mappings = {
|
146
183
|
'openai': 'openai_api_key',
|
147
184
|
'wandb': 'wandb_api_key',
|
148
185
|
'huggingface': 'huggingface_token',
|
149
186
|
'gitarsenal-openai': 'gitarsenal_openai_api_key'
|
150
187
|
}
|
151
188
|
|
152
|
-
if
|
153
|
-
|
154
|
-
print("Supported services: openai, wandb, huggingface, gitarsenal-openai")
|
155
|
-
sys.exit(1)
|
156
|
-
|
157
|
-
credential_key = service_mapping[service]
|
189
|
+
# Use special mapping if it exists, otherwise use generated key
|
190
|
+
credential_key = special_mappings.get(service, credential_key)
|
158
191
|
success = credentials_manager.clear_credential(credential_key)
|
159
192
|
|
160
193
|
if success:
|
@@ -418,38 +418,59 @@ def call_openai_for_debug(command, error_output, api_key=None, current_dir=None,
|
|
418
418
|
except Exception as e:
|
419
419
|
print(f"ā ļø Could not load saved API key: {e}")
|
420
420
|
|
421
|
-
# Then try credentials manager
|
421
|
+
# Then try credentials manager
|
422
422
|
if not api_key:
|
423
|
-
print("š DEBUG: Trying credentials manager
|
423
|
+
print("š DEBUG: Trying credentials manager...")
|
424
424
|
try:
|
425
425
|
from credentials_manager import CredentialsManager
|
426
426
|
credentials_manager = CredentialsManager()
|
427
|
-
api_key = credentials_manager.
|
427
|
+
api_key = credentials_manager.get_openai_api_key()
|
428
428
|
if api_key:
|
429
|
-
print(f"š DEBUG:
|
430
|
-
print(f"š DEBUG:
|
429
|
+
print(f"š DEBUG: API key from credentials manager: Found")
|
430
|
+
print(f"š DEBUG: Credentials manager API key value: {api_key}")
|
431
431
|
# Set in environment for this session
|
432
432
|
os.environ["OPENAI_API_KEY"] = api_key
|
433
433
|
else:
|
434
|
-
print(f"š DEBUG:
|
434
|
+
print(f"š DEBUG: API key from credentials manager: Not found")
|
435
435
|
except ImportError as e:
|
436
436
|
print(f"š DEBUG: Credentials manager not available: {e}")
|
437
437
|
# Fall back to direct input if credentials_manager is not available
|
438
438
|
pass
|
439
439
|
|
440
|
-
#
|
440
|
+
# Finally, prompt the user if still no API key
|
441
441
|
if not api_key:
|
442
|
-
print("š DEBUG: No
|
443
|
-
print("
|
444
|
-
|
442
|
+
print("š DEBUG: No API key found in any source, prompting user...")
|
443
|
+
print("\n" + "="*60)
|
444
|
+
print("š OPENAI API KEY REQUIRED FOR DEBUGGING")
|
445
|
+
print("="*60)
|
446
|
+
print("To debug failed commands, an OpenAI API key is needed.")
|
447
|
+
print("š Please paste your OpenAI API key below:")
|
448
|
+
print(" (Your input will be hidden for security)")
|
449
|
+
print("-" * 60)
|
450
|
+
|
451
|
+
try:
|
452
|
+
api_key = getpass.getpass("OpenAI API Key: ").strip()
|
453
|
+
if not api_key:
|
454
|
+
print("ā No API key provided. Skipping debugging.")
|
455
|
+
return None
|
456
|
+
print("ā
API key received successfully!")
|
457
|
+
print(f"š DEBUG: User-provided API key: {api_key}")
|
458
|
+
# Save the API key to environment for future use in this session
|
459
|
+
os.environ["OPENAI_API_KEY"] = api_key
|
460
|
+
except KeyboardInterrupt:
|
461
|
+
print("\nā API key input cancelled by user.")
|
462
|
+
return None
|
463
|
+
except Exception as e:
|
464
|
+
print(f"ā Error getting API key: {e}")
|
465
|
+
return None
|
445
466
|
|
446
467
|
# If we still don't have an API key, we can't proceed
|
447
468
|
if not api_key:
|
448
|
-
print("ā No
|
449
|
-
print("š”
|
469
|
+
print("ā No OpenAI API key available. Cannot perform LLM debugging.")
|
470
|
+
print("š” To enable LLM debugging, set the OPENAI_API_KEY environment variable")
|
450
471
|
return None
|
451
472
|
|
452
|
-
print(f"ā
|
473
|
+
print(f"ā
OpenAI API key available (length: {len(api_key)})")
|
453
474
|
|
454
475
|
# Gather additional context to help with debugging
|
455
476
|
directory_context = ""
|
@@ -2338,6 +2359,29 @@ def get_setup_commands_from_gitingest(repo_url):
|
|
2338
2359
|
if commands:
|
2339
2360
|
print(f"ā
Successfully fetched {len(commands)} setup commands from API at {api_url}")
|
2340
2361
|
|
2362
|
+
# Enhanced response handling for API key detection
|
2363
|
+
if "requiredApiKeys" in result:
|
2364
|
+
api_keys = result.get("requiredApiKeys", [])
|
2365
|
+
if api_keys:
|
2366
|
+
print(f"\nš Required API Keys ({len(api_keys)}):")
|
2367
|
+
for i, api_key in enumerate(api_keys, 1):
|
2368
|
+
status = "š“ Required" if api_key.get("required", False) else "š” Optional"
|
2369
|
+
print(f" {i}. {api_key.get('name', 'Unknown')} - {status}")
|
2370
|
+
print(f" Service: {api_key.get('service', 'Unknown')}")
|
2371
|
+
print(f" Description: {api_key.get('description', 'No description')}")
|
2372
|
+
if api_key.get('example'):
|
2373
|
+
print(f" Example: {api_key.get('example')}")
|
2374
|
+
if api_key.get('documentation_url'):
|
2375
|
+
print(f" Docs: {api_key.get('documentation_url')}")
|
2376
|
+
print()
|
2377
|
+
|
2378
|
+
# Display setup complexity if available
|
2379
|
+
if "setupComplexity" in result:
|
2380
|
+
complexity = result.get("setupComplexity", "medium")
|
2381
|
+
estimated_time = result.get("estimatedSetupTime", "Unknown")
|
2382
|
+
print(f"š Setup Complexity: {complexity.upper()}")
|
2383
|
+
print(f"ā±ļø Estimated Time: {estimated_time}")
|
2384
|
+
|
2341
2385
|
# Print the commands
|
2342
2386
|
print("\nš Setup Commands:")
|
2343
2387
|
for i, cmd in enumerate(commands, 1):
|
@@ -2359,6 +2359,29 @@ def get_setup_commands_from_gitingest(repo_url):
|
|
2359
2359
|
if commands:
|
2360
2360
|
print(f"ā
Successfully fetched {len(commands)} setup commands from API at {api_url}")
|
2361
2361
|
|
2362
|
+
# Enhanced response handling for API key detection
|
2363
|
+
if "requiredApiKeys" in result:
|
2364
|
+
api_keys = result.get("requiredApiKeys", [])
|
2365
|
+
if api_keys:
|
2366
|
+
print(f"\nš Required API Keys ({len(api_keys)}):")
|
2367
|
+
for i, api_key in enumerate(api_keys, 1):
|
2368
|
+
status = "š“ Required" if api_key.get("required", False) else "š” Optional"
|
2369
|
+
print(f" {i}. {api_key.get('name', 'Unknown')} - {status}")
|
2370
|
+
print(f" Service: {api_key.get('service', 'Unknown')}")
|
2371
|
+
print(f" Description: {api_key.get('description', 'No description')}")
|
2372
|
+
if api_key.get('example'):
|
2373
|
+
print(f" Example: {api_key.get('example')}")
|
2374
|
+
if api_key.get('documentation_url'):
|
2375
|
+
print(f" Docs: {api_key.get('documentation_url')}")
|
2376
|
+
print()
|
2377
|
+
|
2378
|
+
# Display setup complexity if available
|
2379
|
+
if "setupComplexity" in result:
|
2380
|
+
complexity = result.get("setupComplexity", "medium")
|
2381
|
+
estimated_time = result.get("estimatedSetupTime", "Unknown")
|
2382
|
+
print(f"š Setup Complexity: {complexity.upper()}")
|
2383
|
+
print(f"ā±ļø Estimated Time: {estimated_time}")
|
2384
|
+
|
2362
2385
|
# Print the commands
|
2363
2386
|
print("\nš Setup Commands:")
|
2364
2387
|
for i, cmd in enumerate(commands, 1):
|