autoverse-cli 0.28.2__tar.gz → 0.29.1.dev408__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 (57) hide show
  1. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/PKG-INFO +22 -1
  2. autoverse_cli-0.29.1.dev408/README.md +64 -0
  3. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/pyproject.toml +1 -1
  4. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/autoverse_cli.egg-info/PKG-INFO +22 -1
  5. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/app_version.py +1 -1
  6. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/race_cloud.py +86 -15
  7. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/race_cloud_util.py +47 -14
  8. autoverse_cli-0.28.2/README.md +0 -43
  9. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/LICENSE +0 -0
  10. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/setup.cfg +0 -0
  11. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/autoverse_cli.egg-info/SOURCES.txt +0 -0
  12. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/autoverse_cli.egg-info/dependency_links.txt +0 -0
  13. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/autoverse_cli.egg-info/entry_points.txt +0 -0
  14. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/autoverse_cli.egg-info/requires.txt +0 -0
  15. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/autoverse_cli.egg-info/top_level.txt +0 -0
  16. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/__init__.py +0 -0
  17. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/argparse_help.py +0 -0
  18. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/avrs.py +0 -0
  19. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/can_tool.py +0 -0
  20. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/can_tool_util.py +0 -0
  21. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/cfg.py +0 -0
  22. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/launcher.py +0 -0
  23. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/launcher_util.py +0 -0
  24. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/race_cloud_bridge_can.py +0 -0
  25. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/race_cloud_cfg_util.py +0 -0
  26. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/race_cloud_fwd_api.py +0 -0
  27. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/change_camera.py +0 -0
  28. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/code_booz.py +0 -0
  29. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/demo.py +0 -0
  30. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/dump_sim_config.py +0 -0
  31. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/environment.py +0 -0
  32. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/fault_injection.py +0 -0
  33. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/get_object_config.py +0 -0
  34. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/get_web_viz_meta.py +0 -0
  35. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/leaderboard.py +0 -0
  36. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/list_sim_objects.py +0 -0
  37. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/log_path.py +0 -0
  38. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/misc.py +0 -0
  39. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/move_to_landmark.py +0 -0
  40. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/npc.py +0 -0
  41. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/race_control.py +0 -0
  42. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/request.py +0 -0
  43. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/reset_to_track.py +0 -0
  44. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/rest_request.py +0 -0
  45. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/restart.py +0 -0
  46. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/scenario_control.py +0 -0
  47. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/spawn_object.py +0 -0
  48. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/teleport.py +0 -0
  49. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/toggle_hud.py +0 -0
  50. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/vd.py +0 -0
  51. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/vehicle_input.py +0 -0
  52. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/requests/vehicle_replay.py +0 -0
  53. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/shell_completion.py +0 -0
  54. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/simconfig.py +0 -0
  55. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/simconfig_util.py +0 -0
  56. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/tests.py +0 -0
  57. {autoverse_cli-0.28.2 → autoverse_cli-0.29.1.dev408}/src/avrs/util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autoverse-cli
3
- Version: 0.28.2
3
+ Version: 0.29.1.dev408
4
4
  Summary: The Autoverse CLI
5
5
  Author-email: Dan Kamrath <dan.kamrath@autonomalabs.com>
6
6
  License: # End-User License Agreement (EULA) of the Autonoma AutoVerse CLI
@@ -52,10 +52,31 @@ The new implementation of the Autoverse CLI
52
52
 
53
53
  ## Installation
54
54
 
55
+ ### Stable Release (Recommended)
55
56
  ```bash
56
57
  pip install autoverse-cli
57
58
  ```
58
59
 
60
+ ### Development Versions
61
+
62
+ Development versions are published from feature branches and follow the format `X.Y.Z.devN`.
63
+
64
+ ```bash
65
+ # Install the latest development version
66
+ pip install autoverse-cli --pre
67
+
68
+ # Install a specific development version
69
+ pip install autoverse-cli==0.29.1.dev123
70
+
71
+ # Check available versions (including dev)
72
+ pip index versions autoverse-cli
73
+
74
+ # Upgrade to latest dev version
75
+ pip install --upgrade --pre autoverse-cli
76
+ ```
77
+
78
+ > **Note:** `pip install autoverse-cli` (without `--pre`) always installs the latest stable release from `main`. Development versions require the `--pre` flag explicitly.
79
+
59
80
  ## Shell Completion
60
81
 
61
82
  To enable tab completion for the `avrs` command, run:
@@ -0,0 +1,64 @@
1
+ # Autoverse CLI
2
+
3
+ The new implementation of the Autoverse CLI
4
+
5
+ ## Installation
6
+
7
+ ### Stable Release (Recommended)
8
+ ```bash
9
+ pip install autoverse-cli
10
+ ```
11
+
12
+ ### Development Versions
13
+
14
+ Development versions are published from feature branches and follow the format `X.Y.Z.devN`.
15
+
16
+ ```bash
17
+ # Install the latest development version
18
+ pip install autoverse-cli --pre
19
+
20
+ # Install a specific development version
21
+ pip install autoverse-cli==0.29.1.dev123
22
+
23
+ # Check available versions (including dev)
24
+ pip index versions autoverse-cli
25
+
26
+ # Upgrade to latest dev version
27
+ pip install --upgrade --pre autoverse-cli
28
+ ```
29
+
30
+ > **Note:** `pip install autoverse-cli` (without `--pre`) always installs the latest stable release from `main`. Development versions require the `--pre` flag explicitly.
31
+
32
+ ## Shell Completion
33
+
34
+ To enable tab completion for the `avrs` command, run:
35
+
36
+ ```bash
37
+ avrs --install-completion
38
+ ```
39
+
40
+ Then reload your shell:
41
+
42
+ ```bash
43
+ source ~/.bashrc # or ~/.zshrc, ~/.config/fish/config.fish, etc.
44
+ ```
45
+
46
+ For full details, see [SHELL_COMPLETION.md](SHELL_COMPLETION.md).
47
+
48
+ ### Supported Shells
49
+
50
+ - Bash
51
+ - Zsh
52
+ - Fish
53
+ - Tcsh
54
+
55
+ ### Quick Usage Examples
56
+
57
+ ```bash
58
+ # List all available commands
59
+ avrs <TAB>
60
+
61
+ # Complete subcommand arguments
62
+ avrs launcher <TAB>
63
+ avrs restart <TAB>
64
+ ```
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "autoverse-cli"
3
- version = "0.28.2"
3
+ version = "0.29.1.dev408"
4
4
  dependencies = [
5
5
  "boto3",
6
6
  "cantools",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autoverse-cli
3
- Version: 0.28.2
3
+ Version: 0.29.1.dev408
4
4
  Summary: The Autoverse CLI
5
5
  Author-email: Dan Kamrath <dan.kamrath@autonomalabs.com>
6
6
  License: # End-User License Agreement (EULA) of the Autonoma AutoVerse CLI
@@ -52,10 +52,31 @@ The new implementation of the Autoverse CLI
52
52
 
53
53
  ## Installation
54
54
 
55
+ ### Stable Release (Recommended)
55
56
  ```bash
56
57
  pip install autoverse-cli
57
58
  ```
58
59
 
60
+ ### Development Versions
61
+
62
+ Development versions are published from feature branches and follow the format `X.Y.Z.devN`.
63
+
64
+ ```bash
65
+ # Install the latest development version
66
+ pip install autoverse-cli --pre
67
+
68
+ # Install a specific development version
69
+ pip install autoverse-cli==0.29.1.dev123
70
+
71
+ # Check available versions (including dev)
72
+ pip index versions autoverse-cli
73
+
74
+ # Upgrade to latest dev version
75
+ pip install --upgrade --pre autoverse-cli
76
+ ```
77
+
78
+ > **Note:** `pip install autoverse-cli` (without `--pre`) always installs the latest stable release from `main`. Development versions require the `--pre` flag explicitly.
79
+
59
80
  ## Shell Completion
60
81
 
61
82
  To enable tab completion for the `avrs` command, run:
@@ -2,7 +2,7 @@ import http.client
2
2
  import json
3
3
 
4
4
  def get_app_version():
5
- return '0.28.2'
5
+ return '0.29.1.dev408'
6
6
 
7
7
  def check_app_is_latest():
8
8
  pass
@@ -2,6 +2,7 @@ import subprocess
2
2
  import base64
3
3
  import logging
4
4
  import time
5
+ import ipaddress
5
6
  from avrs.cfg import *
6
7
  from avrs.race_cloud_util import *
7
8
  from avrs.race_cloud_cfg_util import *
@@ -11,6 +12,47 @@ from avrs.util import *
11
12
  from avrs.requests.request import AvrsApiRequest
12
13
  from argparse import RawTextHelpFormatter
13
14
 
15
+
16
+ def is_valid_public_ip(value):
17
+ """Check if a string is a valid public IP address (not private, not loopback, not reserved)."""
18
+ try:
19
+ ip = ipaddress.ip_address(value)
20
+ # Reject private, loopback, reserved, multicast, and link-local addresses
21
+ return not (ip.is_private or ip.is_loopback or ip.is_reserved or
22
+ ip.is_multicast or ip.is_link_local)
23
+ except ValueError:
24
+ return False
25
+
26
+
27
+ def parse_sim_target(value):
28
+ """
29
+ Parse sim_target argument: can be a legacy index (0-5) or a public IP address.
30
+ Returns (is_valid, parsed_value, is_ip).
31
+ """
32
+ # First, check if it's a legacy integer index (0-5)
33
+ try:
34
+ index = int(value)
35
+ if 0 <= index <= 5:
36
+ return (True, index, False)
37
+ else:
38
+ return (False, "Legacy index must be between 0 and 5", False)
39
+ except ValueError:
40
+ pass
41
+
42
+ # Check if it's a valid public IP address
43
+ try:
44
+ ip = ipaddress.ip_address(value)
45
+ if is_valid_public_ip(value):
46
+ # Valid public IP address
47
+ return (True, value, True)
48
+ else:
49
+ # IP is private, loopback, or otherwise not public
50
+ return (False, "IP address must be public (not private, loopback, or reserved)", False)
51
+ except ValueError:
52
+ pass
53
+
54
+ return (False, "Must be a legacy index (0-5) or a valid public IP address", False)
55
+
14
56
  class AvrsRaceCloud(AvrsApiRequest):
15
57
  def __init__(self, parser, cfg):
16
58
  self.cfg = cfg
@@ -24,10 +66,9 @@ class AvrsRaceCloud(AvrsApiRequest):
24
66
  'connect',
25
67
  help='connect to an instance for cloud racing')
26
68
  connect_parser.add_argument(
27
- 'sim_index',
28
- type = int,
29
- choices = [0, 1, 2, 3, 4, 5],
30
- help='the index of the simulator instance to connect to')
69
+ 'sim_target',
70
+ type=str,
71
+ help='simulator target: legacy index (0-5) or PUBLIC IP address of the server instance (private IPs not allowed)')
31
72
  connect_parser.add_argument(
32
73
  'team_name',
33
74
  help='the name of the team to race under')
@@ -74,10 +115,9 @@ class AvrsRaceCloud(AvrsApiRequest):
74
115
  'sim-ctrl',
75
116
  help='control the sim program (start, stop, restart, reset)')
76
117
  sim_ctrl_parser.add_argument(
77
- 'sim_index',
78
- type=int,
79
- choices=[0, 1, 2, 3, 4, 5],
80
- help='the index of the simulator instance to apply the action')
118
+ 'sim_target',
119
+ type=str,
120
+ help='simulator target: legacy index (0-5) or PUBLIC IP address of the server instance (private IPs not allowed)')
81
121
  sim_ctrl_parser.add_argument(
82
122
  'action',
83
123
  choices=['start', 'stop', 'restart', 'reset-connection', 'get-log'],
@@ -169,6 +209,12 @@ class AvrsRaceCloud(AvrsApiRequest):
169
209
  def race_connect(self, args):
170
210
  logger = logging.getLogger('avrs')
171
211
 
212
+ # Validate sim_target (can be legacy index 0-5 or public IP only)
213
+ is_valid, parsed_value, is_ip = parse_sim_target(args.sim_target)
214
+ if not is_valid:
215
+ print('invalid sim_target: {}'.format(parsed_value))
216
+ return
217
+
172
218
  # make api call to begin connection
173
219
  our_ip = get_local_instance_ip()
174
220
 
@@ -176,8 +222,9 @@ class AvrsRaceCloud(AvrsApiRequest):
176
222
  print('this machines IP was returned as localhost. was this run on the cloud instance?')
177
223
  return
178
224
 
179
- logger.info('starting race-cloud connect for team {} to instance {}'.format(
180
- args.team_name, args.sim_index))
225
+ target_display = args.sim_target if is_ip else 'index {}'.format(parsed_value)
226
+ logger.info('starting race-cloud connect for team {} to {}'.format(
227
+ args.team_name, target_display))
181
228
  print('connecting to race with team name: {}'.format(args.team_name))
182
229
 
183
230
  if args.no_restart_sim:
@@ -217,7 +264,7 @@ class AvrsRaceCloud(AvrsApiRequest):
217
264
 
218
265
  connection_request = {
219
266
  'action': 'connect',
220
- 'sim_index': args.sim_index,
267
+ 'sim_id': str(parsed_value), # Can be index (0-5) or public IP address only
221
268
  'ip_to_reserve': our_ip,
222
269
  'team_name': args.team_name,
223
270
  'sim_id_override': args.instance_id,
@@ -241,9 +288,27 @@ class AvrsRaceCloud(AvrsApiRequest):
241
288
 
242
289
  slot_info = {}
243
290
  for k, v in rbody.items():
244
- #print('out: {}'.format(v['stdout']))
245
- #print('err: {}'.format(v['stderr']))
246
- slot_info = json.loads(v['stdout'])
291
+ logger.info('Processing response for key: {}'.format(k))
292
+ logger.info('stdout: {}'.format(v.get('stdout', '')))
293
+ logger.info('stderr: {}'.format(v.get('stderr', '')))
294
+
295
+ stdout = v.get('stdout', '').strip()
296
+ stderr = v.get('stderr', '').strip()
297
+
298
+ if not stdout:
299
+ print('Error: No stdout from remote command')
300
+ if stderr:
301
+ print('stderr: {}'.format(stderr))
302
+ return
303
+
304
+ try:
305
+ slot_info = json.loads(stdout)
306
+ except json.JSONDecodeError as e:
307
+ print('Error parsing JSON from stdout: {}'.format(e))
308
+ print('stdout content: {}'.format(stdout[:500])) # Print first 500 chars
309
+ if stderr:
310
+ print('stderr: {}'.format(stderr))
311
+ return
247
312
 
248
313
  if not slot_info['ok']:
249
314
  print('issue reserving slot: {}'.format(slot_info['msg']))
@@ -405,6 +470,12 @@ class AvrsRaceCloud(AvrsApiRequest):
405
470
  def remote_sim_ctrl(self, args):
406
471
  logger = logging.getLogger('avrs')
407
472
 
473
+ # Validate sim_target (can be legacy index 0-5 or public IP only)
474
+ is_valid, parsed_value, is_ip = parse_sim_target(args.sim_target)
475
+ if not is_valid:
476
+ print('invalid sim_target: {}'.format(parsed_value))
477
+ return
478
+
408
479
  # go ahead and reset local connection as well
409
480
  if args.action == 'reset-connection':
410
481
  reset_race_cloud_connection()
@@ -413,7 +484,7 @@ class AvrsRaceCloud(AvrsApiRequest):
413
484
 
414
485
  reset_request = {
415
486
  'action': args.action,
416
- 'sim_index': args.sim_index,
487
+ 'sim_id': str(parsed_value), # Can be index (0-5) or public IP address only
417
488
  'ip_to_reserve': our_ip,
418
489
  'sim_id_override': args.instance_id,
419
490
  'ensure_instance_is_running': False
@@ -1,7 +1,10 @@
1
1
  import os
2
2
  import json
3
- import http.client
4
3
  import logging
4
+ import boto3
5
+ from botocore.auth import SigV4Auth
6
+ from botocore.awsrequest import AWSRequest
7
+ import urllib.request
5
8
  from avrs.util import *
6
9
 
7
10
  BASH_KILL_PROCESS_SCRIPT = '''
@@ -360,23 +363,53 @@ def call_race_cloud_api(body):
360
363
  logger = logging.getLogger('avrs')
361
364
  logger.info('calling race-cloud api with body: {}'.format(body))
362
365
 
363
- api_url = 'gitzels0l7.execute-api.us-east-1.amazonaws.com'
366
+ url = 'https://9gca6018p0.execute-api.us-east-1.amazonaws.com/backend/race-connect'
367
+ region = 'us-east-1'
364
368
 
365
- connection = http.client.HTTPSConnection(api_url)
366
- headers = {
367
- 'Content-type': 'application/json',
368
- 'x-api-key': '7aQ83sJ89Q2DZ8NdIi9aUTBuUS2uyix5QoDwrl1j'
369
- }
370
- body = json.dumps(body).encode('utf-8')
371
- connection.request('POST', '/beta/connect', body, headers)
372
- response = connection.getresponse()
373
- if response.status != 200:
374
- return (False, 'response had status code {}'.format(response))
375
- return (True, response.read().decode('utf-8'))
369
+ # Get credentials from boto3 session (uses IAM role on EC2)
370
+ session = boto3.Session()
371
+ credentials = session.get_credentials()
372
+
373
+ # Prepare the request body
374
+ body_json = json.dumps(body)
375
+
376
+ # Create AWS request for signing
377
+ request = AWSRequest(
378
+ method='POST',
379
+ url=url,
380
+ data=body_json,
381
+ headers={'Content-Type': 'application/json'}
382
+ )
383
+
384
+ # Sign the request with SigV4
385
+ SigV4Auth(credentials, 'execute-api', region).add_auth(request)
386
+
387
+ # Make the request using urllib
388
+ try:
389
+ req = urllib.request.Request(
390
+ url,
391
+ data=body_json.encode('utf-8'),
392
+ headers=dict(request.headers),
393
+ method='POST'
394
+ )
395
+ with urllib.request.urlopen(req) as response:
396
+ response_body = response.read().decode('utf-8')
397
+ return (True, response_body)
398
+ except urllib.error.HTTPError as e:
399
+ error_body = e.read().decode('utf-8')
400
+ logger.error('API error - status: {}, body: {}'.format(e.code, error_body))
401
+ return (False, 'response had status code {} - {}'.format(e.code, error_body))
402
+ except Exception as e:
403
+ logger.error('API request failed: {}'.format(str(e)))
404
+ return (False, 'request failed: {}'.format(str(e)))
376
405
 
377
406
  def get_api_script_response(raw):
378
- decoded = json.loads(raw)['body']
379
407
  logger = logging.getLogger('avrs')
408
+ # Parse API Gateway response, then parse the body which is also JSON string
409
+ api_response = json.loads(raw)
410
+ body_str = api_response['body']
411
+ # Body is a JSON string from Lambda Proxy integration
412
+ decoded = json.loads(body_str) if isinstance(body_str, str) else body_str
380
413
  logger.info('race cloud api response: {}'.format(decoded))
381
414
  if decoded['script_response']['statusCode'] != 200:
382
415
  return (False, 'inner response had bad status code {}'.format(decoded))
@@ -1,43 +0,0 @@
1
- # Autoverse CLI
2
-
3
- The new implementation of the Autoverse CLI
4
-
5
- ## Installation
6
-
7
- ```bash
8
- pip install autoverse-cli
9
- ```
10
-
11
- ## Shell Completion
12
-
13
- To enable tab completion for the `avrs` command, run:
14
-
15
- ```bash
16
- avrs --install-completion
17
- ```
18
-
19
- Then reload your shell:
20
-
21
- ```bash
22
- source ~/.bashrc # or ~/.zshrc, ~/.config/fish/config.fish, etc.
23
- ```
24
-
25
- For full details, see [SHELL_COMPLETION.md](SHELL_COMPLETION.md).
26
-
27
- ### Supported Shells
28
-
29
- - Bash
30
- - Zsh
31
- - Fish
32
- - Tcsh
33
-
34
- ### Quick Usage Examples
35
-
36
- ```bash
37
- # List all available commands
38
- avrs <TAB>
39
-
40
- # Complete subcommand arguments
41
- avrs launcher <TAB>
42
- avrs restart <TAB>
43
- ```