[teamai] Push 87 resource(s) from XingfenD
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
"""State management for model-support-checker.
|
||||
|
||||
State lives in <skill root>/.state/ (gitignored via .gitignore) so the
|
||||
first-run choice (GitHub PAT vs local clone) survives across runs without
|
||||
being tracked by git. The GitHub token itself is NEVER stored here.
|
||||
"""
|
||||
|
||||
from .doctor import doctor, print_report
|
||||
from .persistence import load, save, reset
|
||||
from .setup import first_run_menu, ensure_setup
|
||||
from .refresh import start_refresh
|
||||
|
||||
__all__ = [
|
||||
"load",
|
||||
"save",
|
||||
"reset",
|
||||
"first_run_menu",
|
||||
"ensure_setup",
|
||||
"start_refresh",
|
||||
"doctor",
|
||||
"print_report",
|
||||
]
|
||||
@@ -0,0 +1,40 @@
|
||||
"""Repository cloning and validation."""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from ..framework_strategies import STRATEGIES
|
||||
from .constants import REPOS_DIR
|
||||
|
||||
|
||||
def clone(url, target):
|
||||
"""Clone url into target (full history -- shallow clones break step 4)."""
|
||||
if os.path.isdir(os.path.join(target, ".git")):
|
||||
print(f" reusing existing clone: {target}")
|
||||
return target
|
||||
os.makedirs(os.path.dirname(target), exist_ok=True)
|
||||
print(f" cloning {url} -> {target} (full history, may take a while)...")
|
||||
r = subprocess.run(["git", "clone", url, target])
|
||||
if r.returncode != 0:
|
||||
raise RuntimeError(f"git clone failed for {url}")
|
||||
return target
|
||||
|
||||
|
||||
def validate_checkout(path, fw_name):
|
||||
"""Validate that a path looks like a valid framework checkout."""
|
||||
strategy = STRATEGIES[fw_name]
|
||||
if not os.path.isfile(os.path.join(path, strategy.models_dir, "__init__.py")):
|
||||
print(
|
||||
f" WARNING: {strategy.models_dir} not found under {path}; "
|
||||
f"is this really a {strategy.label} checkout?"
|
||||
)
|
||||
|
||||
|
||||
def get_clone_url(fw_name):
|
||||
"""Get the clone URL for a framework."""
|
||||
return f"https://github.com/{STRATEGIES[fw_name].repo}"
|
||||
|
||||
|
||||
def get_default_clone_path(fw_name):
|
||||
"""Get the default clone path for a framework."""
|
||||
return os.path.join(REPOS_DIR, fw_name)
|
||||
@@ -0,0 +1,8 @@
|
||||
"""State constants."""
|
||||
|
||||
import os
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
STATE_DIR = os.path.join(ROOT, ".state")
|
||||
REPOS_DIR = os.path.join(STATE_DIR, "repos")
|
||||
STATE_FILE = os.path.join(STATE_DIR, "state.json")
|
||||
@@ -0,0 +1,169 @@
|
||||
"""Health checks for persisted setup state.
|
||||
|
||||
The `doctor()` function inspects `.state/state.json` and the configured
|
||||
framework checkouts, returning a list of actionable issues. It is run
|
||||
automatically on every invocation so callers (human or agent) do not need
|
||||
to manually inspect `.state/` with `ls` or `cat`.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from ..framework_strategies import STRATEGIES
|
||||
from .constants import STATE_FILE
|
||||
|
||||
|
||||
class Issue:
|
||||
"""A single doctor issue with severity and an actionable message."""
|
||||
|
||||
def __init__(self, severity, message, framework=None):
|
||||
self.severity = severity # "error" | "warning"
|
||||
self.message = message
|
||||
self.framework = framework
|
||||
|
||||
def __str__(self):
|
||||
prefix = "ERROR" if self.severity == "error" else "WARN"
|
||||
if self.framework:
|
||||
return f"[{prefix} {self.framework}] {self.message}"
|
||||
return f"[{prefix}] {self.message}"
|
||||
|
||||
|
||||
def doctor(st, args=None, framework=None):
|
||||
"""Check setup state and local checkouts.
|
||||
|
||||
Args:
|
||||
st: The loaded state dict, or None if no state file exists.
|
||||
args: Optional argparse namespace with path overrides.
|
||||
framework: Framework name to limit the check to, or None/'all' to check
|
||||
every configured framework.
|
||||
|
||||
Returns:
|
||||
A list of Issue objects. An empty list means the configuration looks
|
||||
healthy enough to proceed.
|
||||
"""
|
||||
issues = []
|
||||
|
||||
if st is None:
|
||||
issues.append(
|
||||
Issue(
|
||||
"error",
|
||||
f"No setup state found ({STATE_FILE} missing). "
|
||||
"Run: python3 main.py --setup local",
|
||||
)
|
||||
)
|
||||
return issues
|
||||
|
||||
mode = st.get("mode")
|
||||
if mode not in ("local", "token"):
|
||||
issues.append(
|
||||
Issue(
|
||||
"error",
|
||||
f"Invalid mode '{mode}' in state. Run: python3 main.py --setup local",
|
||||
)
|
||||
)
|
||||
return issues
|
||||
|
||||
if mode == "token":
|
||||
token = _get_token(args)
|
||||
if not token:
|
||||
issues.append(
|
||||
Issue(
|
||||
"warning",
|
||||
"GitHub token mode but no GITHUB_TOKEN set. "
|
||||
"Code search results will be best-effort only.",
|
||||
)
|
||||
)
|
||||
return issues
|
||||
|
||||
# Local mode: validate the requested framework path(s).
|
||||
frameworks = list(STRATEGIES) if framework in (None, "all") else [framework]
|
||||
for fw_name in frameworks:
|
||||
if fw_name not in STRATEGIES:
|
||||
issues.append(Issue("error", f"Unknown framework: {fw_name}"))
|
||||
continue
|
||||
strategy = STRATEGIES[fw_name]
|
||||
path_key = f"{fw_name.replace('-', '_')}_path"
|
||||
configured_path = st.get(path_key)
|
||||
override_path = _get_override_path(args, fw_name)
|
||||
path = override_path or configured_path
|
||||
|
||||
if not configured_path and not override_path:
|
||||
issues.append(
|
||||
Issue(
|
||||
"error",
|
||||
f"No local checkout configured. Run: python3 main.py --setup local --{fw_name}-path /path/to/{fw_name}",
|
||||
framework=strategy.label,
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
if override_path and not configured_path:
|
||||
issues.append(
|
||||
Issue(
|
||||
"warning",
|
||||
f"Using one-time override {override_path}; state is missing a saved path.",
|
||||
framework=strategy.label,
|
||||
)
|
||||
)
|
||||
|
||||
if not os.path.isdir(path):
|
||||
issues.append(
|
||||
Issue(
|
||||
"error",
|
||||
f"Configured path does not exist: {path}",
|
||||
framework=strategy.label,
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
if not os.path.isdir(os.path.join(path, ".git")):
|
||||
issues.append(
|
||||
Issue(
|
||||
"error",
|
||||
f"Path is not a git repository: {path}",
|
||||
framework=strategy.label,
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
init_file = os.path.join(path, strategy.models_dir, "__init__.py")
|
||||
if not os.path.isfile(init_file):
|
||||
issues.append(
|
||||
Issue(
|
||||
"warning",
|
||||
f"{strategy.models_dir}/__init__.py not found under {path}; "
|
||||
"is this really a checkout?",
|
||||
framework=strategy.label,
|
||||
)
|
||||
)
|
||||
|
||||
return issues
|
||||
|
||||
|
||||
def _get_token(args):
|
||||
if args and getattr(args, "token", None):
|
||||
return args.token
|
||||
return os.environ.get("GITHUB_TOKEN")
|
||||
|
||||
|
||||
def _get_override_path(args, fw_name):
|
||||
if args is None:
|
||||
return None
|
||||
attr = f"{fw_name.replace('-', '_')}_path"
|
||||
return getattr(args, attr, None)
|
||||
|
||||
|
||||
def print_report(issues):
|
||||
"""Print doctor issues in a consistent format.
|
||||
|
||||
Returns True if any errors were reported.
|
||||
"""
|
||||
has_errors = any(i.severity == "error" for i in issues)
|
||||
if not issues:
|
||||
print("doctor: setup state looks healthy.")
|
||||
return False
|
||||
|
||||
print("=== doctor ===")
|
||||
for issue in issues:
|
||||
print(f" {issue}")
|
||||
print()
|
||||
return has_errors
|
||||
@@ -0,0 +1,33 @@
|
||||
"""State persistence: load, save, reset."""
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
from .constants import STATE_DIR, STATE_FILE, REPOS_DIR
|
||||
|
||||
|
||||
def load():
|
||||
"""Return the saved state dict, or None if not set up yet."""
|
||||
try:
|
||||
with open(STATE_FILE, encoding="utf-8") as f:
|
||||
st = json.load(f)
|
||||
return st if isinstance(st, dict) and st.get("mode") else None
|
||||
except (OSError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def save(st):
|
||||
os.makedirs(STATE_DIR, exist_ok=True)
|
||||
with open(STATE_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(st, f, indent=2)
|
||||
return st
|
||||
|
||||
|
||||
def reset():
|
||||
"""Forget setup state. Cloned repos under .state/repos/ are kept and will
|
||||
be reused automatically by a later `--setup local`."""
|
||||
try:
|
||||
os.remove(STATE_FILE)
|
||||
print(f"Removed {STATE_FILE} (cloned repos kept at {REPOS_DIR}).")
|
||||
except FileNotFoundError:
|
||||
print("No saved state found.")
|
||||
@@ -0,0 +1,68 @@
|
||||
"""Background checkout refresh."""
|
||||
|
||||
import subprocess
|
||||
import threading
|
||||
|
||||
|
||||
def fetch_status(path, result, key):
|
||||
"""Background worker: `git fetch` a local checkout and count how far
|
||||
behind its upstream it is. Writes into result[key]; NEVER raises — any
|
||||
failure is recorded as {"error": ...} so the main flow is never blocked."""
|
||||
info = {"path": path}
|
||||
try:
|
||||
remotes = subprocess.run(
|
||||
["git", "-C", path, "remote"],
|
||||
capture_output=True, text=True,
|
||||
).stdout.strip()
|
||||
if not remotes:
|
||||
info["no_upstream"] = True
|
||||
result[key] = info
|
||||
return
|
||||
f = subprocess.run(
|
||||
["git", "-C", path, "fetch", "--quiet", "origin"],
|
||||
capture_output=True, text=True, timeout=300,
|
||||
)
|
||||
if f.returncode != 0:
|
||||
lines = [ln for ln in f.stderr.strip().splitlines() if ln.strip()]
|
||||
info["error"] = lines[-1] if lines else "git fetch failed"
|
||||
else:
|
||||
up = subprocess.run(
|
||||
["git", "-C", path, "rev-parse", "--abbrev-ref",
|
||||
"--symbolic-full-name", "@{upstream}"],
|
||||
capture_output=True, text=True,
|
||||
)
|
||||
head = subprocess.run(
|
||||
["git", "-C", path, "rev-parse", "--abbrev-ref", "HEAD"],
|
||||
capture_output=True, text=True,
|
||||
).stdout.strip()
|
||||
if up.returncode != 0 or head in ("", "HEAD"):
|
||||
info["no_upstream"] = True
|
||||
else:
|
||||
cnt = subprocess.run(
|
||||
["git", "-C", path, "rev-list", "--count",
|
||||
f"HEAD..{up.stdout.strip()}"],
|
||||
capture_output=True, text=True,
|
||||
)
|
||||
if cnt.returncode == 0 and cnt.stdout.strip().isdigit():
|
||||
info["behind"] = int(cnt.stdout.strip())
|
||||
else:
|
||||
info["no_upstream"] = True
|
||||
except (subprocess.SubprocessError, OSError, ValueError) as e:
|
||||
# ponytail: broad catch is the point — refresh must never be fatal
|
||||
info["error"] = str(e)
|
||||
result[key] = info
|
||||
|
||||
|
||||
def start_refresh(framework_paths):
|
||||
"""Spawn daemon threads to refresh local checkouts concurrently.
|
||||
|
||||
Returns (results_dict, threads); results are filled in as workers finish.
|
||||
"""
|
||||
results = {}
|
||||
threads = []
|
||||
for key, path in framework_paths.items():
|
||||
t = threading.Thread(target=fetch_status, args=(path, results, key),
|
||||
daemon=True)
|
||||
t.start()
|
||||
threads.append(t)
|
||||
return results, threads
|
||||
@@ -0,0 +1,95 @@
|
||||
"""Interactive setup and first-run menu."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from ..framework_strategies import STRATEGIES
|
||||
from .clone import clone, validate_checkout, get_clone_url, get_default_clone_path
|
||||
from .constants import REPOS_DIR, STATE_FILE
|
||||
from .persistence import save
|
||||
|
||||
|
||||
def print_tradeoffs():
|
||||
"""Print the tradeoffs between local clone and GitHub PAT modes."""
|
||||
print(
|
||||
"First-run setup: choose how to access vLLM/SGLang sources.\n"
|
||||
"\n"
|
||||
" 1) Local clone (recommended)\n"
|
||||
" + definitive results: files grepped on disk, no rate limits\n"
|
||||
" + fast repeat checks; version detection from full git history\n"
|
||||
" + works offline after the initial clone\n"
|
||||
" - one-time download (vLLM full history ~1 GB+, SGLang smaller)\n"
|
||||
" - needs occasional 'git pull' or answers go stale\n"
|
||||
"\n"
|
||||
" 2) GitHub PAT\n"
|
||||
" + no disk usage; always reflects remote main\n"
|
||||
" - code search 403s without a token; anonymous results are\n"
|
||||
" best-effort only\n"
|
||||
" - API rate limits can break batch/version checks\n"
|
||||
" - GITHUB_TOKEN must be provided every run (never stored here)"
|
||||
)
|
||||
|
||||
|
||||
def first_run_menu():
|
||||
"""Interactive TTY menu. Returns the chosen mode ('local' | 'token')."""
|
||||
print_tradeoffs()
|
||||
while True:
|
||||
choice = input("Choose [1/2] (default 1): ").strip()
|
||||
if choice in ("", "1"):
|
||||
return "local"
|
||||
if choice == "2":
|
||||
return "token"
|
||||
print("Please enter 1 or 2.")
|
||||
|
||||
|
||||
def ensure_setup(mode, args):
|
||||
"""Create and persist setup state. Returns the new state dict."""
|
||||
st = {"mode": mode}
|
||||
if mode == "local":
|
||||
vllm_path = args.vllm_path
|
||||
sglang_path = args.sglang_path
|
||||
vllm_ascend_path = getattr(args, "vllm_ascend_path", None)
|
||||
|
||||
if sys.stdin.isatty():
|
||||
if not vllm_path:
|
||||
raw = input(
|
||||
f"vLLM checkout path [Enter = clone into {REPOS_DIR}/vllm]: "
|
||||
).strip()
|
||||
vllm_path = raw or None
|
||||
if not sglang_path:
|
||||
raw = input(
|
||||
f"SGLang checkout path [Enter = clone into {REPOS_DIR}/sglang]: "
|
||||
).strip()
|
||||
sglang_path = raw or None
|
||||
if not vllm_ascend_path:
|
||||
raw = input(
|
||||
f"vLLM-Ascend checkout path [Enter = clone into {REPOS_DIR}/vllm-ascend]: "
|
||||
).strip()
|
||||
vllm_ascend_path = raw or None
|
||||
|
||||
if not vllm_path:
|
||||
vllm_path = clone(get_clone_url("vllm"), get_default_clone_path("vllm"))
|
||||
if not sglang_path:
|
||||
sglang_path = clone(get_clone_url("sglang"), get_default_clone_path("sglang"))
|
||||
if not vllm_ascend_path:
|
||||
vllm_ascend_path = clone(get_clone_url("vllm-ascend"), get_default_clone_path("vllm-ascend"))
|
||||
|
||||
st["vllm_path"] = os.path.abspath(os.path.expanduser(vllm_path))
|
||||
st["sglang_path"] = os.path.abspath(os.path.expanduser(sglang_path))
|
||||
st["vllm_ascend_path"] = os.path.abspath(os.path.expanduser(vllm_ascend_path))
|
||||
|
||||
validate_checkout(st["vllm_path"], "vllm")
|
||||
validate_checkout(st["sglang_path"], "sglang")
|
||||
validate_checkout(st["vllm_ascend_path"], "vllm-ascend")
|
||||
elif mode == "token":
|
||||
if not args.token and not os.environ.get("GITHUB_TOKEN"):
|
||||
print(
|
||||
"NOTE: no GITHUB_TOKEN set. Code search needs it; export "
|
||||
"GITHUB_TOKEN per run (it is never stored in .state/)."
|
||||
)
|
||||
else:
|
||||
raise RuntimeError(f"Unknown setup mode: {mode}")
|
||||
|
||||
save(st)
|
||||
print(f"Setup saved ({mode}) -> {STATE_FILE}")
|
||||
return st
|
||||
Reference in New Issue
Block a user