sima-cli 0.0.15__py3-none-any.whl → 0.0.17__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.
sima_cli/__version__.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # sima_cli/__version__.py
2
- __version__ = "0.0.15"
2
+ __version__ = "0.0.17"
@@ -96,12 +96,12 @@ def login_external():
96
96
  session.headers["X-CSRF-Token"] = csrf_token
97
97
 
98
98
  if _is_session_valid(session):
99
- click.echo("🚀 Reusing existing session.")
99
+ click.echo("🚀 You are already logged in.")
100
100
  return session
101
101
 
102
102
  # Prompt user login
103
103
  _delete_auth_files()
104
- click.echo(f"🔐 Login attempt {attempt}/3")
104
+ click.echo(f"🔐 Sima.ai Developer Portal Login Attempt {attempt}/3")
105
105
  username = click.prompt("Email or Username")
106
106
  password = getpass.getpass("Password: ")
107
107
 
sima_cli/auth/login.py CHANGED
@@ -13,10 +13,13 @@ def login(method: str = "external"):
13
13
  Args:
14
14
  method (str): 'external' (public developer portal) or 'internal' (Artifactory).
15
15
  """
16
- if method == "internal":
17
- return login_internal()
18
- else:
19
- return login_external()
16
+ try:
17
+ if method == "internal":
18
+ return login_internal()
19
+ else:
20
+ return login_external()
21
+ except Exception as e:
22
+ print(f'Unable to login: {e}')
20
23
 
21
24
  def login_internal():
22
25
  """
sima_cli/cli.py CHANGED
@@ -5,6 +5,8 @@ from sima_cli.update.updater import perform_update
5
5
  from sima_cli.model_zoo.model import list_models, download_model, describe_model
6
6
  from sima_cli.utils.config_loader import internal_resource_exists
7
7
  from sima_cli.mla.meminfo import monitor_simaai_mem_chart
8
+ from sima_cli.__version__ import __version__
9
+ from sima_cli.utils.config import CONFIG_PATH
8
10
 
9
11
  # Entry point for the CLI tool using Click's command group decorator
10
12
  @click.group()
@@ -19,6 +21,8 @@ def main(ctx, internal):
19
21
  """
20
22
  ctx.ensure_object(dict)
21
23
 
24
+ os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True)
25
+
22
26
  # Allow env override if --internal not explicitly passed
23
27
  if not internal:
24
28
  internal = os.getenv("SIMA_CLI_INTERNAL", "0") in ("1", "true", "yes")
@@ -50,6 +54,45 @@ def login(ctx):
50
54
  internal = ctx.obj.get("internal", False)
51
55
  perform_login.login("internal" if internal else "external")
52
56
 
57
+ # ----------------------
58
+ # Version Command
59
+ # ----------------------
60
+ @main.command(name="version")
61
+ def version_cmd():
62
+ """Show the version of the CLI tool."""
63
+ click.echo(f"SiMa CLI version: {__version__}")
64
+
65
+ # ----------------------
66
+ # Logout Command
67
+ # ----------------------
68
+ @main.command(name="logout")
69
+ @click.pass_context
70
+ def logout_cmd(ctx):
71
+ """Log out by deleting cached credentials and config files."""
72
+ sima_cli_dir = os.path.expanduser("~/.sima-cli")
73
+ internal = ctx.obj.get("internal", False)
74
+ deleted_any = False
75
+
76
+ if not os.path.isdir(sima_cli_dir):
77
+ click.echo("⚠️ No ~/.sima-cli directory found.")
78
+ return
79
+
80
+ if internal:
81
+ target_files = ["config.json"]
82
+ else:
83
+ target_files = [".sima-cli-cookies.txt", ".sima-cli-csrf.json"]
84
+
85
+ for filename in target_files:
86
+ full_path = os.path.join(sima_cli_dir, filename)
87
+ if os.path.exists(full_path):
88
+ try:
89
+ os.remove(full_path)
90
+ deleted_any = True
91
+ except Exception as e:
92
+ click.echo(f"⚠️ Failed to delete {full_path}: {e}", err=True)
93
+
94
+ click.echo("✅ Logged out successfully.")
95
+
53
96
  # ----------------------
54
97
  # Download Command
55
98
  # ----------------------
@@ -88,14 +131,18 @@ def download(ctx, url, dest):
88
131
  @main.command(name="update")
89
132
  @click.argument('version_or_url')
90
133
  @click.option('--ip', help="Target device IP address for remote firmware update.")
91
-
134
+ @click.option(
135
+ '-y', '--yes',
136
+ is_flag=True,
137
+ help="Skip confirmation after firmware file is downloaded."
138
+ )
92
139
  @click.option(
93
140
  '--passwd',
94
141
  default='edgeai',
95
142
  help="Optional SSH password for remote board (default is 'edgeai')."
96
143
  )
97
144
  @click.pass_context
98
- def update(ctx, version_or_url, ip, passwd):
145
+ def update(ctx, version_or_url, ip, yes, passwd):
99
146
  """
100
147
  Run system update across different environments.
101
148
  Downloads and applies firmware updates for PCIe host or SiMa board.
@@ -104,10 +151,9 @@ def update(ctx, version_or_url, ip, passwd):
104
151
  """
105
152
  internal = ctx.obj.get("internal", False)
106
153
  if not internal:
107
- click.echo(f"external environment is not supported yet..")
154
+ click.echo("External environment is not supported yet.")
108
155
  exit(0)
109
-
110
- perform_update(version_or_url, ip, internal, passwd=passwd)
156
+ perform_update(version_or_url, ip, internal, passwd=passwd, auto_confirm=yes)
111
157
 
112
158
  # ----------------------
113
159
  # Model Zoo Subcommands
@@ -4,6 +4,7 @@ from urllib.parse import urlparse
4
4
  from tqdm import tqdm
5
5
  from typing import List
6
6
  from sima_cli.utils.config import get_auth_token
7
+ from sima_cli.auth.basic_auth import login_external
7
8
 
8
9
  def _list_directory_files(url: str, internal: bool = False) -> List[str]:
9
10
  """
@@ -73,12 +74,19 @@ def download_file_from_url(url: str, dest_folder: str = ".", internal: bool = Fa
73
74
  existing_size = 0
74
75
 
75
76
  try:
76
- auth_token = get_auth_token(internal)
77
- if auth_token:
78
- headers["Authorization"] = f"Bearer {auth_token}"
77
+ if internal:
78
+ auth_token = get_auth_token(internal=True)
79
+ if auth_token:
80
+ headers["Authorization"] = f"Bearer {auth_token}"
81
+ request_fn = requests.get
82
+ head_fn = requests.head
83
+ else:
84
+ session = login_external()
85
+ request_fn = session.get
86
+ head_fn = session.head
79
87
 
80
88
  # HEAD request to get total file size
81
- head = requests.head(url, headers=headers, timeout=10)
89
+ head = head_fn(url, headers=headers, timeout=10)
82
90
  head.raise_for_status()
83
91
  total_size = int(head.headers.get('content-length', 0))
84
92
 
@@ -97,8 +105,8 @@ def download_file_from_url(url: str, dest_folder: str = ".", internal: bool = Fa
97
105
  existing_size = 0
98
106
  mode = 'wb'
99
107
 
100
- # Begin download with headers
101
- with requests.get(url, stream=True, headers=headers, timeout=30) as r:
108
+ # Begin download with appropriate handler
109
+ with request_fn(url, stream=True, headers=headers, timeout=30) as r:
102
110
  r.raise_for_status()
103
111
 
104
112
  content_length = int(r.headers.get('content-length', 0))
File without changes
@@ -0,0 +1,120 @@
1
+ import json
2
+ import platform
3
+ import psutil
4
+ import shutil
5
+ import subprocess
6
+ import sys
7
+ import re
8
+ try:
9
+ from packaging import version
10
+ except ImportError:
11
+ version = None
12
+
13
+ def load_requirements(file_path='system_requirements.json'):
14
+ try:
15
+ with open(file_path, 'r') as f:
16
+ return json.load(f)
17
+ except FileNotFoundError:
18
+ print(f"Error: Requirements file '{file_path}' not found.")
19
+ sys.exit(1)
20
+ except json.JSONDecodeError:
21
+ print(f"Error: Invalid JSON format in '{file_path}'.")
22
+ sys.exit(1)
23
+
24
+ def check_cpu_cores(required_cores):
25
+ actual_cores = psutil.cpu_count(logical=False)
26
+ return actual_cores >= required_cores, f"CPU Cores: {actual_cores} (Required: {required_cores})"
27
+
28
+ def check_memory(required_memory_gb):
29
+ actual_memory = psutil.virtual_memory().total / (1024 ** 3) # Convert bytes to GB
30
+ return actual_memory >= required_memory_gb, f"Memory: {actual_memory:.2f} GB (Required: {required_memory_gb} GB)"
31
+
32
+ def check_storage(required_storage_gb):
33
+ _, _, free = shutil.disk_usage('/')
34
+ free_gb = free / (1024 ** 3) # Convert bytes to GB
35
+ return free_gb >= required_storage_gb, f"Free Storage: {free_gb:.2f} GB (Required: {required_storage_gb} GB)"
36
+
37
+ def check_os(supported_os):
38
+ current_os = platform.system()
39
+ current_version = platform.version()
40
+ system_name = current_os.lower()
41
+
42
+ if system_name == "linux":
43
+ if "Ubuntu 22.04" in supported_os:
44
+ try:
45
+ with open('/etc/os-release') as f:
46
+ os_info = f.read()
47
+ if "Ubuntu 22.04" in os_info:
48
+ return True, "OS: Ubuntu 22.04 (Supported)"
49
+ except FileNotFoundError:
50
+ pass
51
+ elif system_name == "windows":
52
+ if "10" in current_version and "Windows 10" in supported_os:
53
+ return True, "OS: Windows 10 (Supported)"
54
+ if "11" in current_version and "Windows 11" in supported_os:
55
+ return True, "OS: Windows 11 (Supported)"
56
+
57
+ return False, f"OS: {current_os} {current_version} (Not supported)"
58
+
59
+ def check_docker_version(required_version):
60
+ try:
61
+ result = subprocess.run(['docker', '--version'], capture_output=True, text=True)
62
+ match = re.search(r'(\d+\.\d+\.\d+)', result.stdout)
63
+ if not match:
64
+ return False, "Docker: Could not parse version"
65
+ current_version = match.group(1)
66
+ current_os = platform.system().lower()
67
+ required = required_version.get(current_os, None)
68
+ if required is None:
69
+ return True, f"Docker: {current_version} (No version requirement for {current_os})"
70
+ if version:
71
+ result = version.parse(current_version) >= version.parse(required)
72
+ else:
73
+ current_parts = tuple(map(int, current_version.split('.')))
74
+ required_parts = tuple(map(int, required.split('.')))
75
+ result = current_parts >= required_parts
76
+ return result, f"Docker: {current_version} (Required: {required})"
77
+ except FileNotFoundError:
78
+ return False, "Docker: Not installed"
79
+
80
+ def check_python_version(required_version):
81
+ current_version = platform.python_version()
82
+ if version:
83
+ # Use packaging.version for proper version comparison
84
+ result = version.parse(current_version) >= version.parse(required_version)
85
+ else:
86
+ # Fallback to tuple comparison if packaging is not available
87
+ current_parts = tuple(map(int, current_version.split('.')))
88
+ required_parts = tuple(map(int, required_version.split('.')))
89
+ result = current_parts >= required_parts
90
+ return result, f"Python: {current_version} (Required: {required_version})"
91
+
92
+ def main():
93
+ requirements = load_requirements()
94
+
95
+ checks = [
96
+ check_cpu_cores(requirements['cpu_cores']),
97
+ check_memory(requirements['memory_gb']),
98
+ check_storage(requirements['storage_gb']),
99
+ check_os(requirements['supported_os']),
100
+ check_docker_version(requirements['docker_version']),
101
+ check_python_version(requirements['python_min_version'])
102
+ ]
103
+
104
+ print("System Check Results:")
105
+ print("-" * 50)
106
+ all_passed = True
107
+
108
+ for passed, message in checks:
109
+ status = "✓" if passed else "✗"
110
+ print(f"{status} {message}")
111
+ if not passed:
112
+ all_passed = False
113
+
114
+ print("-" * 50)
115
+ print("System Check: " + ("PASSED" if all_passed else "FAILED"))
116
+ if not all_passed:
117
+ print("Please address the failed requirements.")
118
+
119
+ if __name__ == "__main__":
120
+ main()
@@ -326,8 +326,7 @@ def _update_remote(extracted_paths: List[str], ip: str, board: str, passwd: str,
326
326
 
327
327
  return script_path
328
328
 
329
-
330
- def perform_update(version_or_url: str, ip: str = None, internal: bool = False, passwd: str = "edgeai"):
329
+ def perform_update(version_or_url: str, ip: str = None, internal: bool = False, passwd: str = "edgeai", auto_confirm: bool = False):
331
330
  r"""
332
331
  Update the system based on environment and input.
333
332
 
@@ -339,8 +338,9 @@ def perform_update(version_or_url: str, ip: str = None, internal: bool = False,
339
338
  Args:
340
339
  version_or_url (str): Version string or direct URL.
341
340
  ip (str): Optional remote target IP.
342
- board (str): Board type, must be 'davinci' or 'modalix'.
343
- passwd : non-default password in case user has changed the password of the board user `sima`
341
+ internal (bool): If True, enable internal-only behaviors (e.g., Artifactory access).
342
+ passwd (str): Password for the board user (default: "edgeai").
343
+ auto_confirm (bool): If True, auto-confirm firmware update without prompting.
344
344
  """
345
345
  try:
346
346
  board = ''
@@ -360,6 +360,13 @@ def perform_update(version_or_url: str, ip: str = None, internal: bool = False,
360
360
  version_or_url = _pick_from_available_versions(board, version_or_url, internal)
361
361
 
362
362
  extracted_paths = _download_image(version_or_url, board, internal)
363
+
364
+ if not auto_confirm:
365
+ click.confirm(
366
+ "⚠️ Firmware image is ready. Do you want to proceed with the update?",
367
+ abort=True
368
+ )
369
+
363
370
  click.echo("⚠️ DO NOT INTERRUPT THE UPDATE PROCESS...")
364
371
 
365
372
  if len(extracted_paths) > 0:
@@ -367,7 +374,7 @@ def perform_update(version_or_url: str, ip: str = None, internal: bool = False,
367
374
  # Always update the remote device first then update the host driver, otherwise the host would
368
375
  # not be able to connect to the board
369
376
  click.echo("👉 Updating PCIe host driver and downloading firmware...")
370
- script_path = _update_remote(extracted_paths, ip, board, passwd, reboot_and_wait = False)
377
+ script_path = _update_remote(extracted_paths, ip, board, passwd, reboot_and_wait=False)
371
378
  _update_host(script_path, board, ip, passwd)
372
379
  elif env_type == "board":
373
380
  _update_board(extracted_paths, board, passwd)
@@ -375,12 +382,11 @@ def perform_update(version_or_url: str, ip: str = None, internal: bool = False,
375
382
  click.echo("👉 Updating firmware from within the Palette SDK...: Not implemented yet")
376
383
  elif ip:
377
384
  click.echo(f"👉 Updating firmware on remote board at {ip}...")
378
- _update_remote(extracted_paths, ip, board, passwd, reboot_and_wait = True)
385
+ _update_remote(extracted_paths, ip, board, passwd, reboot_and_wait=True)
379
386
  else:
380
387
  click.echo("❌ Unknown environment. Use --ip to specify target device.")
381
388
  else:
382
389
  click.echo("❌ Unable to retrieve target board information")
383
390
 
384
391
  except Exception as e:
385
- click.echo(f"❌ Update failed {e}")
386
-
392
+ click.echo(f"❌ Update failed: {e}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sima-cli
3
- Version: 0.0.15
3
+ Version: 0.0.17
4
4
  Summary: CLI tool for SiMa Developer Portal to download models, firmware, and apps.
5
5
  Home-page: https://developer.sima.ai/
6
6
  Author: SiMa.ai
@@ -23,6 +23,7 @@ Requires-Dist: pyyaml
23
23
  Requires-Dist: paramiko
24
24
  Requires-Dist: plotext
25
25
  Requires-Dist: rich
26
+ Requires-Dist: InquirerPy
26
27
  Dynamic: author
27
28
  Dynamic: license-file
28
29
  Dynamic: requires-python
@@ -1,31 +1,33 @@
1
1
  sima_cli/__init__.py,sha256=Nb2jSg9-CX1XvSc1c21U9qQ3atINxphuNkNfmR-9P3o,332
2
2
  sima_cli/__main__.py,sha256=ehzD6AZ7zGytC2gLSvaJatxeD0jJdaEvNJvwYeGsWOg,69
3
- sima_cli/__version__.py,sha256=rZ8VyuhqgF22Ho9wHPc5IESWFORxhypVEyKqL_-8IvU,49
4
- sima_cli/cli.py,sha256=yd4ClOInhKAFA2ffMX1lUPRvWVziMZLHToSTAr_eyAA,6894
3
+ sima_cli/__version__.py,sha256=G3g_P43Qcy0TawgeYyi8kSrDK1EYHEk1Yis6srHT0Kg,49
4
+ sima_cli/cli.py,sha256=Kk8mjLGntxEBz8uTwy-Uocwzt_8JaNPKB1np6_rk5iU,8365
5
5
  sima_cli/app_zoo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  sima_cli/app_zoo/app.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  sima_cli/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- sima_cli/auth/basic_auth.py,sha256=xS_EC0iYyozDSrZEoz44lU5dLBk6covxiCv09WiQECw,4264
9
- sima_cli/auth/login.py,sha256=Tpe5ZRau4QrlQ6Zxg1rBco4qZ2nr4rkfZAohiTPBbVk,3687
8
+ sima_cli/auth/basic_auth.py,sha256=pcocI6v496vC7v5MLYPZq3AEgD-2DdkzNFZiKsbx3eQ,4290
9
+ sima_cli/auth/login.py,sha256=e9wBEeo_60qplODHBeK84R7zusT3K07kdFoZC1mkSrQ,3778
10
10
  sima_cli/data/resources_internal.yaml,sha256=zlQD4cSnZK86bLtTWuvEudZTARKiuIKmB--Jv4ajL8o,200
11
11
  sima_cli/data/resources_public.yaml,sha256=ZT1CzPrGMfSLVWiRJfW2-jb-ilmh7yNlkqyO5Fvqk58,178
12
12
  sima_cli/download/__init__.py,sha256=6y4O2FOCYFR2jdnQoVi3hRtEoZ0Gw6rydlTy1SGJ5FE,218
13
- sima_cli/download/downloader.py,sha256=zL8daM7Fqj1evzfQ9EHL1CVbuYL0_aQNhromqm7LkE0,4863
13
+ sima_cli/download/downloader.py,sha256=5-Dhr4wFpK6CudinCQeQVBShToUxijsVN2pv6NoL9sM,5156
14
14
  sima_cli/mla/meminfo.py,sha256=ndc8kQJmWGEIdvNh6iIhATGdrkqM2pbddr_eHxaPNfg,1466
15
15
  sima_cli/model_zoo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  sima_cli/model_zoo/model.py,sha256=q91Nrg62j1TqwPO8HiX4nlEFCCmzNEFcyFTBVMbJm8w,9836
17
+ sima_cli/sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ sima_cli/sdk/syscheck.py,sha256=h9zCULW67y4i2hqiGc-hc1ucBDShA5FAe9NxwBGq-fM,4575
17
19
  sima_cli/update/__init__.py,sha256=0P-z-rSaev40IhfJXytK3AFWv2_sdQU4Ry6ei2sEus0,66
18
20
  sima_cli/update/local.py,sha256=jiGrwuU2Z1HV_RT1_dYuI_Ish-f818AvCEk7sAM3l94,3032
19
21
  sima_cli/update/query.py,sha256=eOTC2ZAWbFFf_0h8D-MO1HrIsQYRc7fu5OyeFNEAv48,2168
20
22
  sima_cli/update/remote.py,sha256=ePlnvlGHrASMMjYGM9w-6hMeDMgGiJu_BlHLamU1YtI,8420
21
- sima_cli/update/updater.py,sha256=GtYOyhZj_Xk99iI-Zj4hGywAnitkah2MuMoE9NEa9V0,15228
23
+ sima_cli/update/updater.py,sha256=8NcXl_bWcjOo3ucl7WgShSLTbTga8cWpxJeUR5tnj2E,15546
22
24
  sima_cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
25
  sima_cli/utils/artifactory.py,sha256=6YyVpzVm8ATy7NEwT9nkWx-wptkXrvG7Wl_zDT6jmLs,2390
24
26
  sima_cli/utils/config.py,sha256=wE-cPQqY_gOqaP8t01xsRHD9tBUGk9MgBUm2GYYxI3E,1616
25
27
  sima_cli/utils/config_loader.py,sha256=7I5we1yiCai18j9R9jvhfUzAmT3OjAqVK35XSLuUw8c,2005
26
28
  sima_cli/utils/env.py,sha256=LJy2eO8cfEYsLuC7p3BT_FAoaZc9emtq6NYhHRBpiBE,5512
27
29
  sima_cli/utils/network.py,sha256=UvqxbqbWUczGFyO-t1SybG7Q-x9kjUVRNIn_D6APzy8,1252
28
- sima_cli-0.0.15.dist-info/licenses/LICENSE,sha256=a260OFuV4SsMZ6sQCkoYbtws_4o2deFtbnT9kg7Rfd4,1082
30
+ sima_cli-0.0.17.dist-info/licenses/LICENSE,sha256=a260OFuV4SsMZ6sQCkoYbtws_4o2deFtbnT9kg7Rfd4,1082
29
31
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
32
  tests/test_app_zoo.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
33
  tests/test_auth.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -34,8 +36,8 @@ tests/test_download.py,sha256=t87DwxlHs26_ws9rpcHGwr_OrcRPd3hz6Zmm0vRee2U,4465
34
36
  tests/test_firmware.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
37
  tests/test_model_zoo.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
38
  tests/test_utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
- sima_cli-0.0.15.dist-info/METADATA,sha256=Gfm1zm3xrURxtFf9DMeq5d5vjkko8Mnk8sWVpvW4EU8,3605
38
- sima_cli-0.0.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
39
- sima_cli-0.0.15.dist-info/entry_points.txt,sha256=xRYrDq1nCs6R8wEdB3c1kKuimxEjWJkHuCzArQPT0Xk,47
40
- sima_cli-0.0.15.dist-info/top_level.txt,sha256=FtrbAUdHNohtEPteOblArxQNwoX9_t8qJQd59fagDlc,15
41
- sima_cli-0.0.15.dist-info/RECORD,,
39
+ sima_cli-0.0.17.dist-info/METADATA,sha256=6GVfk37R0BxeQCaWxfPK_VUfElAJfLWeAtbtPkakV1I,3631
40
+ sima_cli-0.0.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
41
+ sima_cli-0.0.17.dist-info/entry_points.txt,sha256=xRYrDq1nCs6R8wEdB3c1kKuimxEjWJkHuCzArQPT0Xk,47
42
+ sima_cli-0.0.17.dist-info/top_level.txt,sha256=FtrbAUdHNohtEPteOblArxQNwoX9_t8qJQd59fagDlc,15
43
+ sima_cli-0.0.17.dist-info/RECORD,,