hypercli-cli 0.8.3__tar.gz → 0.8.4__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.3 → hypercli_cli-0.8.4}/PKG-INFO +1 -1
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/claw.py +158 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/pyproject.toml +1 -1
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/.gitignore +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/README.md +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/__init__.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/billing.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/cli.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/comfyui.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/flow.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/instances.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/jobs.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/keys.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/llm.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/onboard.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/output.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/renders.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/tui/__init__.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/tui/job_monitor.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/user.py +0 -0
- {hypercli_cli-0.8.3 → hypercli_cli-0.8.4}/hypercli_cli/wallet.py +0 -0
|
@@ -404,3 +404,161 @@ def openclaw_setup(
|
|
|
404
404
|
if default:
|
|
405
405
|
console.print(f" default model: hyperclaw/{models[0]['id']}")
|
|
406
406
|
console.print("\nRun: [bold]openclaw gateway restart[/bold]")
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
# ---------------------------------------------------------------------------
|
|
410
|
+
# hyper claw config — generate / apply provider configs for various tools
|
|
411
|
+
# ---------------------------------------------------------------------------
|
|
412
|
+
|
|
413
|
+
def _resolve_api_key(key: str | None) -> str:
|
|
414
|
+
"""Resolve API key from --key flag or ~/.hypercli/claw-key.json."""
|
|
415
|
+
if key:
|
|
416
|
+
return key
|
|
417
|
+
if CLAW_KEY_PATH.exists():
|
|
418
|
+
with open(CLAW_KEY_PATH) as f:
|
|
419
|
+
k = json.load(f).get("key", "")
|
|
420
|
+
if k:
|
|
421
|
+
return k
|
|
422
|
+
console.print("[red]❌ No API key found.[/red]")
|
|
423
|
+
console.print("Either pass [bold]--key sk-...[/bold] or subscribe first:")
|
|
424
|
+
console.print(" [bold]hyper claw subscribe 1aiu[/bold]")
|
|
425
|
+
raise typer.Exit(1)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def _config_openclaw(api_key: str, models: list[dict]) -> dict:
|
|
429
|
+
"""OpenClaw openclaw.json provider snippet."""
|
|
430
|
+
return {
|
|
431
|
+
"models": {
|
|
432
|
+
"mode": "merge",
|
|
433
|
+
"providers": {
|
|
434
|
+
"hyperclaw": {
|
|
435
|
+
"baseUrl": "https://api.hyperclaw.app/v1",
|
|
436
|
+
"apiKey": api_key,
|
|
437
|
+
"api": "openai-completions",
|
|
438
|
+
"models": models,
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
"agents": {
|
|
443
|
+
"defaults": {
|
|
444
|
+
"models": {
|
|
445
|
+
f"hyperclaw/{models[0]['id']}": {"alias": "kimi"}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def _config_opencode(api_key: str, models: list[dict]) -> dict:
|
|
453
|
+
"""OpenCode opencode.json provider snippet."""
|
|
454
|
+
model_entries = {}
|
|
455
|
+
for m in models:
|
|
456
|
+
model_entries[m["id"]] = {"name": m["id"]}
|
|
457
|
+
return {
|
|
458
|
+
"$schema": "https://opencode.ai/config.json",
|
|
459
|
+
"provider": {
|
|
460
|
+
"hypercli": {
|
|
461
|
+
"npm": "@ai-sdk/openai-compatible",
|
|
462
|
+
"name": "HyperCLI",
|
|
463
|
+
"options": {
|
|
464
|
+
"baseURL": "https://api.hyperclaw.app/v1",
|
|
465
|
+
"apiKey": api_key,
|
|
466
|
+
},
|
|
467
|
+
"models": model_entries,
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def _config_env(api_key: str, models: list[dict]) -> str:
|
|
474
|
+
"""Shell env vars for generic OpenAI-compatible tools."""
|
|
475
|
+
lines = [
|
|
476
|
+
f'export OPENAI_API_KEY="{api_key}"',
|
|
477
|
+
'export OPENAI_BASE_URL="https://api.hyperclaw.app/v1"',
|
|
478
|
+
f'# Available models: {", ".join(m["id"] for m in models)}',
|
|
479
|
+
]
|
|
480
|
+
return "\n".join(lines)
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
FORMAT_CHOICES = ["openclaw", "opencode", "env"]
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
@app.command("config")
|
|
487
|
+
def config_cmd(
|
|
488
|
+
format: str = typer.Argument(
|
|
489
|
+
None,
|
|
490
|
+
help=f"Output format: {', '.join(FORMAT_CHOICES)}. Omit to show all.",
|
|
491
|
+
),
|
|
492
|
+
key: str = typer.Option(None, "--key", "-k", help="API key (sk-...). Falls back to ~/.hypercli/claw-key.json"),
|
|
493
|
+
apply: bool = typer.Option(False, "--apply", help="Write config to the appropriate file (openclaw/opencode only)"),
|
|
494
|
+
dev: bool = typer.Option(False, "--dev", help="Use dev API"),
|
|
495
|
+
):
|
|
496
|
+
"""Generate provider configs for OpenClaw, OpenCode, and other tools.
|
|
497
|
+
|
|
498
|
+
Examples:
|
|
499
|
+
hyper claw config # Show all configs
|
|
500
|
+
hyper claw config openclaw # OpenClaw snippet
|
|
501
|
+
hyper claw config opencode --key sk-... # OpenCode with explicit key
|
|
502
|
+
hyper claw config openclaw --apply # Write directly to openclaw.json
|
|
503
|
+
hyper claw config env # Shell export lines
|
|
504
|
+
"""
|
|
505
|
+
api_key = _resolve_api_key(key)
|
|
506
|
+
api_base = DEV_API_BASE if dev else PROD_API_BASE
|
|
507
|
+
|
|
508
|
+
# Validate key & fetch models
|
|
509
|
+
console.print(f"[dim]Validating key against {api_base}...[/dim]")
|
|
510
|
+
models = fetch_models(api_key, api_base)
|
|
511
|
+
model_names = ", ".join(m["id"] for m in models)
|
|
512
|
+
console.print(f"[green]✓[/green] Key valid — models: [bold]{model_names}[/bold]\n")
|
|
513
|
+
|
|
514
|
+
formats = [format] if format else FORMAT_CHOICES
|
|
515
|
+
for fmt in formats:
|
|
516
|
+
if fmt not in FORMAT_CHOICES:
|
|
517
|
+
console.print(f"[red]Unknown format: {fmt}[/red]")
|
|
518
|
+
console.print(f"Choose from: {', '.join(FORMAT_CHOICES)}")
|
|
519
|
+
raise typer.Exit(1)
|
|
520
|
+
|
|
521
|
+
for fmt in formats:
|
|
522
|
+
if fmt == "openclaw":
|
|
523
|
+
snippet = _config_openclaw(api_key, models)
|
|
524
|
+
_show_snippet("OpenClaw", "~/.openclaw/openclaw.json", snippet, apply, OPENCLAW_CONFIG_PATH)
|
|
525
|
+
elif fmt == "opencode":
|
|
526
|
+
snippet = _config_opencode(api_key, models)
|
|
527
|
+
target = Path.cwd() / "opencode.json"
|
|
528
|
+
_show_snippet("OpenCode", "opencode.json", snippet, apply, target)
|
|
529
|
+
elif fmt == "env":
|
|
530
|
+
console.print("[bold]── Shell Environment ──[/bold]")
|
|
531
|
+
console.print(_config_env(api_key, models))
|
|
532
|
+
console.print()
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def _show_snippet(name: str, path_hint: str, data: dict, apply: bool, target_path: Path):
|
|
536
|
+
"""Print a JSON snippet and optionally apply it."""
|
|
537
|
+
console.print(f"[bold]── {name} ({path_hint}) ──[/bold]")
|
|
538
|
+
formatted = json.dumps(data, indent=2)
|
|
539
|
+
console.print(formatted)
|
|
540
|
+
console.print()
|
|
541
|
+
|
|
542
|
+
if apply:
|
|
543
|
+
if target_path.exists():
|
|
544
|
+
with open(target_path) as f:
|
|
545
|
+
existing = json.load(f)
|
|
546
|
+
_deep_merge(existing, data)
|
|
547
|
+
merged = existing
|
|
548
|
+
else:
|
|
549
|
+
merged = data
|
|
550
|
+
|
|
551
|
+
target_path.parent.mkdir(parents=True, exist_ok=True)
|
|
552
|
+
with open(target_path, "w") as f:
|
|
553
|
+
json.dump(merged, f, indent=2)
|
|
554
|
+
f.write("\n")
|
|
555
|
+
console.print(f"[green]✅ Written to {target_path}[/green]\n")
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
def _deep_merge(base: dict, overlay: dict):
|
|
559
|
+
"""Recursively merge overlay into base (mutates base)."""
|
|
560
|
+
for k, v in overlay.items():
|
|
561
|
+
if k in base and isinstance(base[k], dict) and isinstance(v, dict):
|
|
562
|
+
_deep_merge(base[k], v)
|
|
563
|
+
else:
|
|
564
|
+
base[k] = v
|
|
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
|
|
File without changes
|