Files
tai/tai_pkg/clirun.py
T

54 lines
2.5 KiB
Python
Raw Normal View History

"""Shared subprocess runners for CLI backends."""
import re
import subprocess
from tai_pkg.errors import BackendError
from tai_pkg.text import Text
__all__ = ["Cli"]
class Cli:
"""Cli."""
@staticmethod
def _cli_unknown_flag(stderr):
return bool(re.search(r"unknown (option|flag|command)|unrecognised|unrecognized|invalid flag|not found|no such option", stderr or "", re.IGNORECASE))
@staticmethod
def _cli_auth_failure(text):
return bool(re.search(r"not (logged in|authenticated)|auth|api key|unauthorized|401|login required|please (login|log in|authenticate)", text or "", re.IGNORECASE))
@staticmethod
def _cli_run(argv, prompt_input, timeout, label):
try:
done = subprocess.run(argv, input=prompt_input, stdin=subprocess.DEVNULL if prompt_input is None else None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=timeout)
except subprocess.TimeoutExpired:
raise BackendError("%s run timed out after %ds" % (label, timeout))
except OSError as exc:
raise BackendError("%s run failed: %s" % (label, Text.short_error(exc)))
return done
@staticmethod
def _cli_version_detail(done, fallback):
return (done.stdout.strip() or done.stderr.strip()).splitlines()[0][:60] if (done.stdout.strip() or done.stderr.strip()) else fallback
@staticmethod
def _cli_version_only_health(binary, fallback_name):
"""Shared by the CLIs with no cheap, read-only way to check real login
state (muse, grok): `--version` only proves the binary runs, never that
it's actually authenticated, so this deliberately never claims "ok" or
"subscription" -- a claim this check cannot back up (see codex_health/
claude_health for the two CLIs that DO expose a real status command,
used instead of this). Caught a real bug: this used to print "ok,
subscription" unconditionally on a successful --version, which is false
whenever the CLI is installed but never logged in."""
try:
done = subprocess.run([binary, "--version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=15)
except (OSError, subprocess.SubprocessError) as exc:
return "fail: %s" % Text.short_error(exc)[:60]
if done.returncode != 0:
return "fail: exit %d" % done.returncode
return "cli found (%s), login unverified: no status command" % Cli._cli_version_detail(done, fallback_name)