chore: initialize K1 connector pre-production scaffold
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
"""NDC XGRIDS K1 connector research tooling."""
|
||||
|
||||
__version__ = "0.1.0"
|
||||
@@ -0,0 +1,172 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import TypedDict
|
||||
|
||||
import typer
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
from k1link import __version__
|
||||
|
||||
app = typer.Typer(
|
||||
name="k1link",
|
||||
help="Safe, evidence-led research tooling for an owner-controlled XGRIDS K1.",
|
||||
no_args_is_help=True,
|
||||
)
|
||||
console = Console()
|
||||
|
||||
|
||||
class ToolStatus(TypedDict):
|
||||
name: str
|
||||
available: bool
|
||||
path: str | None
|
||||
|
||||
|
||||
class NetworkStatus(TypedDict):
|
||||
wifi_interface: str | None
|
||||
default_route_interface: str | None
|
||||
vpn_default_route: bool
|
||||
|
||||
|
||||
class DoctorPayload(TypedDict):
|
||||
k1link_version: str
|
||||
python_version: str
|
||||
python_executable: str
|
||||
python_is_3_12: bool
|
||||
local_venv: bool
|
||||
platform: str
|
||||
machine: str
|
||||
network: NetworkStatus
|
||||
tools: list[ToolStatus]
|
||||
notes: list[str]
|
||||
|
||||
|
||||
def _tool_status(name: str) -> ToolStatus:
|
||||
path = shutil.which(name)
|
||||
return {"name": name, "available": path is not None, "path": path}
|
||||
|
||||
|
||||
def _command_output(args: list[str]) -> str | None:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
args,
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5,
|
||||
)
|
||||
except (OSError, subprocess.SubprocessError):
|
||||
return None
|
||||
if result.returncode != 0:
|
||||
return None
|
||||
return result.stdout.strip()
|
||||
|
||||
|
||||
def _default_route_interface() -> str | None:
|
||||
output = _command_output(["route", "-n", "get", "default"])
|
||||
if output is None:
|
||||
return None
|
||||
for line in output.splitlines():
|
||||
key, separator, value = line.strip().partition(":")
|
||||
if separator and key == "interface":
|
||||
return value.strip()
|
||||
return None
|
||||
|
||||
|
||||
def _wifi_interface() -> str | None:
|
||||
output = _command_output(["networksetup", "-listallhardwareports"])
|
||||
if output is None:
|
||||
return None
|
||||
blocks = output.split("\n\n")
|
||||
for block in blocks:
|
||||
if "Hardware Port: Wi-Fi" not in block:
|
||||
continue
|
||||
for line in block.splitlines():
|
||||
key, separator, value = line.partition(":")
|
||||
if separator and key.strip() == "Device":
|
||||
return value.strip()
|
||||
return None
|
||||
|
||||
|
||||
def _doctor_payload() -> DoctorPayload:
|
||||
executable = Path(sys.executable)
|
||||
default_route = _default_route_interface()
|
||||
wifi_interface = _wifi_interface()
|
||||
notes = [
|
||||
"Bluetooth permission is intentionally not requested by doctor.",
|
||||
"Missing tshark/nmap is acceptable before the network-analysis gate.",
|
||||
"No Homebrew or system changes are performed by this command.",
|
||||
]
|
||||
if default_route is not None and default_route.startswith("utun"):
|
||||
notes.append(
|
||||
"Default route uses a VPN/tunnel interface; future K1 commands must resolve "
|
||||
"the route for the confirmed K1 IP instead of assuming the default route."
|
||||
)
|
||||
return {
|
||||
"k1link_version": __version__,
|
||||
"python_version": platform.python_version(),
|
||||
"python_executable": str(executable),
|
||||
"python_is_3_12": sys.version_info[:2] == (3, 12),
|
||||
"local_venv": Path(sys.prefix).name == ".venv",
|
||||
"platform": platform.platform(),
|
||||
"machine": platform.machine(),
|
||||
"network": {
|
||||
"wifi_interface": wifi_interface,
|
||||
"default_route_interface": default_route,
|
||||
"vpn_default_route": bool(default_route and default_route.startswith("utun")),
|
||||
},
|
||||
"tools": [_tool_status(name) for name in ("uv", "tcpdump", "tshark", "nmap", "ffmpeg")],
|
||||
"notes": notes,
|
||||
}
|
||||
|
||||
|
||||
@app.callback()
|
||||
def main() -> None:
|
||||
"""Run safe research commands for an owner-controlled XGRIDS K1."""
|
||||
|
||||
|
||||
@app.command()
|
||||
def doctor(
|
||||
json_output: bool = typer.Option(False, "--json", help="Emit machine-readable JSON."),
|
||||
) -> None:
|
||||
"""Inspect the local toolchain without touching the K1 or system configuration."""
|
||||
payload = _doctor_payload()
|
||||
if json_output:
|
||||
typer.echo(json.dumps(payload, ensure_ascii=False, indent=2))
|
||||
return
|
||||
|
||||
console.print(f"k1link {payload['k1link_version']}")
|
||||
console.print(f"Python {payload['python_version']} ({payload['python_executable']})")
|
||||
console.print(
|
||||
"Local .venv: " + ("[green]yes[/green]" if payload["local_venv"] else "[red]no[/red]")
|
||||
)
|
||||
network = payload["network"]
|
||||
console.print(
|
||||
"Wi-Fi interface: "
|
||||
f"{network['wifi_interface'] or '-'}; default route: "
|
||||
f"{network['default_route_interface'] or '-'}"
|
||||
)
|
||||
|
||||
table = Table(title="External tools")
|
||||
table.add_column("Tool")
|
||||
table.add_column("Available")
|
||||
table.add_column("Path")
|
||||
for item in payload["tools"]:
|
||||
table.add_row(
|
||||
str(item["name"]),
|
||||
"yes" if item["available"] else "no",
|
||||
str(item["path"] or "-"),
|
||||
)
|
||||
console.print(table)
|
||||
for note in payload["notes"]:
|
||||
console.print(f"- {note}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
Reference in New Issue
Block a user