gitarsenal-cli 1.9.18 → 1.9.20

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 CHANGED
@@ -1 +1 @@
1
- {"created":"2025-08-06T08:11:48.991Z","packages":["modal","gitingest","requests","anthropic"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
1
+ {"created":"2025-08-06T11:31:44.083Z","packages":["modal","gitingest","requests","anthropic"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitarsenal-cli",
3
- "version": "1.9.18",
3
+ "version": "1.9.20",
4
4
  "description": "CLI tool for creating Modal sandboxes with GitHub repositories",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -145,7 +145,7 @@ class CredentialsManager:
145
145
  # First try to fetch from server using fetch_modal_tokens (GitArsenal's key)
146
146
  try:
147
147
  from fetch_modal_tokens import get_tokens
148
- _, _, api_key = get_tokens()
148
+ _, _, api_key, _ = get_tokens()
149
149
  if api_key and validate_openai_key(api_key):
150
150
  # Set in environment for future use
151
151
  os.environ["OPENAI_API_KEY"] = api_key
@@ -220,6 +220,27 @@ class CredentialsManager:
220
220
  prompt = "A Weights & Biases API key is required.\nYou can get your API key from: https://wandb.ai/authorize"
221
221
  return self.get_credential("wandb_api_key", prompt, is_password=True, validate_func=validate_wandb_key)
222
222
 
223
+ def get_anthropic_api_key(self):
224
+ """Get Anthropic API key with validation"""
225
+ def validate_anthropic_key(key):
226
+ # Anthropic keys usually start with "sk-ant-" and are typically 48+ characters
227
+ return key.startswith("sk-ant-") and len(key) > 40
228
+
229
+ # First check stored credentials
230
+ credentials = self.load_credentials()
231
+ if "anthropic_api_key" in credentials:
232
+ stored_key = credentials["anthropic_api_key"]
233
+ if validate_anthropic_key(stored_key):
234
+ return stored_key
235
+
236
+ # Then check environment variable
237
+ env_key = os.environ.get("ANTHROPIC_API_KEY")
238
+ if env_key and validate_anthropic_key(env_key):
239
+ return env_key
240
+
241
+ prompt = "An Anthropic API key is required.\nYou can get your API key from: https://console.anthropic.com/"
242
+ return self.get_credential("anthropic_api_key", prompt, is_password=True, validate_func=validate_anthropic_key)
243
+
223
244
  def clear_credential(self, key):
224
245
  """Remove a specific credential"""
225
246
  credentials = self.load_credentials()
@@ -259,6 +280,7 @@ class CredentialsManager:
259
280
  import os
260
281
  security_vars = [
261
282
  "OPENAI_API_KEY",
283
+ "ANTHROPIC_API_KEY",
262
284
  "HUGGINGFACE_TOKEN",
263
285
  "WANDB_API_KEY",
264
286
  "MODAL_TOKEN_ID",
@@ -39,29 +39,30 @@ def fetch_default_tokens_from_gitarsenal():
39
39
  token_id = data.get("modalTokenId")
40
40
  token_secret = data.get("modalTokenSecret")
41
41
  openai_api_key = data.get("openaiApiKey")
42
+ anthropic_api_key = data.get("anthropicApiKey")
42
43
 
43
44
  if token_id and token_secret:
44
45
  # print("✅ Successfully fetched default tokens from gitarsenal.dev")
45
- return token_id, token_secret, openai_api_key
46
+ return token_id, token_secret, openai_api_key, anthropic_api_key
46
47
  else:
47
48
  print("❌ Modal tokens not found in gitarsenal.dev response")
48
- return None, None, None
49
+ return None, None, None, None
49
50
  except json.JSONDecodeError:
50
51
  print("❌ Invalid JSON response from gitarsenal.dev")
51
- return None, None, None
52
+ return None, None, None, None
52
53
  else:
53
54
  print(f"❌ Failed to fetch from gitarsenal.dev: {response.status_code} - {response.text[:200]}")
54
- return None, None, None
55
+ return None, None, None, None
55
56
 
56
57
  except requests.exceptions.Timeout:
57
58
  print("❌ Request timeout when fetching from gitarsenal.dev")
58
- return None, None, None
59
+ return None, None, None, None
59
60
  except requests.exceptions.ConnectionError:
60
61
  print("❌ Connection failed to gitarsenal.dev")
61
- return None, None, None
62
+ return None, None, None, None
62
63
  except requests.exceptions.RequestException as e:
63
64
  print(f"❌ Request failed to gitarsenal.dev: {e}")
64
- return None, None, None
65
+ return None, None, None, None
65
66
 
66
67
  def fetch_tokens_from_proxy(proxy_url=None, api_key=None):
67
68
  """
@@ -89,12 +90,12 @@ def fetch_tokens_from_proxy(proxy_url=None, api_key=None):
89
90
  if not proxy_url:
90
91
  # print("❌ No proxy URL provided or found in environment")
91
92
  print("💡 Set MODAL_PROXY_URL environment variable or use --proxy-url argument")
92
- return None, None, None
93
+ return None, None, None, None
93
94
 
94
95
  if not api_key:
95
96
  print("❌ No API key provided or found in environment")
96
97
  print("💡 Set MODAL_PROXY_API_KEY environment variable or use --proxy-api-key argument")
97
- return None, None, None
98
+ return None, None, None, None
98
99
 
99
100
  # Ensure the URL ends with a slash
100
101
  if not proxy_url.endswith("/"):
@@ -117,41 +118,42 @@ def fetch_tokens_from_proxy(proxy_url=None, api_key=None):
117
118
  token_id = data.get("token_id")
118
119
  token_secret = data.get("token_secret")
119
120
  openai_api_key = data.get("openai_api_key")
121
+ anthropic_api_key = data.get("anthropic_api_key")
120
122
 
121
123
  if token_id and token_secret:
122
124
  print("✅ Successfully fetched tokens from proxy server")
123
- return token_id, token_secret, openai_api_key
125
+ return token_id, token_secret, openai_api_key, anthropic_api_key
124
126
  else:
125
127
  print("❌ Tokens not found in response")
126
- return None, None, None
128
+ return None, None, None, None
127
129
  else:
128
130
  print(f"❌ Failed to fetch tokens: {response.status_code} - {response.text}")
129
- return None, None, None
131
+ return None, None, None, None
130
132
  except Exception as e:
131
133
  print(f"❌ Error fetching tokens: {e}")
132
- return None, None, None
134
+ return None, None, None, None
133
135
 
134
136
  def get_tokens():
135
137
  """
136
- Get Modal tokens and OpenAI API key, trying to fetch from the proxy server first.
138
+ Get Modal tokens, OpenAI API key, and Anthropic API key, trying to fetch from the proxy server first.
137
139
  Also sets the tokens in environment variables.
138
140
 
139
141
  Returns:
140
- tuple: (token_id, token_secret, openai_api_key)
142
+ tuple: (token_id, token_secret, openai_api_key, anthropic_api_key)
141
143
  """
142
144
  # Try to fetch from the proxy server
143
- token_id, token_secret, openai_api_key = fetch_tokens_from_proxy()
145
+ token_id, token_secret, openai_api_key, anthropic_api_key = fetch_tokens_from_proxy()
144
146
 
145
147
  # If we couldn't fetch from the server, try to get default tokens from gitarsenal.dev
146
148
  if not token_id or not token_secret:
147
149
  # print("⚠️ Proxy server failed, trying to fetch default tokens from gitarsenal.dev")
148
- token_id, token_secret, openai_api_key = fetch_default_tokens_from_gitarsenal()
150
+ token_id, token_secret, openai_api_key, anthropic_api_key = fetch_default_tokens_from_gitarsenal()
149
151
 
150
152
  # If we still don't have tokens, we can't proceed
151
153
  if not token_id or not token_secret:
152
154
  print("❌ Failed to fetch tokens from both proxy server and gitarsenal.dev")
153
155
  print("💡 Please check your network connection and API endpoints")
154
- return None, None, None
156
+ return None, None, None, None
155
157
 
156
158
  # Debug print the full token values
157
159
  # print("\n🔍 DEBUG: FULL TOKEN VALUES:")
@@ -169,7 +171,11 @@ def get_tokens():
169
171
  if openai_api_key:
170
172
  os.environ["OPENAI_API_KEY"] = openai_api_key
171
173
 
172
- return token_id, token_secret, openai_api_key
174
+ # Set Anthropic API key if available
175
+ if anthropic_api_key:
176
+ os.environ["ANTHROPIC_API_KEY"] = anthropic_api_key
177
+
178
+ return token_id, token_secret, openai_api_key, anthropic_api_key
173
179
 
174
180
  if __name__ == "__main__":
175
181
  # Parse command-line arguments if run directly
@@ -190,22 +196,26 @@ if __name__ == "__main__":
190
196
  print(f"✅ Set MODAL_PROXY_API_KEY from command line")
191
197
 
192
198
  # Get tokens
193
- token_id, token_secret, openai_api_key = get_tokens()
199
+ token_id, token_secret, openai_api_key, anthropic_api_key = get_tokens()
194
200
  print(f"Token ID: {token_id}")
195
201
  print(f"Token Secret: {token_secret}")
196
202
  print(f"OpenAI API Key: {openai_api_key[:5] + '...' if openai_api_key else None}")
203
+ print(f"Anthropic API Key: {anthropic_api_key[:5] + '...' if anthropic_api_key else None}")
197
204
 
198
205
  # Check if tokens are set in environment variables
199
206
  print(f"\n🔍 DEBUG: Checking environment variables")
200
207
  print(f"🔍 MODAL_TOKEN_ID exists: {'Yes' if os.environ.get('MODAL_TOKEN_ID') else 'No'}")
201
208
  print(f"🔍 MODAL_TOKEN_SECRET exists: {'Yes' if os.environ.get('MODAL_TOKEN_SECRET') else 'No'}")
202
209
  print(f"🔍 OPENAI_API_KEY exists: {'Yes' if os.environ.get('OPENAI_API_KEY') else 'No'}")
210
+ print(f"🔍 ANTHROPIC_API_KEY exists: {'Yes' if os.environ.get('ANTHROPIC_API_KEY') else 'No'}")
203
211
  if os.environ.get('MODAL_TOKEN_ID'):
204
212
  print(f"🔍 MODAL_TOKEN_ID length: {len(os.environ.get('MODAL_TOKEN_ID'))}")
205
213
  if os.environ.get('MODAL_TOKEN_SECRET'):
206
214
  print(f"🔍 MODAL_TOKEN_SECRET length: {len(os.environ.get('MODAL_TOKEN_SECRET'))}")
207
215
  if os.environ.get('OPENAI_API_KEY'):
208
216
  print(f"🔍 OPENAI_API_KEY length: {len(os.environ.get('OPENAI_API_KEY'))}")
217
+ if os.environ.get('ANTHROPIC_API_KEY'):
218
+ print(f"🔍 ANTHROPIC_API_KEY length: {len(os.environ.get('ANTHROPIC_API_KEY'))}")
209
219
 
210
220
  # Write the tokens to a file for use by other scripts
211
221
  tokens_file = Path(__file__).parent / "modal_tokens.json"
@@ -213,7 +223,8 @@ if __name__ == "__main__":
213
223
  json.dump({
214
224
  "token_id": token_id,
215
225
  "token_secret": token_secret,
216
- "openai_api_key": openai_api_key
226
+ "openai_api_key": openai_api_key,
227
+ "anthropic_api_key": anthropic_api_key
217
228
  }, f)
218
229
  print(f"\n✅ Tokens written to {tokens_file}")
219
230
 
@@ -234,7 +245,7 @@ if __name__ == "__main__":
234
245
  f.write(f"token_secret = {token_secret}\n")
235
246
  print(f"✅ Created .modalconfig file at {modalconfig_file}")
236
247
 
237
- # Create or update .env file with OpenAI API key
248
+ # Create or update .env file with API keys
238
249
  env_file = Path.home() / ".env"
239
250
  env_content = ""
240
251
  if env_file.exists():
@@ -255,6 +266,20 @@ if __name__ == "__main__":
255
266
  f.write(env_content)
256
267
  print(f"✅ Updated OpenAI API key in {env_file}")
257
268
 
269
+ # Update or add ANTHROPIC_API_KEY
270
+ if anthropic_api_key:
271
+ if "ANTHROPIC_API_KEY" in env_content:
272
+ # Replace existing key
273
+ import re
274
+ env_content = re.sub(r'ANTHROPIC_API_KEY=.*\n', f'ANTHROPIC_API_KEY={anthropic_api_key}\n', env_content)
275
+ else:
276
+ # Add new key
277
+ env_content += f'\nANTHROPIC_API_KEY={anthropic_api_key}\n'
278
+
279
+ with open(env_file, 'w') as f:
280
+ f.write(env_content)
281
+ print(f"✅ Updated Anthropic API key in {env_file}")
282
+
258
283
  # Try to use the Modal CLI to set the token
259
284
  try:
260
285
  print(f"\n🔄 Setting token via Modal CLI...")
@@ -42,7 +42,7 @@ except Exception as e:
42
42
  try:
43
43
  # First, try to import the fetch_modal_tokens module
44
44
  from fetch_modal_tokens import get_tokens
45
- TOKEN_ID, TOKEN_SECRET = get_tokens()
45
+ TOKEN_ID, TOKEN_SECRET, _, _ = get_tokens()
46
46
 
47
47
  # Check if we got valid tokens
48
48
  if TOKEN_ID is None or TOKEN_SECRET is None:
@@ -22,7 +22,7 @@ from pathlib import Path
22
22
  try:
23
23
  # First, try to import the fetch_modal_tokens module
24
24
  from fetch_modal_tokens import get_tokens
25
- TOKEN_ID, TOKEN_SECRET = get_tokens()
25
+ TOKEN_ID, TOKEN_SECRET, _, _ = get_tokens()
26
26
  print(f"✅ Using tokens from proxy server or defaults")
27
27
  except ImportError:
28
28
  # If the module is not available, use hardcoded tokens
@@ -118,7 +118,7 @@ def setup_modal_auth():
118
118
  # Import the fetch_modal_tokens module
119
119
  logger.info("Fetching Modal tokens from proxy server...")
120
120
  from fetch_modal_tokens import get_tokens
121
- token_id, token_secret = get_tokens()
121
+ token_id, token_secret, _, _ = get_tokens()
122
122
  logger.info("Modal tokens fetched successfully")
123
123
 
124
124
  # Set the tokens in environment variables
@@ -462,7 +462,7 @@ def create_ssh_container():
462
462
  # Import the fetch_modal_tokens module
463
463
  logger.info("Fetching Modal tokens from proxy server in thread...")
464
464
  from fetch_modal_tokens import get_tokens
465
- token_id, token_secret = get_tokens()
465
+ token_id, token_secret, _, _ = get_tokens()
466
466
  logger.info("Modal tokens fetched successfully in thread")
467
467
 
468
468
  # Set the tokens in environment variables
@@ -25,7 +25,7 @@ import time
25
25
  try:
26
26
  # First, try to import the fetch_modal_tokens module
27
27
  from fetch_modal_tokens import get_tokens
28
- TOKEN_ID, TOKEN_SECRET = get_tokens()
28
+ TOKEN_ID, TOKEN_SECRET, _, _ = get_tokens()
29
29
  print(f"✅ Using tokens from proxy server or defaults")
30
30
  except ImportError:
31
31
  # If the module is not available, use hardcoded tokens