supervaizer 0.10.5__py3-none-any.whl

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 (76) hide show
  1. supervaizer/__init__.py +97 -0
  2. supervaizer/__version__.py +10 -0
  3. supervaizer/account.py +308 -0
  4. supervaizer/account_service.py +93 -0
  5. supervaizer/admin/routes.py +1293 -0
  6. supervaizer/admin/static/js/job-start-form.js +373 -0
  7. supervaizer/admin/templates/agent_detail.html +145 -0
  8. supervaizer/admin/templates/agents.html +249 -0
  9. supervaizer/admin/templates/agents_grid.html +82 -0
  10. supervaizer/admin/templates/base.html +233 -0
  11. supervaizer/admin/templates/case_detail.html +230 -0
  12. supervaizer/admin/templates/cases_list.html +182 -0
  13. supervaizer/admin/templates/cases_table.html +134 -0
  14. supervaizer/admin/templates/console.html +389 -0
  15. supervaizer/admin/templates/dashboard.html +153 -0
  16. supervaizer/admin/templates/job_detail.html +192 -0
  17. supervaizer/admin/templates/job_start_test.html +109 -0
  18. supervaizer/admin/templates/jobs_list.html +180 -0
  19. supervaizer/admin/templates/jobs_table.html +122 -0
  20. supervaizer/admin/templates/navigation.html +163 -0
  21. supervaizer/admin/templates/recent_activity.html +81 -0
  22. supervaizer/admin/templates/server.html +105 -0
  23. supervaizer/admin/templates/server_status_cards.html +121 -0
  24. supervaizer/admin/templates/supervaize_instructions.html +212 -0
  25. supervaizer/agent.py +956 -0
  26. supervaizer/case.py +432 -0
  27. supervaizer/cli.py +395 -0
  28. supervaizer/common.py +324 -0
  29. supervaizer/deploy/__init__.py +16 -0
  30. supervaizer/deploy/cli.py +305 -0
  31. supervaizer/deploy/commands/__init__.py +9 -0
  32. supervaizer/deploy/commands/clean.py +294 -0
  33. supervaizer/deploy/commands/down.py +119 -0
  34. supervaizer/deploy/commands/local.py +460 -0
  35. supervaizer/deploy/commands/plan.py +167 -0
  36. supervaizer/deploy/commands/status.py +169 -0
  37. supervaizer/deploy/commands/up.py +281 -0
  38. supervaizer/deploy/docker.py +377 -0
  39. supervaizer/deploy/driver_factory.py +42 -0
  40. supervaizer/deploy/drivers/__init__.py +39 -0
  41. supervaizer/deploy/drivers/aws_app_runner.py +607 -0
  42. supervaizer/deploy/drivers/base.py +196 -0
  43. supervaizer/deploy/drivers/cloud_run.py +570 -0
  44. supervaizer/deploy/drivers/do_app_platform.py +504 -0
  45. supervaizer/deploy/health.py +404 -0
  46. supervaizer/deploy/state.py +210 -0
  47. supervaizer/deploy/templates/Dockerfile.template +44 -0
  48. supervaizer/deploy/templates/debug_env.py +69 -0
  49. supervaizer/deploy/templates/docker-compose.yml.template +37 -0
  50. supervaizer/deploy/templates/dockerignore.template +66 -0
  51. supervaizer/deploy/templates/entrypoint.sh +20 -0
  52. supervaizer/deploy/utils.py +52 -0
  53. supervaizer/event.py +181 -0
  54. supervaizer/examples/controller_template.py +196 -0
  55. supervaizer/instructions.py +145 -0
  56. supervaizer/job.py +392 -0
  57. supervaizer/job_service.py +156 -0
  58. supervaizer/lifecycle.py +417 -0
  59. supervaizer/parameter.py +233 -0
  60. supervaizer/protocol/__init__.py +11 -0
  61. supervaizer/protocol/a2a/__init__.py +21 -0
  62. supervaizer/protocol/a2a/model.py +227 -0
  63. supervaizer/protocol/a2a/routes.py +99 -0
  64. supervaizer/py.typed +1 -0
  65. supervaizer/routes.py +917 -0
  66. supervaizer/server.py +553 -0
  67. supervaizer/server_utils.py +54 -0
  68. supervaizer/storage.py +462 -0
  69. supervaizer/telemetry.py +81 -0
  70. supervaizer/utils/__init__.py +16 -0
  71. supervaizer/utils/version_check.py +56 -0
  72. supervaizer-0.10.5.dist-info/METADATA +317 -0
  73. supervaizer-0.10.5.dist-info/RECORD +76 -0
  74. supervaizer-0.10.5.dist-info/WHEEL +4 -0
  75. supervaizer-0.10.5.dist-info/entry_points.txt +2 -0
  76. supervaizer-0.10.5.dist-info/licenses/LICENSE.md +346 -0
@@ -0,0 +1,294 @@
1
+ # Copyright (c) 2024-2025 Alain Prasquier - Supervaize.com. All rights reserved.
2
+ #
3
+ # This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
+ # If a copy of the MPL was not distributed with this file, you can obtain one at
5
+ # https://mozilla.org/MPL/2.0/.
6
+
7
+ """
8
+ Clean Command
9
+
10
+ This module provides functionality to clean up deployment artifacts and generated files.
11
+ """
12
+
13
+ import shutil
14
+ from pathlib import Path
15
+ from typing import Optional
16
+
17
+ from rich.console import Console
18
+ from rich.prompt import Confirm
19
+
20
+ from supervaizer.common import log
21
+
22
+ console = Console()
23
+
24
+
25
+ def clean_deployment(
26
+ deployment_dir: Optional[Path] = None,
27
+ force: bool = False,
28
+ verbose: bool = False,
29
+ ) -> None:
30
+ """
31
+ Clean up deployment artifacts and generated files.
32
+
33
+ Args:
34
+ deployment_dir: Path to deployment directory (default: .deployment)
35
+ force: Skip confirmation prompt
36
+ verbose: Show detailed output
37
+ """
38
+ if deployment_dir is None:
39
+ deployment_dir = Path(".deployment")
40
+
41
+ # Check if deployment directory exists
42
+ if not deployment_dir.exists():
43
+ console.print(f"[yellow]No deployment directory found at {deployment_dir}[/]")
44
+ console.print("Nothing to clean up.")
45
+ return
46
+
47
+ # Show what will be deleted
48
+ console.print(f"[bold blue]Cleaning deployment directory: {deployment_dir}[/]")
49
+
50
+ if verbose:
51
+ console.print("\n[bold]Contents to be deleted:[/]")
52
+ try:
53
+ for item in deployment_dir.rglob("*"):
54
+ if item.is_file():
55
+ console.print(f" 📄 {item.relative_to(deployment_dir)}")
56
+ elif item.is_dir():
57
+ console.print(f" 📁 {item.relative_to(deployment_dir)}/")
58
+ except Exception as e:
59
+ log.debug(f"Error listing directory contents: {e}")
60
+
61
+ # Calculate total size
62
+ total_size = 0
63
+ file_count = 0
64
+ try:
65
+ for item in deployment_dir.rglob("*"):
66
+ if item.is_file():
67
+ total_size += item.stat().st_size
68
+ file_count += 1
69
+ except Exception as e:
70
+ log.debug(f"Error calculating directory size: {e}")
71
+
72
+ if file_count > 0:
73
+ size_mb = total_size / (1024 * 1024)
74
+ console.print(f"\n[bold]Summary:[/] {file_count} files, {size_mb:.2f} MB")
75
+
76
+ # Confirmation prompt (unless forced)
77
+ if not force:
78
+ console.print(
79
+ "\n[yellow]This will permanently delete all deployment artifacts.[/]"
80
+ )
81
+ console.print("This includes:")
82
+ console.print(" • Generated Docker files")
83
+ console.print(" • Deployment state")
84
+ console.print(" • Configuration files")
85
+ console.print(" • Logs and debug information")
86
+
87
+ if not Confirm.ask("\n[bold red]Are you sure you want to continue?[/]"):
88
+ console.print("[yellow]Cleanup cancelled.[/]")
89
+ return
90
+
91
+ # Perform cleanup
92
+ try:
93
+ console.print(f"\n[bold]Deleting {deployment_dir}...[/]")
94
+ shutil.rmtree(deployment_dir)
95
+ console.print("[green]✓[/] Deployment directory cleaned successfully")
96
+
97
+ # Show what was cleaned
98
+ console.print("\n[bold green]Cleanup completed![/]")
99
+ console.print(f"Removed: {deployment_dir}")
100
+ if file_count > 0:
101
+ console.print(f"Files deleted: {file_count}")
102
+ console.print(f"Space freed: {size_mb:.2f} MB")
103
+
104
+ # Show next steps
105
+ console.print("\n[bold]Next steps:[/]")
106
+ console.print(
107
+ " • Run [bold]supervaizer deploy local[/] to regenerate files for local testing"
108
+ )
109
+ console.print(
110
+ " • Run [bold]supervaizer deploy up[/] to deploy to cloud platforms"
111
+ )
112
+ console.print(
113
+ " • Run [bold]supervaizer deploy plan[/] to plan new deployments"
114
+ )
115
+
116
+ except PermissionError as e:
117
+ console.print(
118
+ f"[bold red]Error:[/] Permission denied while deleting {deployment_dir}"
119
+ )
120
+ console.print(
121
+ "Make sure no processes are using files in the deployment directory."
122
+ )
123
+ console.print(f"Details: {e}")
124
+ raise RuntimeError(f"Failed to clean deployment directory: {e}") from e
125
+ except Exception as e:
126
+ console.print("[bold red]Error:[/] Failed to clean deployment directory")
127
+ console.print(f"Details: {e}")
128
+ raise RuntimeError(f"Failed to clean deployment directory: {e}") from e
129
+
130
+
131
+ def clean_docker_artifacts(
132
+ force: bool = False,
133
+ verbose: bool = False,
134
+ ) -> None:
135
+ """
136
+ Clean up Docker-related artifacts only.
137
+
138
+ Args:
139
+ force: Skip confirmation prompt
140
+ verbose: Show detailed output
141
+ """
142
+ deployment_dir = Path(".deployment")
143
+
144
+ if not deployment_dir.exists():
145
+ console.print("[yellow]No deployment directory found[/]")
146
+ return
147
+
148
+ # List of Docker-related files to clean
149
+ docker_files = [
150
+ "Dockerfile",
151
+ ".dockerignore",
152
+ "docker-compose.yml",
153
+ "docker-compose.yaml",
154
+ ]
155
+
156
+ docker_dirs = [
157
+ "logs",
158
+ ]
159
+
160
+ files_to_delete = []
161
+ dirs_to_delete = []
162
+
163
+ # Find files to delete
164
+ for file_name in docker_files:
165
+ file_path = deployment_dir / file_name
166
+ if file_path.exists():
167
+ files_to_delete.append(file_path)
168
+
169
+ # Find directories to delete
170
+ for dir_name in docker_dirs:
171
+ dir_path = deployment_dir / dir_name
172
+ if dir_path.exists() and dir_path.is_dir():
173
+ dirs_to_delete.append(dir_path)
174
+
175
+ if not files_to_delete and not dirs_to_delete:
176
+ console.print("[yellow]No Docker artifacts found to clean[/]")
177
+ return
178
+
179
+ # Show what will be deleted
180
+ console.print("[bold blue]Cleaning Docker artifacts[/]")
181
+
182
+ if verbose:
183
+ console.print("\n[bold]Files to be deleted:[/]")
184
+ for file_path in files_to_delete:
185
+ console.print(f" 📄 {file_path.relative_to(deployment_dir)}")
186
+
187
+ console.print("\n[bold]Directories to be deleted:[/]")
188
+ for dir_path in dirs_to_delete:
189
+ console.print(f" 📁 {dir_path.relative_to(deployment_dir)}/")
190
+
191
+ # Confirmation prompt (unless forced)
192
+ if not force:
193
+ console.print("\n[yellow]This will delete Docker-related files only.[/]")
194
+ console.print("Deployment state and configuration will be preserved.")
195
+
196
+ if not Confirm.ask("\n[bold red]Continue with Docker cleanup?[/]"):
197
+ console.print("[yellow]Cleanup cancelled.[/]")
198
+ return
199
+
200
+ # Perform cleanup
201
+ deleted_count = 0
202
+
203
+ try:
204
+ # Delete files
205
+ for file_path in files_to_delete:
206
+ if verbose:
207
+ console.print(f"Deleting {file_path.relative_to(deployment_dir)}...")
208
+ file_path.unlink()
209
+ deleted_count += 1
210
+
211
+ # Delete directories
212
+ for dir_path in dirs_to_delete:
213
+ if verbose:
214
+ console.print(f"Deleting {dir_path.relative_to(deployment_dir)}/...")
215
+ shutil.rmtree(dir_path)
216
+ deleted_count += 1
217
+
218
+ console.print("[green]✓[/] Docker artifacts cleaned successfully")
219
+ console.print(f"Deleted {deleted_count} items")
220
+
221
+ except Exception as e:
222
+ console.print("[bold red]Error:[/] Failed to clean Docker artifacts")
223
+ console.print(f"Details: {e}")
224
+ raise RuntimeError(f"Failed to clean Docker artifacts: {e}") from e
225
+
226
+
227
+ def clean_state_only(
228
+ force: bool = False,
229
+ verbose: bool = False,
230
+ ) -> None:
231
+ """
232
+ Clean up deployment state only, preserving generated files.
233
+
234
+ Args:
235
+ force: Skip confirmation prompt
236
+ verbose: Show detailed output
237
+ """
238
+ deployment_dir = Path(".deployment")
239
+
240
+ if not deployment_dir.exists():
241
+ console.print("[yellow]No deployment directory found[/]")
242
+ return
243
+
244
+ # State-related files to clean
245
+ state_files = [
246
+ "state.json",
247
+ "config.yaml",
248
+ "config.yml",
249
+ ]
250
+
251
+ files_to_delete = []
252
+
253
+ # Find state files to delete
254
+ for file_name in state_files:
255
+ file_path = deployment_dir / file_name
256
+ if file_path.exists():
257
+ files_to_delete.append(file_path)
258
+
259
+ if not files_to_delete:
260
+ console.print("[yellow]No state files found to clean[/]")
261
+ return
262
+
263
+ # Show what will be deleted
264
+ console.print("[bold blue]Cleaning deployment state[/]")
265
+
266
+ if verbose:
267
+ console.print("\n[bold]State files to be deleted:[/]")
268
+ for file_path in files_to_delete:
269
+ console.print(f" 📄 {file_path.relative_to(deployment_dir)}")
270
+
271
+ # Confirmation prompt (unless forced)
272
+ if not force:
273
+ console.print("\n[yellow]This will delete deployment state only.[/]")
274
+ console.print("Generated Docker files will be preserved.")
275
+ console.print("You will need to redeploy to recreate the state.")
276
+
277
+ if not Confirm.ask("\n[bold red]Continue with state cleanup?[/]"):
278
+ console.print("[yellow]Cleanup cancelled.[/]")
279
+ return
280
+
281
+ # Perform cleanup
282
+ try:
283
+ for file_path in files_to_delete:
284
+ if verbose:
285
+ console.print(f"Deleting {file_path.relative_to(deployment_dir)}...")
286
+ file_path.unlink()
287
+
288
+ console.print("[green]✓[/] Deployment state cleaned successfully")
289
+ console.print(f"Deleted {len(files_to_delete)} state files")
290
+
291
+ except Exception as e:
292
+ console.print("[bold red]Error:[/] Failed to clean deployment state")
293
+ console.print(f"Details: {e}")
294
+ raise RuntimeError(f"Failed to clean deployment state: {e}") from e
@@ -0,0 +1,119 @@
1
+ # Copyright (c) 2024-2025 Alain Prasquier - Supervaize.com. All rights reserved.
2
+ #
3
+ # This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
+ # If a copy of the MPL was not distributed with this file, you can obtain one at
5
+ # https://mozilla.org/MPL/2.0/.
6
+
7
+ """
8
+ Down Command
9
+
10
+ Destroy the service and cleanup resources.
11
+ """
12
+
13
+ from pathlib import Path
14
+ from typing import Optional
15
+
16
+ from rich.console import Console
17
+ from rich.prompt import Confirm
18
+
19
+ from supervaizer.common import log
20
+ from supervaizer.deploy.driver_factory import create_driver, get_supported_platforms
21
+ from supervaizer.deploy.state import StateManager
22
+
23
+ console = Console()
24
+
25
+
26
+ def deploy_down(
27
+ platform: str,
28
+ name: Optional[str] = None,
29
+ env: str = "dev",
30
+ region: Optional[str] = None,
31
+ project_id: Optional[str] = None,
32
+ yes: bool = False,
33
+ verbose: bool = False,
34
+ source_dir: Optional[Path] = None,
35
+ ) -> None:
36
+ """Destroy the service and cleanup resources."""
37
+ # Validate platform
38
+ if platform not in get_supported_platforms():
39
+ console.print(f"[bold red]Error:[/] Unsupported platform: {platform}")
40
+ console.print(f"Supported platforms: {', '.join(get_supported_platforms())}")
41
+ return
42
+
43
+ # Set defaults
44
+ if not name:
45
+ name = (source_dir or Path.cwd()).name
46
+ if not region:
47
+ region = _get_default_region(platform)
48
+
49
+ console.print(f"[bold red]Destroying service on {platform}[/bold red]")
50
+ console.print(f"Service name: {name}")
51
+ console.print(f"Environment: {env}")
52
+ console.print(f"Region: {region}")
53
+ if project_id:
54
+ console.print(f"Project ID: {project_id}")
55
+
56
+ try:
57
+ # Check local state
58
+ deployment_dir = (source_dir or Path.cwd()) / ".deployment"
59
+ state_manager = StateManager(deployment_dir)
60
+ state = state_manager.load_state()
61
+
62
+ if state:
63
+ console.print("\n[bold]Current Deployment:[/bold]")
64
+ console.print(f" Service URL: {state.service_url}")
65
+ console.print(f" Image Tag: {state.image_tag}")
66
+ console.print(f" Status: {state.status}")
67
+
68
+ # Confirmation prompt
69
+ if not yes:
70
+ if not Confirm.ask(f"\nAre you sure you want to destroy {name}-{env}?"):
71
+ console.print("[yellow]Destruction cancelled[/yellow]")
72
+ return
73
+
74
+ # Create driver
75
+ driver = create_driver(platform, region, project_id)
76
+
77
+ # Check prerequisites
78
+ prerequisites = driver.check_prerequisites()
79
+ if prerequisites:
80
+ console.print("[bold red]Prerequisites not met:[/]")
81
+ for prereq in prerequisites:
82
+ console.print(f" • {prereq}")
83
+ return
84
+
85
+ # Destroy service
86
+ console.print("\n[bold]Destroying service...[/bold]")
87
+ result = driver.destroy_service(name, env, keep_secrets=False)
88
+
89
+ if result.success:
90
+ console.print("[bold green]Service destroyed successfully[/bold green]")
91
+
92
+ # Clean up local state
93
+ if state_manager.state_file.exists():
94
+ state_manager.delete_state()
95
+ console.print("Cleaned up local deployment state")
96
+
97
+ # Clean up deployment directory
98
+ if deployment_dir.exists():
99
+ import shutil
100
+
101
+ shutil.rmtree(deployment_dir)
102
+ console.print("Cleaned up deployment directory")
103
+
104
+ else:
105
+ console.print(f"[bold red]Destruction failed:[/] {result.error_message}")
106
+
107
+ except Exception as e:
108
+ log.error(f"Destruction failed: {e}")
109
+ console.print(f"[bold red]Destruction failed:[/] {e}")
110
+
111
+
112
+ def _get_default_region(platform: str) -> str:
113
+ """Get default region for platform."""
114
+ defaults = {
115
+ "cloud-run": "us-central1",
116
+ "aws-app-runner": "us-east-1",
117
+ "do-app-platform": "nyc3",
118
+ }
119
+ return defaults.get(platform, "us-central1")