gitarsenal-cli 1.9.21 → 1.9.24

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.
Files changed (34) hide show
  1. package/.venv_status.json +1 -1
  2. package/package.json +1 -1
  3. package/python/__pycache__/auth_manager.cpython-313.pyc +0 -0
  4. package/python/__pycache__/command_manager.cpython-313.pyc +0 -0
  5. package/python/__pycache__/fetch_modal_tokens.cpython-313.pyc +0 -0
  6. package/python/__pycache__/llm_debugging.cpython-313.pyc +0 -0
  7. package/python/__pycache__/modal_container.cpython-313.pyc +0 -0
  8. package/python/__pycache__/shell.cpython-313.pyc +0 -0
  9. package/python/api_integration.py +0 -0
  10. package/python/command_manager.py +613 -0
  11. package/python/credentials_manager.py +0 -0
  12. package/python/fetch_modal_tokens.py +0 -0
  13. package/python/fix_modal_token.py +0 -0
  14. package/python/fix_modal_token_advanced.py +0 -0
  15. package/python/gitarsenal.py +0 -0
  16. package/python/gitarsenal_proxy_client.py +0 -0
  17. package/python/llm_debugging.py +1369 -0
  18. package/python/modal_container.py +626 -0
  19. package/python/setup.py +15 -0
  20. package/python/setup_modal_token.py +0 -39
  21. package/python/shell.py +627 -0
  22. package/python/test_modalSandboxScript.py +75 -2639
  23. package/scripts/postinstall.js +22 -23
  24. package/python/__pycache__/credentials_manager.cpython-313.pyc +0 -0
  25. package/python/__pycache__/test_modalSandboxScript.cpython-313.pyc +0 -0
  26. package/python/__pycache__/test_modalSandboxScript_stable.cpython-313.pyc +0 -0
  27. package/python/debug_delete.py +0 -167
  28. package/python/documentation.py +0 -76
  29. package/python/fix_setup_commands.py +0 -116
  30. package/python/modal_auth_patch.py +0 -178
  31. package/python/modal_proxy_service.py +0 -665
  32. package/python/modal_token_solution.py +0 -293
  33. package/python/test_dynamic_commands.py +0 -147
  34. package/test_modalSandboxScript.py +0 -5004
@@ -293,29 +293,28 @@ async function postinstall() {
293
293
  }
294
294
  }
295
295
 
296
- // Check if the original script exists
297
- if (!scriptFound && await fs.pathExists(originalScriptPath)) {
298
- console.log(chalk.green('✅ Found original Python script in mcp-server'));
299
- await fs.copy(originalScriptPath, pythonScriptPath);
300
- scriptFound = true;
301
- } else {
302
- // Try to find the script in common locations
303
- console.log(chalk.yellow('⚠️ Original script not found in expected location. Searching for alternatives...'));
304
-
305
- const possibleLocations = [
306
- path.join(process.cwd(), 'test_modalSandboxScript.py'),
307
- path.join(process.cwd(), 'mcp-server', 'src', 'utils', 'test_modalSandboxScript.py'),
308
- path.join(process.cwd(), 'src', 'utils', 'test_modalSandboxScript.py'),
309
- path.join(process.cwd(), 'utils', 'test_modalSandboxScript.py'),
310
- path.join(process.cwd(), 'scripts', 'test_modalSandboxScript.py')
311
- ];
312
-
313
- for (const location of possibleLocations) {
314
- if (await fs.pathExists(location)) {
315
- console.log(chalk.green(`✅ Found Python script at ${location}`));
316
- await fs.copy(location, pythonScriptPath);
317
- scriptFound = true;
318
- break;
296
+ // Only try to copy if the script doesn't exist or is minimal
297
+ if (!scriptFound) {
298
+ // Check if the original script exists in a different location
299
+ if (await fs.pathExists(originalScriptPath)) {
300
+ console.log(chalk.green('✅ Found original Python script in mcp-server'));
301
+ await fs.copy(originalScriptPath, pythonScriptPath);
302
+ scriptFound = true;
303
+ } else {
304
+ // Try to find the script in common locations
305
+ console.log(chalk.yellow('⚠️ Original script not found in expected location. Searching for alternatives...'));
306
+
307
+ const possibleLocations = [
308
+ path.join(process.cwd(), 'python', 'test_modalSandboxScript.py'),
309
+ ];
310
+
311
+ for (const location of possibleLocations) {
312
+ if (await fs.pathExists(location) && location !== pythonScriptPath) {
313
+ console.log(chalk.green(`✅ Found Python script at ${location}`));
314
+ await fs.copy(location, pythonScriptPath);
315
+ scriptFound = true;
316
+ break;
317
+ }
319
318
  }
320
319
  }
321
320
  }
@@ -1,167 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Debug script for GitArsenal Keys delete functionality
4
- """
5
-
6
- import sys
7
- import os
8
- from pathlib import Path
9
-
10
- # Add the current directory to the path
11
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
12
-
13
- from credentials_manager import CredentialsManager
14
- from gitarsenal_keys import handle_delete
15
-
16
- def test_delete_functionality():
17
- """Test the delete functionality step by step"""
18
- print("🔍 Debugging GitArsenal Keys Delete Functionality")
19
- print("=" * 60)
20
-
21
- # Initialize credentials manager
22
- credentials_manager = CredentialsManager()
23
-
24
- print(f"📁 Credentials file: {credentials_manager.credentials_file}")
25
- print(f"📁 Config directory: {credentials_manager.config_dir}")
26
-
27
- # Check if credentials file exists
28
- if credentials_manager.credentials_file.exists():
29
- print("✅ Credentials file exists")
30
- else:
31
- print("❌ Credentials file does not exist")
32
- return
33
-
34
- # Load current credentials
35
- credentials = credentials_manager.load_credentials()
36
- print(f"📋 Current credentials: {list(credentials.keys())}")
37
-
38
- # Test different service mappings
39
- test_services = ['openai', 'wandb', 'huggingface', 'gitarsenal-openai', 'claude']
40
-
41
- for service in test_services:
42
- print(f"\n🔍 Testing service: {service}")
43
-
44
- # Generate credential key from service name
45
- credential_key = f"{service.replace('-', '_')}_api_key"
46
-
47
- # Special mappings for backward compatibility
48
- special_mappings = {
49
- 'openai': 'openai_api_key',
50
- 'wandb': 'wandb_api_key',
51
- 'huggingface': 'huggingface_token',
52
- 'gitarsenal-openai': 'gitarsenal_openai_api_key'
53
- }
54
-
55
- # Use special mapping if it exists, otherwise use generated key
56
- credential_key = special_mappings.get(service, credential_key)
57
-
58
- print(f" Service: {service}")
59
- print(f" Generated key: {service.replace('-', '_')}_api_key")
60
- print(f" Final key: {credential_key}")
61
- print(f" Exists in credentials: {credential_key in credentials}")
62
-
63
- if credential_key in credentials:
64
- print(f" Current value: {credentials[credential_key][:8]}...")
65
-
66
- # Test the clear_credential method directly
67
- print(f"\n🧪 Testing clear_credential method directly")
68
-
69
- # Try to delete a key that exists
70
- existing_keys = list(credentials.keys())
71
- if existing_keys:
72
- test_key = existing_keys[0]
73
- print(f" Testing deletion of: {test_key}")
74
-
75
- # Check if key exists before deletion
76
- before_delete = test_key in credentials
77
- print(f" Key exists before deletion: {before_delete}")
78
-
79
- # Delete the key
80
- success = credentials_manager.clear_credential(test_key)
81
- print(f" Deletion success: {success}")
82
-
83
- # Check if key exists after deletion
84
- credentials_after = credentials_manager.load_credentials()
85
- after_delete = test_key in credentials_after
86
- print(f" Key exists after deletion: {after_delete}")
87
-
88
- # Restore the key for testing
89
- if not after_delete and before_delete:
90
- credentials_after[test_key] = credentials[test_key]
91
- credentials_manager.save_credentials(credentials_after)
92
- print(f" ✅ Key restored for further testing")
93
-
94
- # Test with a non-existent key
95
- print(f"\n🧪 Testing deletion of non-existent key")
96
- fake_key = "fake_api_key_12345"
97
- success = credentials_manager.clear_credential(fake_key)
98
- print(f" Deletion of non-existent key success: {success}")
99
-
100
- print(f"\n✅ Debug test completed!")
101
-
102
- def test_delete_command():
103
- """Test the delete command with mock arguments"""
104
- print(f"\n🔧 Testing delete command with mock arguments")
105
- print("=" * 60)
106
-
107
- from gitarsenal_keys import handle_delete
108
- import argparse
109
-
110
- # Create mock arguments
111
- class MockArgs:
112
- def __init__(self, service):
113
- self.service = service
114
-
115
- # Test with different services
116
- test_services = ['openai', 'wandb', 'huggingface']
117
-
118
- for service in test_services:
119
- print(f"\n🔍 Testing delete command for: {service}")
120
-
121
- try:
122
- args = MockArgs(service)
123
- handle_delete(None, args) # This will fail because we need a real credentials manager
124
- except Exception as e:
125
- print(f" Error: {e}")
126
-
127
- print(f"\n✅ Delete command test completed!")
128
-
129
- def show_usage_examples():
130
- """Show how to use the delete command"""
131
- print(f"\n📋 Usage Examples")
132
- print("=" * 60)
133
-
134
- print("To delete an API key:")
135
- print(" python gitarsenal_keys.py delete --service openai")
136
- print(" python gitarsenal_keys.py delete --service wandb")
137
- print(" python gitarsenal_keys.py delete --service huggingface")
138
- print(" python gitarsenal_keys.py delete --service gitarsenal-openai")
139
-
140
- print("\nTo list all stored keys:")
141
- print(" python gitarsenal_keys.py list")
142
-
143
- print("\nTo view a specific key (masked):")
144
- print(" python gitarsenal_keys.py view --service openai")
145
-
146
- print("\nTo add a new key:")
147
- print(" python gitarsenal_keys.py add --service openai --key sk-...")
148
- print(" python gitarsenal_keys.py add --service openai # Interactive mode")
149
-
150
- if __name__ == "__main__":
151
- print("GitArsenal Keys Delete Debug Tool")
152
- print("=" * 60)
153
-
154
- try:
155
- test_delete_functionality()
156
- test_delete_command()
157
- show_usage_examples()
158
-
159
- print(f"\n🎉 Debug completed!")
160
- print(f"\nTo test the actual delete command:")
161
- print(f" python gitarsenal_keys.py delete --service openai")
162
-
163
- except Exception as e:
164
- print(f"\n❌ Debug failed with error: {e}")
165
- import traceback
166
- traceback.print_exc()
167
- sys.exit(1)
@@ -1,76 +0,0 @@
1
- def show_usage_examples():
2
- """Display usage examples for the script."""
3
- print("Usage Examples\n")
4
-
5
- print("🔐 Authentication Commands")
6
- print("┌────────────────────────────────────────────────────────────────────────────────────┐")
7
- print("│ gitarsenal --register # Register new account │")
8
- print("│ gitarsenal --login # Login to existing account │")
9
- print("│ gitarsenal --logout # Logout from account │")
10
- print("│ gitarsenal --user-info # Show current user information │")
11
- print("│ gitarsenal --change-password # Change password │")
12
- print("│ gitarsenal --delete-account # Delete account │")
13
- print("│ gitarsenal --store-api-key openai # Store OpenAI API key │")
14
- print("│ gitarsenal --auth # Interactive auth management │")
15
- print("└────────────────────────────────────────────────────────────────────────────────────┘\n")
16
-
17
- print("Basic Container Creation")
18
- print("┌────────────────────────────────────────────────────────────────────────┐")
19
- print("│ gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git │")
20
- print("└────────────────────────────────────────────────────────────────────────┘\n")
21
-
22
- print("With Setup Commands")
23
- print("┌────────────────────────────────────────────────────────────────────────────────────────────────────┐")
24
- print("│ gitarsenal --gpu A100 --repo-url https://github.com/username/repo.git \\ │")
25
- print("│ --setup-commands \"pip install -r requirements.txt\" \"python setup.py install\" │")
26
- print("└────────────────────────────────────────────────────────────────────────────────────────────────────┘\n")
27
-
28
- print("With Persistent Storage")
29
- print("┌────────────────────────────────────────────────────────────────────────────────────┐")
30
- print("│ gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git \\ │")
31
- print("│ --volume-name my-persistent-volume │")
32
- print("└────────────────────────────────────────────────────────────────────────────────────┘\n")
33
-
34
- print("With GitIngest API (default)")
35
- print("┌────────────────────────────────────────────────────────────────────────────────────┐")
36
- print("│ gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git │")
37
- print("└────────────────────────────────────────────────────────────────────────────────────┘\n")
38
-
39
- print("Without GitIngest API")
40
- print("┌────────────────────────────────────────────────────────────────────────────────────┐")
41
- print("│ gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git \\ │")
42
- print("│ --no-gitingest │")
43
- print("└────────────────────────────────────────────────────────────────────────────────────┘\n")
44
-
45
- print("With Original API")
46
- print("┌────────────────────────────────────────────────────────────────────────────────────┐")
47
- print("│ gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git \\ │")
48
- print("│ --use-api │")
49
- print("└────────────────────────────────────────────────────────────────────────────────────┘\n")
50
-
51
- print("Development Mode (Skip Authentication)")
52
- print("┌────────────────────────────────────────────────────────────────────────────────────┐")
53
- print("│ gitarsenal --skip-auth --gpu A10G --repo-url https://github.com/username/repo.git │")
54
- print("└────────────────────────────────────────────────────────────────────────────────────┘\n")
55
-
56
- print("Available GPU Options:")
57
- print(" T4, L4, A10G, A100-40GB, A100-80GB, L40S, H100, H200, B200")
58
- print()
59
- print("Authentication Behavior:")
60
- print(" • First time: Interactive registration/login required")
61
- print(" • Subsequent runs: Automatic login with stored session")
62
- print(" • Use --skip-auth for development (bypasses auth)")
63
- print()
64
- print("GPU Selection Behavior:")
65
- print(" • With --gpu: Uses specified GPU without prompting")
66
- print(" • Without --gpu: Shows interactive GPU selection menu")
67
- print()
68
- print("Examples:")
69
- print(" # First time setup (will prompt for registration):")
70
- print(" gitarsenal --gpu A10G --repo-url https://github.com/username/repo.git")
71
- print()
72
- print(" # Subsequent runs (automatic login):")
73
- print(" gitarsenal --repo-url https://github.com/username/repo.git")
74
- print()
75
- print(" # Development mode (skip authentication):")
76
- print(" gitarsenal --skip-auth --repo-url https://github.com/username/repo.git")
@@ -1,116 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Fix setup commands for open-r1 repository
4
- """
5
-
6
- import os
7
- import sys
8
- import subprocess
9
-
10
- # Original problematic commands
11
- original_commands = [
12
- "git clone https://github.com/huggingface/open-r1.git",
13
- "cd open-r1",
14
- "uv venv openr1 --python 3.11 && source openr1/bin/activate && uv pip install --upgrade pip",
15
- "uv pip install vllm==0.8.5.post1",
16
- "uv pip install setuptools && uv pip install flash-attn --no-build-isolation"
17
- ]
18
-
19
- # Fixed commands
20
- fixed_commands = [
21
- "git clone https://github.com/huggingface/open-r1.git",
22
- "cd open-r1",
23
- "uv venv openr1 --python 3.11 && . openr1/bin/activate && uv pip install --upgrade pip",
24
- ". openr1/bin/activate && uv pip install vllm==0.8.5.post1",
25
- ". openr1/bin/activate && uv pip install setuptools && uv pip install flash-attn --no-build-isolation"
26
- ]
27
-
28
- def run_command(cmd, cwd=None):
29
- """Run a command and return the result"""
30
- print(f"\n▶ {cmd}")
31
-
32
- try:
33
- result = subprocess.run(
34
- cmd,
35
- shell=True,
36
- text=True,
37
- capture_output=True,
38
- cwd=cwd
39
- )
40
-
41
- # Print output
42
- if result.stdout:
43
- print(result.stdout)
44
-
45
- # Print error
46
- if result.stderr:
47
- print(f"Error: {result.stderr}")
48
-
49
- # Return success/failure
50
- return result.returncode == 0, result.stdout, result.stderr
51
- except Exception as e:
52
- print(f"Error executing command: {e}")
53
- return False, "", str(e)
54
-
55
- def main():
56
- """Main function"""
57
- print("🔧 Fixing setup commands for open-r1 repository")
58
-
59
- # Check if we're in the right directory
60
- cwd = os.getcwd()
61
- print(f"📂 Current directory: {cwd}")
62
-
63
- # Check if we need to change directory
64
- if not cwd.endswith('open-r1'):
65
- parent_dir = cwd
66
- # Check if open-r1 exists in the current directory
67
- if os.path.exists(os.path.join(cwd, 'open-r1')):
68
- print(f"📂 Found open-r1 directory, changing to it")
69
- os.chdir(os.path.join(cwd, 'open-r1'))
70
- cwd = os.getcwd()
71
- print(f"📂 New current directory: {cwd}")
72
-
73
- # Run the fixed commands
74
- for i, cmd in enumerate(fixed_commands):
75
- print(f"\n📋 Running command {i+1}/{len(fixed_commands)}: {cmd}")
76
-
77
- # Skip git clone if the directory already exists
78
- if cmd.startswith("git clone") and os.path.exists("open-r1"):
79
- print("✅ Repository already cloned, skipping")
80
- continue
81
-
82
- # Skip cd if we're already in the right directory
83
- if cmd.startswith("cd "):
84
- target_dir = cmd.split(" ", 1)[1]
85
- if cwd.endswith(target_dir):
86
- print(f"✅ Already in {target_dir}, skipping")
87
- continue
88
-
89
- # Run the command
90
- success, stdout, stderr = run_command(cmd)
91
-
92
- # Check if the command succeeded
93
- if not success:
94
- print(f"❌ Command failed: {cmd}")
95
- print(f"❌ Error: {stderr}")
96
-
97
- # If this is a cd command, try to continue
98
- if cmd.startswith("cd "):
99
- print("⚠️ Directory change failed, but continuing with next command")
100
- continue
101
-
102
- # For other commands, ask if the user wants to continue
103
- try:
104
- choice = input("Continue with next command? (y/n): ").strip().lower()
105
- if choice != 'y':
106
- print("🛑 Stopping execution")
107
- return 1
108
- except:
109
- print("🛑 Stopping execution due to error")
110
- return 1
111
-
112
- print("\n✅ All commands executed")
113
- return 0
114
-
115
- if __name__ == "__main__":
116
- sys.exit(main())
@@ -1,178 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Modal Authentication Patcher
4
-
5
- This script directly patches Modal's authentication system to always return our token.
6
- It should be imported before any Modal code is used.
7
-
8
- Usage:
9
- import modal_auth_patch
10
- import modal
11
- # Now Modal will use our token
12
- """
13
-
14
- import os
15
- import sys
16
- import importlib
17
- import types
18
- import json
19
- from pathlib import Path
20
-
21
- # Try to get tokens from the proxy server
22
- try:
23
- # First, try to import the fetch_modal_tokens module
24
- from fetch_modal_tokens import get_tokens
25
- TOKEN_ID, TOKEN_SECRET, _, _ = get_tokens()
26
- print(f"✅ Using tokens from proxy server or defaults")
27
- except ImportError:
28
- # If the module is not available, use hardcoded tokens
29
- # print(f"⚠️ Using default tokens")
30
-
31
- # Set environment variables
32
- os.environ["MODAL_TOKEN_ID"] = TOKEN_ID
33
- os.environ["MODAL_TOKEN_SECRET"] = TOKEN_SECRET
34
-
35
- # Create token files
36
- modal_dir = Path.home() / ".modal"
37
- modal_dir.mkdir(exist_ok=True)
38
- token_file = modal_dir / "token.json"
39
- with open(token_file, 'w') as f:
40
- f.write(f'{{"token_id": "{TOKEN_ID}", "token_secret": "{TOKEN_SECRET}"}}')
41
-
42
- modalconfig_file = Path.home() / ".modalconfig"
43
- with open(modalconfig_file, 'w') as f:
44
- f.write(f"token_id = {TOKEN_ID}\n")
45
- f.write(f"token_secret = {TOKEN_SECRET}\n")
46
-
47
- # Define functions that will always return our tokens
48
- def get_token_id(*args, **kwargs):
49
- return TOKEN_ID
50
-
51
- def get_token_secret(*args, **kwargs):
52
- return TOKEN_SECRET
53
-
54
- # Patch Modal's authentication system
55
- try:
56
- # Try to import modal.config
57
- import modal.config
58
-
59
- # Create a fake auth config object
60
- class FakeAuthConfig:
61
- token_id = TOKEN_ID
62
- token_secret = TOKEN_SECRET
63
-
64
- def get_token_id(self, *args, **kwargs):
65
- return TOKEN_ID
66
-
67
- def get_token_secret(self, *args, **kwargs):
68
- return TOKEN_SECRET
69
-
70
- # Replace Modal's auth config with our fake one
71
- modal.config._auth_config = FakeAuthConfig()
72
-
73
- # Also patch any token-related functions
74
- for name in dir(modal.config):
75
- if "token_id" in name.lower():
76
- try:
77
- attr = getattr(modal.config, name)
78
- if callable(attr):
79
- setattr(modal.config, name, get_token_id)
80
- except:
81
- pass
82
- elif "token_secret" in name.lower() or "token" in name.lower():
83
- try:
84
- attr = getattr(modal.config, name)
85
- if callable(attr):
86
- setattr(modal.config, name, get_token_secret)
87
- except:
88
- pass
89
-
90
- print("✅ Modal authentication patched successfully")
91
- except ImportError:
92
- # Modal not installed yet, we'll monkey-patch it when it's imported
93
- print("⚠️ Modal not installed yet, setting up import hook")
94
-
95
- # Original import function
96
- original_import = __import__
97
-
98
- # Our custom import function
99
- def custom_import(name, globals=None, locals=None, fromlist=(), level=0):
100
- # Call the original import function
101
- module = original_import(name, globals, locals, fromlist, level)
102
-
103
- # Check if this is modal or a submodule
104
- if name == "modal" or name.startswith("modal."):
105
- try:
106
- # Try to patch modal.config
107
- if hasattr(module, "config"):
108
- config = module.config
109
-
110
- # Create a fake auth config object if needed
111
- if not hasattr(config, "_auth_config"):
112
- class FakeAuthConfig:
113
- token_id = TOKEN_ID
114
- token_secret = TOKEN_SECRET
115
-
116
- def get_token_id(self, *args, **kwargs):
117
- return TOKEN_ID
118
-
119
- def get_token_secret(self, *args, **kwargs):
120
- return TOKEN_SECRET
121
-
122
- config._auth_config = FakeAuthConfig()
123
- else:
124
- # Patch existing auth config
125
- config._auth_config.token_id = TOKEN_ID
126
- config._auth_config.token_secret = TOKEN_SECRET
127
-
128
- # Patch methods
129
- if hasattr(config._auth_config, "get_token_id"):
130
- config._auth_config.get_token_id = get_token_id
131
- if hasattr(config._auth_config, "get_token_secret"):
132
- config._auth_config.get_token_secret = get_token_secret
133
-
134
- # Also patch any token-related functions
135
- for name in dir(config):
136
- if "token_id" in name.lower():
137
- try:
138
- attr = getattr(config, name)
139
- if callable(attr):
140
- setattr(config, name, get_token_id)
141
- except:
142
- pass
143
- elif "token_secret" in name.lower() or "token" in name.lower():
144
- try:
145
- attr = getattr(config, name)
146
- if callable(attr):
147
- setattr(config, name, get_token_secret)
148
- except:
149
- pass
150
-
151
- print("✅ Modal authentication patched during import")
152
- except Exception as e:
153
- print(f"⚠️ Error patching Modal: {e}")
154
-
155
- return module
156
-
157
- # Replace the built-in import function
158
- sys.modules["builtins"].__import__ = custom_import
159
-
160
- print("✅ Modal authentication patch installed")
161
-
162
- # Test the patch if Modal is already imported
163
- try:
164
- import modal
165
- print("Testing Modal authentication patch...")
166
-
167
- # Create a simple app
168
- app = modal.App("test-auth-patch")
169
-
170
- @app.function()
171
- def hello():
172
- return "Hello from patched Modal!"
173
-
174
- print("✅ Modal app created successfully")
175
- except ImportError:
176
- print("⚠️ Modal not installed, patch will be applied when it's imported")
177
- except Exception as e:
178
- print(f"❌ Error testing Modal patch: {e}")