gitarsenal-cli 1.9.11 โ†’ 1.9.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/.venv_status.json CHANGED
@@ -1 +1 @@
1
- {"created":"2025-08-04T14:50:01.089Z","packages":["modal","gitingest","requests"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
1
+ {"created":"2025-08-06T07:22:37.370Z","packages":["modal","gitingest","requests"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
package/bin/gitarsenal.js CHANGED
@@ -347,6 +347,7 @@ program.parse(process.argv);
347
347
 
348
348
  async function runContainerCommand(options) {
349
349
  try {
350
+ console.log(chalk.blue('๐Ÿ” DEBUG: runContainerCommand called with options:'), options);
350
351
  // If show-examples flag is set, just show examples and exit
351
352
  if (options.showExamples) {
352
353
  await runContainer({
@@ -491,6 +492,7 @@ async function runContainerCommand(options) {
491
492
  }
492
493
 
493
494
  // Confirm settings (configuration will be shown by Python script after GPU selection)
495
+ console.log(chalk.gray(`๐Ÿ” Debug: skipConfirmation = ${skipConfirmation}, options.yes = ${options.yes}`));
494
496
  if (!skipConfirmation) {
495
497
  const confirmAnswers = await inquirer.prompt([
496
498
  {
@@ -512,12 +514,14 @@ async function runContainerCommand(options) {
512
514
 
513
515
  // Run the container
514
516
  try {
517
+ console.log(chalk.gray(`๐Ÿ” Debug: skipConfirmation = ${skipConfirmation}`));
515
518
  await runContainer({
516
519
  repoUrl,
517
520
  gpuType,
518
521
  volumeName,
519
522
  setupCommands,
520
- useApi
523
+ useApi,
524
+ yes: skipConfirmation
521
525
  });
522
526
 
523
527
  } catch (containerError) {
package/lib/sandbox.js CHANGED
@@ -43,7 +43,8 @@ async function runContainer(options) {
43
43
  volumeName,
44
44
  setupCommands = [],
45
45
  useApi = true,
46
- showExamples = false
46
+ showExamples = false,
47
+ yes = false
47
48
  } = options;
48
49
 
49
50
  // Get the path to the Python script
@@ -100,6 +101,12 @@ async function runContainer(options) {
100
101
  args.push('--use-api');
101
102
  }
102
103
 
104
+ // Add --yes flag to skip confirmation prompts
105
+ if (yes) {
106
+ args.push('--yes');
107
+ console.log(chalk.gray(`๐Ÿ” Debug: Adding --yes flag to Python script`));
108
+ }
109
+
103
110
  // Handle manual setup commands if provided
104
111
  if (setupCommands.length > 0) {
105
112
  // Create a temporary file to store setup commands
@@ -110,6 +117,7 @@ async function runContainer(options) {
110
117
 
111
118
  // Log the command being executed
112
119
  console.log(chalk.dim(`\nExecuting: python ${args.join(' ')}`));
120
+ console.log(chalk.gray(`๐Ÿ” Debug: yes parameter = ${yes}`));
113
121
 
114
122
  // Run the Python script without spinner to avoid terminal interference
115
123
  console.log(chalk.dim('Launching container...'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitarsenal-cli",
3
- "version": "1.9.11",
3
+ "version": "1.9.13",
4
4
  "description": "CLI tool for creating Modal sandboxes with GitHub repositories",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -0,0 +1,76 @@
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")
@@ -4,4 +4,5 @@ pathlib>=1.0.1
4
4
  python-dotenv>=1.0.0
5
5
  flask>=2.0.0
6
6
  flask-cors>=3.0.0
7
- pexpect>=4.8.0
7
+ pexpect>=4.8.0
8
+ anthropic>=0.18.0
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test script to verify Claude fallback functionality
4
+ """
5
+
6
+ import os
7
+ import sys
8
+
9
+ # Add the current directory to the path so we can import the main module
10
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
11
+
12
+ def test_claude_fallback():
13
+ """Test the Claude fallback functionality"""
14
+ print("๐Ÿงช Testing Claude fallback functionality...")
15
+
16
+ # Test 1: Check if anthropic is imported correctly
17
+ try:
18
+ from test_modalSandboxScript import anthropic
19
+ if anthropic is not None:
20
+ print("โœ… Anthropic library imported successfully")
21
+ else:
22
+ print("โš ๏ธ Anthropic library not available")
23
+ except ImportError as e:
24
+ print(f"โŒ Failed to import anthropic: {e}")
25
+ return False
26
+
27
+ # Test 2: Check if ANTHROPIC_API_KEY is set
28
+ anthropic_api_key = os.environ.get("ANTHROPIC_API_KEY")
29
+ if anthropic_api_key:
30
+ print("โœ… ANTHROPIC_API_KEY found in environment")
31
+ else:
32
+ print("โš ๏ธ ANTHROPIC_API_KEY not found in environment")
33
+ print("๐Ÿ’ก Set ANTHROPIC_API_KEY to test Claude functionality")
34
+
35
+ # Test 3: Test a simple Claude API call
36
+ if anthropic is not None and anthropic_api_key:
37
+ try:
38
+ client = anthropic.Anthropic(api_key=anthropic_api_key)
39
+ message = client.messages.create(
40
+ model="claude-3-5-sonnet-20241022",
41
+ max_tokens=50,
42
+ messages=[
43
+ {"role": "user", "content": "Hello, please respond with 'Claude is working!'"}
44
+ ]
45
+ )
46
+ response = message.content[0].text.strip()
47
+ print(f"โœ… Claude API test successful: {response}")
48
+ return True
49
+ except Exception as e:
50
+ print(f"โŒ Claude API test failed: {e}")
51
+ return False
52
+ else:
53
+ print("โš ๏ธ Skipping Claude API test (missing library or API key)")
54
+ return False
55
+
56
+ def test_openai_fallback():
57
+ """Test the OpenAI fallback functionality"""
58
+ print("\n๐Ÿงช Testing OpenAI fallback functionality...")
59
+
60
+ # Test 1: Check if OpenAI API key is set
61
+ openai_api_key = os.environ.get("OPENAI_API_KEY")
62
+ if openai_api_key:
63
+ print("โœ… OPENAI_API_KEY found in environment")
64
+ else:
65
+ print("โš ๏ธ OPENAI_API_KEY not found in environment")
66
+ print("๐Ÿ’ก Set OPENAI_API_KEY to test OpenAI functionality")
67
+
68
+ # Test 2: Test a simple OpenAI API call
69
+ if openai_api_key:
70
+ try:
71
+ import openai
72
+ client = openai.OpenAI(api_key=openai_api_key)
73
+ response = client.chat.completions.create(
74
+ model="gpt-3.5-turbo",
75
+ messages=[
76
+ {"role": "user", "content": "Hello, please respond with 'OpenAI is working!'"}
77
+ ],
78
+ max_tokens=50
79
+ )
80
+ response_text = response.choices[0].message.content.strip()
81
+ print(f"โœ… OpenAI API test successful: {response_text}")
82
+ return True
83
+ except Exception as e:
84
+ print(f"โŒ OpenAI API test failed: {e}")
85
+ return False
86
+ else:
87
+ print("โš ๏ธ Skipping OpenAI API test (missing API key)")
88
+ return False
89
+
90
+ def main():
91
+ """Main test function"""
92
+ print("๐Ÿš€ Starting Claude fallback tests...")
93
+ print("=" * 50)
94
+
95
+ claude_success = test_claude_fallback()
96
+ openai_success = test_openai_fallback()
97
+
98
+ print("\n" + "=" * 50)
99
+ print("๐Ÿ“Š Test Results:")
100
+ print(f"Claude API: {'โœ… Working' if claude_success else 'โŒ Failed'}")
101
+ print(f"OpenAI API: {'โœ… Working' if openai_success else 'โŒ Failed'}")
102
+
103
+ if claude_success and openai_success:
104
+ print("\n๐ŸŽ‰ Both APIs are working! Claude fallback is ready.")
105
+ elif claude_success:
106
+ print("\nโœ… Claude API is working! Can be used as fallback.")
107
+ elif openai_success:
108
+ print("\nโœ… OpenAI API is working! Claude fallback will be used when OpenAI fails.")
109
+ else:
110
+ print("\nโŒ Neither API is working. Please check your API keys.")
111
+
112
+ print("\n๐Ÿ’ก To test the fallback functionality:")
113
+ print("1. Set both OPENAI_API_KEY and ANTHROPIC_API_KEY")
114
+ print("2. Run the main script with a failing command")
115
+ print("3. Watch for '๐Ÿ”„ Trying Claude-4-Sonnet as fallback...' messages")
116
+
117
+ if __name__ == "__main__":
118
+ main()