nepher-cli-test 0.2.7__tar.gz → 0.2.8__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 (30) hide show
  1. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/PKG-INFO +49 -63
  2. nepher_cli_test-0.2.8/README.md +172 -0
  3. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/pyproject.toml +6 -5
  4. nepher_cli_test-0.2.8/src/nepher_cli/__init__.py +10 -0
  5. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/cli.py +6 -1
  6. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/commands/account.py +73 -1
  7. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/commands/tournament.py +39 -9
  8. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/config.py +2 -4
  9. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/tournament/api.py +20 -3
  10. nepher_cli_test-0.2.7/README.test.md +0 -186
  11. nepher_cli_test-0.2.7/src/nepher_cli/__init__.py +0 -3
  12. nepher_cli_test-0.2.7/src/nepher_cli/cli_test.py +0 -19
  13. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/.gitignore +0 -0
  14. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/__main__.py +0 -0
  15. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/commands/__init__.py +0 -0
  16. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/commands/envhub.py +0 -0
  17. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/commands/hackathon.py +0 -0
  18. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/commands/highlight.py +0 -0
  19. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/commands/simstore.py +0 -0
  20. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/core/__init__.py +0 -0
  21. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/core/credentials.py +0 -0
  22. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/core/http.py +0 -0
  23. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/envhub/__init__.py +0 -0
  24. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/envhub/cache.py +0 -0
  25. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/envhub/config.py +0 -0
  26. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/py.typed +0 -0
  27. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/tournament/__init__.py +0 -0
  28. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/tournament/agent_check.py +0 -0
  29. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/tournament/packer.py +0 -0
  30. {nepher_cli_test-0.2.7 → nepher_cli_test-0.2.8}/src/nepher_cli/tournament/wallet.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nepher-cli-test
3
- Version: 0.2.7
4
- Summary: npcli-test — Nepher CLI for staging (api.staging.nepher.ai)
3
+ Version: 0.2.8
4
+ Summary: npcli — unified Nepher command-line interface for accounts, hackathons, EnvHub, tournaments, and SimStore
5
5
  Project-URL: Homepage, https://github.com/nepher-ai/nepher-cli
6
6
  Author: Nepher
7
7
  License: MIT
@@ -26,90 +26,76 @@ Requires-Dist: pytest>=8.0.0; extra == 'dev'
26
26
  Requires-Dist: ruff>=0.4.0; extra == 'dev'
27
27
  Description-Content-Type: text/markdown
28
28
 
29
- # nepher-cli-test
29
+ # nepher-cli
30
30
 
31
- **Staging build** of the [Nepher CLI](https://github.com/nepher-ai/nepher-cli) — same commands as production, but defaults to **staging APIs** (`api.staging.nepher.ai`).
32
-
33
- For production, use [`nepher-cli`](https://pypi.org/project/nepher-cli/) and the `npcli` command instead.
31
+ The unified CLI for [Nepher Robotics](https://nepher.ai) — accounts, hackathons, EnvHub, tournaments, and SimStore from a single tool.
34
32
 
35
33
  **Requires:** Python 3.10+
36
34
 
37
35
  ## Install
38
36
 
39
37
  ```bash
40
- pip install nepher-cli-test
38
+ pip install nepher-cli
41
39
  ```
42
40
 
43
- The `npcli-test` command is registered after install.
41
+ Both `npcli` and `nepher-cli` entry points are registered after install.
44
42
 
45
43
  ```bash
46
- npcli-test --version
47
- npcli-test --help
44
+ npcli --version
45
+ npcli --help
48
46
  ```
49
47
 
50
- ## Staging API endpoints
51
-
52
- | Service | Default base |
53
- |---------|--------------|
54
- | Account | `https://api.staging.nepher.ai/account` |
55
- | Tournament | `https://api.staging.nepher.ai/tournament` |
56
- | EnvHub | `https://api.staging.nepher.ai/envhub` |
57
- | Hackathon | `https://api.staging.nepher.ai/hackathon` |
58
- | SimStore | `https://simstore-staging.nepher.ai` |
59
-
60
- Override with `NEPHER_API_URL` (and service-specific vars) if needed.
61
-
62
48
  ## Commands
63
49
 
64
50
  | Command / Group | Description |
65
51
  |-----------------|-------------|
66
- | `npcli-test login` | Log in with a Nepher API key |
67
- | `npcli-test whoami` | Show the currently authenticated user |
68
- | `npcli-test logout` | Clear locally stored credentials |
69
- | `npcli-test account` | API keys and coldkey registration |
70
- | `npcli-test tournament` | Browse tournaments, submit agents, leaderboards |
71
- | `npcli-test envhub` | Manage Isaac Lab environment bundles |
72
- | `npcli-test hackathon` | Browse and submit to hackathons |
73
- | `npcli-test simstore` | SimStore marketplace *(coming soon)* |
52
+ | `npcli login` | Log in with a Nepher API key |
53
+ | `npcli whoami` | Show the currently authenticated user |
54
+ | `npcli logout` | Clear locally stored credentials |
55
+ | `npcli account` | API keys and coldkey registration |
56
+ | `npcli tournament` | Browse tournaments, submit agents, leaderboards |
57
+ | `npcli envhub` | Manage Isaac Lab environment bundles |
58
+ | `npcli hackathon` | Browse and submit to hackathons |
59
+ | `npcli simstore` | SimStore marketplace *(coming soon)* |
74
60
 
75
61
  ## Quick Start
76
62
 
77
63
  ### Authenticate
78
64
 
79
65
  ```bash
80
- npcli-test login --api-key nepher_xxxxxxxx
81
- npcli-test whoami
82
- npcli-test logout
66
+ npcli login --api-key nepher_xxxxxxxx
67
+ npcli whoami
68
+ npcli logout
83
69
  ```
84
70
 
85
- Get a staging API key at [staging.nepher.ai/account](https://staging.nepher.ai/account) → Account → API Keys.
71
+ Get your API key at [nepher.ai/account](https://nepher.ai/account) → Account → API Keys.
86
72
  For CI/CD, set `NEPHER_API_KEY=nepher_xxxxxxxx` instead of logging in.
87
73
 
88
74
  ### Tournaments
89
75
 
90
76
  ```bash
91
- npcli-test tournament list
92
- npcli-test tournament list-active
93
- npcli-test tournament status <tournament_id>
94
- npcli-test tournament leaderboard <tournament_id>
77
+ npcli tournament list
78
+ npcli tournament list-active
79
+ npcli tournament status <tournament_id>
80
+ npcli tournament leaderboard <tournament_id>
95
81
  ```
96
82
 
97
83
  Check your agent directory structure (no extra dependencies needed):
98
84
 
99
85
  ```bash
100
- npcli-test tournament check --path ./my-agent
101
- npcli-test tournament check --path ./my-agent --verbose # also show recommended-file warnings
86
+ npcli tournament check --path ./my-agent
87
+ npcli tournament check --path ./my-agent --verbose # also show recommended-file warnings
102
88
  ```
103
89
 
104
90
  Submit an agent (requires `bittensor-wallet` for wallet signing):
105
91
 
106
92
  ```bash
107
93
  pip install bittensor-wallet
108
- # or: pip install "nepher-cli-test[bittensor]"
94
+ # or: pip install "nepher-cli[bittensor]"
109
95
  ```
110
96
 
111
97
  ```bash
112
- npcli-test tournament submit --path ./my-agent --wallet-name miner --wallet-hotkey default
98
+ npcli tournament submit --path ./my-agent --wallet-name miner --wallet-hotkey default
113
99
  ```
114
100
 
115
101
  Full options for `submit`:
@@ -127,20 +113,20 @@ Full options for `submit`:
127
113
  ### EnvHub
128
114
 
129
115
  ```bash
130
- npcli-test envhub list
131
- npcli-test envhub download <env_id>
132
- npcli-test envhub upload ./my-bundle --category navigation
133
- npcli-test envhub cache list
134
- npcli-test envhub cache info
135
- npcli-test envhub cache clear
116
+ npcli envhub list
117
+ npcli envhub download <env_id>
118
+ npcli envhub upload ./my-bundle --category navigation
119
+ npcli envhub cache list
120
+ npcli envhub cache info
121
+ npcli envhub cache clear
136
122
  ```
137
123
 
138
124
  ### Hackathons
139
125
 
140
126
  ```bash
141
- npcli-test hackathon list
127
+ npcli hackathon list
142
128
 
143
- npcli-test hackathon submit \
129
+ npcli hackathon submit \
144
130
  --title "My entry" \
145
131
  --submission ./my-project \
146
132
  --assets ./my-assets
@@ -160,14 +146,14 @@ Full options:
160
146
 
161
147
  ### API Keys
162
148
 
163
- `list` / `create` / `revoke` need a **JWT session** from `npcli-test account login`.
149
+ `list` / `create` / `revoke` need a **JWT session** from `npcli account login`.
164
150
  Do **not** pass `--api-key` on these commands (that flag sends `X-API-Key`, which the account API rejects for key management).
165
151
 
166
152
  ```bash
167
- npcli-test account login --api-key nepher_...
168
- npcli-test account api-keys list
169
- npcli-test account api-keys create --name "CI key" --platform hackathon
170
- npcli-test account api-keys revoke <key_id>
153
+ npcli account login --api-key nepher_...
154
+ npcli account api-keys list
155
+ npcli account api-keys create --name "CI key" --platform hackathon
156
+ npcli account api-keys revoke <key_id>
171
157
  ```
172
158
 
173
159
  ### Coldkey Registration
@@ -176,7 +162,7 @@ Bind a Bittensor coldkey to your account (requires `bittensor-wallet`; `btcli` i
176
162
 
177
163
  ```bash
178
164
  pip install bittensor-wallet
179
- npcli-test account register-coldkey --wallet <wallet_name>
165
+ npcli account register-coldkey --wallet <wallet_name>
180
166
  ```
181
167
 
182
168
  Signing uses the local coldkey via `bittensor-wallet` and does not import `btcli`. If you still have a mixed Bittensor venv (`scalecodec` + `cyscale`), `register-coldkey` keeps working as long as `bittensor-wallet` is installed.
@@ -192,21 +178,21 @@ Signing uses the local coldkey via `bittensor-wallet` and does not import `btcli
192
178
 
193
179
  | Error | Fix |
194
180
  |-------|-----|
195
- | `npcli-test: command not found` | Ensure `pip install` succeeded and Python scripts dir is on `PATH` |
181
+ | `npcli: command not found` | Ensure `pip install` succeeded and Python scripts dir is on `PATH` |
196
182
  | `invalid api key format` | Key must start with `nepher_` |
197
183
  | `api key does not have hackathon access` | Enable Hackathon scope or use an unrestricted key |
198
- | `api key expired` | Run `npcli-test account api-keys create` |
184
+ | `api key expired` | Run `npcli account api-keys create` |
199
185
  | `Several hackathons are accepting submissions` | Re-run with `--hackathon-id` |
200
186
  | `bittensor-wallet not installed` | `pip install bittensor-wallet` (needed for `tournament submit` and `account register-coldkey`) |
201
- | `Not logged in` | `npcli-test login --api-key nepher_...` |
202
- | `Conflict detected: 'scalecodec' ... conflicts with 'cyscale'` | Leftover `scalecodec` after a Bittensor upgrade. Prefer `pip install bittensor-wallet` so npcli-test never needs `btcli`. To repair `btcli` itself: `pip uninstall scalecodec cyscale -y && pip install -U cyscale --force-reinstall` |
187
+ | `Not logged in` | `npcli login --api-key nepher_...` |
188
+ | `Conflict detected: 'scalecodec' ... conflicts with 'cyscale'` | Leftover `scalecodec` after a Bittensor upgrade. Prefer `pip install bittensor-wallet` so npcli never needs `btcli`. To repair `btcli` itself: `pip uninstall scalecodec cyscale -y && pip install -U cyscale --force-reinstall` |
203
189
 
204
190
  Run any command with `--help` for full flag details:
205
191
 
206
192
  ```bash
207
- npcli-test --help
208
- npcli-test hackathon submit --help
209
- npcli-test tournament submit --help
193
+ npcli --help
194
+ npcli hackathon submit --help
195
+ npcli tournament submit --help
210
196
  ```
211
197
 
212
198
  ## License
@@ -0,0 +1,172 @@
1
+ # nepher-cli
2
+
3
+ The unified CLI for [Nepher Robotics](https://nepher.ai) — accounts, hackathons, EnvHub, tournaments, and SimStore from a single tool.
4
+
5
+ **Requires:** Python 3.10+
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install nepher-cli
11
+ ```
12
+
13
+ Both `npcli` and `nepher-cli` entry points are registered after install.
14
+
15
+ ```bash
16
+ npcli --version
17
+ npcli --help
18
+ ```
19
+
20
+ ## Commands
21
+
22
+ | Command / Group | Description |
23
+ |-----------------|-------------|
24
+ | `npcli login` | Log in with a Nepher API key |
25
+ | `npcli whoami` | Show the currently authenticated user |
26
+ | `npcli logout` | Clear locally stored credentials |
27
+ | `npcli account` | API keys and coldkey registration |
28
+ | `npcli tournament` | Browse tournaments, submit agents, leaderboards |
29
+ | `npcli envhub` | Manage Isaac Lab environment bundles |
30
+ | `npcli hackathon` | Browse and submit to hackathons |
31
+ | `npcli simstore` | SimStore marketplace *(coming soon)* |
32
+
33
+ ## Quick Start
34
+
35
+ ### Authenticate
36
+
37
+ ```bash
38
+ npcli login --api-key nepher_xxxxxxxx
39
+ npcli whoami
40
+ npcli logout
41
+ ```
42
+
43
+ Get your API key at [nepher.ai/account](https://nepher.ai/account) → Account → API Keys.
44
+ For CI/CD, set `NEPHER_API_KEY=nepher_xxxxxxxx` instead of logging in.
45
+
46
+ ### Tournaments
47
+
48
+ ```bash
49
+ npcli tournament list
50
+ npcli tournament list-active
51
+ npcli tournament status <tournament_id>
52
+ npcli tournament leaderboard <tournament_id>
53
+ ```
54
+
55
+ Check your agent directory structure (no extra dependencies needed):
56
+
57
+ ```bash
58
+ npcli tournament check --path ./my-agent
59
+ npcli tournament check --path ./my-agent --verbose # also show recommended-file warnings
60
+ ```
61
+
62
+ Submit an agent (requires `bittensor-wallet` for wallet signing):
63
+
64
+ ```bash
65
+ pip install bittensor-wallet
66
+ # or: pip install "nepher-cli[bittensor]"
67
+ ```
68
+
69
+ ```bash
70
+ npcli tournament submit --path ./my-agent --wallet-name miner --wallet-hotkey default
71
+ ```
72
+
73
+ Full options for `submit`:
74
+
75
+ ```
76
+ --path <path> Agent directory
77
+ --wallet-name <str> Bittensor wallet name (default: miner)
78
+ --wallet-hotkey <str> Bittensor wallet hotkey (default: default)
79
+ --api-key <key> Nepher API key (falls back to stored credentials)
80
+ --tournament-id <id> Target tournament ID (required when multiple are active)
81
+ --api-url <url> Override tournament API URL
82
+ -v / --verbose Verbose output
83
+ ```
84
+
85
+ ### EnvHub
86
+
87
+ ```bash
88
+ npcli envhub list
89
+ npcli envhub download <env_id>
90
+ npcli envhub upload ./my-bundle --category navigation
91
+ npcli envhub cache list
92
+ npcli envhub cache info
93
+ npcli envhub cache clear
94
+ ```
95
+
96
+ ### Hackathons
97
+
98
+ ```bash
99
+ npcli hackathon list
100
+
101
+ npcli hackathon submit \
102
+ --title "My entry" \
103
+ --submission ./my-project \
104
+ --assets ./my-assets
105
+ ```
106
+
107
+ Full options:
108
+
109
+ ```
110
+ --hackathon-id <uuid> Required when multiple hackathons are open
111
+ --title <str> Entry title
112
+ --description <markdown> Entry description
113
+ --thumbnail <file> Cover image (JPEG, PNG, WebP, GIF)
114
+ --submission <path> Project folder or submission.zip
115
+ --assets <path> Assets folder or assets.zip (images, videos, PDFs)
116
+ --public-source Mark source as public
117
+ ```
118
+
119
+ ### API Keys
120
+
121
+ `list` / `create` / `revoke` need a **JWT session** from `npcli account login`.
122
+ Do **not** pass `--api-key` on these commands (that flag sends `X-API-Key`, which the account API rejects for key management).
123
+
124
+ ```bash
125
+ npcli account login --api-key nepher_...
126
+ npcli account api-keys list
127
+ npcli account api-keys create --name "CI key" --platform hackathon
128
+ npcli account api-keys revoke <key_id>
129
+ ```
130
+
131
+ ### Coldkey Registration
132
+
133
+ Bind a Bittensor coldkey to your account (requires `bittensor-wallet`; `btcli` is optional fallback):
134
+
135
+ ```bash
136
+ pip install bittensor-wallet
137
+ npcli account register-coldkey --wallet <wallet_name>
138
+ ```
139
+
140
+ Signing uses the local coldkey via `bittensor-wallet` and does not import `btcli`. If you still have a mixed Bittensor venv (`scalecodec` + `cyscale`), `register-coldkey` keeps working as long as `bittensor-wallet` is installed.
141
+
142
+ ## API Key Requirements
143
+
144
+ - Must start with `nepher_`
145
+ - Must be active and not expired
146
+ - `hackathon submit` requires **Hackathon** scope (or an unrestricted key)
147
+ - `tournament submit` requires **Tournament** scope (or an unrestricted key)
148
+
149
+ ## Troubleshooting
150
+
151
+ | Error | Fix |
152
+ |-------|-----|
153
+ | `npcli: command not found` | Ensure `pip install` succeeded and Python scripts dir is on `PATH` |
154
+ | `invalid api key format` | Key must start with `nepher_` |
155
+ | `api key does not have hackathon access` | Enable Hackathon scope or use an unrestricted key |
156
+ | `api key expired` | Run `npcli account api-keys create` |
157
+ | `Several hackathons are accepting submissions` | Re-run with `--hackathon-id` |
158
+ | `bittensor-wallet not installed` | `pip install bittensor-wallet` (needed for `tournament submit` and `account register-coldkey`) |
159
+ | `Not logged in` | `npcli login --api-key nepher_...` |
160
+ | `Conflict detected: 'scalecodec' ... conflicts with 'cyscale'` | Leftover `scalecodec` after a Bittensor upgrade. Prefer `pip install bittensor-wallet` so npcli never needs `btcli`. To repair `btcli` itself: `pip uninstall scalecodec cyscale -y && pip install -U cyscale --force-reinstall` |
161
+
162
+ Run any command with `--help` for full flag details:
163
+
164
+ ```bash
165
+ npcli --help
166
+ npcli hackathon submit --help
167
+ npcli tournament submit --help
168
+ ```
169
+
170
+ ## License
171
+
172
+ MIT
@@ -4,9 +4,9 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "nepher-cli-test"
7
- version = "0.2.7"
8
- description = "npcli-test — Nepher CLI for staging (api.staging.nepher.ai)"
9
- readme = "README.test.md"
7
+ version = "0.2.8"
8
+ description = "npcli — unified Nepher command-line interface for accounts, hackathons, EnvHub, tournaments, and SimStore"
9
+ readme = "README.md"
10
10
  requires-python = ">=3.10"
11
11
  license = { text = "MIT" }
12
12
  authors = [{ name = "Nepher" }]
@@ -36,7 +36,8 @@ dev = [
36
36
  ]
37
37
 
38
38
  [project.scripts]
39
- npcli-test = "nepher_cli.cli_test:main"
39
+ npcli = "nepher_cli.cli:main"
40
+ nepher-cli = "nepher_cli.cli:main"
40
41
 
41
42
  [project.urls]
42
43
  Homepage = "https://github.com/nepher-ai/nepher-cli"
@@ -46,7 +47,7 @@ packages = ["src/nepher_cli"]
46
47
  core-metadata-version = "2.4"
47
48
 
48
49
  [tool.hatch.build.targets.sdist]
49
- include = ["src/nepher_cli", "README.test.md", "pyproject.toml"]
50
+ include = ["src/nepher_cli", "README.md", "pyproject.toml"]
50
51
  core-metadata-version = "2.4"
51
52
 
52
53
  [tool.ruff]
@@ -0,0 +1,10 @@
1
+ """npcli — unified Nepher command-line interface."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib.metadata import PackageNotFoundError, version
6
+
7
+ try:
8
+ __version__ = version("nepher-cli")
9
+ except PackageNotFoundError: # pragma: no cover
10
+ __version__ = "0.0.0"
@@ -15,7 +15,7 @@ from nepher_cli.commands.tournament import tournament
15
15
  @click.group(
16
16
  context_settings={"help_option_names": ["-h", "--help"], "max_content_width": 100},
17
17
  )
18
- @click.version_option(version=__version__)
18
+ @click.version_option(version=__version__, package_name="nepher-cli", prog_name="npcli")
19
19
  def main() -> None:
20
20
  """npcli — the unified Nepher command-line interface.
21
21
 
@@ -39,6 +39,11 @@ def main() -> None:
39
39
  npcli envhub list
40
40
  npcli tournament list
41
41
 
42
+ \b
43
+ Tournament submit requires bittensor-wallet for wallet signing:
44
+ pip install bittensor-wallet
45
+ # or: pip install "nepher-cli[bittensor]"
46
+
42
47
  Run any sub-command with --help for details and examples.
43
48
 
44
49
  API keys are created at https://nepher.ai/account (Account > API Keys).
@@ -396,7 +396,7 @@ def register_coldkey(wallet: str, api_key: str, base_url: str) -> int:
396
396
 
397
397
  @click.group("account")
398
398
  def account() -> None:
399
- """Manage your Nepher account — login, API keys, and coldkey registration."""
399
+ """Manage your Nepher account — login, API keys, coldkey, and platform balance."""
400
400
 
401
401
 
402
402
  # ── Auth ────────────────────────────────────────────────────────────────────
@@ -627,6 +627,78 @@ def api_keys_revoke(key_id: str, api_key: str | None) -> None:
627
627
  # ── Coldkey ──────────────────────────────────────────────────────────────────
628
628
 
629
629
 
630
+ @account.command("balance")
631
+ @click.option(
632
+ "--api-key", "--apikey", "api_key",
633
+ default=None, envvar="NEPHER_API_KEY", metavar="KEY",
634
+ help="Nepher API key (nepher_...). Falls back to stored credentials.",
635
+ )
636
+ def cmd_balance(api_key: str | None) -> None:
637
+ """Show platform balance used for submission fees and unlocks."""
638
+ headers = _require_auth(api_key)
639
+ url = f"{ACCOUNT_BACKEND.rstrip('/')}/api/v1/billing/balance"
640
+ try:
641
+ r = httpx.get(url, headers=headers, timeout=30.0)
642
+ except httpx.RequestError as e:
643
+ console.print(f"[red]Network error[/red]: {e}")
644
+ raise SystemExit(1) from e
645
+ if r.status_code >= 400:
646
+ console.print(f"[red]{parse_error_body(r.text) or r.text.strip() or f'HTTP {r.status_code}'}[/red]")
647
+ raise SystemExit(1)
648
+ body = r.json()
649
+ console.print(f" Balance : [bold]{body.get('balance_tao', 0)} TAO[/bold]")
650
+ if body.get("coldkey"):
651
+ console.print(f" Coldkey : {body['coldkey']}")
652
+ else:
653
+ console.print(" Coldkey : [yellow]not registered[/yellow] — run npcli account register-coldkey")
654
+ if body.get("network"):
655
+ console.print(f" Network : {body['network']}")
656
+ console.print(
657
+ " Deposit : "
658
+ + ("available via Account → Billing on the website" if body.get("deposit_available") else "unavailable")
659
+ )
660
+
661
+
662
+ @account.command("ledger")
663
+ @click.option("--limit", default=20, show_default=True, help="Number of ledger rows.")
664
+ @click.option(
665
+ "--api-key", "--apikey", "api_key",
666
+ default=None, envvar="NEPHER_API_KEY", metavar="KEY",
667
+ help="Nepher API key (nepher_...). Falls back to stored credentials.",
668
+ )
669
+ def cmd_ledger(limit: int, api_key: str | None) -> None:
670
+ """Show recent platform billing history (deposits, fees, unlocks)."""
671
+ headers = _require_auth(api_key)
672
+ url = f"{ACCOUNT_BACKEND.rstrip('/')}/api/v1/billing/ledger"
673
+ try:
674
+ r = httpx.get(url, headers=headers, params={"limit": limit}, timeout=30.0)
675
+ except httpx.RequestError as e:
676
+ console.print(f"[red]Network error[/red]: {e}")
677
+ raise SystemExit(1) from e
678
+ if r.status_code >= 400:
679
+ console.print(f"[red]{parse_error_body(r.text) or r.text.strip() or f'HTTP {r.status_code}'}[/red]")
680
+ raise SystemExit(1)
681
+ items = (r.json() or {}).get("items") or []
682
+ if not items:
683
+ console.print("[dim]No billing activity yet.[/dim]")
684
+ return
685
+ table = Table(show_header=True, header_style="bold")
686
+ table.add_column("When")
687
+ table.add_column("Type")
688
+ table.add_column("Amount (TAO)", justify="right")
689
+ table.add_column("Balance after", justify="right")
690
+ table.add_column("Details")
691
+ for row in items:
692
+ table.add_row(
693
+ str(row.get("created_at") or "—"),
694
+ str(row.get("entry_type") or "—"),
695
+ f"{float(row.get('amount_tao') or 0):.6f}",
696
+ f"{float(row.get('balance_after_tao') or 0):.6f}",
697
+ str(row.get("description") or "—"),
698
+ )
699
+ console.print(table)
700
+
701
+
630
702
  @account.command("register-coldkey")
631
703
  @click.option("--wallet", required=True, metavar="NAME", help="Bittensor wallet name. Must exist in your local btcli wallet.")
632
704
  @click.option(
@@ -530,6 +530,7 @@ def tournament_submit(
530
530
 
531
531
  Requires [bold]bittensor-wallet[/bold] for wallet signing:
532
532
  pip install bittensor-wallet
533
+ # or: pip install "nepher-cli[bittensor]"
533
534
  """
534
535
  resolved_key = _resolve_api_key(api_key)
535
536
  resolved_url = api_url or TOURNAMENT_BACKEND
@@ -581,16 +582,43 @@ def tournament_submit(
581
582
  resolved_tournament_id = token_data["tournament_id"]
582
583
  upload_token = token_data["upload_token"]
583
584
 
585
+ fee = token_data.get("submission_fee_tao")
586
+ if fee is not None:
587
+ console.print(
588
+ f"Submission fee: [bold]{fee} TAO[/bold] "
589
+ f"(debited from platform balance on upload)"
590
+ )
591
+ fee_min = token_data.get("submission_fee_min_tao")
592
+ fee_max = token_data.get("submission_fee_max_tao")
593
+ fee_dur = token_data.get("submission_fee_duration_hours")
594
+ if fee_min is not None and fee_max is not None:
595
+ console.print(
596
+ f" [dim]Fee curve: {fee_max} → {fee_min} TAO"
597
+ + (f" over {fee_dur}h" if fee_dur is not None else "")
598
+ + "[/dim]"
599
+ )
600
+
584
601
  console.print("Uploading agent...")
585
- agent_id = await tournament_api.upload_agent(
586
- api_key=resolved_key,
587
- api_url=resolved_url,
588
- tournament_id=resolved_tournament_id,
589
- upload_token=upload_token,
590
- miner_hotkey=miner_hotkey,
591
- content_hash=content_hash,
592
- file_path=archive,
593
- )
602
+ try:
603
+ upload_result = await tournament_api.upload_agent(
604
+ api_key=resolved_key,
605
+ api_url=resolved_url,
606
+ tournament_id=resolved_tournament_id,
607
+ upload_token=upload_token,
608
+ miner_hotkey=miner_hotkey,
609
+ content_hash=content_hash,
610
+ file_path=archive,
611
+ )
612
+ except tournament_api.UploadChargeError as e:
613
+ console.print(f"[red]Submission fee failed:[/red] {e}")
614
+ console.print(
615
+ " Check balance with [bold]npcli account balance[/bold], "
616
+ "then deposit TAO on Account → Billing."
617
+ )
618
+ return 1
619
+
620
+ agent_id = upload_result["agent_id"]
621
+ charged = upload_result.get("submission_fee_tao")
594
622
 
595
623
  t_title = _tournament_title(token_data)
596
624
  t_task = _tournament_task_name(token_data)
@@ -599,6 +627,8 @@ def tournament_submit(
599
627
  console.print("[green]Agent submitted successfully.[/green]")
600
628
  console.print(f" Agent ID : [bold]{agent_id}[/bold]")
601
629
  console.print(f" Tournament ID: [bold]{resolved_tournament_id}[/bold]")
630
+ if charged is not None:
631
+ console.print(f" Fee charged : [bold]{charged} TAO[/bold]")
602
632
  if t_title and t_title != "—":
603
633
  console.print(f" Title : {t_title}")
604
634
  if t_task and t_task != "—":
@@ -5,10 +5,8 @@ from __future__ import annotations
5
5
  import os
6
6
 
7
7
  # Unified public API host (embedded product mounts). SimStore stays separate.
8
- DEFAULT_WEBSITE_API = "https://api.nepher.ai"
9
- STAGING_WEBSITE_API = "https://api.staging.nepher.ai"
10
- SIMSTORE_BACKEND_DEFAULT = "https://api.simstore.nepher.ai"
11
- STAGING_SIMSTORE_BACKEND = "https://simstore-staging.nepher.ai"
8
+ DEFAULT_WEBSITE_API = "https://api.staing.nepher.ai"
9
+ SIMSTORE_BACKEND_DEFAULT = "https://api.simstore-staging.nepher.ai"
12
10
 
13
11
 
14
12
  def website_api_base() -> str:
@@ -21,6 +21,14 @@ def _json_headers(api_key: str) -> dict[str, str]:
21
21
  }
22
22
 
23
23
 
24
+ class UploadChargeError(RuntimeError):
25
+ """Raised when upload fails due to payment / platform balance."""
26
+
27
+ def __init__(self, message: str, *, status_code: int = 402):
28
+ super().__init__(message)
29
+ self.status_code = status_code
30
+
31
+
24
32
  def _raise_for_error(response: httpx.Response) -> None:
25
33
  if response.status_code < 400:
26
34
  return
@@ -29,6 +37,8 @@ def _raise_for_error(response: httpx.Response) -> None:
29
37
  or response.text.strip()
30
38
  or f"HTTP {response.status_code}"
31
39
  )
40
+ if response.status_code == 402:
41
+ raise UploadChargeError(msg, status_code=402)
32
42
  raise RuntimeError(msg)
33
43
 
34
44
 
@@ -76,8 +86,11 @@ async def upload_agent(
76
86
  miner_hotkey: str,
77
87
  content_hash: str,
78
88
  file_path: Path,
79
- ) -> str:
80
- """POST /api/v1/agents/upload/{tournament_id} (multipart) → agent_id string."""
89
+ ) -> dict[str, Any]:
90
+ """POST /api/v1/agents/upload/{tournament_id} (multipart) → response dict.
91
+
92
+ Returns at least ``agent_id``; may include ``submission_fee_tao``.
93
+ """
81
94
  url = f"{api_url.rstrip('/')}/api/v1/agents/upload/{tournament_id}"
82
95
  headers = {
83
96
  "X-API-Key": api_key,
@@ -97,4 +110,8 @@ async def upload_agent(
97
110
  agent_id = data.get("id") or data.get("agent_id")
98
111
  if not agent_id:
99
112
  raise RuntimeError(f"No agent ID in upload response: {data}")
100
- return str(agent_id)
113
+ return {
114
+ "agent_id": str(agent_id),
115
+ "submission_fee_tao": data.get("submission_fee_tao"),
116
+ "raw": data,
117
+ }
@@ -1,186 +0,0 @@
1
- # nepher-cli-test
2
-
3
- **Staging build** of the [Nepher CLI](https://github.com/nepher-ai/nepher-cli) — same commands as production, but defaults to **staging APIs** (`api.staging.nepher.ai`).
4
-
5
- For production, use [`nepher-cli`](https://pypi.org/project/nepher-cli/) and the `npcli` command instead.
6
-
7
- **Requires:** Python 3.10+
8
-
9
- ## Install
10
-
11
- ```bash
12
- pip install nepher-cli-test
13
- ```
14
-
15
- The `npcli-test` command is registered after install.
16
-
17
- ```bash
18
- npcli-test --version
19
- npcli-test --help
20
- ```
21
-
22
- ## Staging API endpoints
23
-
24
- | Service | Default base |
25
- |---------|--------------|
26
- | Account | `https://api.staging.nepher.ai/account` |
27
- | Tournament | `https://api.staging.nepher.ai/tournament` |
28
- | EnvHub | `https://api.staging.nepher.ai/envhub` |
29
- | Hackathon | `https://api.staging.nepher.ai/hackathon` |
30
- | SimStore | `https://simstore-staging.nepher.ai` |
31
-
32
- Override with `NEPHER_API_URL` (and service-specific vars) if needed.
33
-
34
- ## Commands
35
-
36
- | Command / Group | Description |
37
- |-----------------|-------------|
38
- | `npcli-test login` | Log in with a Nepher API key |
39
- | `npcli-test whoami` | Show the currently authenticated user |
40
- | `npcli-test logout` | Clear locally stored credentials |
41
- | `npcli-test account` | API keys and coldkey registration |
42
- | `npcli-test tournament` | Browse tournaments, submit agents, leaderboards |
43
- | `npcli-test envhub` | Manage Isaac Lab environment bundles |
44
- | `npcli-test hackathon` | Browse and submit to hackathons |
45
- | `npcli-test simstore` | SimStore marketplace *(coming soon)* |
46
-
47
- ## Quick Start
48
-
49
- ### Authenticate
50
-
51
- ```bash
52
- npcli-test login --api-key nepher_xxxxxxxx
53
- npcli-test whoami
54
- npcli-test logout
55
- ```
56
-
57
- Get a staging API key at [staging.nepher.ai/account](https://staging.nepher.ai/account) → Account → API Keys.
58
- For CI/CD, set `NEPHER_API_KEY=nepher_xxxxxxxx` instead of logging in.
59
-
60
- ### Tournaments
61
-
62
- ```bash
63
- npcli-test tournament list
64
- npcli-test tournament list-active
65
- npcli-test tournament status <tournament_id>
66
- npcli-test tournament leaderboard <tournament_id>
67
- ```
68
-
69
- Check your agent directory structure (no extra dependencies needed):
70
-
71
- ```bash
72
- npcli-test tournament check --path ./my-agent
73
- npcli-test tournament check --path ./my-agent --verbose # also show recommended-file warnings
74
- ```
75
-
76
- Submit an agent (requires `bittensor-wallet` for wallet signing):
77
-
78
- ```bash
79
- pip install bittensor-wallet
80
- # or: pip install "nepher-cli-test[bittensor]"
81
- ```
82
-
83
- ```bash
84
- npcli-test tournament submit --path ./my-agent --wallet-name miner --wallet-hotkey default
85
- ```
86
-
87
- Full options for `submit`:
88
-
89
- ```
90
- --path <path> Agent directory
91
- --wallet-name <str> Bittensor wallet name (default: miner)
92
- --wallet-hotkey <str> Bittensor wallet hotkey (default: default)
93
- --api-key <key> Nepher API key (falls back to stored credentials)
94
- --tournament-id <id> Target tournament ID (required when multiple are active)
95
- --api-url <url> Override tournament API URL
96
- -v / --verbose Verbose output
97
- ```
98
-
99
- ### EnvHub
100
-
101
- ```bash
102
- npcli-test envhub list
103
- npcli-test envhub download <env_id>
104
- npcli-test envhub upload ./my-bundle --category navigation
105
- npcli-test envhub cache list
106
- npcli-test envhub cache info
107
- npcli-test envhub cache clear
108
- ```
109
-
110
- ### Hackathons
111
-
112
- ```bash
113
- npcli-test hackathon list
114
-
115
- npcli-test hackathon submit \
116
- --title "My entry" \
117
- --submission ./my-project \
118
- --assets ./my-assets
119
- ```
120
-
121
- Full options:
122
-
123
- ```
124
- --hackathon-id <uuid> Required when multiple hackathons are open
125
- --title <str> Entry title
126
- --description <markdown> Entry description
127
- --thumbnail <file> Cover image (JPEG, PNG, WebP, GIF)
128
- --submission <path> Project folder or submission.zip
129
- --assets <path> Assets folder or assets.zip (images, videos, PDFs)
130
- --public-source Mark source as public
131
- ```
132
-
133
- ### API Keys
134
-
135
- `list` / `create` / `revoke` need a **JWT session** from `npcli-test account login`.
136
- Do **not** pass `--api-key` on these commands (that flag sends `X-API-Key`, which the account API rejects for key management).
137
-
138
- ```bash
139
- npcli-test account login --api-key nepher_...
140
- npcli-test account api-keys list
141
- npcli-test account api-keys create --name "CI key" --platform hackathon
142
- npcli-test account api-keys revoke <key_id>
143
- ```
144
-
145
- ### Coldkey Registration
146
-
147
- Bind a Bittensor coldkey to your account (requires `bittensor-wallet`; `btcli` is optional fallback):
148
-
149
- ```bash
150
- pip install bittensor-wallet
151
- npcli-test account register-coldkey --wallet <wallet_name>
152
- ```
153
-
154
- Signing uses the local coldkey via `bittensor-wallet` and does not import `btcli`. If you still have a mixed Bittensor venv (`scalecodec` + `cyscale`), `register-coldkey` keeps working as long as `bittensor-wallet` is installed.
155
-
156
- ## API Key Requirements
157
-
158
- - Must start with `nepher_`
159
- - Must be active and not expired
160
- - `hackathon submit` requires **Hackathon** scope (or an unrestricted key)
161
- - `tournament submit` requires **Tournament** scope (or an unrestricted key)
162
-
163
- ## Troubleshooting
164
-
165
- | Error | Fix |
166
- |-------|-----|
167
- | `npcli-test: command not found` | Ensure `pip install` succeeded and Python scripts dir is on `PATH` |
168
- | `invalid api key format` | Key must start with `nepher_` |
169
- | `api key does not have hackathon access` | Enable Hackathon scope or use an unrestricted key |
170
- | `api key expired` | Run `npcli-test account api-keys create` |
171
- | `Several hackathons are accepting submissions` | Re-run with `--hackathon-id` |
172
- | `bittensor-wallet not installed` | `pip install bittensor-wallet` (needed for `tournament submit` and `account register-coldkey`) |
173
- | `Not logged in` | `npcli-test login --api-key nepher_...` |
174
- | `Conflict detected: 'scalecodec' ... conflicts with 'cyscale'` | Leftover `scalecodec` after a Bittensor upgrade. Prefer `pip install bittensor-wallet` so npcli-test never needs `btcli`. To repair `btcli` itself: `pip uninstall scalecodec cyscale -y && pip install -U cyscale --force-reinstall` |
175
-
176
- Run any command with `--help` for full flag details:
177
-
178
- ```bash
179
- npcli-test --help
180
- npcli-test hackathon submit --help
181
- npcli-test tournament submit --help
182
- ```
183
-
184
- ## License
185
-
186
- MIT
@@ -1,3 +0,0 @@
1
- """npcli — unified Nepher command-line interface."""
2
-
3
- __version__ = "0.2.7"
@@ -1,19 +0,0 @@
1
- """npcli-test — staging entry point (defaults to api.staging.nepher.ai)."""
2
-
3
- from __future__ import annotations
4
-
5
- import os
6
-
7
- # Set staging defaults before any nepher_cli submodule imports config.
8
- os.environ.setdefault("NEPHER_API_URL", "https://api.staging.nepher.ai")
9
- os.environ.setdefault("NEPHER_SIMSTORE_API_URL", "https://simstore-staging.nepher.ai")
10
-
11
-
12
- def main() -> None:
13
- from nepher_cli.cli import main as cli_main
14
-
15
- cli_main()
16
-
17
-
18
- if __name__ == "__main__":
19
- raise SystemExit(main())