godfather-cli 1.0.1__tar.gz

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.
@@ -0,0 +1,3 @@
1
+ include README.md
2
+ include LICENSE
3
+ recursive-include godfather_cli *.py
@@ -0,0 +1,212 @@
1
+ Metadata-Version: 2.4
2
+ Name: godfather-cli
3
+ Version: 1.0.1
4
+ Summary: AI Society Godfather CLI - RunPod Environment Manager
5
+ Author-email: AI Society ASU <theaisocietyasu@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/theaisocietyasu/godfather
8
+ Project-URL: Repository, https://github.com/theaisocietyasu/godfather
9
+ Project-URL: Issues, https://github.com/theaisocietyasu/godfather/issues
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.7
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Requires-Python: >=3.7
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: requests>=2.25.0
22
+ Requires-Dist: rich>=13.0.0
23
+
24
+ # Godfather CLI
25
+
26
+ Beautiful command-line interface for managing AI Society ASU RunPod environments.
27
+
28
+ ![CLI Demo](https://img.shields.io/badge/python-3.7+-blue.svg)
29
+ ![License](https://img.shields.io/badge/license-MIT-green.svg)
30
+
31
+ ## ✨ Features
32
+
33
+ - 🎨 **Beautiful Interface** - Rich terminal UI with colors, tables, and panels
34
+ - 🔐 **Secure Authentication** - Discord-based authentication
35
+ - 🚀 **Pod Management** - List and connect to available RunPod environments
36
+ - 🔌 **SSH Integration** - Automatic SSH key setup and connection
37
+ - 📊 **Status Monitoring** - Check authentication and configuration status
38
+
39
+ ## 📦 Installation
40
+
41
+ ### Option 1: Install from PyPI (Recommended)
42
+
43
+ ```bash
44
+ pip install godfather-cli
45
+ ```
46
+
47
+ ### Option 2: Install from GitHub
48
+
49
+ ```bash
50
+ pip install git+https://github.com/theaisocietyasu/godfather.git#subdirectory=cli
51
+ ```
52
+
53
+ ### Option 3: Install for Development
54
+
55
+ ```bash
56
+ git clone https://github.com/theaisocietyasu/godfather.git
57
+ cd godfather/cli
58
+ pip install -e .
59
+ ```
60
+
61
+ ## 🚀 Quick Start
62
+
63
+ 1. **Run the CLI**:
64
+ ```bash
65
+ godfather
66
+ ```
67
+
68
+ 2. **Authenticate**:
69
+ - Visit the admin portal to get your authentication token
70
+ - Paste the token when prompted
71
+
72
+ 3. **Connect to a Pod**:
73
+ - Select option `2` to connect to a pod
74
+ - Choose from available pods
75
+ - Automatically SSH into your isolated workspace
76
+
77
+ ## 📖 Usage
78
+
79
+ ### Interactive Menu
80
+
81
+ Simply run:
82
+ ```bash
83
+ godfather
84
+ ```
85
+
86
+ You'll see a beautiful menu:
87
+ ```
88
+ ╔═══════════════════════════════════════╗
89
+ ║ Godfather CLI ║
90
+ ║ AI Society RunPod Environment Manager ║
91
+ ╚═══════════════════════════════════════╝
92
+
93
+ ╭──────── What would you like to do? ──────────╮
94
+ │ 1. 📋 List available pods │
95
+ │ 2. 🔌 Connect to a pod │
96
+ │ 3. 📊 Show status │
97
+ │ 4. 🚪 Logout │
98
+ │ 5. 👋 Exit │
99
+ ╰──────────────────────────────────────────────╯
100
+ ```
101
+
102
+ ### Command-Line Interface
103
+
104
+ ```bash
105
+ # List available pods
106
+ godfather list
107
+
108
+ # Connect to a specific pod
109
+ godfather connect <pod-id>
110
+
111
+ # Connect interactively
112
+ godfather connect
113
+
114
+ # Show CLI status
115
+ godfather status
116
+
117
+ # Logout
118
+ godfather logout
119
+
120
+ # Re-authenticate
121
+ godfather auth
122
+
123
+ # Use custom API URL
124
+ godfather --api-url https://your-api.com list
125
+ ```
126
+
127
+ ## 🔑 Authentication
128
+
129
+ 1. Get your authentication token from: `https://your-godfather-instance.com/cli-auth`
130
+ 2. Run `godfather` or `godfather auth`
131
+ 3. Paste your token when prompted
132
+ 4. Token is securely stored in `~/.godfather/config.json`
133
+
134
+ ## 🛠️ Configuration
135
+
136
+ Configuration is stored in `~/.godfather/config.json`:
137
+
138
+ ```json
139
+ {
140
+ "token": "discord_<user_id>_<timestamp>",
141
+ "discord_user_id": "<your_discord_id>"
142
+ }
143
+ ```
144
+
145
+ ### Environment Variables
146
+
147
+ You can override the API URL with:
148
+
149
+ ```bash
150
+ export GODFATHER_API_URL="https://your-api.com"
151
+ # or
152
+ export BACKEND_URL="https://your-api.com"
153
+ # or
154
+ export NEXT_PUBLIC_BACKEND_URL="https://your-api.com"
155
+ ```
156
+
157
+ ## 🎨 Features in Detail
158
+
159
+ ### Beautiful Tables
160
+
161
+ Pod listings display in rich, colorful tables:
162
+
163
+ ```
164
+ 🚀 Available Pods (3)
165
+ ╭───┬────────┬─────────────┬──────────────┬───────────╮
166
+ │ # │ Status │ Name │ ID │ Created │
167
+ ├───┼────────┼─────────────┼──────────────┼───────────┤
168
+ │ 1 │ 🟢 RUN │ ml-training │ abc123def... │ 2 days ago│
169
+ │ 2 │ 🟢 RUN │ gpu-dev │ xyz789ghi... │ 1 week ago│
170
+ │ 3 │ 🔴 OFF │ testing │ jkl456mno... │ 3 days ago│
171
+ ╰───┴────────┴─────────────┴──────────────┴───────────╯
172
+ ```
173
+
174
+ ### Status Dashboard
175
+
176
+ ```
177
+ Godfather CLI Status
178
+ ╭─────────────────────┬─────────────────────────────╮
179
+ │ 🔐 Authentication │ ✓ Authenticated │
180
+ │ 🌐 API Connection │ ✓ Connected │
181
+ │ 🏠 Config Directory │ /home/user/.godfather │
182
+ │ 🔗 API Endpoint │ https://api.example.com │
183
+ ╰─────────────────────┴─────────────────────────────╯
184
+ ```
185
+
186
+ ## 🤝 Contributing
187
+
188
+ Contributions are welcome! Please feel free to submit a Pull Request.
189
+
190
+ 1. Fork the repository
191
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
192
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
193
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
194
+ 5. Open a Pull Request
195
+
196
+ ## 📝 License
197
+
198
+ This project is licensed under the MIT License - see the LICENSE file for details.
199
+
200
+ ## 🆘 Support
201
+
202
+ - **Issues**: [GitHub Issues](https://github.com/theaisocietyasu/godfather/issues)
203
+ - **Discord**: Contact AI Society ASU administrators
204
+ - **Email**: admin@ais-asu.com
205
+
206
+ ## 🎓 About
207
+
208
+ Built with ❤️ by [AI Society at Arizona State University](https://github.com/theaisocietyasu)
209
+
210
+ ---
211
+
212
+ **Note**: You need to be a member of the AI Society Discord server with appropriate permissions to use this CLI.
@@ -0,0 +1,189 @@
1
+ # Godfather CLI
2
+
3
+ Beautiful command-line interface for managing AI Society ASU RunPod environments.
4
+
5
+ ![CLI Demo](https://img.shields.io/badge/python-3.7+-blue.svg)
6
+ ![License](https://img.shields.io/badge/license-MIT-green.svg)
7
+
8
+ ## ✨ Features
9
+
10
+ - 🎨 **Beautiful Interface** - Rich terminal UI with colors, tables, and panels
11
+ - 🔐 **Secure Authentication** - Discord-based authentication
12
+ - 🚀 **Pod Management** - List and connect to available RunPod environments
13
+ - 🔌 **SSH Integration** - Automatic SSH key setup and connection
14
+ - 📊 **Status Monitoring** - Check authentication and configuration status
15
+
16
+ ## 📦 Installation
17
+
18
+ ### Option 1: Install from PyPI (Recommended)
19
+
20
+ ```bash
21
+ pip install godfather-cli
22
+ ```
23
+
24
+ ### Option 2: Install from GitHub
25
+
26
+ ```bash
27
+ pip install git+https://github.com/theaisocietyasu/godfather.git#subdirectory=cli
28
+ ```
29
+
30
+ ### Option 3: Install for Development
31
+
32
+ ```bash
33
+ git clone https://github.com/theaisocietyasu/godfather.git
34
+ cd godfather/cli
35
+ pip install -e .
36
+ ```
37
+
38
+ ## 🚀 Quick Start
39
+
40
+ 1. **Run the CLI**:
41
+ ```bash
42
+ godfather
43
+ ```
44
+
45
+ 2. **Authenticate**:
46
+ - Visit the admin portal to get your authentication token
47
+ - Paste the token when prompted
48
+
49
+ 3. **Connect to a Pod**:
50
+ - Select option `2` to connect to a pod
51
+ - Choose from available pods
52
+ - Automatically SSH into your isolated workspace
53
+
54
+ ## 📖 Usage
55
+
56
+ ### Interactive Menu
57
+
58
+ Simply run:
59
+ ```bash
60
+ godfather
61
+ ```
62
+
63
+ You'll see a beautiful menu:
64
+ ```
65
+ ╔═══════════════════════════════════════╗
66
+ ║ Godfather CLI ║
67
+ ║ AI Society RunPod Environment Manager ║
68
+ ╚═══════════════════════════════════════╝
69
+
70
+ ╭──────── What would you like to do? ──────────╮
71
+ │ 1. 📋 List available pods │
72
+ │ 2. 🔌 Connect to a pod │
73
+ │ 3. 📊 Show status │
74
+ │ 4. 🚪 Logout │
75
+ │ 5. 👋 Exit │
76
+ ╰──────────────────────────────────────────────╯
77
+ ```
78
+
79
+ ### Command-Line Interface
80
+
81
+ ```bash
82
+ # List available pods
83
+ godfather list
84
+
85
+ # Connect to a specific pod
86
+ godfather connect <pod-id>
87
+
88
+ # Connect interactively
89
+ godfather connect
90
+
91
+ # Show CLI status
92
+ godfather status
93
+
94
+ # Logout
95
+ godfather logout
96
+
97
+ # Re-authenticate
98
+ godfather auth
99
+
100
+ # Use custom API URL
101
+ godfather --api-url https://your-api.com list
102
+ ```
103
+
104
+ ## 🔑 Authentication
105
+
106
+ 1. Get your authentication token from: `https://your-godfather-instance.com/cli-auth`
107
+ 2. Run `godfather` or `godfather auth`
108
+ 3. Paste your token when prompted
109
+ 4. Token is securely stored in `~/.godfather/config.json`
110
+
111
+ ## 🛠️ Configuration
112
+
113
+ Configuration is stored in `~/.godfather/config.json`:
114
+
115
+ ```json
116
+ {
117
+ "token": "discord_<user_id>_<timestamp>",
118
+ "discord_user_id": "<your_discord_id>"
119
+ }
120
+ ```
121
+
122
+ ### Environment Variables
123
+
124
+ You can override the API URL with:
125
+
126
+ ```bash
127
+ export GODFATHER_API_URL="https://your-api.com"
128
+ # or
129
+ export BACKEND_URL="https://your-api.com"
130
+ # or
131
+ export NEXT_PUBLIC_BACKEND_URL="https://your-api.com"
132
+ ```
133
+
134
+ ## 🎨 Features in Detail
135
+
136
+ ### Beautiful Tables
137
+
138
+ Pod listings display in rich, colorful tables:
139
+
140
+ ```
141
+ 🚀 Available Pods (3)
142
+ ╭───┬────────┬─────────────┬──────────────┬───────────╮
143
+ │ # │ Status │ Name │ ID │ Created │
144
+ ├───┼────────┼─────────────┼──────────────┼───────────┤
145
+ │ 1 │ 🟢 RUN │ ml-training │ abc123def... │ 2 days ago│
146
+ │ 2 │ 🟢 RUN │ gpu-dev │ xyz789ghi... │ 1 week ago│
147
+ │ 3 │ 🔴 OFF │ testing │ jkl456mno... │ 3 days ago│
148
+ ╰───┴────────┴─────────────┴──────────────┴───────────╯
149
+ ```
150
+
151
+ ### Status Dashboard
152
+
153
+ ```
154
+ Godfather CLI Status
155
+ ╭─────────────────────┬─────────────────────────────╮
156
+ │ 🔐 Authentication │ ✓ Authenticated │
157
+ │ 🌐 API Connection │ ✓ Connected │
158
+ │ 🏠 Config Directory │ /home/user/.godfather │
159
+ │ 🔗 API Endpoint │ https://api.example.com │
160
+ ╰─────────────────────┴─────────────────────────────╯
161
+ ```
162
+
163
+ ## 🤝 Contributing
164
+
165
+ Contributions are welcome! Please feel free to submit a Pull Request.
166
+
167
+ 1. Fork the repository
168
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
169
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
170
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
171
+ 5. Open a Pull Request
172
+
173
+ ## 📝 License
174
+
175
+ This project is licensed under the MIT License - see the LICENSE file for details.
176
+
177
+ ## 🆘 Support
178
+
179
+ - **Issues**: [GitHub Issues](https://github.com/theaisocietyasu/godfather/issues)
180
+ - **Discord**: Contact AI Society ASU administrators
181
+ - **Email**: admin@ais-asu.com
182
+
183
+ ## 🎓 About
184
+
185
+ Built with ❤️ by [AI Society at Arizona State University](https://github.com/theaisocietyasu)
186
+
187
+ ---
188
+
189
+ **Note**: You need to be a member of the AI Society Discord server with appropriate permissions to use this CLI.
@@ -0,0 +1,7 @@
1
+ """
2
+ Godfather CLI package
3
+ """
4
+
5
+ __version__ = "1.0.0"
6
+ __author__ = "AI Society ASU"
7
+ __email__ = "admin@ais-asu.com"
@@ -0,0 +1,135 @@
1
+ """CLI Authentication module"""
2
+ import os
3
+ import json
4
+ import requests
5
+ import getpass
6
+ from pathlib import Path
7
+ from typing import Dict, Optional
8
+ from rich.console import Console
9
+ from rich.panel import Panel
10
+ from rich import box
11
+ from rich.prompt import Prompt
12
+
13
+ console = Console()
14
+
15
+
16
+ class CLIAuthenticator:
17
+ """Handle CLI authentication"""
18
+
19
+ def __init__(self, api_base: str, config_dir: Path):
20
+ self.api_base = api_base
21
+ self.config_dir = config_dir
22
+ self.config_file = config_dir / 'config.json'
23
+ self.config = self.load_config()
24
+
25
+ def load_config(self) -> Dict:
26
+ """Load configuration from file"""
27
+ if self.config_file.exists():
28
+ try:
29
+ with open(self.config_file, 'r') as f:
30
+ return json.load(f)
31
+ except (json.JSONDecodeError, IOError):
32
+ pass
33
+ return {}
34
+
35
+ def save_config(self):
36
+ """Save configuration to file"""
37
+ self.config_dir.mkdir(exist_ok=True)
38
+ with open(self.config_file, 'w') as f:
39
+ json.dump(self.config, f, indent=2)
40
+
41
+ def authenticate(self) -> bool:
42
+ """Authenticate user via CLI token"""
43
+ panel = Panel(
44
+ f"[cyan]Visit the admin portal to get your authentication token:[/cyan]\n"
45
+ f"[bold white]{self.api_base}/cli-auth[/bold white]",
46
+ title="[bold magenta]🔐 Authentication Required[/bold magenta]",
47
+ border_style="magenta",
48
+ box=box.ROUNDED
49
+ )
50
+ console.print(panel)
51
+ console.print()
52
+
53
+ token = Prompt.ask("[cyan]Enter your authentication token[/cyan]", password=True).strip()
54
+ if not token:
55
+ console.print("[red]✗[/red] No token provided")
56
+ return False
57
+
58
+ # Extract Discord ID from token (format: discord_<ID>_<timestamp>)
59
+ try:
60
+ if token.startswith('discord_'):
61
+ parts = token.split('_')
62
+ if len(parts) >= 2:
63
+ discord_user_id = parts[1]
64
+ else:
65
+ console.print("[red]✗[/red] Invalid token format")
66
+ return False
67
+ else:
68
+ console.print("[red]✗[/red] Invalid token format")
69
+ return False
70
+ except:
71
+ console.print("[red]✗[/red] Invalid token format")
72
+ return False
73
+
74
+ # Verify token with backend
75
+ try:
76
+ response = requests.post(
77
+ f'{self.api_base}/api/auth/verify',
78
+ json={'discord_user_id': discord_user_id},
79
+ timeout=10
80
+ )
81
+
82
+ if response.status_code == 200:
83
+ self.config['token'] = token
84
+ self.config['discord_user_id'] = discord_user_id
85
+ self.save_config()
86
+ console.print("[green]✓[/green] Authentication successful!")
87
+ return True
88
+ else:
89
+ error = response.json().get('error', 'Authentication failed')
90
+ console.print(f"[red]✗[/red] Authentication failed: {error}")
91
+ return False
92
+
93
+ except requests.RequestException as e:
94
+ console.print(f"[red]✗[/red] Connection error: {e}")
95
+ return False
96
+
97
+ def get_token(self) -> Optional[str]:
98
+ """Get authentication token"""
99
+ return self.config.get('token')
100
+
101
+ def get_discord_user_id(self) -> Optional[str]:
102
+ """Get Discord user ID"""
103
+ return self.config.get('discord_user_id')
104
+
105
+ def is_authenticated(self) -> bool:
106
+ """Check if user is authenticated"""
107
+ return 'token' in self.config
108
+
109
+ def logout(self):
110
+ """Clear authentication token"""
111
+ if 'token' in self.config:
112
+ del self.config['token']
113
+ self.save_config()
114
+ console.print("[green]✓[/green] Logged out successfully")
115
+ else:
116
+ console.print("[yellow]ℹ[/yellow] You were not logged in")
117
+
118
+ def verify_token(self) -> bool:
119
+ """Verify current token is still valid"""
120
+ if not self.is_authenticated():
121
+ return False
122
+
123
+ discord_user_id = self.config.get('discord_user_id')
124
+ if not discord_user_id:
125
+ return False
126
+
127
+ try:
128
+ response = requests.post(
129
+ f'{self.api_base}/api/auth/verify',
130
+ json={'discord_user_id': discord_user_id},
131
+ timeout=5
132
+ )
133
+ return response.status_code == 200
134
+ except:
135
+ return False
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ AI Society Godfather CLI - Modular version
4
+ Command line interface for connecting to RunPod environments
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import argparse
10
+ from pathlib import Path
11
+ from rich.console import Console
12
+ from rich.panel import Panel
13
+ from rich.table import Table
14
+ from rich import box
15
+ from rich.prompt import Prompt, Confirm
16
+ from rich.progress import Progress, SpinnerColumn, TextColumn
17
+
18
+ from .auth import CLIAuthenticator
19
+ from .pod_manager import PodManager
20
+ from .ssh_connector import SSHConnector
21
+
22
+ console = Console()
23
+
24
+
25
+ class GodfatherCLI:
26
+ """Main CLI application"""
27
+
28
+ def __init__(self):
29
+ self.config_dir = Path.home() / '.godfather'
30
+
31
+ # Auto-detect API URL from multiple possible environment variables
32
+ # Priority: GODFATHER_API_URL > BACKEND_URL > NEXT_PUBLIC_BACKEND_URL > NEXT_PUBLIC_API_URL
33
+ self.api_base = (
34
+ os.getenv('GODFATHER_API_URL') or
35
+ os.getenv('BACKEND_URL') or
36
+ os.getenv('NEXT_PUBLIC_BACKEND_URL') or
37
+ (os.getenv('NEXT_PUBLIC_API_URL', '').replace('/api', '')) or
38
+ 'https://8bzhwve1ri5cw2-80.proxy.runpod.net' # Fallback to RunPod proxy
39
+ )
40
+
41
+ # Initialize components
42
+ self.authenticator = CLIAuthenticator(self.api_base, self.config_dir)
43
+ self.pod_manager = PodManager(self.api_base)
44
+ self.ssh_connector = SSHConnector(self.api_base, self.config_dir)
45
+
46
+ def print_banner(self):
47
+ """Print CLI banner"""
48
+ banner = Panel.fit(
49
+ "[bold magenta]Godfather CLI[/bold magenta]\n"
50
+ "[dim]AI Society RunPod Environment Manager[/dim]",
51
+ border_style="magenta",
52
+ box=box.DOUBLE
53
+ )
54
+ console.print(banner)
55
+ console.print()
56
+
57
+ def ensure_authenticated(self) -> bool:
58
+ """Ensure user is authenticated"""
59
+ if not self.authenticator.is_authenticated():
60
+ return self.authenticator.authenticate()
61
+
62
+ # Verify token is still valid
63
+ if not self.authenticator.verify_token():
64
+ console.print("[yellow]⚠[/yellow] Token expired. Please re-authenticate.")
65
+ return self.authenticator.authenticate()
66
+
67
+ return True
68
+
69
+ def list_pods(self):
70
+ """List available public pods"""
71
+ if not self.ensure_authenticated():
72
+ return
73
+
74
+ discord_user_id = self.authenticator.get_discord_user_id()
75
+ self.pod_manager.list_pods(discord_user_id)
76
+
77
+ def connect_to_pod(self, pod_id: str = None):
78
+ """Connect to a specific pod"""
79
+ if not self.ensure_authenticated():
80
+ return
81
+
82
+ discord_user_id = self.authenticator.get_discord_user_id()
83
+
84
+ # Select pod if not provided
85
+ if not pod_id:
86
+ pod_id = self.pod_manager.select_pod(discord_user_id)
87
+ if not pod_id:
88
+ return
89
+
90
+ console.print(f"[cyan]🔌 Connecting to pod {pod_id[:8]}...[/cyan]")
91
+
92
+ # Get connection details
93
+ ssh_info = self.pod_manager.get_connection_info(pod_id, discord_user_id)
94
+ if not ssh_info:
95
+ return
96
+
97
+ # Fetch SSH key
98
+ if not self.ssh_connector.fetch_ssh_key(discord_user_id):
99
+ return
100
+
101
+ # Establish SSH connection
102
+ self.ssh_connector.connect(ssh_info)
103
+
104
+ def status(self):
105
+ """Show CLI status and configuration"""
106
+ table = Table(title="[bold cyan]Godfather CLI Status[/bold cyan]", box=box.ROUNDED, border_style="cyan")
107
+ table.add_column("Setting", style="cyan bold", no_wrap=True)
108
+ table.add_column("Value", style="white")
109
+
110
+ if self.authenticator.is_authenticated():
111
+ table.add_row("🔐 Authentication", "[green]✓ Authenticated[/green]")
112
+ if self.authenticator.verify_token():
113
+ table.add_row("🌐 API Connection", "[green]✓ Connected[/green]")
114
+ else:
115
+ table.add_row("🌐 API Connection", "[yellow]⚠ Token expired[/yellow]")
116
+ else:
117
+ table.add_row("🔐 Authentication", "[red]✗ Not authenticated[/red]")
118
+
119
+ table.add_row("🏠 Config Directory", str(self.config_dir))
120
+ table.add_row("🔗 API Endpoint", self.api_base)
121
+
122
+ console.print(table)
123
+
124
+ def logout(self):
125
+ """Clear authentication token"""
126
+ self.authenticator.logout()
127
+
128
+ def authenticate(self):
129
+ """Trigger authentication"""
130
+ self.authenticator.authenticate()
131
+
132
+ def interactive_menu(self):
133
+ """Show interactive menu"""
134
+ self.print_banner()
135
+
136
+ while True:
137
+ console.print()
138
+ menu = Table.grid(padding=(0, 2))
139
+ menu.add_column(style="cyan bold", justify="right")
140
+ menu.add_column(style="white")
141
+
142
+ menu.add_row("1.", "📋 List available pods")
143
+ menu.add_row("2.", "🔌 Connect to a pod")
144
+ menu.add_row("3.", "📊 Show status")
145
+ menu.add_row("4.", "🚪 Logout")
146
+ menu.add_row("5.", "👋 Exit")
147
+
148
+ panel = Panel(
149
+ menu,
150
+ title="[bold cyan]What would you like to do?[/bold cyan]",
151
+ border_style="cyan",
152
+ box=box.ROUNDED
153
+ )
154
+ console.print(panel)
155
+
156
+ try:
157
+ choice = Prompt.ask("\n[cyan]Enter your choice[/cyan]", choices=["1", "2", "3", "4", "5"], default="1")
158
+ console.print()
159
+
160
+ if choice == '1':
161
+ self.list_pods()
162
+ elif choice == '2':
163
+ self.connect_to_pod()
164
+ elif choice == '3':
165
+ self.status()
166
+ elif choice == '4':
167
+ self.logout()
168
+ elif choice == '5':
169
+ console.print("[bold magenta]👋 Goodbye![/bold magenta]")
170
+ break
171
+
172
+ except KeyboardInterrupt:
173
+ console.print("\n[bold magenta]👋 Goodbye![/bold magenta]")
174
+ break
175
+
176
+
177
+ def main():
178
+ """Main CLI entry point"""
179
+ parser = argparse.ArgumentParser(
180
+ description='AI Society Godfather CLI - RunPod Environment Manager',
181
+ formatter_class=argparse.RawDescriptionHelpFormatter,
182
+ epilog="""
183
+ Examples:
184
+ godfather list # List available pods
185
+ godfather connect # Interactive pod connection
186
+ godfather connect <pod-id> # Connect to specific pod
187
+ godfather status # Show CLI status
188
+ godfather logout # Clear authentication
189
+
190
+ For support, contact AI Society administrators.
191
+ """
192
+ )
193
+
194
+ parser.add_argument(
195
+ 'command',
196
+ nargs='?',
197
+ choices=['list', 'connect', 'status', 'logout', 'auth'],
198
+ help='Command to execute'
199
+ )
200
+ parser.add_argument(
201
+ 'pod_id',
202
+ nargs='?',
203
+ help='Pod ID for connect command'
204
+ )
205
+ parser.add_argument(
206
+ '--api-url',
207
+ help='Override API base URL'
208
+ )
209
+
210
+ args = parser.parse_args()
211
+
212
+ # Override API URL if provided
213
+ if args.api_url:
214
+ os.environ['GODFATHER_API_URL'] = args.api_url
215
+
216
+ cli = GodfatherCLI()
217
+
218
+ # If no command provided, show interactive menu
219
+ if not args.command:
220
+ cli.interactive_menu()
221
+ return
222
+
223
+ # Execute command
224
+ if args.command == 'list':
225
+ cli.list_pods()
226
+ elif args.command == 'connect':
227
+ cli.connect_to_pod(args.pod_id)
228
+ elif args.command == 'status':
229
+ cli.status()
230
+ elif args.command == 'logout':
231
+ cli.logout()
232
+ elif args.command == 'auth':
233
+ cli.authenticate()
234
+
235
+
236
+ if __name__ == '__main__':
237
+ main()
@@ -0,0 +1,132 @@
1
+ """CLI Pod Operations module"""
2
+ import requests
3
+ from typing import List, Dict, Optional
4
+ from rich.console import Console
5
+ from rich.table import Table
6
+ from rich import box
7
+ from rich.prompt import IntPrompt
8
+
9
+ console = Console()
10
+
11
+
12
+ class PodManager:
13
+ """Handle pod operations"""
14
+
15
+ def __init__(self, api_base: str):
16
+ self.api_base = api_base
17
+
18
+ def get_public_pods(self, discord_user_id: str) -> List[Dict]:
19
+ """Get list of public pods available for connection"""
20
+ try:
21
+ headers = {'X-Discord-User-ID': discord_user_id}
22
+ response = requests.get(
23
+ f'{self.api_base}/api/pods/public',
24
+ headers=headers,
25
+ timeout=10
26
+ )
27
+
28
+ if response.status_code == 200:
29
+ return response.json().get('pods', [])
30
+ elif response.status_code == 401:
31
+ console.print("[red]✗[/red] Authentication failed. Please re-authenticate.")
32
+ return []
33
+ else:
34
+ error = response.json().get('error', 'Failed to fetch pods')
35
+ console.print(f"[red]✗[/red] Error: {error}")
36
+ return []
37
+
38
+ except requests.RequestException as e:
39
+ console.print(f"[red]✗[/red] Connection error: {e}")
40
+ return []
41
+
42
+ def get_connection_info(self, pod_id: str, discord_user_id: str) -> Optional[Dict]:
43
+ """Get SSH connection information for a pod"""
44
+ try:
45
+ headers = {'X-Discord-User-ID': discord_user_id}
46
+ response = requests.post(
47
+ f'{self.api_base}/api/pods/{pod_id}/connect',
48
+ headers=headers,
49
+ timeout=10
50
+ )
51
+
52
+ if response.status_code == 200:
53
+ return response.json().get('ssh_info')
54
+ else:
55
+ error = response.json().get('error', 'Connection failed')
56
+ console.print(f"[red]✗[/red] Connection failed: {error}")
57
+ return None
58
+
59
+ except requests.RequestException as e:
60
+ console.print(f"[red]✗[/red] Connection error: {e}")
61
+ return None
62
+
63
+ def list_pods(self, discord_user_id: str):
64
+ """List available public pods"""
65
+ console.print("[cyan]📡 Fetching available pods...[/cyan]")
66
+ pods = self.get_public_pods(discord_user_id)
67
+
68
+ if not pods:
69
+ console.print("[yellow]😔 No public pods available at the moment.[/yellow]")
70
+ console.print(" [dim]Ask a godfather to create and make pods public.[/dim]")
71
+ return
72
+
73
+ table = Table(title=f"[bold cyan]🚀 Available Pods ({len(pods)})[/bold cyan]", box=box.ROUNDED, border_style="cyan")
74
+ table.add_column("#", style="dim", width=3)
75
+ table.add_column("Status", justify="center", width=8)
76
+ table.add_column("Name", style="cyan bold")
77
+ table.add_column("ID", style="dim")
78
+ table.add_column("Created", style="white")
79
+
80
+ for i, pod in enumerate(pods, 1):
81
+ status = pod.get('status', 'Unknown')
82
+ if status == 'RUNNING':
83
+ status_display = "[green]� RUN[/green]"
84
+ else:
85
+ status_display = "[red]🔴 OFF[/red]"
86
+
87
+ table.add_row(
88
+ str(i),
89
+ status_display,
90
+ pod['name'],
91
+ pod['id'][:12] + "...",
92
+ pod.get('created_at', 'Unknown')
93
+ )
94
+
95
+ console.print()
96
+ console.print(table)
97
+
98
+ def select_pod(self, discord_user_id: str) -> Optional[str]:
99
+ """Interactive pod selection"""
100
+ pods = self.get_public_pods(discord_user_id)
101
+
102
+ if not pods:
103
+ console.print("[yellow]😔 No public pods available.[/yellow]")
104
+ return None
105
+
106
+ table = Table(title="[bold cyan]🚀 Select a Pod[/bold cyan]", box=box.SIMPLE, border_style="cyan")
107
+ table.add_column("#", style="cyan bold", width=3)
108
+ table.add_column("Status", justify="center", width=8)
109
+ table.add_column("Name", style="white")
110
+ table.add_column("ID", style="dim")
111
+
112
+ for i, pod in enumerate(pods, 1):
113
+ status = pod.get('status', 'Unknown')
114
+ status_display = "[green]🟢 RUN[/green]" if status == 'RUNNING' else "[red]🔴 OFF[/red]"
115
+
116
+ table.add_row(
117
+ str(i),
118
+ status_display,
119
+ pod['name'],
120
+ pod['id'][:12] + "..."
121
+ )
122
+
123
+ console.print()
124
+ console.print(table)
125
+ console.print()
126
+
127
+ try:
128
+ choice = IntPrompt.ask("[cyan]Select a pod number[/cyan]", choices=[str(i) for i in range(1, len(pods) + 1)])
129
+ return pods[choice - 1]['id']
130
+ except (KeyboardInterrupt, EOFError):
131
+ console.print("\n[yellow]Selection cancelled[/yellow]")
132
+ return None
@@ -0,0 +1,145 @@
1
+ """CLI SSH Connection module"""
2
+ import os
3
+ import subprocess
4
+ import requests
5
+ from pathlib import Path
6
+ from typing import Dict, Optional
7
+
8
+
9
+ class SSHConnector:
10
+ """Handle SSH connections to pods"""
11
+
12
+ def __init__(self, api_base: str, config_dir: Path):
13
+ self.api_base = api_base
14
+ self.ssh_key_dir = config_dir / 'ssh'
15
+ self.ssh_key_file = self.ssh_key_dir / 'godfather_key'
16
+
17
+ def fetch_ssh_key(self, discord_user_id: str) -> bool:
18
+ """Fetch SSH private key from API and save it"""
19
+ print("🔑 Fetching SSH key...")
20
+ try:
21
+ headers = {'X-Discord-User-ID': discord_user_id}
22
+ response = requests.get(
23
+ f'{self.api_base}/api/ssh-key',
24
+ headers=headers,
25
+ timeout=10
26
+ )
27
+
28
+ if response.status_code != 200:
29
+ error = response.json().get('error', 'Unknown error')
30
+ print(f"❌ Failed to fetch SSH key: {error}")
31
+ return False
32
+
33
+ private_key = response.json().get('private_key')
34
+ if not private_key:
35
+ print("❌ No SSH key returned from API")
36
+ return False
37
+
38
+ # Ensure proper formatting
39
+ if '\\n' in private_key:
40
+ private_key = private_key.replace('\\n', '\n')
41
+
42
+ if not private_key.endswith('\n'):
43
+ private_key += '\n'
44
+
45
+ # Save SSH key
46
+ self.ssh_key_dir.mkdir(exist_ok=True)
47
+
48
+ with open(self.ssh_key_file, 'w') as f:
49
+ f.write(private_key)
50
+
51
+ # Set correct permissions
52
+ os.chmod(self.ssh_key_file, 0o600)
53
+ print("✅ SSH key ready")
54
+
55
+ return True
56
+
57
+ except requests.RequestException as e:
58
+ print(f"❌ Failed to fetch SSH key: {e}")
59
+ return False
60
+ except IOError as e:
61
+ print(f"❌ Failed to save SSH key: {e}")
62
+ return False
63
+
64
+ def connect(self, ssh_info: Dict) -> int:
65
+ """Establish SSH connection to pod"""
66
+ host = ssh_info.get('host')
67
+ port = ssh_info.get('port', 22)
68
+ username = ssh_info.get('username', 'root')
69
+ user_folder = ssh_info.get('user_folder', 'user')
70
+ is_admin = ssh_info.get('is_admin', False)
71
+
72
+ if not host:
73
+ print("❌ No host information available")
74
+ return 1
75
+
76
+ print(f"🔗 Connecting to {host}:{port}")
77
+ print(f"👤 User workspace: /workspace/users/{user_folder}")
78
+
79
+ if is_admin:
80
+ print("👑 Admin mode: Full system access")
81
+ else:
82
+ print("🔒 Restricted mode: Limited to your workspace")
83
+
84
+ print("\n📁 Setting up your personal workspace...")
85
+
86
+ # Setup user workspace
87
+ admin_flag = "true" if is_admin else "false"
88
+ setup_command = f"/usr/local/bin/godfather-user-setup.sh {user_folder} {admin_flag}"
89
+
90
+ # Build SSH connection command
91
+ ssh_command = [
92
+ 'ssh',
93
+ '-t',
94
+ '-i', str(self.ssh_key_file),
95
+ '-o', 'StrictHostKeyChecking=no',
96
+ '-o', 'UserKnownHostsFile=/dev/null',
97
+ '-p', str(port),
98
+ f'{username}@{host}',
99
+ f'PROFILE=$({setup_command}) && source $PROFILE && exec bash'
100
+ ]
101
+
102
+ try:
103
+ print("🚪 Opening SSH session...")
104
+
105
+ if is_admin:
106
+ print("✅ You have full admin access (sudo available)")
107
+ else:
108
+ print("💡 You're in your personal workspace")
109
+ print("🤝 You can also access /workspace/shared for collaboration")
110
+ print("⚠️ Restricted mode: No sudo access")
111
+
112
+ print("📝 Type 'exit' to disconnect\n")
113
+
114
+ # Execute SSH connection
115
+ result = subprocess.run(ssh_command)
116
+
117
+ if result.returncode != 0:
118
+ print("\n❌ SSH connection failed!")
119
+ print("\n⚠️ SSH Key Setup Required")
120
+ print("=" * 60)
121
+ print("The pod needs to have the SSH key configured first.")
122
+ print("\nOption 1: Use the godfather-base Docker image (recommended)")
123
+ print(" - The image automatically sets up SSH on startup")
124
+ print(" - Image: theaisocietyasu/godfather-base:latest")
125
+ print("\nOption 2: Manual setup in RunPod web terminal:")
126
+ print("\n mkdir -p /root/.ssh && \\")
127
+ print(f' echo "$GODFATHER_SSH_PUBLIC_KEY" >> /root/.ssh/authorized_keys && \\')
128
+ print(" chmod 700 /root/.ssh && \\")
129
+ print(" chmod 600 /root/.ssh/authorized_keys")
130
+ print("\n💡 The GODFATHER_SSH_PUBLIC_KEY environment variable is already set in your pod.")
131
+ print("=" * 60)
132
+ return result.returncode
133
+ else:
134
+ print("\n👋 Disconnected from pod")
135
+ return 0
136
+
137
+ except KeyboardInterrupt:
138
+ print("\n👋 Connection cancelled")
139
+ return 1
140
+ except FileNotFoundError:
141
+ print("❌ SSH client not found. Please install OpenSSH client.")
142
+ return 1
143
+ except subprocess.SubprocessError as e:
144
+ print(f"❌ SSH connection failed: {e}")
145
+ return 1
@@ -0,0 +1,212 @@
1
+ Metadata-Version: 2.4
2
+ Name: godfather-cli
3
+ Version: 1.0.1
4
+ Summary: AI Society Godfather CLI - RunPod Environment Manager
5
+ Author-email: AI Society ASU <theaisocietyasu@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/theaisocietyasu/godfather
8
+ Project-URL: Repository, https://github.com/theaisocietyasu/godfather
9
+ Project-URL: Issues, https://github.com/theaisocietyasu/godfather/issues
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.7
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Requires-Python: >=3.7
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: requests>=2.25.0
22
+ Requires-Dist: rich>=13.0.0
23
+
24
+ # Godfather CLI
25
+
26
+ Beautiful command-line interface for managing AI Society ASU RunPod environments.
27
+
28
+ ![CLI Demo](https://img.shields.io/badge/python-3.7+-blue.svg)
29
+ ![License](https://img.shields.io/badge/license-MIT-green.svg)
30
+
31
+ ## ✨ Features
32
+
33
+ - 🎨 **Beautiful Interface** - Rich terminal UI with colors, tables, and panels
34
+ - 🔐 **Secure Authentication** - Discord-based authentication
35
+ - 🚀 **Pod Management** - List and connect to available RunPod environments
36
+ - 🔌 **SSH Integration** - Automatic SSH key setup and connection
37
+ - 📊 **Status Monitoring** - Check authentication and configuration status
38
+
39
+ ## 📦 Installation
40
+
41
+ ### Option 1: Install from PyPI (Recommended)
42
+
43
+ ```bash
44
+ pip install godfather-cli
45
+ ```
46
+
47
+ ### Option 2: Install from GitHub
48
+
49
+ ```bash
50
+ pip install git+https://github.com/theaisocietyasu/godfather.git#subdirectory=cli
51
+ ```
52
+
53
+ ### Option 3: Install for Development
54
+
55
+ ```bash
56
+ git clone https://github.com/theaisocietyasu/godfather.git
57
+ cd godfather/cli
58
+ pip install -e .
59
+ ```
60
+
61
+ ## 🚀 Quick Start
62
+
63
+ 1. **Run the CLI**:
64
+ ```bash
65
+ godfather
66
+ ```
67
+
68
+ 2. **Authenticate**:
69
+ - Visit the admin portal to get your authentication token
70
+ - Paste the token when prompted
71
+
72
+ 3. **Connect to a Pod**:
73
+ - Select option `2` to connect to a pod
74
+ - Choose from available pods
75
+ - Automatically SSH into your isolated workspace
76
+
77
+ ## 📖 Usage
78
+
79
+ ### Interactive Menu
80
+
81
+ Simply run:
82
+ ```bash
83
+ godfather
84
+ ```
85
+
86
+ You'll see a beautiful menu:
87
+ ```
88
+ ╔═══════════════════════════════════════╗
89
+ ║ Godfather CLI ║
90
+ ║ AI Society RunPod Environment Manager ║
91
+ ╚═══════════════════════════════════════╝
92
+
93
+ ╭──────── What would you like to do? ──────────╮
94
+ │ 1. 📋 List available pods │
95
+ │ 2. 🔌 Connect to a pod │
96
+ │ 3. 📊 Show status │
97
+ │ 4. 🚪 Logout │
98
+ │ 5. 👋 Exit │
99
+ ╰──────────────────────────────────────────────╯
100
+ ```
101
+
102
+ ### Command-Line Interface
103
+
104
+ ```bash
105
+ # List available pods
106
+ godfather list
107
+
108
+ # Connect to a specific pod
109
+ godfather connect <pod-id>
110
+
111
+ # Connect interactively
112
+ godfather connect
113
+
114
+ # Show CLI status
115
+ godfather status
116
+
117
+ # Logout
118
+ godfather logout
119
+
120
+ # Re-authenticate
121
+ godfather auth
122
+
123
+ # Use custom API URL
124
+ godfather --api-url https://your-api.com list
125
+ ```
126
+
127
+ ## 🔑 Authentication
128
+
129
+ 1. Get your authentication token from: `https://your-godfather-instance.com/cli-auth`
130
+ 2. Run `godfather` or `godfather auth`
131
+ 3. Paste your token when prompted
132
+ 4. Token is securely stored in `~/.godfather/config.json`
133
+
134
+ ## 🛠️ Configuration
135
+
136
+ Configuration is stored in `~/.godfather/config.json`:
137
+
138
+ ```json
139
+ {
140
+ "token": "discord_<user_id>_<timestamp>",
141
+ "discord_user_id": "<your_discord_id>"
142
+ }
143
+ ```
144
+
145
+ ### Environment Variables
146
+
147
+ You can override the API URL with:
148
+
149
+ ```bash
150
+ export GODFATHER_API_URL="https://your-api.com"
151
+ # or
152
+ export BACKEND_URL="https://your-api.com"
153
+ # or
154
+ export NEXT_PUBLIC_BACKEND_URL="https://your-api.com"
155
+ ```
156
+
157
+ ## 🎨 Features in Detail
158
+
159
+ ### Beautiful Tables
160
+
161
+ Pod listings display in rich, colorful tables:
162
+
163
+ ```
164
+ 🚀 Available Pods (3)
165
+ ╭───┬────────┬─────────────┬──────────────┬───────────╮
166
+ │ # │ Status │ Name │ ID │ Created │
167
+ ├───┼────────┼─────────────┼──────────────┼───────────┤
168
+ │ 1 │ 🟢 RUN │ ml-training │ abc123def... │ 2 days ago│
169
+ │ 2 │ 🟢 RUN │ gpu-dev │ xyz789ghi... │ 1 week ago│
170
+ │ 3 │ 🔴 OFF │ testing │ jkl456mno... │ 3 days ago│
171
+ ╰───┴────────┴─────────────┴──────────────┴───────────╯
172
+ ```
173
+
174
+ ### Status Dashboard
175
+
176
+ ```
177
+ Godfather CLI Status
178
+ ╭─────────────────────┬─────────────────────────────╮
179
+ │ 🔐 Authentication │ ✓ Authenticated │
180
+ │ 🌐 API Connection │ ✓ Connected │
181
+ │ 🏠 Config Directory │ /home/user/.godfather │
182
+ │ 🔗 API Endpoint │ https://api.example.com │
183
+ ╰─────────────────────┴─────────────────────────────╯
184
+ ```
185
+
186
+ ## 🤝 Contributing
187
+
188
+ Contributions are welcome! Please feel free to submit a Pull Request.
189
+
190
+ 1. Fork the repository
191
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
192
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
193
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
194
+ 5. Open a Pull Request
195
+
196
+ ## 📝 License
197
+
198
+ This project is licensed under the MIT License - see the LICENSE file for details.
199
+
200
+ ## 🆘 Support
201
+
202
+ - **Issues**: [GitHub Issues](https://github.com/theaisocietyasu/godfather/issues)
203
+ - **Discord**: Contact AI Society ASU administrators
204
+ - **Email**: admin@ais-asu.com
205
+
206
+ ## 🎓 About
207
+
208
+ Built with ❤️ by [AI Society at Arizona State University](https://github.com/theaisocietyasu)
209
+
210
+ ---
211
+
212
+ **Note**: You need to be a member of the AI Society Discord server with appropriate permissions to use this CLI.
@@ -0,0 +1,14 @@
1
+ MANIFEST.in
2
+ README.md
3
+ pyproject.toml
4
+ godfather_cli/__init__.py
5
+ godfather_cli/auth.py
6
+ godfather_cli/cli.py
7
+ godfather_cli/pod_manager.py
8
+ godfather_cli/ssh_connector.py
9
+ godfather_cli.egg-info/PKG-INFO
10
+ godfather_cli.egg-info/SOURCES.txt
11
+ godfather_cli.egg-info/dependency_links.txt
12
+ godfather_cli.egg-info/entry_points.txt
13
+ godfather_cli.egg-info/requires.txt
14
+ godfather_cli.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ godfather = godfather_cli.cli:main
@@ -0,0 +1,2 @@
1
+ requests>=2.25.0
2
+ rich>=13.0.0
@@ -0,0 +1 @@
1
+ godfather_cli
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["setuptools>=45", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "godfather-cli"
7
+ version = "1.0.1"
8
+ description = "AI Society Godfather CLI - RunPod Environment Manager"
9
+ authors = [
10
+ {name = "AI Society ASU", email = "theaisocietyasu@gmail.com"}
11
+ ]
12
+ license = {text = "MIT"}
13
+ readme = "README.md"
14
+ requires-python = ">=3.7"
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.7",
21
+ "Programming Language :: Python :: 3.8",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ ]
26
+ dependencies = [
27
+ "requests>=2.25.0",
28
+ "rich>=13.0.0",
29
+ ]
30
+
31
+ [project.scripts]
32
+ godfather = "godfather_cli.cli:main"
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/theaisocietyasu/godfather"
36
+ Repository = "https://github.com/theaisocietyasu/godfather"
37
+ Issues = "https://github.com/theaisocietyasu/godfather/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+