plato-sdk-v2 2.7.6__py3-none-any.whl → 2.7.7__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.
plato/cli/main.py ADDED
@@ -0,0 +1,193 @@
1
+ """Plato CLI - Main entry point."""
2
+
3
+ import os
4
+ import platform
5
+ import shutil
6
+ from pathlib import Path
7
+
8
+ import typer
9
+ from dotenv import load_dotenv
10
+
11
+ from plato.cli.agent import agent_app
12
+ from plato.cli.chronos import chronos_app
13
+ from plato.cli.pm import pm_app
14
+ from plato.cli.sandbox import sandbox_app
15
+ from plato.cli.utils import console
16
+ from plato.cli.world import world_app
17
+
18
+
19
+ def _find_bundled_cli() -> str | None:
20
+ """
21
+ Find the Plato Go CLI binary.
22
+
23
+ Returns:
24
+ Path to the CLI binary if found, None otherwise.
25
+ """
26
+ # Check locations in order of preference
27
+ search_paths = []
28
+
29
+ # 1. Bundled in package (plato-cli) - go up from cli/ to v1/
30
+ binary_name = "plato-cli.exe" if platform.system().lower() == "windows" else "plato-cli"
31
+ package_dir = Path(__file__).resolve().parent.parent # v1/
32
+ bin_dir = package_dir / "bin"
33
+ search_paths.append(bin_dir / binary_name)
34
+
35
+ # 2. plato-client/cli/bin/plato (development location)
36
+ # Navigate from python-sdk/plato/v1/cli/main.py to plato-client/cli/bin/plato
37
+ plato_client_dir = package_dir.parent.parent.parent # Go up to plato-client
38
+ go_binary_name = "plato.exe" if platform.system().lower() == "windows" else "plato"
39
+ search_paths.append(plato_client_dir / "cli" / "bin" / go_binary_name)
40
+
41
+ # 3. Check PATH for 'plato-cli' only (not 'plato' to avoid finding Python entry point)
42
+ which_result = shutil.which(binary_name)
43
+ if which_result:
44
+ search_paths.append(Path(which_result))
45
+
46
+ # Return first found executable that is NOT the Python entry point
47
+ python_entry_point = shutil.which("plato") # This is the Python CLI
48
+ for path in search_paths:
49
+ if path.exists() and os.access(path, os.X_OK):
50
+ # Skip if this is the Python entry point (would cause infinite recursion)
51
+ if python_entry_point and str(path.resolve()) == str(Path(python_entry_point).resolve()):
52
+ continue
53
+ return str(path)
54
+
55
+ return None
56
+
57
+
58
+ # Load environment variables
59
+ load_dotenv()
60
+ load_dotenv(dotenv_path=os.path.join(os.path.expanduser("~"), ".env"))
61
+ load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), ".env"))
62
+
63
+
64
+ # =============================================================================
65
+ # MAIN APP
66
+ # =============================================================================
67
+
68
+ app = typer.Typer(help="[bold blue]Plato CLI[/bold blue] - Manage Plato environments and simulators.")
69
+
70
+ # Register sub-apps
71
+ app.add_typer(sandbox_app, name="sandbox")
72
+ app.add_typer(pm_app, name="pm")
73
+ app.add_typer(agent_app, name="agent")
74
+ app.add_typer(world_app, name="world")
75
+ app.add_typer(chronos_app, name="chronos")
76
+
77
+
78
+ # =============================================================================
79
+ # TOP-LEVEL COMMANDS
80
+ # =============================================================================
81
+
82
+
83
+ @app.command(context_settings={"allow_extra_args": True, "ignore_unknown_options": True})
84
+ def hub(
85
+ ctx: typer.Context,
86
+ ):
87
+ """Launch the Plato Hub CLI (interactive TUI for managing simulators).
88
+
89
+ Opens the Go-based Plato CLI which provides an interactive terminal UI for
90
+ browsing simulators, launching environments, and managing VMs. Any additional
91
+ arguments are passed through to the Go CLI.
92
+
93
+ Common subcommands: 'clone <service>', 'credentials', or no args for interactive mode.
94
+ """
95
+ # Find the bundled CLI binary
96
+ plato_bin = _find_bundled_cli()
97
+
98
+ if not plato_bin:
99
+ console.print("[red]❌ Plato CLI binary not found in package[/red]")
100
+ console.print("\n[yellow]The bundled CLI binary was not found in this installation.[/yellow]")
101
+ console.print("This indicates an installation issue with the plato-sdk package.")
102
+ console.print("\n[yellow]💡 Try reinstalling the package:[/yellow]")
103
+ console.print(" pip install --upgrade --force-reinstall plato-sdk")
104
+ console.print("\n[dim]If the issue persists, please report it at:[/dim]")
105
+ console.print("[dim]https://github.com/plato-app/plato-client/issues[/dim]")
106
+ raise typer.Exit(1)
107
+
108
+ # Get any additional arguments passed after 'hub'
109
+ args = ctx.args if hasattr(ctx, "args") else []
110
+
111
+ try:
112
+ # Launch the Go CLI, passing through all arguments
113
+ # Use execvp to replace the current process so the TUI works properly
114
+ os.execvp(plato_bin, [plato_bin] + args)
115
+ except Exception as e:
116
+ console.print(f"[red]❌ Failed to launch Plato Hub: {e}[/red]")
117
+ raise typer.Exit(1) from e
118
+
119
+
120
+ @app.command()
121
+ def clone(
122
+ service: str = typer.Argument(..., help="Service name to clone (e.g., espocrm)"),
123
+ ):
124
+ """Clone a service repository from Plato Hub (Gitea).
125
+
126
+ Clones the simulator source code to your local machine for development or review.
127
+
128
+ Arguments:
129
+ service: Service name to clone (e.g., 'espocrm', 'gitea')
130
+ """
131
+ plato_bin = _find_bundled_cli()
132
+ if not plato_bin:
133
+ console.print("[red]❌ Plato CLI binary not found[/red]")
134
+ console.print("[yellow]Cannot clone without the Go CLI binary.[/yellow]")
135
+ raise typer.Exit(1)
136
+
137
+ try:
138
+ os.execvp(plato_bin, [plato_bin, "clone", service])
139
+ except Exception as e:
140
+ console.print(f"[red]❌ Failed to clone: {e}[/red]")
141
+ raise typer.Exit(1) from e
142
+
143
+
144
+ @app.command()
145
+ def credentials():
146
+ """Display your Plato Hub (Gitea) credentials.
147
+
148
+ Shows the username and password needed to access Plato's Gitea repositories
149
+ for cloning and pushing simulator code.
150
+ """
151
+ plato_bin = _find_bundled_cli()
152
+ if not plato_bin:
153
+ console.print("[red]❌ Plato CLI binary not found[/red]")
154
+ console.print("[yellow]Cannot show credentials without the Go CLI binary.[/yellow]")
155
+ raise typer.Exit(1)
156
+
157
+ try:
158
+ os.execvp(plato_bin, [plato_bin, "credentials"])
159
+ except Exception as e:
160
+ console.print(f"[red]❌ Failed to get credentials: {e}[/red]")
161
+ raise typer.Exit(1) from e
162
+
163
+
164
+ @app.command(
165
+ context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
166
+ help="Explore simulation APIs (list, info, endpoints, spec)",
167
+ )
168
+ def sims(ctx: typer.Context):
169
+ """Explore simulation APIs - list sims, view endpoints, get OpenAPI specs."""
170
+ from plato.sims import cli as sims_cli
171
+
172
+ # Pass all arguments to the sims CLI
173
+ sims_cli.main(ctx.args)
174
+
175
+
176
+ # =============================================================================
177
+ # ENTRY POINT
178
+ # =============================================================================
179
+
180
+ # force bump to v36
181
+ # TEST/MOCK: This comment marks test-related code. Used for verification in release workflow.
182
+
183
+
184
+ def main():
185
+ """Main entry point for the Plato CLI."""
186
+ app()
187
+
188
+
189
+ # Backward compatibility
190
+ cli = main
191
+
192
+ if __name__ == "__main__":
193
+ main()