htcli 1.1.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.
- htcli-1.1.0.dist-info/METADATA +509 -0
- htcli-1.1.0.dist-info/RECORD +140 -0
- htcli-1.1.0.dist-info/WHEEL +4 -0
- htcli-1.1.0.dist-info/entry_points.txt +2 -0
- htcli-1.1.0.dist-info/licenses/LICENSE +21 -0
- src/__init__.py +0 -0
- src/htcli/__init__.py +5 -0
- src/htcli/client/__init__.py +338 -0
- src/htcli/client/extrinsics/__init__.py +26 -0
- src/htcli/client/extrinsics/base.py +487 -0
- src/htcli/client/extrinsics/consensus.py +79 -0
- src/htcli/client/extrinsics/governance.py +714 -0
- src/htcli/client/extrinsics/identity.py +490 -0
- src/htcli/client/extrinsics/node.py +1054 -0
- src/htcli/client/extrinsics/overwatch.py +401 -0
- src/htcli/client/extrinsics/staking.py +1504 -0
- src/htcli/client/extrinsics/subnet.py +2218 -0
- src/htcli/client/extrinsics/validator.py +203 -0
- src/htcli/client/extrinsics/wallet.py +323 -0
- src/htcli/client/offchain/__init__.py +10 -0
- src/htcli/client/offchain/backup.py +385 -0
- src/htcli/client/offchain/config.py +541 -0
- src/htcli/client/offchain/wallet.py +839 -0
- src/htcli/client/rpc/__init__.py +20 -0
- src/htcli/client/rpc/chain.py +568 -0
- src/htcli/client/rpc/node.py +783 -0
- src/htcli/client/rpc/overwatch.py +680 -0
- src/htcli/client/rpc/staking.py +216 -0
- src/htcli/client/rpc/subnet.py +2104 -0
- src/htcli/client/rpc/wallet.py +912 -0
- src/htcli/commands/__init__.py +31 -0
- src/htcli/commands/chain/__init__.py +66 -0
- src/htcli/commands/chain/display.py +204 -0
- src/htcli/commands/chain/handlers.py +260 -0
- src/htcli/commands/config/__init__.py +158 -0
- src/htcli/commands/config/display.py +353 -0
- src/htcli/commands/config/handlers.py +347 -0
- src/htcli/commands/config/prompts.py +357 -0
- src/htcli/commands/consensus/__init__.py +61 -0
- src/htcli/commands/consensus/handlers.py +100 -0
- src/htcli/commands/governance/__init__.py +49 -0
- src/htcli/commands/governance/handlers.py +81 -0
- src/htcli/commands/node/__init__.py +304 -0
- src/htcli/commands/node/display.py +749 -0
- src/htcli/commands/node/error_handling.py +470 -0
- src/htcli/commands/node/handlers.py +844 -0
- src/htcli/commands/node/prompts.py +346 -0
- src/htcli/commands/overwatch/__init__.py +219 -0
- src/htcli/commands/overwatch/display.py +396 -0
- src/htcli/commands/overwatch/error_handling.py +276 -0
- src/htcli/commands/overwatch/handlers.py +443 -0
- src/htcli/commands/overwatch/prompts.py +359 -0
- src/htcli/commands/stake/__init__.py +736 -0
- src/htcli/commands/stake/display.py +1103 -0
- src/htcli/commands/stake/error_handling.py +425 -0
- src/htcli/commands/stake/handlers.py +1902 -0
- src/htcli/commands/stake/prompts.py +1080 -0
- src/htcli/commands/subnet/__init__.py +639 -0
- src/htcli/commands/subnet/display.py +801 -0
- src/htcli/commands/subnet/error_handling.py +524 -0
- src/htcli/commands/subnet/handlers.py +2855 -0
- src/htcli/commands/subnet/prompts.py +1225 -0
- src/htcli/commands/validator/__init__.py +192 -0
- src/htcli/commands/validator/display.py +54 -0
- src/htcli/commands/validator/handlers.py +340 -0
- src/htcli/commands/wallet/__init__.py +546 -0
- src/htcli/commands/wallet/display.py +806 -0
- src/htcli/commands/wallet/error_handling.py +210 -0
- src/htcli/commands/wallet/handlers.py +3040 -0
- src/htcli/commands/wallet/prompts.py +1518 -0
- src/htcli/config.py +184 -0
- src/htcli/dependencies.py +186 -0
- src/htcli/errors/__init__.py +63 -0
- src/htcli/errors/base.py +141 -0
- src/htcli/errors/display.py +20 -0
- src/htcli/errors/handlers.py +710 -0
- src/htcli/main.py +343 -0
- src/htcli/models/__init__.py +21 -0
- src/htcli/models/enums/enum_types.py +35 -0
- src/htcli/models/errors.py +103 -0
- src/htcli/models/requests/__init__.py +197 -0
- src/htcli/models/requests/config.py +70 -0
- src/htcli/models/requests/consensus.py +19 -0
- src/htcli/models/requests/governance.py +38 -0
- src/htcli/models/requests/identity.py +51 -0
- src/htcli/models/requests/key.py +22 -0
- src/htcli/models/requests/node.py +91 -0
- src/htcli/models/requests/overwatch.py +64 -0
- src/htcli/models/requests/staking.py +580 -0
- src/htcli/models/requests/subnet.py +195 -0
- src/htcli/models/requests/validator.py +139 -0
- src/htcli/models/requests/wallet.py +118 -0
- src/htcli/models/responses/__init__.py +147 -0
- src/htcli/models/responses/base.py +18 -0
- src/htcli/models/responses/chain.py +39 -0
- src/htcli/models/responses/config.py +58 -0
- src/htcli/models/responses/identity.py +102 -0
- src/htcli/models/responses/overwatch.py +51 -0
- src/htcli/models/responses/staking.py +502 -0
- src/htcli/models/responses/subnet.py +856 -0
- src/htcli/models/responses/wallet.py +185 -0
- src/htcli/ui/__init__.py +87 -0
- src/htcli/ui/colors.py +309 -0
- src/htcli/ui/components/__init__.py +60 -0
- src/htcli/ui/components/panels.py +174 -0
- src/htcli/ui/components/progress.py +166 -0
- src/htcli/ui/components/spinners.py +92 -0
- src/htcli/ui/components/tables.py +809 -0
- src/htcli/ui/components/trees.py +721 -0
- src/htcli/ui/display.py +336 -0
- src/htcli/ui/prompts.py +870 -0
- src/htcli/utils/__init__.py +76 -0
- src/htcli/utils/blockchain/__init__.py +75 -0
- src/htcli/utils/blockchain/formatting.py +368 -0
- src/htcli/utils/blockchain/patches.py +286 -0
- src/htcli/utils/blockchain/peer_id.py +186 -0
- src/htcli/utils/blockchain/staking.py +448 -0
- src/htcli/utils/blockchain/type_registry.py +1373 -0
- src/htcli/utils/blockchain/validation.py +179 -0
- src/htcli/utils/cache.py +613 -0
- src/htcli/utils/constants.py +38 -0
- src/htcli/utils/legacy/__init__.py +12 -0
- src/htcli/utils/legacy/colors.py +311 -0
- src/htcli/utils/legacy/crypto.py +1176 -0
- src/htcli/utils/legacy/formatting.py +452 -0
- src/htcli/utils/legacy/interactive.py +306 -0
- src/htcli/utils/legacy/subnet_manifest.py +265 -0
- src/htcli/utils/legacy/validation.py +488 -0
- src/htcli/utils/logging.py +183 -0
- src/htcli/utils/network/__init__.py +20 -0
- src/htcli/utils/network/subnet.py +344 -0
- src/htcli/utils/prompts.py +27 -0
- src/htcli/utils/scale_codec.py +155 -0
- src/htcli/utils/validation/__init__.py +57 -0
- src/htcli/utils/validation/prompt_validators.py +267 -0
- src/htcli/utils/wallet/__init__.py +65 -0
- src/htcli/utils/wallet/auth.py +151 -0
- src/htcli/utils/wallet/core.py +1069 -0
- src/htcli/utils/wallet/crypto.py +1615 -0
- src/htcli/utils/wallet/migration.py +159 -0
src/htcli/main.py
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Main CLI entry point for the Hypertensor CLI.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import inspect
|
|
6
|
+
import signal
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
import typer
|
|
12
|
+
from rich.align import Align
|
|
13
|
+
from rich.console import Console
|
|
14
|
+
from rich.text import Text
|
|
15
|
+
from typer.core import TyperArgument, TyperGroup
|
|
16
|
+
|
|
17
|
+
from . import __version__
|
|
18
|
+
from .ui.display import get_console, print_error, print_warning
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _patch_click_make_metavar_compat() -> None:
|
|
22
|
+
"""Patch Click 8.2+ metavar signature for Typer 0.15 compatibility."""
|
|
23
|
+
signature = inspect.signature(click.core.Parameter.make_metavar)
|
|
24
|
+
if "ctx" not in signature.parameters:
|
|
25
|
+
if "ctx" not in inspect.signature(TyperArgument.make_metavar).parameters:
|
|
26
|
+
return
|
|
27
|
+
else:
|
|
28
|
+
original_make_metavar = click.core.Parameter.make_metavar
|
|
29
|
+
|
|
30
|
+
def compat_make_metavar(self, ctx=None):
|
|
31
|
+
if ctx is None:
|
|
32
|
+
ctx = click.Context(click.Command(self.name or "htcli"))
|
|
33
|
+
return original_make_metavar(self, ctx)
|
|
34
|
+
|
|
35
|
+
click.core.Parameter.make_metavar = compat_make_metavar
|
|
36
|
+
|
|
37
|
+
if "ctx" not in inspect.signature(TyperArgument.make_metavar).parameters:
|
|
38
|
+
|
|
39
|
+
def compat_typer_argument_make_metavar(self, ctx=None):
|
|
40
|
+
if self.metavar is not None:
|
|
41
|
+
return self.metavar
|
|
42
|
+
if ctx is None:
|
|
43
|
+
ctx = click.Context(click.Command(self.name or "htcli"))
|
|
44
|
+
var = (self.name or "").upper()
|
|
45
|
+
if not self.required:
|
|
46
|
+
var = f"[{var}]"
|
|
47
|
+
type_var = self.type.get_metavar(param=self, ctx=ctx)
|
|
48
|
+
if type_var:
|
|
49
|
+
var += f":{type_var}"
|
|
50
|
+
if self.nargs != 1:
|
|
51
|
+
var += "..."
|
|
52
|
+
return var
|
|
53
|
+
|
|
54
|
+
TyperArgument.make_metavar = compat_typer_argument_make_metavar
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
_patch_click_make_metavar_compat()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Set up global exception handler for KeyboardInterrupt
|
|
61
|
+
def _handle_keyboard_interrupt_exception(exc_type, exc_value, exc_traceback):
|
|
62
|
+
"""Handle unhandled KeyboardInterrupt exceptions with a clean message."""
|
|
63
|
+
if exc_type is KeyboardInterrupt:
|
|
64
|
+
get_console().print()
|
|
65
|
+
print_warning("Operation cancelled")
|
|
66
|
+
sys.exit(130) # Standard exit code for SIGINT (Ctrl+C)
|
|
67
|
+
else:
|
|
68
|
+
# For other exceptions, use default handler
|
|
69
|
+
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Set up signal handler for Ctrl+C at the earliest possible point
|
|
73
|
+
def _handle_keyboard_interrupt(signum, frame):
|
|
74
|
+
"""Handle Ctrl+C gracefully with a clean message."""
|
|
75
|
+
get_console().print()
|
|
76
|
+
print_warning("Operation cancelled")
|
|
77
|
+
sys.exit(130) # Standard exit code for SIGINT (Ctrl+C)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# Register signal handler for SIGINT (Ctrl+C)
|
|
81
|
+
signal.signal(signal.SIGINT, _handle_keyboard_interrupt)
|
|
82
|
+
|
|
83
|
+
# Set up global exception hook to catch unhandled KeyboardInterrupt
|
|
84
|
+
sys.excepthook = _handle_keyboard_interrupt_exception
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
from .commands import (
|
|
88
|
+
chain_app,
|
|
89
|
+
config_app,
|
|
90
|
+
consensus_app,
|
|
91
|
+
governance_app,
|
|
92
|
+
node_app,
|
|
93
|
+
overwatch_app,
|
|
94
|
+
stake_app,
|
|
95
|
+
subnet_app,
|
|
96
|
+
validator_app,
|
|
97
|
+
wallet_app,
|
|
98
|
+
)
|
|
99
|
+
from .config import apply_network_profile, load_config
|
|
100
|
+
from .dependencies import set_config
|
|
101
|
+
from .utils.logging import get_logger, setup_logging
|
|
102
|
+
except KeyboardInterrupt:
|
|
103
|
+
# Handle Ctrl+C during imports
|
|
104
|
+
get_console().print()
|
|
105
|
+
print_warning("Operation cancelled")
|
|
106
|
+
sys.exit(130)
|
|
107
|
+
|
|
108
|
+
# ASCII art banner for HTCLI
|
|
109
|
+
BANNER = """
|
|
110
|
+
██╗ ██╗████████╗ ██████╗██╗ ██╗
|
|
111
|
+
██║ ██║╚══██╔══╝██╔════╝██║ ██║
|
|
112
|
+
███████║ ██║ ██║ ██║ ██║
|
|
113
|
+
██╔══██║ ██║ ██║ ██║ ██║
|
|
114
|
+
██║ ██║ ██║ ╚██████╗███████╗██║
|
|
115
|
+
╚═╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝╚═╝
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
TAGLINE = "Hypertensor Blockchain CLI - Your Gateway to Decentralized AI"
|
|
119
|
+
|
|
120
|
+
console = Console()
|
|
121
|
+
|
|
122
|
+
# Initialize logging
|
|
123
|
+
logger = get_logger(__name__)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def get_ascii_art():
|
|
127
|
+
"""Return ASCII art for the CLI (legacy function for compatibility)."""
|
|
128
|
+
return BANNER
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def show_banner():
|
|
132
|
+
"""Display the styled ASCII art banner with gradient colors."""
|
|
133
|
+
banner_lines = BANNER.strip().split("\n")
|
|
134
|
+
# Gradient from bright cyan through blue to purple
|
|
135
|
+
colors = ["bright_cyan", "cyan", "blue", "bright_blue", "magenta", "bright_magenta"]
|
|
136
|
+
|
|
137
|
+
styled_banner = Text()
|
|
138
|
+
for i, line in enumerate(banner_lines):
|
|
139
|
+
color = colors[i % len(colors)]
|
|
140
|
+
styled_banner.append(line + "\n", style=color)
|
|
141
|
+
|
|
142
|
+
console.print(Align.center(styled_banner))
|
|
143
|
+
console.print(Align.center(Text(TAGLINE, style="italic bright_yellow")))
|
|
144
|
+
console.print()
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class BannerGroup(TyperGroup):
|
|
148
|
+
"""Custom Typer group that shows banner before help output."""
|
|
149
|
+
|
|
150
|
+
def format_help(self, ctx, formatter):
|
|
151
|
+
# Show banner before help
|
|
152
|
+
show_banner()
|
|
153
|
+
super().format_help(ctx, formatter)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
app = typer.Typer(
|
|
157
|
+
name="htcli",
|
|
158
|
+
help="Hypertensor Blockchain CLI - Manage subnets, wallets, and chain operations.",
|
|
159
|
+
add_completion=True,
|
|
160
|
+
rich_markup_mode=None,
|
|
161
|
+
no_args_is_help=False,
|
|
162
|
+
cls=BannerGroup,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Global configuration
|
|
166
|
+
config = None
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
@app.callback(invoke_without_command=True)
|
|
170
|
+
def main(
|
|
171
|
+
config_file: Path | None = typer.Option(
|
|
172
|
+
None, "--config", "-c", help="Configuration file path"
|
|
173
|
+
),
|
|
174
|
+
endpoint: str | None = typer.Option(
|
|
175
|
+
None, "--endpoint", "-e", help="Blockchain endpoint"
|
|
176
|
+
),
|
|
177
|
+
subtensor_network: str | None = typer.Option(
|
|
178
|
+
None,
|
|
179
|
+
"--subtensor.network",
|
|
180
|
+
"--subtensor-network",
|
|
181
|
+
help="Compatibility network selector (main, test, local)",
|
|
182
|
+
),
|
|
183
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Verbose output"),
|
|
184
|
+
output_format: str = typer.Option(
|
|
185
|
+
"table", "--format", "-f", help="Output format (table/json/csv)"
|
|
186
|
+
),
|
|
187
|
+
version: bool = typer.Option(
|
|
188
|
+
False,
|
|
189
|
+
"--version",
|
|
190
|
+
help="Show the htcli version and exit.",
|
|
191
|
+
is_eager=True,
|
|
192
|
+
),
|
|
193
|
+
):
|
|
194
|
+
"""Hypertensor Blockchain CLI - Manage subnets, wallets, and chain operations."""
|
|
195
|
+
global config
|
|
196
|
+
|
|
197
|
+
if version:
|
|
198
|
+
console.print(f"htcli v{__version__}")
|
|
199
|
+
console.print("Developed by ShiftLayer LLC")
|
|
200
|
+
raise typer.Exit()
|
|
201
|
+
|
|
202
|
+
# Initialize logging based on verbosity
|
|
203
|
+
log_level = "DEBUG" if verbose else "INFO"
|
|
204
|
+
setup_logging(
|
|
205
|
+
level=log_level, enable_console_logging=False
|
|
206
|
+
) # Disable console logging to avoid interfering with CLI output
|
|
207
|
+
|
|
208
|
+
logger.info(f"HTCLI starting with log level: {log_level}")
|
|
209
|
+
|
|
210
|
+
# Show beautiful welcome screen when no command is provided
|
|
211
|
+
import sys
|
|
212
|
+
|
|
213
|
+
# Skip config loading for help commands to avoid hanging
|
|
214
|
+
is_help = "--help" in sys.argv or "-h" in sys.argv
|
|
215
|
+
|
|
216
|
+
if len(sys.argv) == 1:
|
|
217
|
+
from rich.panel import Panel
|
|
218
|
+
from rich.table import Table
|
|
219
|
+
|
|
220
|
+
# Display styled banner
|
|
221
|
+
show_banner()
|
|
222
|
+
|
|
223
|
+
# Create a beautiful welcome panel
|
|
224
|
+
welcome_text = Text()
|
|
225
|
+
welcome_text.append("Welcome to ", style="bold white")
|
|
226
|
+
welcome_text.append("Hypertensor CLI", style="bold cyan")
|
|
227
|
+
welcome_text.append(
|
|
228
|
+
"\nYour gateway to the Hypertensor blockchain ecosystem",
|
|
229
|
+
style="italic dim",
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
welcome_panel = Panel(
|
|
233
|
+
welcome_text,
|
|
234
|
+
title="[bold cyan]HTCLI[/bold cyan]",
|
|
235
|
+
border_style="cyan",
|
|
236
|
+
padding=(1, 2),
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
console.print(welcome_panel)
|
|
240
|
+
console.print()
|
|
241
|
+
|
|
242
|
+
# Create command categories table
|
|
243
|
+
table = Table(
|
|
244
|
+
title="[bold cyan]Available Commands[/bold cyan]",
|
|
245
|
+
show_header=True,
|
|
246
|
+
header_style="bold magenta",
|
|
247
|
+
)
|
|
248
|
+
table.add_column("Category", style="cyan", no_wrap=True)
|
|
249
|
+
table.add_column("Description", style="white")
|
|
250
|
+
table.add_column("Example", style="dim")
|
|
251
|
+
|
|
252
|
+
table.add_row("config", "Configuration management", "htcli config init")
|
|
253
|
+
table.add_row("subnet", "Subnet operations", "htcli subnet list")
|
|
254
|
+
table.add_row("node", "Node management", "htcli node register --subnet-id 1")
|
|
255
|
+
table.add_row(
|
|
256
|
+
"stake",
|
|
257
|
+
"Staking operations",
|
|
258
|
+
"htcli stake add --subnet-id 1 --amount 100",
|
|
259
|
+
)
|
|
260
|
+
table.add_row("wallet", "Wallet management", "htcli wallet generate-coldkey")
|
|
261
|
+
table.add_row(
|
|
262
|
+
"validator",
|
|
263
|
+
"Validator operations",
|
|
264
|
+
"htcli validator register --hotkey 0x...",
|
|
265
|
+
)
|
|
266
|
+
table.add_row("chain", "Chain & network operations", "htcli chain info")
|
|
267
|
+
table.add_row(
|
|
268
|
+
"consensus",
|
|
269
|
+
"Consensus operations",
|
|
270
|
+
"htcli consensus propose --subnet 1 --data 0x123",
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
console.print(table)
|
|
274
|
+
console.print()
|
|
275
|
+
|
|
276
|
+
# Quick tips section
|
|
277
|
+
tips_panel = Panel(
|
|
278
|
+
"[bold yellow]Quick Tips:[/bold yellow]\n"
|
|
279
|
+
"• [bold cyan]🔑 Setup Keys:[/bold cyan] htcli wallet generate-coldkey --name my-wallet\n"
|
|
280
|
+
"• [bold cyan]Check Identity:[/bold cyan] htcli wallet identity --help\n"
|
|
281
|
+
"• [bold cyan]Filter Assets:[/bold cyan] Use command filters such as --coldkey where supported\n"
|
|
282
|
+
"• [bold cyan]Get Help:[/bold cyan] Use --help with any command\n"
|
|
283
|
+
"• [bold cyan]JSON Output:[/bold cyan] Use global --format json before the command group",
|
|
284
|
+
title="[bold yellow]💡 Getting Started[/bold yellow]",
|
|
285
|
+
border_style="yellow",
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
console.print(tips_panel)
|
|
289
|
+
raise typer.Exit()
|
|
290
|
+
|
|
291
|
+
# Load configuration only if not a help command (help commands don't need config)
|
|
292
|
+
if not is_help:
|
|
293
|
+
config = load_config(config_file)
|
|
294
|
+
|
|
295
|
+
if subtensor_network:
|
|
296
|
+
try:
|
|
297
|
+
config = apply_network_profile(config, subtensor_network)
|
|
298
|
+
except ValueError as e:
|
|
299
|
+
print_error(str(e))
|
|
300
|
+
raise typer.Exit(1) from e
|
|
301
|
+
|
|
302
|
+
# Override endpoint if provided
|
|
303
|
+
if endpoint:
|
|
304
|
+
config.network.endpoint = endpoint
|
|
305
|
+
|
|
306
|
+
# Set global options
|
|
307
|
+
config.output.verbose = verbose
|
|
308
|
+
config.output.format = output_format
|
|
309
|
+
|
|
310
|
+
# Store config globally for lazy client initialization
|
|
311
|
+
# Client will be initialized only when needed for blockchain operations
|
|
312
|
+
set_config(config)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
# Include the main command groups with new folder-based structure
|
|
316
|
+
app.add_typer(wallet_app, name="wallet", help="Wallet and key management")
|
|
317
|
+
app.add_typer(subnet_app, name="subnet", help="Subnet operations")
|
|
318
|
+
app.add_typer(stake_app, name="stake", help="Staking operations and management")
|
|
319
|
+
app.add_typer(chain_app, name="chain", help="Chain operations")
|
|
320
|
+
app.add_typer(node_app, name="node", help="Node management operations")
|
|
321
|
+
app.add_typer(config_app, name="config", help="Configuration management")
|
|
322
|
+
app.add_typer(overwatch_app, name="overwatch", help="Overwatch node operations")
|
|
323
|
+
app.add_typer(consensus_app, name="consensus", help="Consensus operations")
|
|
324
|
+
app.add_typer(governance_app, name="governance", help="Governance operations")
|
|
325
|
+
app.add_typer(validator_app, name="validator", help="Validator operations")
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
if __name__ == "__main__":
|
|
329
|
+
try:
|
|
330
|
+
app()
|
|
331
|
+
except KeyboardInterrupt:
|
|
332
|
+
# User pressed Ctrl+C - exit cleanly with a friendly message
|
|
333
|
+
get_console().print()
|
|
334
|
+
print_warning("Operation cancelled")
|
|
335
|
+
sys.exit(130) # Standard exit code for SIGINT (Ctrl+C)
|
|
336
|
+
except Exception as e:
|
|
337
|
+
# For any other unexpected errors during app initialization
|
|
338
|
+
# (typer should handle most errors, but this is a safety net)
|
|
339
|
+
logger.error(f"Unexpected error in main: {e}", exc_info=True)
|
|
340
|
+
get_console().print()
|
|
341
|
+
print_error("An unexpected error occurred")
|
|
342
|
+
get_console().print(f"[dim]{str(e)}[/dim]")
|
|
343
|
+
sys.exit(1)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HTCLI Models Package.
|
|
3
|
+
|
|
4
|
+
This package contains all Pydantic models for requests, responses, and errors.
|
|
5
|
+
Models are organized into separate folders for better maintainability.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Import all request models
|
|
9
|
+
# Import error models (keep existing structure)
|
|
10
|
+
from .errors import *
|
|
11
|
+
from .requests import *
|
|
12
|
+
|
|
13
|
+
# Import all response models
|
|
14
|
+
from .responses import *
|
|
15
|
+
|
|
16
|
+
# Re-export everything for backward compatibility
|
|
17
|
+
__all__ = [
|
|
18
|
+
# All request models are exported from requests package
|
|
19
|
+
# All response models are exported from responses package
|
|
20
|
+
# All error models are exported from errors package
|
|
21
|
+
]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from enum import Enum, IntEnum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class KeyType(IntEnum):
|
|
5
|
+
"""Supported key types for subnet registration."""
|
|
6
|
+
|
|
7
|
+
RSA = 0
|
|
8
|
+
ED25519 = 1
|
|
9
|
+
SECP256K1 = 2
|
|
10
|
+
ECDSA = 3
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class VoteType(str, Enum):
|
|
14
|
+
"""Vote types for proposals."""
|
|
15
|
+
|
|
16
|
+
YAY = "Yay"
|
|
17
|
+
NAY = "Nay"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SubnetState(str, Enum):
|
|
21
|
+
"""Subnet state enumeration."""
|
|
22
|
+
|
|
23
|
+
REGISTERED = "Registered"
|
|
24
|
+
ACTIVE = "Active"
|
|
25
|
+
PAUSED = "Paused"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SubnetNodeClass(str, Enum):
|
|
29
|
+
"""Subnet node class enumeration."""
|
|
30
|
+
|
|
31
|
+
REGISTERED = "Registered"
|
|
32
|
+
IDLE = "Idle"
|
|
33
|
+
INCLUDED = "Included"
|
|
34
|
+
VALIDATOR = "Validator"
|
|
35
|
+
DEACTIVATED = "Deactivated"
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pydantic models for error structures.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Optional
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ErrorResponse(BaseModel):
|
|
11
|
+
"""Standard error response model."""
|
|
12
|
+
|
|
13
|
+
success: bool = Field(False, description="Always false for errors")
|
|
14
|
+
error: str = Field(..., description="Error type")
|
|
15
|
+
message: str = Field(..., description="Human-readable error message")
|
|
16
|
+
code: int = Field(..., description="Error code")
|
|
17
|
+
details: Optional[dict[str, Any]] = Field(
|
|
18
|
+
None, description="Optional error details"
|
|
19
|
+
)
|
|
20
|
+
timestamp: str = Field(..., description="ISO timestamp")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ValidationError(BaseModel):
|
|
24
|
+
"""Validation error model."""
|
|
25
|
+
|
|
26
|
+
field: str = Field(..., description="Field name")
|
|
27
|
+
value: Any = Field(..., description="Invalid value")
|
|
28
|
+
constraint: str = Field(..., description="Constraint that was violated")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class NetworkError(BaseModel):
|
|
32
|
+
"""Network error model."""
|
|
33
|
+
|
|
34
|
+
endpoint: str = Field(..., description="Failed endpoint")
|
|
35
|
+
status_code: Optional[int] = Field(None, description="HTTP status code")
|
|
36
|
+
timeout: bool = Field(False, description="Whether the error was due to timeout")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class RPCError(BaseModel):
|
|
40
|
+
"""RPC error model."""
|
|
41
|
+
|
|
42
|
+
method: str = Field(..., description="RPC method that failed")
|
|
43
|
+
params: Optional[dict[str, Any]] = Field(None, description="RPC parameters")
|
|
44
|
+
error_code: Optional[int] = Field(None, description="RPC error code")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class BusinessLogicError(BaseModel):
|
|
48
|
+
"""Business logic error model."""
|
|
49
|
+
|
|
50
|
+
operation: str = Field(..., description="Operation that failed")
|
|
51
|
+
reason: str = Field(..., description="Reason for failure")
|
|
52
|
+
recoverable: bool = Field(True, description="Whether the error is recoverable")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# Error code ranges
|
|
56
|
+
ERROR_CODES = {
|
|
57
|
+
"AuthenticationFailed": (1001, 1999),
|
|
58
|
+
"ValidationError": (2001, 2999),
|
|
59
|
+
"NetworkError": (3001, 3999),
|
|
60
|
+
"RPCError": (4001, 4999),
|
|
61
|
+
"BusinessLogicError": (5001, 5999),
|
|
62
|
+
"SubnetError": (6001, 6999),
|
|
63
|
+
"StakingError": (7001, 7999),
|
|
64
|
+
"ValidationError": (8001, 8999),
|
|
65
|
+
"GovernanceError": (9001, 9999),
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Specific error codes
|
|
69
|
+
SPECIFIC_ERROR_CODES = {
|
|
70
|
+
# Subnet errors
|
|
71
|
+
"INVALID_SUBNET_PATH": 1001,
|
|
72
|
+
"INSUFFICIENT_MEMORY": 1002,
|
|
73
|
+
"INVALID_REGISTRATION_PERIOD": 1003,
|
|
74
|
+
"DUPLICATE_SUBNET_PATH": 1004,
|
|
75
|
+
"INSUFFICIENT_BALANCE_FOR_REGISTRATION": 1005,
|
|
76
|
+
"SUBNET_NOT_FOUND": 2001,
|
|
77
|
+
"SUBNET_ALREADY_ACTIVATED": 2002,
|
|
78
|
+
"INSUFFICIENT_NODES_FOR_ACTIVATION": 2003,
|
|
79
|
+
"REGISTRATION_PERIOD_NOT_COMPLETED": 2004,
|
|
80
|
+
# Node errors
|
|
81
|
+
"SUBNET_NOT_ACTIVATED": 4002,
|
|
82
|
+
"NODE_ALREADY_EXISTS": 4003,
|
|
83
|
+
"INVALID_PEER_ID_FORMAT": 4004,
|
|
84
|
+
"INSUFFICIENT_STAKE_FOR_NODE": 4005,
|
|
85
|
+
# Staking errors
|
|
86
|
+
"NODE_NOT_FOUND": 5002,
|
|
87
|
+
"INSUFFICIENT_BALANCE": 5003,
|
|
88
|
+
"INVALID_STAKE_AMOUNT": 5004,
|
|
89
|
+
"STAKE_LIMIT_EXCEEDED": 5005,
|
|
90
|
+
"INSUFFICIENT_STAKE_TO_REMOVE": 6002,
|
|
91
|
+
"STAKE_STILL_IN_UNBONDING_PERIOD": 6003,
|
|
92
|
+
# Validation errors
|
|
93
|
+
"SUBNET_NOT_ACTIVE": 7002,
|
|
94
|
+
"INVALID_VALIDATION_DATA": 7003,
|
|
95
|
+
"VALIDATION_RATE_LIMIT_EXCEEDED": 7004,
|
|
96
|
+
# Governance errors
|
|
97
|
+
"INVALID_PROPOSAL_DATA": 8003,
|
|
98
|
+
"INSUFFICIENT_STAKE_FOR_PROPOSAL": 8004,
|
|
99
|
+
"PROPOSAL_NOT_FOUND": 9001,
|
|
100
|
+
"INVALID_VOTE_TYPE": 9002,
|
|
101
|
+
"ALREADY_VOTED": 9003,
|
|
102
|
+
"VOTING_PERIOD_ENDED": 9004,
|
|
103
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Request models for HTCLI.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
# Wallet-related requests
|
|
6
|
+
# Config-related requests
|
|
7
|
+
from .config import (
|
|
8
|
+
ConfigEditRequest,
|
|
9
|
+
ConfigGetRequest,
|
|
10
|
+
ConfigInitRequest,
|
|
11
|
+
ConfigPathRequest,
|
|
12
|
+
ConfigSetRequest,
|
|
13
|
+
ConfigShowRequest,
|
|
14
|
+
ConfigValidateRequest,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# Governance-related requests
|
|
18
|
+
from .governance import (
|
|
19
|
+
GovernanceCollectiveRemoveOverwatchNodeRequest,
|
|
20
|
+
GovernanceCollectiveRemoveSubnetNodeRequest,
|
|
21
|
+
GovernanceCollectiveRemoveSubnetRequest,
|
|
22
|
+
GovernanceParameterUpdateRequest,
|
|
23
|
+
GovernancePauseRequest,
|
|
24
|
+
GovernanceUnpauseRequest,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Identity-related requests
|
|
28
|
+
from .identity import (
|
|
29
|
+
IdentityAcceptRequest,
|
|
30
|
+
IdentityRegisterRequest,
|
|
31
|
+
IdentityRemoveRequest,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Key-related requests
|
|
35
|
+
from .key import KeyGenerateRequest, KeyImportRequest
|
|
36
|
+
|
|
37
|
+
# Node-related requests
|
|
38
|
+
from .node import (
|
|
39
|
+
SubnetNodeActivateRequest,
|
|
40
|
+
SubnetNodeBootnodeUpdateRequest,
|
|
41
|
+
SubnetNodePauseRequest,
|
|
42
|
+
SubnetNodePeerIdUpdateRequest,
|
|
43
|
+
SubnetNodeReactivateRequest,
|
|
44
|
+
SubnetNodeRegisterRequest,
|
|
45
|
+
SubnetNodeRemoveRequest,
|
|
46
|
+
SubnetNodeUpdateRequest,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Overwatch-related requests
|
|
50
|
+
from .overwatch import (
|
|
51
|
+
OverwatchNodeAnyoneRemoveRequest,
|
|
52
|
+
OverwatchNodePeerIdUpdateRequest,
|
|
53
|
+
OverwatchNodeRegisterRequest,
|
|
54
|
+
OverwatchNodeRemoveRequest,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Staking-related requests
|
|
58
|
+
from .staking import (
|
|
59
|
+
ClaimUnbondingsRequest,
|
|
60
|
+
DelegateStakeAddRequest,
|
|
61
|
+
DelegateStakeDonateRequest,
|
|
62
|
+
DelegateStakeRemoveRequest,
|
|
63
|
+
DelegateStakeSwapRequest,
|
|
64
|
+
DelegateStakeTransferRequest,
|
|
65
|
+
NodeDelegateStakeAddRequest,
|
|
66
|
+
NodeDelegateStakeDonateRequest,
|
|
67
|
+
NodeDelegateStakeRemoveRequest,
|
|
68
|
+
NodeDelegateStakeSwapRequest,
|
|
69
|
+
NodeDelegateStakeTransferRequest,
|
|
70
|
+
OverwatchStakeAddRequest,
|
|
71
|
+
OverwatchStakeRemoveRequest,
|
|
72
|
+
StakeAddRequest,
|
|
73
|
+
StakeRemoveRequest,
|
|
74
|
+
StakeSwapFromNodeToSubnetRequest,
|
|
75
|
+
StakeSwapFromSubnetToNodeRequest,
|
|
76
|
+
StakeSwapFromSubnetToValidatorRequest,
|
|
77
|
+
StakeSwapFromValidatorToSubnetRequest,
|
|
78
|
+
StakeSwapQueueUpdateRequest,
|
|
79
|
+
ValidatorDelegateStakeAddRequest,
|
|
80
|
+
ValidatorDelegateStakeDonateRequest,
|
|
81
|
+
ValidatorDelegateStakeRemoveRequest,
|
|
82
|
+
ValidatorDelegateStakeSwapRequest,
|
|
83
|
+
ValidatorDelegateStakeTransferRequest,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Subnet-related requests
|
|
87
|
+
from .subnet import (
|
|
88
|
+
SubnetActivateRequest,
|
|
89
|
+
SubnetConfigUpdateRequest,
|
|
90
|
+
SubnetOwnershipAcceptRequest,
|
|
91
|
+
SubnetOwnershipTransferRequest,
|
|
92
|
+
SubnetRegisterRequest,
|
|
93
|
+
SubnetRemoveRequest,
|
|
94
|
+
SubnetUpdateRequest,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Validator-related requests
|
|
98
|
+
from .validator import (
|
|
99
|
+
ValidatorColdkeyUpdateRequest,
|
|
100
|
+
ValidatorDelegateAccountUpdateRequest,
|
|
101
|
+
ValidatorDelegateRewardRateUpdateRequest,
|
|
102
|
+
ValidatorHotkeyUpdateRequest,
|
|
103
|
+
ValidatorIdentityUpdateRequest,
|
|
104
|
+
ValidatorRegisterRequest,
|
|
105
|
+
)
|
|
106
|
+
from .wallet import (
|
|
107
|
+
PreseededWalletRequest,
|
|
108
|
+
WalletBalanceRequest,
|
|
109
|
+
WalletCreateRequest,
|
|
110
|
+
WalletDeleteRequest,
|
|
111
|
+
WalletRestoreRequest,
|
|
112
|
+
WalletTransferRequest,
|
|
113
|
+
WalletUpdateRequest,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
__all__ = [
|
|
117
|
+
# Wallet requests
|
|
118
|
+
"WalletCreateRequest",
|
|
119
|
+
"WalletRestoreRequest",
|
|
120
|
+
"WalletUpdateRequest",
|
|
121
|
+
"WalletDeleteRequest",
|
|
122
|
+
"WalletTransferRequest",
|
|
123
|
+
"WalletBalanceRequest",
|
|
124
|
+
"PreseededWalletRequest",
|
|
125
|
+
# Staking requests
|
|
126
|
+
"StakeAddRequest",
|
|
127
|
+
"StakeRemoveRequest",
|
|
128
|
+
"ClaimUnbondingsRequest",
|
|
129
|
+
"DelegateStakeAddRequest",
|
|
130
|
+
"DelegateStakeRemoveRequest",
|
|
131
|
+
"DelegateStakeTransferRequest",
|
|
132
|
+
"DelegateStakeSwapRequest",
|
|
133
|
+
"DelegateStakeDonateRequest",
|
|
134
|
+
"ValidatorDelegateStakeAddRequest",
|
|
135
|
+
"ValidatorDelegateStakeRemoveRequest",
|
|
136
|
+
"ValidatorDelegateStakeTransferRequest",
|
|
137
|
+
"ValidatorDelegateStakeSwapRequest",
|
|
138
|
+
"ValidatorDelegateStakeDonateRequest",
|
|
139
|
+
"NodeDelegateStakeAddRequest",
|
|
140
|
+
"NodeDelegateStakeRemoveRequest",
|
|
141
|
+
"NodeDelegateStakeTransferRequest",
|
|
142
|
+
"NodeDelegateStakeSwapRequest",
|
|
143
|
+
"NodeDelegateStakeDonateRequest",
|
|
144
|
+
"StakeSwapFromNodeToSubnetRequest",
|
|
145
|
+
"StakeSwapFromSubnetToNodeRequest",
|
|
146
|
+
"StakeSwapFromValidatorToSubnetRequest",
|
|
147
|
+
"StakeSwapFromSubnetToValidatorRequest",
|
|
148
|
+
"StakeSwapQueueUpdateRequest",
|
|
149
|
+
"OverwatchStakeAddRequest",
|
|
150
|
+
"OverwatchStakeRemoveRequest",
|
|
151
|
+
# Identity requests
|
|
152
|
+
"IdentityRegisterRequest",
|
|
153
|
+
"IdentityAcceptRequest",
|
|
154
|
+
"IdentityRemoveRequest",
|
|
155
|
+
# Governance requests
|
|
156
|
+
"GovernancePauseRequest",
|
|
157
|
+
"GovernanceUnpauseRequest",
|
|
158
|
+
"GovernanceCollectiveRemoveSubnetRequest",
|
|
159
|
+
"GovernanceCollectiveRemoveSubnetNodeRequest",
|
|
160
|
+
"GovernanceCollectiveRemoveOverwatchNodeRequest",
|
|
161
|
+
"GovernanceParameterUpdateRequest",
|
|
162
|
+
# Node requests
|
|
163
|
+
"SubnetNodeRegisterRequest",
|
|
164
|
+
"SubnetNodeActivateRequest",
|
|
165
|
+
"SubnetNodePauseRequest",
|
|
166
|
+
"SubnetNodeReactivateRequest",
|
|
167
|
+
"SubnetNodeRemoveRequest",
|
|
168
|
+
"SubnetNodeUpdateRequest",
|
|
169
|
+
"SubnetNodePeerIdUpdateRequest",
|
|
170
|
+
"SubnetNodeBootnodeUpdateRequest",
|
|
171
|
+
# Subnet requests
|
|
172
|
+
"SubnetRegisterRequest",
|
|
173
|
+
"SubnetActivateRequest",
|
|
174
|
+
"SubnetRemoveRequest",
|
|
175
|
+
"SubnetUpdateRequest",
|
|
176
|
+
"SubnetConfigUpdateRequest",
|
|
177
|
+
"SubnetOwnershipTransferRequest",
|
|
178
|
+
"SubnetOwnershipAcceptRequest",
|
|
179
|
+
# Validator requests
|
|
180
|
+
"ValidatorRegisterRequest",
|
|
181
|
+
"ValidatorDelegateRewardRateUpdateRequest",
|
|
182
|
+
"ValidatorDelegateAccountUpdateRequest",
|
|
183
|
+
"ValidatorHotkeyUpdateRequest",
|
|
184
|
+
"ValidatorColdkeyUpdateRequest",
|
|
185
|
+
"ValidatorIdentityUpdateRequest",
|
|
186
|
+
# Config requests
|
|
187
|
+
"ConfigInitRequest",
|
|
188
|
+
"ConfigShowRequest",
|
|
189
|
+
"ConfigSetRequest",
|
|
190
|
+
"ConfigGetRequest",
|
|
191
|
+
"ConfigValidateRequest",
|
|
192
|
+
"ConfigPathRequest",
|
|
193
|
+
"ConfigEditRequest",
|
|
194
|
+
# Key requests
|
|
195
|
+
"KeyGenerateRequest",
|
|
196
|
+
"KeyImportRequest",
|
|
197
|
+
]
|