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.
- cyberwave_cli-0.11.0/PKG-INFO +17 -0
- cyberwave_cli-0.11.0/README.md +190 -0
- cyberwave_cli-0.11.0/pyproject.toml +37 -0
- cyberwave_cli-0.11.0/setup.cfg +4 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/__init__.py +1 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/core.py +42 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/__init__.py +1 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/assets/__init__.py +1 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/assets/app.py +87 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/auth/__init__.py +1 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/auth/app.py +340 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/devices/__init__.py +1 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/devices/app.py +49 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/edge/app.py +149 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/environments/app.py +75 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/loader.py +43 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/projects/__init__.py +1 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/projects/app.py +55 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/sensors/app.py +138 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/sim/app.py +17 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/telemetry/__init__.py +1 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/telemetry/app.py +17 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli/plugins/twins/app.py +66 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli.egg-info/PKG-INFO +17 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli.egg-info/SOURCES.txt +32 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli.egg-info/dependency_links.txt +1 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli.egg-info/entry_points.txt +11 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli.egg-info/requires.txt +19 -0
- cyberwave_cli-0.11.0/src/cyberwave_cli.egg-info/top_level.txt +1 -0
- cyberwave_cli-0.11.0/tests/test_assets_cli.py +132 -0
- cyberwave_cli-0.11.0/tests/test_core.py +81 -0
- cyberwave_cli-0.11.0/tests/test_devices_cli.py +93 -0
- cyberwave_cli-0.11.0/tests/test_edge_cli.py +114 -0
- 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 @@
|
|
|
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
|