feat: add self-update command and bump to 2.0.1

- Add `coinhunter update` CLI command for pipx/pip upgrade
- README: document update behavior and recommend pipx install
- Dynamic version badge with cacheSeconds=60
- Version bump: 2.0.0 → 2.0.1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-16 18:00:43 +08:00
parent 52cd76a750
commit b78845eb43
6 changed files with 71 additions and 5 deletions

View File

@@ -1,3 +1,8 @@
"""CoinHunter V2."""
__version__ = "2.0.0"
try:
from importlib.metadata import version
__version__ = version("coinhunter")
except Exception: # pragma: no cover
__version__ = "unknown"

View File

@@ -10,7 +10,7 @@ from . import __version__
from .binance.spot_client import SpotBinanceClient
from .binance.um_futures_client import UMFuturesClient
from .config import ensure_init_files, get_binance_credentials, load_config
from .runtime import get_runtime_paths, print_json
from .runtime import get_runtime_paths, print_json, self_update
from .services import account_service, market_service, opportunity_service, trade_service
@@ -102,6 +102,8 @@ def build_parser() -> argparse.ArgumentParser:
scan_parser = opportunity_subparsers.add_parser("scan")
scan_parser.add_argument("--symbols", nargs="*")
subparsers.add_parser("update", help="Upgrade coinhunter to the latest version")
return parser
@@ -231,6 +233,10 @@ def main(argv: list[str] | None = None) -> int:
return 0
parser.error("opportunity requires `portfolio` or `scan`")
if args.command == "update":
print_json(self_update())
return 0
parser.error(f"Unsupported command {args.command}")
return 2
except Exception as exc:

View File

@@ -4,6 +4,9 @@ from __future__ import annotations
import json
import os
import shutil
import subprocess
import sys
from dataclasses import asdict, dataclass, is_dataclass
from datetime import date, datetime
from pathlib import Path
@@ -50,3 +53,17 @@ def json_default(value: Any) -> Any:
def print_json(payload: Any) -> None:
print(json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True, default=json_default))
def self_update() -> dict[str, Any]:
if shutil.which("pipx"):
cmd = ["pipx", "upgrade", "coinhunter"]
else:
cmd = [sys.executable, "-m", "pip", "install", "--upgrade", "coinhunter"]
result = subprocess.run(cmd, capture_output=True, text=True)
return {
"command": " ".join(cmd),
"returncode": result.returncode,
"stdout": result.stdout.strip(),
"stderr": result.stderr.strip(),
}