hypercli-cli 0.8.0__tar.gz → 0.8.1__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.
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/PKG-INFO +3 -3
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/wallet.py +169 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/pyproject.toml +3 -3
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/.gitignore +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/README.md +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/__init__.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/billing.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/claw.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/cli.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/comfyui.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/flow.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/instances.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/jobs.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/keys.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/llm.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/output.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/renders.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/tui/__init__.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/tui/job_monitor.py +0 -0
- {hypercli_cli-0.8.0 → hypercli_cli-0.8.1}/hypercli_cli/user.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hypercli-cli
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.1
|
|
4
4
|
Summary: CLI for HyperCLI - GPU orchestration and LLM API
|
|
5
5
|
Project-URL: Homepage, https://hypercli.com
|
|
6
6
|
Project-URL: Documentation, https://docs.hypercli.com
|
|
@@ -21,7 +21,7 @@ Requires-Dist: argon2-cffi>=25.0.0; extra == 'all'
|
|
|
21
21
|
Requires-Dist: eth-account>=0.13.0; extra == 'all'
|
|
22
22
|
Requires-Dist: hypercli-sdk[comfyui]>=0.7.1; extra == 'all'
|
|
23
23
|
Requires-Dist: web3>=7.0.0; extra == 'all'
|
|
24
|
-
Requires-Dist: x402[httpx]>=2.0.0; extra == 'all'
|
|
24
|
+
Requires-Dist: x402[evm,httpx]>=2.0.0; extra == 'all'
|
|
25
25
|
Provides-Extra: comfyui
|
|
26
26
|
Requires-Dist: hypercli-sdk[comfyui]>=0.7.1; extra == 'comfyui'
|
|
27
27
|
Provides-Extra: dev
|
|
@@ -32,7 +32,7 @@ Requires-Dist: argon2-cffi>=25.0.0; extra == 'wallet'
|
|
|
32
32
|
Requires-Dist: eth-account>=0.13.0; extra == 'wallet'
|
|
33
33
|
Requires-Dist: qrcode[pil]>=7.4.0; extra == 'wallet'
|
|
34
34
|
Requires-Dist: web3>=7.0.0; extra == 'wallet'
|
|
35
|
-
Requires-Dist: x402[httpx]>=2.0.0; extra == 'wallet'
|
|
35
|
+
Requires-Dist: x402[evm,httpx]>=2.0.0; extra == 'wallet'
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
37
|
|
|
38
38
|
# HyperCLI CLI
|
|
@@ -240,6 +240,175 @@ def balance():
|
|
|
240
240
|
console.print(f"\n[green]✓[/green] You have [bold]{balance_usdc:.2f} USDC[/bold]")
|
|
241
241
|
|
|
242
242
|
|
|
243
|
+
@app.command("topup")
|
|
244
|
+
def topup(
|
|
245
|
+
amount: str = typer.Argument(help="Amount in USDC to top up (max 6 decimals)"),
|
|
246
|
+
api_url: str = typer.Option(None, help="API URL override"),
|
|
247
|
+
):
|
|
248
|
+
"""Top up account balance via Orchestra x402 endpoint.
|
|
249
|
+
|
|
250
|
+
Flow:
|
|
251
|
+
1) Resolve user_id via GET /api/user using your existing API key
|
|
252
|
+
2) POST /api/x402/top_up with {user_id, amount}
|
|
253
|
+
3) Handle 402 and retry with x402 payment headers
|
|
254
|
+
|
|
255
|
+
Examples:
|
|
256
|
+
hyper wallet topup 10
|
|
257
|
+
hyper wallet topup 25.50
|
|
258
|
+
"""
|
|
259
|
+
require_wallet_deps()
|
|
260
|
+
from decimal import Decimal, InvalidOperation
|
|
261
|
+
import httpx
|
|
262
|
+
from hypercli.config import get_api_key, get_api_url
|
|
263
|
+
|
|
264
|
+
try:
|
|
265
|
+
from x402 import x402ClientSync
|
|
266
|
+
from x402.http import x402HTTPClientSync
|
|
267
|
+
from x402.mechanisms.evm import EthAccountSigner
|
|
268
|
+
from x402.mechanisms.evm.exact.register import register_exact_evm_client
|
|
269
|
+
except ImportError:
|
|
270
|
+
console.print("[red]❌ x402 payment requires wallet/x402 dependencies[/red]")
|
|
271
|
+
console.print("\nInstall with:")
|
|
272
|
+
console.print(" [bold]pip install 'hypercli-cli[wallet]'[/bold]")
|
|
273
|
+
raise typer.Exit(1)
|
|
274
|
+
|
|
275
|
+
try:
|
|
276
|
+
amount_dec = Decimal(amount)
|
|
277
|
+
except InvalidOperation:
|
|
278
|
+
console.print(f"[red]❌ Invalid amount: {amount}[/red]")
|
|
279
|
+
raise typer.Exit(1)
|
|
280
|
+
|
|
281
|
+
if amount_dec <= 0:
|
|
282
|
+
console.print("[red]❌ Amount must be greater than 0[/red]")
|
|
283
|
+
raise typer.Exit(1)
|
|
284
|
+
if amount_dec.as_tuple().exponent < -6:
|
|
285
|
+
console.print("[red]❌ Amount supports at most 6 decimals[/red]")
|
|
286
|
+
raise typer.Exit(1)
|
|
287
|
+
|
|
288
|
+
amount_atomic = int(amount_dec * Decimal("1000000"))
|
|
289
|
+
|
|
290
|
+
# Step 1: Load wallet
|
|
291
|
+
account = load_wallet()
|
|
292
|
+
console.print(f"[green]✓[/green] Wallet: {account.address}")
|
|
293
|
+
|
|
294
|
+
# Step 2: Check USDC balance
|
|
295
|
+
w3 = Web3(Web3.HTTPProvider(BASE_RPC))
|
|
296
|
+
usdc_abi = [
|
|
297
|
+
{
|
|
298
|
+
"constant": True,
|
|
299
|
+
"inputs": [{"name": "_owner", "type": "address"}],
|
|
300
|
+
"name": "balanceOf",
|
|
301
|
+
"outputs": [{"name": "balance", "type": "uint256"}],
|
|
302
|
+
"type": "function",
|
|
303
|
+
}
|
|
304
|
+
]
|
|
305
|
+
usdc = w3.eth.contract(address=USDC_CONTRACT, abi=usdc_abi)
|
|
306
|
+
balance_raw = usdc.functions.balanceOf(account.address).call()
|
|
307
|
+
balance_usdc = Decimal(balance_raw) / Decimal("1000000")
|
|
308
|
+
|
|
309
|
+
console.print(f"[green]✓[/green] Balance: {balance_usdc:.6f} USDC")
|
|
310
|
+
|
|
311
|
+
if balance_raw < amount_atomic:
|
|
312
|
+
console.print(
|
|
313
|
+
f"\n[red]❌ Insufficient balance: {balance_usdc:.6f} < {amount_dec:.6f} USDC[/red]"
|
|
314
|
+
)
|
|
315
|
+
console.print(f"Send USDC on Base to: [bold]{account.address}[/bold]")
|
|
316
|
+
raise typer.Exit(1)
|
|
317
|
+
|
|
318
|
+
# Step 3: Set up x402 v2 client
|
|
319
|
+
api_key = get_api_key()
|
|
320
|
+
if not api_key:
|
|
321
|
+
console.print("[red]❌ API key required for top-up[/red]")
|
|
322
|
+
console.print(
|
|
323
|
+
"Set it with: [bold]hyper configure[/bold] or [bold]hyper wallet login[/bold]"
|
|
324
|
+
)
|
|
325
|
+
raise typer.Exit(1)
|
|
326
|
+
|
|
327
|
+
base_url = (api_url or get_api_url()).rstrip("/")
|
|
328
|
+
user_endpoint = f"{base_url}/api/user"
|
|
329
|
+
topup_endpoint = f"{base_url}/api/x402/top_up"
|
|
330
|
+
auth_headers = {
|
|
331
|
+
"Authorization": f"Bearer {api_key}",
|
|
332
|
+
"Content-Type": "application/json",
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
signer = EthAccountSigner(account)
|
|
336
|
+
x402_client = x402ClientSync()
|
|
337
|
+
register_exact_evm_client(x402_client, signer)
|
|
338
|
+
http_client = x402HTTPClientSync(x402_client)
|
|
339
|
+
|
|
340
|
+
with httpx.Client(timeout=30) as client:
|
|
341
|
+
# Step 4: Resolve user_id from API key
|
|
342
|
+
console.print("\n[bold]Resolving user...[/bold]")
|
|
343
|
+
user_resp = client.get(user_endpoint, headers=auth_headers)
|
|
344
|
+
if user_resp.status_code != 200:
|
|
345
|
+
console.print(
|
|
346
|
+
f"[red]❌ Failed to get user: {user_resp.status_code} {user_resp.text}[/red]"
|
|
347
|
+
)
|
|
348
|
+
raise typer.Exit(1)
|
|
349
|
+
|
|
350
|
+
user_id = user_resp.json().get("user_id")
|
|
351
|
+
if not user_id:
|
|
352
|
+
console.print("[red]❌ /api/user response missing user_id[/red]")
|
|
353
|
+
raise typer.Exit(1)
|
|
354
|
+
|
|
355
|
+
payload = {"user_id": user_id, "amount": float(amount_dec)}
|
|
356
|
+
|
|
357
|
+
# Step 5: Request top-up (expect 402 then retry with payment)
|
|
358
|
+
console.print(f"[bold]Requesting top-up of ${amount_dec:.2f}...[/bold]")
|
|
359
|
+
resp = client.post(topup_endpoint, headers=auth_headers, json=payload)
|
|
360
|
+
|
|
361
|
+
if resp.status_code == 402:
|
|
362
|
+
console.print("[bold]Signing x402 payment...[/bold]")
|
|
363
|
+
try:
|
|
364
|
+
payment_headers, _ = http_client.handle_402_response(
|
|
365
|
+
dict(resp.headers), resp.content
|
|
366
|
+
)
|
|
367
|
+
except Exception as e:
|
|
368
|
+
console.print(f"[red]❌ Failed to build payment header: {e}[/red]")
|
|
369
|
+
raise typer.Exit(1)
|
|
370
|
+
|
|
371
|
+
console.print("[bold]Submitting payment...[/bold]")
|
|
372
|
+
retry_headers = {**auth_headers, **payment_headers}
|
|
373
|
+
retry_headers["Access-Control-Expose-Headers"] = "PAYMENT-RESPONSE,X-PAYMENT-RESPONSE"
|
|
374
|
+
resp = client.post(topup_endpoint, headers=retry_headers, json=payload)
|
|
375
|
+
|
|
376
|
+
if resp.status_code != 200:
|
|
377
|
+
console.print(f"[red]❌ Top-up failed: {resp.status_code} {resp.text}[/red]")
|
|
378
|
+
try:
|
|
379
|
+
settle = http_client.get_payment_settle_response(lambda name: resp.headers.get(name))
|
|
380
|
+
if getattr(settle, "error_reason", None):
|
|
381
|
+
console.print(f"[red]❌ Payment error: {settle.error_reason}[/red]")
|
|
382
|
+
except Exception:
|
|
383
|
+
pass
|
|
384
|
+
raise typer.Exit(1)
|
|
385
|
+
|
|
386
|
+
result = resp.json()
|
|
387
|
+
|
|
388
|
+
credited = result.get("amount", float(amount_dec))
|
|
389
|
+
wallet = result.get("wallet", account.address)
|
|
390
|
+
tx_id = result.get("transaction_id", "")
|
|
391
|
+
msg = result.get("message", "Top-up successful")
|
|
392
|
+
|
|
393
|
+
console.print(f"\n[bold green]✓ Top-up successful![/bold green]\n")
|
|
394
|
+
console.print(f" User: {result.get('user_id', 'N/A')}")
|
|
395
|
+
console.print(f" Credited: ${credited} USDC")
|
|
396
|
+
console.print(f" Wallet: {wallet}")
|
|
397
|
+
console.print(f" Tx ID: {tx_id or 'N/A'}")
|
|
398
|
+
console.print(f" Message: {msg}")
|
|
399
|
+
|
|
400
|
+
try:
|
|
401
|
+
settle = http_client.get_payment_settle_response(lambda name: resp.headers.get(name))
|
|
402
|
+
if getattr(settle, "transaction", None):
|
|
403
|
+
console.print(f" On-chain: {settle.transaction}")
|
|
404
|
+
if getattr(settle, "network", None):
|
|
405
|
+
console.print(f" Network: {settle.network}")
|
|
406
|
+
except Exception:
|
|
407
|
+
pass
|
|
408
|
+
|
|
409
|
+
console.print()
|
|
410
|
+
|
|
411
|
+
|
|
243
412
|
@app.command("login")
|
|
244
413
|
def wallet_login(
|
|
245
414
|
name: str = typer.Option("cli", help="Name for the generated API key"),
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hypercli-cli"
|
|
7
|
-
version = "0.8.
|
|
7
|
+
version = "0.8.1"
|
|
8
8
|
description = "CLI for HyperCLI - GPU orchestration and LLM API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -28,7 +28,7 @@ comfyui = [
|
|
|
28
28
|
"hypercli-sdk[comfyui]>=0.7.1",
|
|
29
29
|
]
|
|
30
30
|
wallet = [
|
|
31
|
-
"x402[httpx]>=2.0.0",
|
|
31
|
+
"x402[httpx,evm]>=2.0.0",
|
|
32
32
|
"eth-account>=0.13.0",
|
|
33
33
|
"web3>=7.0.0",
|
|
34
34
|
"argon2-cffi>=25.0.0",
|
|
@@ -36,7 +36,7 @@ wallet = [
|
|
|
36
36
|
]
|
|
37
37
|
all = [
|
|
38
38
|
"hypercli-sdk[comfyui]>=0.7.1",
|
|
39
|
-
"x402[httpx]>=2.0.0",
|
|
39
|
+
"x402[httpx,evm]>=2.0.0",
|
|
40
40
|
"eth-account>=0.13.0",
|
|
41
41
|
"web3>=7.0.0",
|
|
42
42
|
"argon2-cffi>=25.0.0",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|