#!/usr/bin/env python3
"""
Nukez CLI — standalone command-line interface for Open Claw skill integration.

Wraps the pynukez SDK directly. No internal nukez_aaap dependencies.
Distributable as part of an Open Claw skill bundle.

Usage:
    python3 nukez_cli.py [--test] [--pretty] <command> [args...]

Commands:
    bootstrap                          Pay, confirm, provision a storage locker
    persist <filename> [options]       Store an artifact with cryptographic receipt
    recall [options]                   Retrieve stored artifacts
    verify [receipt_id]                Verify storage integrity on-chain
    ritual                             Pre-session verification (Principle 1)
    status                             Wallet balance and locker health
    attest [receipt_id]                Anchor merkle root on-chain
    add-operator <pubkey>              Authorize a delegated operator
    remove-operator <pubkey>           Revoke an operator
    list-operators                     List authorized operators

Global Options:
    --test     Use in-memory backend (no network, no wallet)
    --pretty   Human-readable output (default: JSON)

Environment Variables:
    NUKEZ_WALLET_PATH    Path to Solana keypair JSON
    NUKEZ_EVM_KEY        Path to EVM private key JSON
    NUKEZ_EVM_RPC        EVM RPC URL (default: Monad testnet)
    NUKEZ_NETWORK        Network (default: solana-devnet)
    NUKEZ_PROVIDER       Storage provider (default: gcs)
    NUKEZ_GATEWAY_URL    Gateway URL (default: production)
"""
from __future__ import annotations

import argparse
import asyncio
import base64
import hashlib
import json
import os
import sys
import tempfile
import time
import uuid
from pathlib import Path
from typing import Any, Dict, List, Optional

# ---------------------------------------------------------------------------
# pynukez import — try system install, then co-located bundle
# ---------------------------------------------------------------------------
try:
    from pynukez import Nukez
except ImportError:
    _HERE = Path(__file__).resolve().parent
    _BUNDLE = _HERE / "pynukez"
    if not _BUNDLE.exists():
        _BUNDLE = _HERE.parent / "pynukez" / "pynukez"
    if _BUNDLE.exists():
        sys.path.insert(0, str(_BUNDLE.parent))
    try:
        from pynukez import Nukez
    except ImportError:
        Nukez = None  # Will fail gracefully with clear error

# nukez_pay.py — co-located payment helper. pynukez 4.0+ removed
# fund-moving code from the SDK; this helper keeps the bundle self-contained.
try:
    sys.path.insert(0, str(Path(__file__).resolve().parent))
    from nukez_pay import pay_from_request  # type: ignore
except ImportError:
    pay_from_request = None  # type: ignore

# ---------------------------------------------------------------------------
# State persistence — tracks receipt_id/locker_id between invocations
# ---------------------------------------------------------------------------
STATE_DIR = Path.home() / ".nukez"
STATE_FILE = STATE_DIR / "openclaw_state.json"


def _load_state() -> Dict[str, Any]:
    if STATE_FILE.exists():
        try:
            return json.loads(STATE_FILE.read_text())
        except (json.JSONDecodeError, OSError):
            pass
    return {}


def _save_state(state: Dict[str, Any]) -> None:
    STATE_DIR.mkdir(parents=True, exist_ok=True)
    tmp = STATE_FILE.with_suffix(".tmp")
    tmp.write_text(json.dumps(state, indent=2, default=str))
    tmp.rename(STATE_FILE)


# ---------------------------------------------------------------------------
# Embedded FakeBackend for --test mode (no network, no wallet, no imports)
# ---------------------------------------------------------------------------
class _FakeBackend:
    """Minimal in-memory backend for demo/test mode."""

    def __init__(self):
        self._lockers: Dict[str, Dict] = {}
        self._files: Dict[str, Dict[str, bytes]] = {}
        self._receipt_id: Optional[str] = None
        self._locker_id: Optional[str] = None

    def bootstrap(self) -> Dict[str, Any]:
        rid = f"test_{uuid.uuid4().hex[:16]}"
        lid = "locker_" + hashlib.sha256(rid.encode()).hexdigest()[:12]
        self._receipt_id = rid
        self._locker_id = lid
        self._lockers[rid] = {"locker_id": lid, "operator_ids": []}
        self._files[rid] = {}
        return {
            "receipt_id": rid, "locker_id": lid,
            "wallet_pubkey": "TestWallet" + uuid.uuid4().hex[:20],
            "network": "test-local", "provider": "memory",
        }

    def persist(self, receipt_id: str, filename: str, data: bytes,
                tags: Optional[List[str]] = None) -> Dict[str, Any]:
        if receipt_id not in self._files:
            self._files[receipt_id] = {}
        self._files[receipt_id][filename] = data
        content_hash = "sha256:" + hashlib.sha256(data).hexdigest()
        return {
            "receipt_id": receipt_id, "filename": filename,
            "content_hash": content_hash, "size_bytes": len(data),
            "verified": True, "tags": tags or [],
        }

    def recall(self, receipt_id: str, filename: Optional[str] = None,
               tag: Optional[str] = None) -> List[Dict[str, Any]]:
        files = self._files.get(receipt_id, {})
        items = []
        for fn, data in files.items():
            if filename and fn != filename:
                continue
            items.append({
                "filename": fn, "size_bytes": len(data),
                "content_hash": "sha256:" + hashlib.sha256(data).hexdigest(),
                "data_b64": base64.b64encode(data).decode(),
            })
        return items

    def verify(self, receipt_id: str) -> Dict[str, Any]:
        files = self._files.get(receipt_id, {})
        hashes = sorted(
            hashlib.sha256(d).hexdigest() for d in files.values()
        )
        root = hashlib.sha256(
            "|".join(hashes).encode()
        ).hexdigest() if hashes else hashlib.sha256(b"empty").hexdigest()
        return {
            "receipt_id": receipt_id, "valid": True,
            "file_count": len(files),
            "merkle_root": f"sha256:{root}",
            "attestation_tx": f"test_tx_{uuid.uuid4().hex[:8]}",
            "attestation_slot": 999999,
            "verified_at": int(time.time()),
        }

    def status(self, receipt_id: Optional[str] = None) -> Dict[str, Any]:
        file_count = sum(len(f) for f in self._files.values())
        return {
            "wallet_pubkey": "TestWallet",
            "network": "test-local", "provider": "memory",
            "locker_count": len(self._lockers),
            "file_count": file_count,
            "balance": "N/A (test mode)",
        }

    def attest(self, receipt_id: str) -> Dict[str, Any]:
        return {
            "receipt_id": receipt_id,
            "merkle_root": "sha256:" + hashlib.sha256(
                receipt_id.encode()
            ).hexdigest(),
            "tx_signature": f"test_tx_{uuid.uuid4().hex[:12]}",
            "status": "complete",
        }

    def add_operator(self, receipt_id: str, pubkey: str) -> Dict[str, Any]:
        locker = self._lockers.get(receipt_id, {})
        ops = locker.setdefault("operator_ids", [])
        if pubkey not in ops:
            ops.append(pubkey)
        return {"ok": True, "operator_ids": ops}

    def remove_operator(self, receipt_id: str, pubkey: str) -> Dict[str, Any]:
        locker = self._lockers.get(receipt_id, {})
        ops = locker.get("operator_ids", [])
        if pubkey in ops:
            ops.remove(pubkey)
        return {"ok": True, "operator_ids": ops}

    def list_operators(self, receipt_id: str) -> Dict[str, Any]:
        locker = self._lockers.get(receipt_id, {})
        return {"operator_ids": locker.get("operator_ids", [])}


# ---------------------------------------------------------------------------
# Output helpers
# ---------------------------------------------------------------------------
def _json_out(data: dict, pretty: bool = False) -> None:
    if pretty:
        print(json.dumps(data, indent=2, default=str))
    else:
        print(json.dumps(data, default=str))


def _error_out(message: str, code: str = "CLI_ERROR",
               retryable: bool = False) -> None:
    print(json.dumps({
        "ok": False, "error": code,
        "message": message, "retryable": retryable,
    }), file=sys.stderr)
    sys.exit(1)


# ---------------------------------------------------------------------------
# Client factory
# ---------------------------------------------------------------------------
def _make_client() -> Nukez:
    """Create a Nukez client from environment variables."""
    if Nukez is None:
        _error_out(
            "pynukez not installed. Run: pip install pynukez",
            code="MISSING_DEPENDENCY",
        )

    wallet = os.getenv("NUKEZ_WALLET_PATH")
    evm_key = os.getenv("NUKEZ_EVM_KEY")
    evm_rpc = os.getenv("NUKEZ_EVM_RPC")
    gateway = os.getenv("NUKEZ_GATEWAY_URL")

    kwargs: Dict[str, Any] = {}
    if wallet:
        kwargs["keypair_path"] = wallet
    if evm_key:
        kwargs["evm_private_key_path"] = evm_key
    if evm_rpc:
        kwargs["evm_rpc_url"] = evm_rpc
    if gateway:
        kwargs["gateway_url"] = gateway

    if not wallet and not evm_key:
        _error_out(
            "No signing key configured. Set NUKEZ_WALLET_PATH (Ed25519) "
            "or NUKEZ_EVM_KEY (EVM/Monad).",
            code="NO_SIGNING_KEY",
        )

    return Nukez(**kwargs)


def _get_receipt_id(args, state: Dict) -> str:
    """Resolve receipt_id from args or persisted state."""
    rid = getattr(args, "receipt_id", None) or state.get("receipt_id")
    if not rid:
        _error_out(
            "No receipt_id. Run 'bootstrap' first or pass --receipt-id.",
            code="NO_RECEIPT_ID",
        )
    return rid


# ---------------------------------------------------------------------------
# Commands — Test Mode (FakeBackend)
# ---------------------------------------------------------------------------
def _run_test_bootstrap(args):
    fake = _FakeBackend()
    result = fake.bootstrap()
    _save_state({
        "receipt_id": result["receipt_id"],
        "locker_id": result["locker_id"],
        "wallet_pubkey": result["wallet_pubkey"],
        "network": result["network"],
        "provider": result["provider"],
        "test_mode": True,
    })
    # Stash fake for subsequent test commands in same process
    _TEST_BACKENDS[result["receipt_id"]] = fake
    _json_out(result, args.pretty)


_TEST_BACKENDS: Dict[str, _FakeBackend] = {}


def _get_test_backend(receipt_id: str) -> _FakeBackend:
    if receipt_id in _TEST_BACKENDS:
        return _TEST_BACKENDS[receipt_id]
    # Recreate for cross-process invocations
    fake = _FakeBackend()
    fake._receipt_id = receipt_id
    fake._locker_id = "locker_" + hashlib.sha256(
        receipt_id.encode()
    ).hexdigest()[:12]
    fake._lockers[receipt_id] = {
        "locker_id": fake._locker_id, "operator_ids": [],
    }
    fake._files[receipt_id] = {}
    _TEST_BACKENDS[receipt_id] = fake
    return fake


def _run_test_persist(args, state):
    rid = _get_receipt_id(args, state)
    fake = _get_test_backend(rid)
    data = _resolve_data(args)
    tags = args.tags.split(",") if args.tags else None
    result = fake.persist(rid, args.filename, data, tags=tags)
    _json_out(result, args.pretty)


def _run_test_recall(args, state):
    rid = _get_receipt_id(args, state)
    fake = _get_test_backend(rid)
    items = fake.recall(rid, filename=args.filename, tag=args.tag)
    _json_out({"items": items, "count": len(items)}, args.pretty)


def _run_test_verify(args, state):
    rid = getattr(args, "receipt_id", None) or state.get("receipt_id")
    if not rid:
        _error_out("No receipt_id for verify.", code="NO_RECEIPT_ID")
    fake = _get_test_backend(rid)
    result = fake.verify(rid)
    _json_out(result, args.pretty)


def _run_test_ritual(args, state):
    rid = state.get("receipt_id")
    if not rid:
        _json_out({
            "ritual": "SKIP", "reason": "No state file. Run bootstrap first.",
            "principle": "1. Never Trust Yourself Without Proof",
        }, args.pretty)
        return
    fake = _get_test_backend(rid)
    result = fake.verify(rid)
    result["ritual"] = "PASS" if result.get("valid") else "FAIL"
    result["principle"] = "1. Never Trust Yourself Without Proof"
    _json_out(result, args.pretty)


def _run_test_status(args, state):
    rid = state.get("receipt_id")
    fake = _get_test_backend(rid) if rid else _FakeBackend()
    result = fake.status(rid)
    _json_out(result, args.pretty)


def _run_test_attest(args, state):
    rid = _get_receipt_id(args, state)
    fake = _get_test_backend(rid)
    result = fake.attest(rid)
    _json_out(result, args.pretty)


def _run_test_add_operator(args, state):
    rid = _get_receipt_id(args, state)
    fake = _get_test_backend(rid)
    result = fake.add_operator(rid, args.pubkey)
    _json_out(result, args.pretty)


def _run_test_remove_operator(args, state):
    rid = _get_receipt_id(args, state)
    fake = _get_test_backend(rid)
    result = fake.remove_operator(rid, args.pubkey)
    _json_out(result, args.pretty)


def _run_test_list_operators(args, state):
    rid = _get_receipt_id(args, state)
    fake = _get_test_backend(rid)
    result = fake.list_operators(rid)
    _json_out(result, args.pretty)


# ---------------------------------------------------------------------------
# Commands — Live Mode (pynukez SDK)
# ---------------------------------------------------------------------------
def _resolve_data(args) -> bytes:
    """Resolve data from --data string or --file path."""
    if hasattr(args, "data") and args.data:
        return args.data.encode("utf-8")
    if hasattr(args, "file") and args.file:
        p = Path(args.file).expanduser()
        if not p.exists():
            _error_out(f"File not found: {p}", code="FILE_NOT_FOUND")
        return p.read_bytes()
    _error_out("Provide --data or --file for persist.", code="NO_DATA")


def _run_live_bootstrap(args):
    if pay_from_request is None:
        _error_out(
            "nukez_pay.py helper missing. Place it next to nukez_cli.py "
            "or install solana/solders/web3/eth-account/base58 and retry.",
            code="MISSING_PAY_HELPER",
        )

    client = _make_client()
    network = os.getenv("NUKEZ_NETWORK", "solana-mainnet")
    provider = os.getenv("NUKEZ_PROVIDER", "gcs")
    pay_asset_env = os.getenv("NUKEZ_PAY_ASSET")
    pay_network_env = os.getenv("NUKEZ_PAY_NETWORK")
    svm_keypair = os.getenv("NUKEZ_WALLET_PATH")
    evm_keypair = os.getenv("NUKEZ_EVM_KEY")
    svm_rpc = os.getenv("SOLANA_RPC_URL")
    evm_rpc = os.getenv("NUKEZ_EVM_RPC")

    request_kwargs: Dict[str, Any] = {"units": 1, "provider": provider}
    if pay_asset_env:
        request_kwargs["pay_asset"] = pay_asset_env
    if pay_network_env:
        request_kwargs["pay_network"] = pay_network_env

    # 1. Quote
    request = client.request_storage(**request_kwargs)

    # 2. Pay (out-of-band — pynukez 4.0+ does not move funds)
    payment = pay_from_request(
        request,
        svm_keypair=svm_keypair,
        evm_keypair=evm_keypair,
        svm_rpc=svm_rpc,
        evm_rpc=evm_rpc,
        verbose=bool(args.pretty),
    )

    # 3. Confirm
    receipt = client.confirm_storage(
        request.pay_req_id, **payment.confirm_kwargs()
    )

    # 4. Provision locker
    manifest = client.provision_locker(receipt.id)

    # 5. Persist state
    state = {
        "receipt_id": receipt.id,
        "locker_id": manifest.locker_id,
        "wallet_pubkey": receipt.payer_pubkey,
        "network": receipt.network,
        "provider": provider,
        "pay_asset": payment.payment_asset or request.pay_asset,
        "tx_sig": payment.tx_sig,
    }
    _save_state(state)

    _json_out(state, args.pretty)


def _run_live_persist(args, state):
    client = _make_client()
    rid = _get_receipt_id(args, state)
    data = _resolve_data(args)
    tags = args.tags.split(",") if args.tags else []
    content_type = "application/octet-stream"
    if args.filename.endswith(".json"):
        content_type = "application/json"
    elif args.filename.endswith(".md"):
        content_type = "text/markdown"
    elif args.filename.endswith(".txt"):
        content_type = "text/plain"

    # pynukez 4.0+ flow: create_file → upload_bytes → confirm_file
    urls = client.create_file(
        receipt_id=rid,
        filename=args.filename,
        content_type=content_type,
    )
    client.upload_bytes(urls.upload_url, data, content_type=content_type)
    confirm = client.confirm_file(
        receipt_id=rid,
        filename=args.filename,
        confirm_url=urls.confirm_url,
    )

    _json_out({
        "receipt_id": rid,
        "filename": args.filename,
        "content_hash": confirm.content_hash,
        "size_bytes": confirm.size_bytes or len(data),
        "confirmed": confirm.confirmed,
        "tags": tags,
    }, args.pretty)


def _run_live_recall(args, state):
    client = _make_client()
    rid = _get_receipt_id(args, state)
    files = client.list_files(rid)

    items = []
    for f in files:
        fn = f.filename if hasattr(f, "filename") else f.get("filename", "")
        if args.filename and fn != args.filename:
            continue
        items.append({
            "filename": fn,
            "size_bytes": getattr(f, "size_bytes", None) or f.get("size_bytes"),
            "content_hash": getattr(f, "content_hash", None) or f.get("content_hash"),
        })

    _json_out({"items": items, "count": len(items)}, args.pretty)


def _run_live_verify(args, state):
    client = _make_client()
    rid = getattr(args, "receipt_id", None) or state.get("receipt_id")
    if not rid:
        _error_out("No receipt_id for verify.", code="NO_RECEIPT_ID")

    result = client.verify_storage(rid)
    _json_out({
        "receipt_id": rid,
        "valid": getattr(result, "verified", False),
        "merkle_root": getattr(result, "merkle_root", None),
        "manifest_signature": getattr(result, "manifest_signature", None),
        "file_count": getattr(result, "file_count", None),
        "att_code": getattr(result, "att_code", None),
        "verify_url": getattr(result, "verify_url", None),
        "verified_at": int(time.time()),
    }, args.pretty)


def _run_live_ritual(args, state):
    rid = state.get("receipt_id")
    if not rid:
        _json_out({
            "ritual": "SKIP",
            "reason": "No state file. Run bootstrap first.",
            "principle": "1. Never Trust Yourself Without Proof",
        }, args.pretty)
        return

    client = _make_client()
    try:
        result = client.verify_storage(rid)
        valid = getattr(result, "verified", False)
        _json_out({
            "ritual": "PASS" if valid else "FAIL",
            "receipt_id": rid,
            "valid": valid,
            "merkle_root": getattr(result, "merkle_root", None),
            "manifest_signature": getattr(result, "manifest_signature", None),
            "file_count": getattr(result, "file_count", None),
            "verify_url": getattr(result, "verify_url", None),
            "verified_at": int(time.time()),
            "principle": "1. Never Trust Yourself Without Proof",
        }, args.pretty)
    except Exception as e:
        _json_out({
            "ritual": "ERROR",
            "receipt_id": rid,
            "error": str(e),
            "principle": "1. Never Trust Yourself Without Proof",
        }, args.pretty)


def _run_live_status(args, state):
    client = _make_client()
    rid = state.get("receipt_id")
    result = {"network": os.getenv("NUKEZ_NETWORK", "solana-devnet")}

    if rid:
        result["receipt_id"] = rid
        result["locker_id"] = state.get("locker_id")
        try:
            files = client.list_files(rid)
            result["file_count"] = len(files)
        except Exception:
            result["file_count"] = "unknown"

    _json_out(result, args.pretty)


def _run_live_attest(args, state):
    client = _make_client()
    rid = _get_receipt_id(args, state)
    result = client.attest(rid)
    _json_out({
        "receipt_id": rid,
        "merkle_root": getattr(result, "merkle_root", None),
        "file_count": getattr(result, "file_count", None),
        "att_code": getattr(result, "att_code", None),
        "push_ok": getattr(result, "push_ok", None),
        "tx_signature": getattr(result, "tx_signature", None),
        "switchboard_slot": getattr(result, "switchboard_slot", None),
        "status": getattr(result, "status", None),
    }, args.pretty)


def _run_live_add_operator(args, state):
    client = _make_client()
    rid = _get_receipt_id(args, state)
    result = client.add_operator(rid, args.pubkey)
    _json_out({
        "ok": True, "receipt_id": rid,
        "operator_ids": getattr(result, "operator_ids", []),
    }, args.pretty)


def _run_live_remove_operator(args, state):
    client = _make_client()
    rid = _get_receipt_id(args, state)
    result = client.remove_operator(rid, args.pubkey)
    _json_out({
        "ok": True, "receipt_id": rid,
        "operator_ids": getattr(result, "operator_ids", []),
    }, args.pretty)


def _run_live_list_operators(args, state):
    client = _make_client()
    rid = _get_receipt_id(args, state)
    manifest = client.get_manifest(rid)
    ops = manifest.get("operator_ids", []) if isinstance(manifest, dict) else []
    _json_out({"receipt_id": rid, "operator_ids": ops}, args.pretty)


# ---------------------------------------------------------------------------
# Argument parser
# ---------------------------------------------------------------------------
def _build_parser() -> argparse.ArgumentParser:
    p = argparse.ArgumentParser(
        prog="nukez_cli",
        description="Nukez CLI — verifiable cryptographic storage for agents",
    )
    p.add_argument("--test", action="store_true",
                    help="Use in-memory test backend (no network)")
    p.add_argument("--pretty", action="store_true",
                    help="Human-readable output")
    p.add_argument("--receipt-id", default=None,
                    help="Override receipt_id (default: from state file)")

    sub = p.add_subparsers(dest="command", required=True)

    # Add --test, --pretty, --receipt-id to EVERY subparser so they can
    # appear after the subcommand (e.g., "persist x.txt --test")
    def _add_globals(sp):
        sp.add_argument("--test", action="store_true", default=argparse.SUPPRESS)
        sp.add_argument("--pretty", action="store_true", default=argparse.SUPPRESS)
        sp.add_argument("--receipt-id", default=argparse.SUPPRESS)

    # bootstrap
    sp = sub.add_parser("bootstrap", help="Initialize storage locker")
    _add_globals(sp)

    # persist
    sp = sub.add_parser("persist", help="Store an artifact")
    sp.add_argument("filename", help="Filename for the artifact")
    sp.add_argument("--data", help="String data to store")
    sp.add_argument("--file", help="Path to file to store")
    sp.add_argument("--tags", help="Comma-separated tags")
    _add_globals(sp)

    # recall
    sp = sub.add_parser("recall", help="Retrieve stored artifacts")
    sp.add_argument("--filename", help="Filter by filename")
    sp.add_argument("--tag", help="Filter by tag")
    _add_globals(sp)

    # verify
    sp = sub.add_parser("verify", help="Verify storage integrity")
    sp.add_argument("receipt_id", nargs="?", help="Receipt ID (default: from state)")
    _add_globals(sp)

    # ritual
    sp = sub.add_parser("ritual", help="Pre-session verification (Principle 1)")
    _add_globals(sp)

    # status
    sp = sub.add_parser("status", help="System health check")
    _add_globals(sp)

    # attest
    sp = sub.add_parser("attest", help="Anchor merkle root on-chain")
    sp.add_argument("receipt_id", nargs="?", help="Receipt ID")
    _add_globals(sp)

    # add-operator
    sp = sub.add_parser("add-operator", help="Authorize an operator")
    sp.add_argument("pubkey", help="Operator public key (base58 or 0x)")
    _add_globals(sp)

    # remove-operator
    sp = sub.add_parser("remove-operator", help="Revoke an operator")
    sp.add_argument("pubkey", help="Operator public key")
    _add_globals(sp)

    # list-operators
    sp = sub.add_parser("list-operators", help="List authorized operators")
    _add_globals(sp)

    return p


# ---------------------------------------------------------------------------
# Main dispatch
# ---------------------------------------------------------------------------
def main():
    parser = _build_parser()
    args = parser.parse_args()

    # Merge subparser-level flags with top-level (subparser wins)
    args.test = getattr(args, "test", False)
    args.pretty = getattr(args, "pretty", False)
    sub_rid = getattr(args, "receipt_id", None)
    if sub_rid is argparse.SUPPRESS or sub_rid is None:
        pass  # keep top-level
    else:
        args.receipt_id = sub_rid
    if not hasattr(args, "receipt_id"):
        args.receipt_id = None

    state = _load_state()

    # Override receipt_id from CLI flag
    if args.receipt_id:
        state["receipt_id"] = args.receipt_id

    cmd = args.command

    try:
        if args.test:
            # Test mode — embedded FakeBackend
            dispatch_test = {
                "bootstrap": lambda: _run_test_bootstrap(args),
                "persist": lambda: _run_test_persist(args, state),
                "recall": lambda: _run_test_recall(args, state),
                "verify": lambda: _run_test_verify(args, state),
                "ritual": lambda: _run_test_ritual(args, state),
                "status": lambda: _run_test_status(args, state),
                "attest": lambda: _run_test_attest(args, state),
                "add-operator": lambda: _run_test_add_operator(args, state),
                "remove-operator": lambda: _run_test_remove_operator(args, state),
                "list-operators": lambda: _run_test_list_operators(args, state),
            }
            fn = dispatch_test.get(cmd)
            if fn:
                fn()
            else:
                _error_out(f"Unknown command: {cmd}")
        else:
            # Live mode — pynukez SDK
            dispatch_live = {
                "bootstrap": lambda: _run_live_bootstrap(args),
                "persist": lambda: _run_live_persist(args, state),
                "recall": lambda: _run_live_recall(args, state),
                "verify": lambda: _run_live_verify(args, state),
                "ritual": lambda: _run_live_ritual(args, state),
                "status": lambda: _run_live_status(args, state),
                "attest": lambda: _run_live_attest(args, state),
                "add-operator": lambda: _run_live_add_operator(args, state),
                "remove-operator": lambda: _run_live_remove_operator(args, state),
                "list-operators": lambda: _run_live_list_operators(args, state),
            }
            fn = dispatch_live.get(cmd)
            if fn:
                fn()
            else:
                _error_out(f"Unknown command: {cmd}")
    except SystemExit:
        raise
    except Exception as e:
        _error_out(str(e), code=type(e).__name__, retryable=False)


if __name__ == "__main__":
    main()
