sovaria-cli 0.2.0__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.
Files changed (46) hide show
  1. apps/cli/README.md +147 -0
  2. apps/cli/__init__.py +0 -0
  3. apps/cli/src/__init__.py +3 -0
  4. apps/cli/src/commands/__init__.py +1 -0
  5. apps/cli/src/commands/admin.py +160 -0
  6. apps/cli/src/commands/api.py +48 -0
  7. apps/cli/src/commands/audit.py +181 -0
  8. apps/cli/src/commands/auth_product.py +187 -0
  9. apps/cli/src/commands/billing.py +513 -0
  10. apps/cli/src/commands/chrono.py +248 -0
  11. apps/cli/src/commands/context.py +99 -0
  12. apps/cli/src/commands/data.py +272 -0
  13. apps/cli/src/commands/db.py +528 -0
  14. apps/cli/src/commands/deploy.py +1099 -0
  15. apps/cli/src/commands/governance.py +491 -0
  16. apps/cli/src/commands/iam.py +436 -0
  17. apps/cli/src/commands/init_cmd.py +177 -0
  18. apps/cli/src/commands/keys.py +120 -0
  19. apps/cli/src/commands/login.py +842 -0
  20. apps/cli/src/commands/org.py +157 -0
  21. apps/cli/src/commands/policy.py +317 -0
  22. apps/cli/src/commands/project.py +130 -0
  23. apps/cli/src/commands/realtime.py +364 -0
  24. apps/cli/src/commands/scope.py +42 -0
  25. apps/cli/src/commands/shell.py +415 -0
  26. apps/cli/src/commands/sim.py +178 -0
  27. apps/cli/src/commands/storage.py +405 -0
  28. apps/cli/src/commands/vector.py +204 -0
  29. apps/cli/src/main.py +169 -0
  30. apps/cli/src/utils/__init__.py +1 -0
  31. apps/cli/src/utils/api_client.py +329 -0
  32. apps/cli/src/utils/auth_store.py +299 -0
  33. apps/cli/src/utils/config.py +185 -0
  34. apps/cli/src/utils/display.py +62 -0
  35. apps/cli/src/utils/migrations.py +69 -0
  36. apps/cli/src/utils/project_context.py +124 -0
  37. apps/cli/tests/test_auth_store_profiles.py +103 -0
  38. apps/cli/tests/test_cli_security.py +110 -0
  39. apps/cli/tests/test_cli_smoke_paths.py +279 -0
  40. apps/cli/tests/test_config_profiles.py +55 -0
  41. apps/cli/tests/test_main_startup.py +29 -0
  42. apps/cli/tests/test_project_and_commands.py +196 -0
  43. sovaria_cli-0.2.0.dist-info/METADATA +170 -0
  44. sovaria_cli-0.2.0.dist-info/RECORD +46 -0
  45. sovaria_cli-0.2.0.dist-info/WHEEL +4 -0
  46. sovaria_cli-0.2.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,29 @@
1
+ from __future__ import annotations
2
+
3
+ import subprocess
4
+ import sys
5
+
6
+
7
+ def test_cli_module_help() -> None:
8
+ result = subprocess.run(
9
+ [sys.executable, "-m", "apps.cli.src.main", "--help"],
10
+ check=False,
11
+ capture_output=True,
12
+ text=True,
13
+ )
14
+
15
+ assert result.returncode == 0
16
+ assert "Sovaria BaaS command-line interface" in result.stdout
17
+ assert "login" in result.stdout
18
+
19
+
20
+ def test_sov_console_script_help() -> None:
21
+ result = subprocess.run(
22
+ [sys.executable, "-m", "apps.cli.src.main", "--version"],
23
+ check=False,
24
+ capture_output=True,
25
+ text=True,
26
+ )
27
+
28
+ assert result.returncode == 0
29
+ assert "sov version 0.2.0" in result.stdout
@@ -0,0 +1,196 @@
1
+ """Tests for project context resolution and new CLI command paths."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import pytest
10
+
11
+ from apps.cli.src.utils import project_context
12
+
13
+
14
+ def test_resolve_scope_prefers_explicit_flags(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
15
+ config = {
16
+ "project": {"name": "demo"},
17
+ "gateway": {"url": "http://localhost:8000"},
18
+ "scope": {"org_id": "org-local", "project_id": "proj-local", "env_id": ""},
19
+ "features": {"realtime": True, "functions": True, "storage": True},
20
+ }
21
+ config_path = tmp_path / "sovaria.config.json"
22
+ config_path.write_text(json.dumps(config))
23
+
24
+ monkeypatch.chdir(tmp_path)
25
+ monkeypatch.setattr(
26
+ project_context,
27
+ "get_scope",
28
+ lambda profile=None: {"org_id": "org-profile", "project_id": "proj-profile", "env_id": ""},
29
+ )
30
+
31
+ org, project, env = project_context.resolve_scope(
32
+ profile=None,
33
+ org_id="org-flag",
34
+ project_id=None,
35
+ env_id=None,
36
+ )
37
+ assert org == "org-flag"
38
+ assert project == "proj-local"
39
+ assert env == ""
40
+
41
+
42
+ def test_resolve_scope_requires_linked_project(monkeypatch: pytest.MonkeyPatch) -> None:
43
+ monkeypatch.setattr(project_context, "linked_scope", lambda profile=None: {"org_id": "", "project_id": "", "env_id": ""})
44
+ monkeypatch.setattr(
45
+ project_context,
46
+ "get_scope",
47
+ lambda profile=None: {"org_id": "", "project_id": "", "env_id": ""},
48
+ )
49
+ with pytest.raises(ValueError, match="Missing project scope"):
50
+ project_context.resolve_scope(
51
+ profile=None,
52
+ org_id=None,
53
+ project_id=None,
54
+ env_id=None,
55
+ require=True,
56
+ )
57
+
58
+
59
+ def test_sim_discover_path_smoke(monkeypatch: pytest.MonkeyPatch) -> None:
60
+ from apps.cli.src.commands import sim
61
+
62
+ captured: dict[str, Any] = {}
63
+
64
+ def _fake_call_api(**kwargs: Any) -> dict[str, Any]:
65
+ captured.update(kwargs)
66
+ return {"scenarios": []}
67
+
68
+ monkeypatch.setattr(sim, "call_api", _fake_call_api)
69
+ sim.discover(profile=None, org_id=None, project_id=None, env_id=None)
70
+
71
+ assert captured["method"] == "POST"
72
+ assert captured["path"] == "/api/v1/sim/discover"
73
+ assert captured["require_scope"] is True
74
+
75
+
76
+ def test_keys_list_path_smoke(monkeypatch: pytest.MonkeyPatch) -> None:
77
+ from apps.cli.src.commands import keys
78
+
79
+ captured: dict[str, Any] = {}
80
+
81
+ def _fake_call_api(**kwargs: Any) -> list[dict[str, Any]]:
82
+ captured.update(kwargs)
83
+ return []
84
+
85
+ monkeypatch.setattr(keys, "call_api", _fake_call_api)
86
+ keys.list_keys(profile=None, org_id="org-1", project_id="proj-1", env_id=None)
87
+
88
+ assert captured["method"] == "GET"
89
+ assert captured["path"] == "/api/v1/apikeys"
90
+ assert captured["require_scope"] is True
91
+
92
+
93
+ def test_policy_simulate_path_smoke(monkeypatch: pytest.MonkeyPatch) -> None:
94
+ from apps.cli.src.commands import policy
95
+
96
+ captured: dict[str, Any] = {}
97
+
98
+ def _fake_call_api(**kwargs: Any) -> dict[str, Any]:
99
+ captured.update(kwargs)
100
+ return {"allowed": True}
101
+
102
+ monkeypatch.setattr(policy, "call_api", _fake_call_api)
103
+ policy.simulate_policy(
104
+ spl_source="allow all",
105
+ context="{}",
106
+ profile="dev",
107
+ org_id="org-1",
108
+ project_id="proj-1",
109
+ env_id=None,
110
+ )
111
+
112
+ assert captured["method"] == "POST"
113
+ assert captured["path"] == "/api/v1/policies/simulate"
114
+ assert captured["body"] == {"spl_source": "allow all", "context": {}}
115
+
116
+
117
+ def test_db_tx_begin_path_smoke(monkeypatch: pytest.MonkeyPatch) -> None:
118
+ from apps.cli.src.commands import db
119
+
120
+ captured: dict[str, Any] = {}
121
+
122
+ def _fake_call_api(**kwargs: Any) -> dict[str, Any]:
123
+ captured.update(kwargs)
124
+ return {"txid": 1, "snapshot_txid": 1}
125
+
126
+ monkeypatch.setattr(db, "call_api", _fake_call_api)
127
+ db.tx_begin(profile=None, org_id="org-1", project_id="proj-1", env_id=None)
128
+
129
+ assert captured["method"] == "POST"
130
+ assert captured["path"] == "/api/v1/data/rel/transaction/begin"
131
+ assert captured["require_scope"] is True
132
+
133
+
134
+ def test_fn_logs_path_smoke(monkeypatch: pytest.MonkeyPatch) -> None:
135
+ from apps.cli.src.commands import deploy
136
+ from apps.cli.src.utils import api_client
137
+
138
+ captured: dict[str, Any] = {}
139
+
140
+ def _fake_call_api(**kwargs: Any) -> list[dict[str, Any]]:
141
+ captured.update(kwargs)
142
+ return []
143
+
144
+ monkeypatch.setattr(api_client, "call_api", _fake_call_api)
145
+ monkeypatch.setattr(deploy.typer, "echo", lambda *args, **kwargs: None)
146
+ deploy.logs(
147
+ function_name="hello",
148
+ limit=10,
149
+ offset=0,
150
+ status=None,
151
+ profile=None,
152
+ org_id=None,
153
+ project_id="proj-1",
154
+ env_id=None,
155
+ )
156
+
157
+ assert captured["path"] == "/api/v1/fn/functions/hello/logs"
158
+ assert captured["require_scope"] is True
159
+
160
+
161
+ def test_auth_sessions_path_smoke(monkeypatch: pytest.MonkeyPatch) -> None:
162
+ from apps.cli.src.commands import login
163
+ from apps.cli.src.utils import api_client
164
+
165
+ captured: dict[str, Any] = {}
166
+
167
+ def _fake_call_api(**kwargs: Any) -> list[dict[str, Any]]:
168
+ captured.update(kwargs)
169
+ return []
170
+
171
+ monkeypatch.setattr(api_client, "call_api", _fake_call_api)
172
+ monkeypatch.setattr(login.typer, "echo", lambda *args, **kwargs: None)
173
+ login.list_sessions(profile="dev")
174
+
175
+ assert captured["method"] == "GET"
176
+ assert captured["path"] == "/api/v1/auth/sessions"
177
+
178
+
179
+ def test_storage_buckets_uses_call_api(monkeypatch: pytest.MonkeyPatch) -> None:
180
+ from apps.cli.src.commands import storage
181
+
182
+ captured: dict[str, Any] = {}
183
+ output: list[str] = []
184
+
185
+ def _fake_call_api(**kwargs: Any) -> list[dict[str, Any]]:
186
+ captured.update(kwargs)
187
+ return [{"name": "bucket-a", "public": False, "object_count": 1}]
188
+
189
+ monkeypatch.setattr(storage, "call_api", _fake_call_api)
190
+ monkeypatch.setattr(storage.typer, "echo", lambda message, err=False: output.append(str(message)))
191
+
192
+ storage.list_buckets(project_id="proj-1", org_id=None, env_id=None, profile=None)
193
+
194
+ assert captured["path"] == "/api/v1/store/buckets"
195
+ assert captured["require_scope"] is True
196
+ assert any("bucket-a" in line for line in output)
@@ -0,0 +1,170 @@
1
+ Metadata-Version: 2.5
2
+ Name: sovaria-cli
3
+ Version: 0.2.0
4
+ Summary: Sovaria BaaS command-line interface (sov)
5
+ Project-URL: Homepage, https://sovaria.in
6
+ Project-URL: Documentation, https://docs.sovaria.in/cli
7
+ Project-URL: Repository, https://github.com/sovaria/sovaria-cli
8
+ Author: Sovaria Team
9
+ License: MIT
10
+ Requires-Python: >=3.11
11
+ Requires-Dist: httpx>=0.28.1
12
+ Requires-Dist: keyring>=25.0
13
+ Requires-Dist: pyyaml>=6.0
14
+ Requires-Dist: sovaria-sdk>=0.2.0
15
+ Requires-Dist: tomli-w>=1.2.0
16
+ Requires-Dist: typer>=0.17.4
17
+ Provides-Extra: dev
18
+ Requires-Dist: build>=1.2; extra == 'dev'
19
+ Requires-Dist: pytest>=8.0; extra == 'dev'
20
+ Requires-Dist: ruff>=0.9; extra == 'dev'
21
+ Requires-Dist: twine>=6.0; extra == 'dev'
22
+ Description-Content-Type: text/markdown
23
+
24
+ # Sovaria CLI
25
+
26
+ Operator CLI for gateway-backed Sovaria project and platform workflows.
27
+
28
+ ## Run
29
+
30
+ Examples below use `sov ...` command syntax.
31
+
32
+ If `sov` is installed on your PATH:
33
+
34
+ ```bash
35
+ sov --help
36
+ ```
37
+
38
+ From repo root without installation:
39
+
40
+ ```bash
41
+ python -m apps.cli.src.main --help
42
+ ```
43
+
44
+ ## Cross-SDK Happy Path Smoke
45
+
46
+ Use the repository smoke script to validate one shared happy path across:
47
+
48
+ - CLI auth + scoped SQL call
49
+ - TypeScript SDK SQL + engine health
50
+ - Python SDK SQL + engine health
51
+
52
+ ```bash
53
+ SOVARIA_URL=http://localhost:8000 \
54
+ SOVARIA_ORG_ID=<org_uuid> \
55
+ SOVARIA_PROJECT_ID=<project_uuid> \
56
+ SOVARIA_EMAIL=<owner_email> \
57
+ SOVARIA_PASSWORD='<owner_password>' \
58
+ scripts/cli_sdk_happy_path.sh
59
+ ```
60
+
61
+ If you already have valid CLI tokens, omit `SOVARIA_EMAIL` and `SOVARIA_PASSWORD`.
62
+
63
+ ## Core Command Groups
64
+
65
+ - `sov auth ...` auth login/logout
66
+ - `sov scope ...` default org/project/env scope
67
+ - `sov data ...` Atlas-Doc and Atlas-Rel
68
+ - `sov realtime ...` Pulse realtime and e2ee
69
+ - `sov policy ...` Guard policy management
70
+ - `sov audit ...` Echo audit and simulation
71
+ - `sov chrono ...` Chrono timeline/snapshot operations
72
+ - `sov fn ...` Forge function deploy/status/invoke
73
+ - `sov project ...` project config template + scaffold creation
74
+ - `sov api call ...` raw gateway API request
75
+
76
+ ## Project Bootstrap (Config JSON)
77
+
78
+ Create a template config file:
79
+
80
+ ```bash
81
+ sov project init-config my-app --output sovaria.config.json
82
+ ```
83
+
84
+ Then scaffold a project from that config:
85
+
86
+ ```bash
87
+ sov project create --config sovaria.config.json --dir .
88
+ ```
89
+
90
+ ## Function Sandbox Flow
91
+
92
+ Deploy a function bundle (zipped from local folder):
93
+
94
+ ```bash
95
+ sov fn deploy ./my-function --name hello --project <project_id> --note "add audit logging"
96
+ ```
97
+
98
+ Poll deployment status:
99
+
100
+ ```bash
101
+ sov fn status <deploy_id> --project <project_id>
102
+ ```
103
+
104
+ Invoke the deployed function in its project sandbox:
105
+
106
+ ```bash
107
+ sov fn invoke hello --project <project_id> --data '{"message":"hi"}'
108
+ ```
109
+
110
+ Run a simulation invocation (tracked separately from normal invoke):
111
+
112
+ ```bash
113
+ sov fn invoke hello --project <project_id> --simulate --data '{"message":"dry-run"}'
114
+ ```
115
+
116
+ Queue heavy async invocation and wait for completion:
117
+
118
+ ```bash
119
+ sov fn invoke hello --project <project_id> --execution-profile heavy --async --wait --data-file payload.json
120
+ ```
121
+
122
+ List function versions:
123
+
124
+ ```bash
125
+ sov fn versions hello --project <project_id>
126
+ ```
127
+
128
+ List functions with active versions + queue depth:
129
+
130
+ ```bash
131
+ sov fn functions --project <project_id>
132
+ ```
133
+
134
+ List invocation history:
135
+
136
+ ```bash
137
+ sov fn history hello --project <project_id> --mode invoke
138
+ ```
139
+
140
+ List durable async jobs:
141
+
142
+ ```bash
143
+ sov fn jobs hello --project <project_id> --status QUEUED
144
+ ```
145
+
146
+ Promote a specific function version:
147
+
148
+ ```bash
149
+ sov fn promote hello --project <project_id> --version 3 --reason "promote stable release"
150
+ ```
151
+
152
+ Rollback to previous active version:
153
+
154
+ ```bash
155
+ sov fn rollback hello --project <project_id> --reason "rollback regression"
156
+ ```
157
+
158
+ Diff two simulation invocations:
159
+
160
+ ```bash
161
+ sov fn sim-diff hello <left_invocation_id> <right_invocation_id> --project <project_id>
162
+ ```
163
+
164
+ ## Scope Requirement
165
+
166
+ Realtime and relational routes require org/project scope. You can pass scope per command (`--org --project --env`) or set defaults:
167
+
168
+ ```bash
169
+ sov scope set <org_id> <project_id> --env <env_id>
170
+ ```
@@ -0,0 +1,46 @@
1
+ apps/cli/README.md,sha256=vsb2FKzgRUGbaKuejsYwewPhNkPdMIQSQJALwp_6UYo,3293
2
+ apps/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ apps/cli/src/__init__.py,sha256=6s9YuL853tUZg-e54W3cpk4yElFhN4D1fQxS3FHMFc0,58
4
+ apps/cli/src/main.py,sha256=Rnf9SDJvlhniHUMhTsb4HK7722hbQ0VBA8ATlF0Ci7A,8063
5
+ apps/cli/src/commands/__init__.py,sha256=eMuQR40Ye6ei4XbISb4dO1BwFk5RRqKIKGMxrztVu9Y,28
6
+ apps/cli/src/commands/admin.py,sha256=hvYxkeb7pc_B3MInPFlgDeVv5w-MmVqXwfGSV3n_4pM,5380
7
+ apps/cli/src/commands/api.py,sha256=OVVeIsAF4aorrQe6as6QKblEg_hGyzb0rBvXa9n8izk,1868
8
+ apps/cli/src/commands/audit.py,sha256=ltQhP2hu489RQhYkwFrc5nS4FU1klwzk1k91EpqZess,6306
9
+ apps/cli/src/commands/auth_product.py,sha256=fmgtCZNSmmGyrbu_xVIVOz-ffj1wU2G-34QTXC28wU0,6539
10
+ apps/cli/src/commands/billing.py,sha256=10dV8V7HRW6Yo0wBurZPK-FWhay5DpKz3_L5jS6t1RA,16019
11
+ apps/cli/src/commands/chrono.py,sha256=1Kn3W1tZORyK0ViD6QLpBy2P-FGi3lytHZeJydCrzxE,7693
12
+ apps/cli/src/commands/context.py,sha256=wEOkSGKueF5YQLHK-SwTVL54WDJSr6UN3c_L-sFSmBA,3342
13
+ apps/cli/src/commands/data.py,sha256=mwwAmuugZg6LjZveZdVkZCS8dN2L2dKUc6oWhpd_dNI,9090
14
+ apps/cli/src/commands/db.py,sha256=CpBWlCLW3xepqbQxXqOhyi3QktjZ1MJryqpvXM6r3DA,18223
15
+ apps/cli/src/commands/deploy.py,sha256=NC1ETm-7a4D5UPZ7OpwavbqnebrAQ8WDJs83ZVZUXyc,37767
16
+ apps/cli/src/commands/governance.py,sha256=FvjDbb5vH1yRa5KUD9kKJBYndIiywwTG_s_QlK2X_RQ,16032
17
+ apps/cli/src/commands/iam.py,sha256=MDfZMmk1c8nWdKlOjFdGOjpW06iCQ8nagsOo0v9ZohY,14038
18
+ apps/cli/src/commands/init_cmd.py,sha256=1DTSSRAjuQbvUTApBGRq4x5LxR-R-qTi0_OVVCA4ROc,6788
19
+ apps/cli/src/commands/keys.py,sha256=47ny4SEI38GHSM5kBGAEuFH0M8uCssXAA5gp0ZA7U90,4084
20
+ apps/cli/src/commands/login.py,sha256=nh2JYTpe1ihtX0gJ9vh4LRrIBY-rSIjdYSq6GVr4Ejk,30419
21
+ apps/cli/src/commands/org.py,sha256=AntqUHtfvep1aKE1kBbyplPh0B7Lm7B3zSA3PYGAxGc,4827
22
+ apps/cli/src/commands/policy.py,sha256=HGFMOwtLhchMCwZS23b24KGR-J6O64JF1LzJcnpGdAM,10747
23
+ apps/cli/src/commands/project.py,sha256=IXX8fDnabgaW4F6JojUPaStszxzHQkAI4i5Y2fb2ZGo,4222
24
+ apps/cli/src/commands/realtime.py,sha256=XgQ2jpsp5Z1edklwjJX46BlQTe4NQi5lOmoATf8kBic,12761
25
+ apps/cli/src/commands/scope.py,sha256=l8IEZHII4ljpY6BC1AF7lRwpV50WNWBufFzaZJGexaw,1383
26
+ apps/cli/src/commands/shell.py,sha256=UXwo9lts5lQAFUH8o_dFcOKYkiELPSgi2UxRN6S55uk,14006
27
+ apps/cli/src/commands/sim.py,sha256=wRj-DXkoGVs1SepJ77I1zl7JVXNEYLkQfZJJU2nNTlQ,6082
28
+ apps/cli/src/commands/storage.py,sha256=IugNew6VISsGqI4X1zh8fed8i2NnE_BZ-USxa1ZSWWU,14385
29
+ apps/cli/src/commands/vector.py,sha256=LubqnUbQKCYbvqN_qU9FYZ9MF0W99eaPUf5OKU5lOdQ,6953
30
+ apps/cli/src/utils/__init__.py,sha256=vYKSJLLcdWMtOyf5KHVMFNEzHnFG5WTSOz4ymu9JwBk,29
31
+ apps/cli/src/utils/api_client.py,sha256=KfFgJCunCq6yf83gdlQCAogC0r8WRffVVBJ6Lwh63Qs,11836
32
+ apps/cli/src/utils/auth_store.py,sha256=vVyowWnOSCjp6sYgTK1OQBcV_4u853bqMj-ySwsp21Y,9766
33
+ apps/cli/src/utils/config.py,sha256=TudlrHWdrW0h0Qt_vIYy6m238qS1JesL5lV_0Xs-Po8,5718
34
+ apps/cli/src/utils/display.py,sha256=43AShOIyUtOBBWe2TjCjA3oTCQ6DLqXbp-OEab35EPo,1803
35
+ apps/cli/src/utils/migrations.py,sha256=snEw1a7c_3XalJ5Aabz1jexaQOo6xsTwXTyl0MpObKQ,2251
36
+ apps/cli/src/utils/project_context.py,sha256=QMctOGrcHR0JmMbXRyj-ivja4tbIrzx8wkCLHURBgvc,4156
37
+ apps/cli/tests/test_auth_store_profiles.py,sha256=YGedg1XQt5N3WYc23aybrElTbpBnthqPMYXHU4j2w-A,4026
38
+ apps/cli/tests/test_cli_security.py,sha256=4V8i3piABmntJ1d_FFxZLSs91CiJDUIU-Vymi37dqp0,3801
39
+ apps/cli/tests/test_cli_smoke_paths.py,sha256=d8-7bgCjGDJandTZDvkoRvED6KGmAgZ7VWx9aktDCoo,9629
40
+ apps/cli/tests/test_config_profiles.py,sha256=ERUpTOyZ9U8AtA3hIcO_wNlbvP0dGMgDdvMNf__vDlM,1594
41
+ apps/cli/tests/test_main_startup.py,sha256=Hor2XhjsBXUDqCbjsGyTW-MTFUbjBitur8bPTxaNp30,706
42
+ apps/cli/tests/test_project_and_commands.py,sha256=11Qsd570UNzvf30XPbo5b2eQn9T1zTcAvFNkFbc5IoE,6276
43
+ sovaria_cli-0.2.0.dist-info/METADATA,sha256=LQyvB4dnGwTJ_d56LuX2E5xL2Dd-BkRev_f-wGwZ6UI,4026
44
+ sovaria_cli-0.2.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
45
+ sovaria_cli-0.2.0.dist-info/entry_points.txt,sha256=MPAectZWR-aNVegp6O-gS6hVUWikhPq8V-xPQ-T4QPg,52
46
+ sovaria_cli-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ sov = apps.cli.src.main:cli_entry