cyberwave-cli 0.11.0__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.
Files changed (34) hide show
  1. cyberwave_cli-0.11.0/PKG-INFO +17 -0
  2. cyberwave_cli-0.11.0/README.md +190 -0
  3. cyberwave_cli-0.11.0/pyproject.toml +37 -0
  4. cyberwave_cli-0.11.0/setup.cfg +4 -0
  5. cyberwave_cli-0.11.0/src/cyberwave_cli/__init__.py +1 -0
  6. cyberwave_cli-0.11.0/src/cyberwave_cli/core.py +42 -0
  7. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/__init__.py +1 -0
  8. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/assets/__init__.py +1 -0
  9. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/assets/app.py +87 -0
  10. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/auth/__init__.py +1 -0
  11. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/auth/app.py +340 -0
  12. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/devices/__init__.py +1 -0
  13. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/devices/app.py +49 -0
  14. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/edge/app.py +149 -0
  15. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/environments/app.py +75 -0
  16. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/loader.py +43 -0
  17. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/projects/__init__.py +1 -0
  18. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/projects/app.py +55 -0
  19. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/sensors/app.py +138 -0
  20. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/sim/app.py +17 -0
  21. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/telemetry/__init__.py +1 -0
  22. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/telemetry/app.py +17 -0
  23. cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/twins/app.py +66 -0
  24. cyberwave_cli-0.11.0/src/cyberwave_cli.egg-info/PKG-INFO +17 -0
  25. cyberwave_cli-0.11.0/src/cyberwave_cli.egg-info/SOURCES.txt +32 -0
  26. cyberwave_cli-0.11.0/src/cyberwave_cli.egg-info/dependency_links.txt +1 -0
  27. cyberwave_cli-0.11.0/src/cyberwave_cli.egg-info/entry_points.txt +11 -0
  28. cyberwave_cli-0.11.0/src/cyberwave_cli.egg-info/requires.txt +19 -0
  29. cyberwave_cli-0.11.0/src/cyberwave_cli.egg-info/top_level.txt +1 -0
  30. cyberwave_cli-0.11.0/tests/test_assets_cli.py +132 -0
  31. cyberwave_cli-0.11.0/tests/test_core.py +81 -0
  32. cyberwave_cli-0.11.0/tests/test_devices_cli.py +93 -0
  33. cyberwave_cli-0.11.0/tests/test_edge_cli.py +114 -0
  34. cyberwave_cli-0.11.0/tests/test_projects_cli.py +109 -0
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: cyberwave-cli
3
+ Version: 0.11.0
4
+ Summary: Cyberwave command-line interface (plugins, asset pipeline, telemetry)
5
+ Requires-Dist: typer[all]>=0.12
6
+ Requires-Dist: rich>=13
7
+ Requires-Dist: importlib_metadata>=6.0; python_version < "3.10"
8
+ Requires-Dist: setuptools>=61.0
9
+ Requires-Dist: httpx>=0.24.0
10
+ Requires-Dist: tomli>=2.0.0; python_version < "3.11"
11
+ Requires-Dist: tomli-w>=1.0.0
12
+ Provides-Extra: sdk
13
+ Requires-Dist: cyberwave<0.12,>=0.11; extra == "sdk"
14
+ Provides-Extra: test
15
+ Requires-Dist: pytest>=7.0; extra == "test"
16
+ Requires-Dist: pytest-cov; extra == "test"
17
+ Requires-Dist: pytest-mock; extra == "test"
@@ -0,0 +1,190 @@
1
+ # Cyberwave CLI
2
+
3
+ Command-line interface for the Cyberwave Digital Twin Platform. Manage projects, environments, digital twins, and robot integrations from the terminal.
4
+
5
+ ## Installation
6
+
7
+ ### Stable Release (Recommended)
8
+ ```bash
9
+ pip install cyberwave-cli
10
+ ```
11
+
12
+ ### With Full SDK Support
13
+ ```bash
14
+ pip install cyberwave-cli cyberwave cyberwave-robotics-integrations
15
+ ```
16
+
17
+ ### Development Installation
18
+ ```bash
19
+ pipx install cyberwave-cli # Isolated installation
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ### 1. Authentication
25
+ ```bash
26
+ # Login to your Cyberwave instance
27
+ cyberwave auth login --backend-url http://localhost:8000 --frontend-url http://localhost:3000
28
+
29
+ # Check authentication status
30
+ cyberwave auth status
31
+
32
+ # Logout
33
+ cyberwave auth logout
34
+ ```
35
+
36
+ ### 2. Project Management
37
+ ```bash
38
+ # List projects
39
+ cyberwave projects list
40
+
41
+ # Create new project
42
+ cyberwave projects create "My Robot Project" --description "Autonomous robot fleet"
43
+
44
+ # Get project details
45
+ cyberwave projects show <project-uuid>
46
+ ```
47
+
48
+ ### 3. Environment Management
49
+ ```bash
50
+ # List environments
51
+ cyberwave environments list
52
+
53
+ # Create environment
54
+ cyberwave environments create "Test Environment" --project <project-uuid>
55
+
56
+ # Environment details
57
+ cyberwave environments show <environment-uuid>
58
+ ```
59
+
60
+ ### 4. Digital Twin Operations
61
+ ```bash
62
+ # List twins in environment
63
+ cyberwave twins list --environment <environment-uuid>
64
+
65
+ # Add twin from catalog
66
+ cyberwave twins add cyberwave/so101 --environment <environment-uuid>
67
+
68
+ # Control twin position
69
+ cyberwave twins move <twin-uuid> --x 1.0 --y 0.0 --z 0.5
70
+
71
+ # Control robot joints
72
+ cyberwave twins joint <twin-uuid> --joint shoulder --angle 45
73
+ ```
74
+
75
+ ### 5. Device Management
76
+ ```bash
77
+ # Register device
78
+ cyberwave devices register --name "My Robot" --type so100
79
+
80
+ # List devices
81
+ cyberwave devices list
82
+
83
+ # Device status
84
+ cyberwave devices status <device-id>
85
+ ```
86
+
87
+ ### Plugins
88
+
89
+ Plugins are discovered via the `cyberwave.cli.plugins` entry point and loaded automatically.
90
+
91
+ - Built-in: `auth`, `projects`, `devices`, `edge`, `twins`
92
+ - List loaded plugins:
93
+ ```bash
94
+ cyberwave plugins-cmd
95
+ ```
96
+
97
+ ### Devices
98
+
99
+ ```bash
100
+ # Register a device and issue a device token
101
+ cyberwave devices register --project <PROJECT_ID> --name my-edge --type robot/so-arm100
102
+ cyberwave devices issue-offline-token --device <DEVICE_ID>
103
+ ```
104
+
105
+ ### Edge Node (SO-ARM100 example and simulation)
106
+
107
+ Configure and run a CyberWave Edge node that bridges a local driver to the cloud via the SDK.
108
+
109
+ - Initialize config (auto-register and create a device token):
110
+ ```bash
111
+ cyberwave edge init \
112
+ --robot so_arm100 \
113
+ --port /dev/ttyUSB0 \
114
+ --backend http://localhost:8000/api/v1 \
115
+ --project <PROJECT_ID> \
116
+ --device-name edge-soarm100 \
117
+ --device-type robot/so-arm100 \
118
+ --auto-register \
119
+ --use-device-token \
120
+ --config ~/.cyberwave/edge.json
121
+ ```
122
+ - Run:
123
+ ```bash
124
+ cyberwave edge run --config ~/.cyberwave/edge.json
125
+ ```
126
+ - Status:
127
+ ```bash
128
+ cyberwave edge status --config ~/.cyberwave/edge.json
129
+ ```
130
+ - Simulate a virtual camera from a local mp4 (no hardware needed):
131
+ ```bash
132
+ cyberwave edge simulate --sensor <SENSOR_UUID> --video ./sample.mp4 --fps 2
133
+ ```
134
+ - Command mode (optional): set in `~/.cyberwave/edge.json` to route via backend controller
135
+ ```json
136
+ {
137
+ "control_mode": "command",
138
+ "twin_uuid": "<TWIN_UUID>"
139
+ }
140
+ ```
141
+
142
+ ### Twin Control (Unified Command)
143
+
144
+ Send a command to a twin through the backend TeleopController.
145
+
146
+ ```bash
147
+ # Move joints (degrees/radians based on driver semantics)
148
+ cyberwave twins command \
149
+ --twin <TWIN_UUID> \
150
+ --name arm.move_joints \
151
+ --joints "[0,10,0,0,0,0]" \
152
+ --mode both \
153
+ --source cli
154
+
155
+ # Move to pose
156
+ cyberwave twins command \
157
+ --twin <TWIN_UUID> \
158
+ --name arm.move_pose \
159
+ --pose '{"x":0.1, "y":0.2, "z":0.0}' \
160
+ --mode sim
161
+ ```
162
+
163
+ ### Configuration
164
+
165
+ - CLI config: `~/.cyberwave/config.toml` (managed by `cyberwave auth config`)
166
+ - Edge config: `~/.cyberwave/edge.json` (managed by `cyberwave edge init`)
167
+
168
+ ### Security
169
+
170
+ - Tokens are stored in system keychain when available, with JSON fallback.
171
+ - Device tokens are long-lived; prefer them for headless Edge deployments.
172
+
173
+ ### Environments and Sensors (new)
174
+
175
+ List environments for a project and show recent events (latest session per twin):
176
+ ```bash
177
+ cyberwave environments list --project <PROJECT_UUID>
178
+ cyberwave environments events --environment <ENVIRONMENT_UUID> -n 5
179
+ ```
180
+
181
+ Create/list sensors in an environment:
182
+ ```bash
183
+ cyberwave sensors create --environment <ENVIRONMENT_UUID> --name "Living Room Cam" --type camera
184
+ cyberwave sensors list --environment <ENVIRONMENT_UUID>
185
+ ```
186
+
187
+ List analyzer events for a specific sensor from the latest session:
188
+ ```bash
189
+ cyberwave sensors events --environment <ENVIRONMENT_UUID> --sensor <SENSOR_UUID> -n 20
190
+ ```
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "cyberwave-cli"
7
+ version = "0.11.0"
8
+ description = "Cyberwave command-line interface (plugins, asset pipeline, telemetry)"
9
+ dependencies = [
10
+ "typer[all]>=0.12",
11
+ "rich>=13",
12
+ "importlib_metadata>=6.0; python_version < '3.10'",
13
+ "setuptools>=61.0",
14
+ "httpx>=0.24.0",
15
+ "tomli>=2.0.0; python_version < '3.11'",
16
+ "tomli-w>=1.0.0",
17
+ ]
18
+
19
+ [project.optional-dependencies]
20
+ sdk = ["cyberwave>=0.11,<0.12"]
21
+ test = ["pytest>=7.0", "pytest-cov", "pytest-mock"]
22
+
23
+ [project.scripts]
24
+ cyberwave = "cyberwave_cli.core:main"
25
+
26
+ [project.entry-points]
27
+ [project.entry-points."cyberwave.cli.plugins"]
28
+ auth = "cyberwave_cli.plugins.auth.app:app"
29
+ devices = "cyberwave_cli.plugins.devices.app:app"
30
+ projects = "cyberwave_cli.plugins.projects.app:app"
31
+ edge = "cyberwave_cli.plugins.edge.app:app"
32
+ twins = "cyberwave_cli.plugins.twins.app:app"
33
+ environments = "cyberwave_cli.plugins.environments.app:app"
34
+ sensors = "cyberwave_cli.plugins.sensors.app:app"
35
+
36
+ [tool.setuptools.packages.find]
37
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ # Init for cyberwave_cli package
@@ -0,0 +1,42 @@
1
+ import typer
2
+ from rich import print
3
+ from .plugins import loader
4
+
5
+ app = typer.Typer(rich_markup_mode="markdown")
6
+
7
+ def main():
8
+ # Discover and register plugins
9
+ loader.register_all(app)
10
+ # Run the app
11
+ app()
12
+
13
+ @app.callback()
14
+ def callback():
15
+ """
16
+ CyberWave Command-Line Interface
17
+ """
18
+ pass
19
+
20
+ @app.command()
21
+ def version() -> None:
22
+ """Show the installed CLI version."""
23
+ import importlib.metadata
24
+
25
+ cli_version = importlib.metadata.version("cyberwave-cli")
26
+ print(f"CyberWave CLI version: [bold green]{cli_version}[/bold green]")
27
+
28
+
29
+ @app.command()
30
+ def plugins_cmd() -> None:
31
+ """List available CLI plugins."""
32
+ plugin_names = loader.discover_plugins()
33
+ if not plugin_names:
34
+ print("No plugins found")
35
+ else:
36
+ print("Loaded plugins:")
37
+ for name in plugin_names:
38
+ print(f"- {name}")
39
+
40
+
41
+ if __name__ == "__main__":
42
+ main()
@@ -0,0 +1 @@
1
+ # Init for cyberwave_cli.plugins package
@@ -0,0 +1 @@
1
+ # Init for assets plugin
@@ -0,0 +1,87 @@
1
+ import asyncio
2
+ import re
3
+ from pathlib import Path
4
+ from typing import Optional
5
+
6
+ import typer
7
+ from rich import print
8
+
9
+ from cyberwave import Client
10
+
11
+ app = typer.Typer(help="Manage CyberWave assets (upload meshes to the catalog, list).")
12
+
13
+
14
+ def _simple_slugify(text: str) -> str:
15
+ """Very small helper to create URL-friendly slugs."""
16
+ slug = re.sub(r"[^a-zA-Z0-9-]+", "-", text.lower()).strip("-")
17
+ return slug
18
+
19
+
20
+ async def _upload_asset(
21
+ mesh_path: Path,
22
+ name: str,
23
+ workspace_uuid: str,
24
+ project_uuid: str,
25
+ description: Optional[str],
26
+ registry_id: Optional[str],
27
+ ) -> None:
28
+ client = Client()
29
+ await client.login()
30
+ # Create a simple catalog asset and attach a GLB file
31
+ # Prefer high-level helpers if present (test stub API)
32
+ if hasattr(client, "create_asset_definition"):
33
+ created = await client.create_asset_definition(name=name)
34
+ await client.upload_mesh(created["id"], mesh_path)
35
+ await client.add_geometry_to_asset_definition(created["id"])
36
+ print(f":white_check_mark: Created asset '[bold]{name}[/bold]' (ID {created['id']}) and uploaded GLB")
37
+ return
38
+ # Fallback to raw request + upload the GLB
39
+ created = await client._request(
40
+ "POST",
41
+ "/assets",
42
+ json={
43
+ "name": name,
44
+ "description": description or "",
45
+ "public": False,
46
+ "registry_id": registry_id,
47
+ },
48
+ )
49
+ asset = created.json() if hasattr(created, "json") else created
50
+ await client.upload_asset_glb(asset.get("uuid") or asset.get("id"), mesh_path)
51
+ # If no thumbnail, attempt to auto-generate a simple one from the GLB path (placeholder icon)
52
+ # Backend may also generate thumbnails asynchronously; this is a best-effort client-side fallback.
53
+ try:
54
+ # For now, rely on backend pipeline; printing hint for the user.
55
+ print(":bulb: If the asset lacks a thumbnail, the backend will attempt to generate one.")
56
+ except Exception:
57
+ pass
58
+ print(f":white_check_mark: Created asset '[bold]{name}[/bold]' (UUID {asset['uuid']}) and uploaded GLB")
59
+
60
+ @app.command()
61
+ def upload(
62
+ mesh: Path = typer.Argument(..., exists=True, help="Path to a mesh file"),
63
+ name: str = typer.Option(..., "--name", help="Name for the catalog entry"),
64
+ workspace: str = typer.Option(..., "--workspace", "-w", help="Workspace UUID"),
65
+ project: str = typer.Option(..., "--project", "-p", help="Project UUID (for future)"),
66
+ registry_id: Optional[str] = typer.Option(None, "--registry-id", help="Catalog registry identifier (e.g., so/100)"),
67
+ description: Optional[str] = typer.Option(None, "--description", help="Description"),
68
+ ):
69
+ """Upload a mesh and create a catalog asset definition."""
70
+
71
+ asyncio.run(_upload_asset(mesh, name, workspace, project, description, registry_id))
72
+
73
+ @app.command("list") # Explicit command name
74
+ def list_assets():
75
+ """List available assets in CyberWave storage."""
76
+ async def _run() -> None:
77
+ client = Client()
78
+ await client.login()
79
+ assets = await client.list_assets()
80
+ for a in assets:
81
+ rid = a.get("registry_id") or (a.get("metadata", {}) or {}).get("registry_id")
82
+ print(f"{a.get('uuid')} {a.get('name')} registry_id={rid}")
83
+
84
+ asyncio.run(_run())
85
+
86
+ if __name__ == "__main__":
87
+ app()
@@ -0,0 +1 @@
1
+ # Auth plugin for web-based authentication