feat: add portable NexusOS CLI and packaging
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def run_cli(tmp_path: Path, *args: str) -> subprocess.CompletedProcess[str]:
|
||||
env = os.environ.copy()
|
||||
for key in tuple(env):
|
||||
if key.startswith("NEXUS_"):
|
||||
env.pop(key)
|
||||
env["NEXUS_HOME"] = str(tmp_path / "state")
|
||||
env["NEXUS_CONFIG_DIR"] = str(tmp_path / "config")
|
||||
return subprocess.run(
|
||||
[sys.executable, "-m", "management.cli", *args],
|
||||
cwd=ROOT,
|
||||
env=env,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
timeout=30,
|
||||
check=False,
|
||||
)
|
||||
|
||||
|
||||
def test_help_exposes_portable_command_tree(tmp_path):
|
||||
result = run_cli(tmp_path, "--help")
|
||||
assert result.returncode == 0, result.stderr
|
||||
for command in ("init", "config", "provider", "doctor", "serve", "models", "chat"):
|
||||
assert command in result.stdout
|
||||
|
||||
|
||||
def test_legacy_cli_spellings_remain_compatible():
|
||||
from management.cli import _normalize_legacy_argv
|
||||
|
||||
assert _normalize_legacy_argv(["start", "-b"]) == ["start", "backend"]
|
||||
assert _normalize_legacy_argv(["stop", "--ai"]) == ["stop", "ai"]
|
||||
assert _normalize_legacy_argv(["logs", "-m", "--follow"]) == ["logs", "memory", "--follow"]
|
||||
assert _normalize_legacy_argv(["backup", "full"]) == ["backup", "--full"]
|
||||
assert _normalize_legacy_argv(["restore", "-f"]) == ["restore"]
|
||||
assert _normalize_legacy_argv(["help"]) == ["--help"]
|
||||
|
||||
|
||||
def test_init_uses_external_state_and_seeds_playbooks(tmp_path):
|
||||
result = run_cli(tmp_path, "init", "--json")
|
||||
assert result.returncode == 0, result.stderr
|
||||
payload = json.loads(result.stdout)
|
||||
assert Path(payload["state_dir"]) == (tmp_path / "state").resolve()
|
||||
assert payload["seeded_playbooks"] == len(list((ROOT / "data" / "playbooks").glob("*.yaml")))
|
||||
assert len(list((tmp_path / "state" / "data" / "playbooks").glob("*.yaml"))) > 0
|
||||
|
||||
|
||||
def test_config_persists_validated_values(tmp_path):
|
||||
set_result = run_cli(tmp_path, "config", "set", "backend_port", "8123", "--json")
|
||||
assert set_result.returncode == 0, set_result.stderr
|
||||
|
||||
get_result = run_cli(tmp_path, "config", "get", "backend_port", "--json")
|
||||
assert get_result.returncode == 0, get_result.stderr
|
||||
assert json.loads(get_result.stdout)["backend_port"] == 8123
|
||||
|
||||
invalid = run_cli(tmp_path, "config", "set", "backend_port", "70000")
|
||||
assert invalid.returncode == 2
|
||||
assert "between 1 and 65535" in invalid.stderr
|
||||
|
||||
|
||||
def test_remote_provider_configuration_is_explicit(tmp_path):
|
||||
result = run_cli(
|
||||
tmp_path, "provider", "use", "remote", "--url", "http://phone-lan:11434", "--json"
|
||||
)
|
||||
assert result.returncode == 0, result.stderr
|
||||
payload = json.loads(result.stdout)
|
||||
assert payload["provider"] == "ollama-remote"
|
||||
assert payload["url"] == "http://phone-lan:11434"
|
||||
|
||||
values = json.loads((tmp_path / "config" / "config.json").read_text(encoding="utf-8"))
|
||||
assert values["provider"] == "ollama-remote"
|
||||
|
||||
show = run_cli(tmp_path, "provider", "show", "--json")
|
||||
assert show.returncode == 0, show.stderr
|
||||
assert json.loads(show.stdout)["url"] == "http://phone-lan:11434"
|
||||
|
||||
|
||||
def test_serve_rejects_invalid_ports_before_startup(tmp_path):
|
||||
result = run_cli(tmp_path, "serve", "--port", "0")
|
||||
assert result.returncode == 2
|
||||
assert "between 1 and 65535" in result.stderr
|
||||
|
||||
|
||||
def test_remote_provider_is_never_stopped_or_force_killed(monkeypatch):
|
||||
from management import ncp
|
||||
|
||||
killed_ports = []
|
||||
killed_patterns = []
|
||||
monkeypatch.setattr(ncp.settings, "manage_ollama", False)
|
||||
monkeypatch.setattr(ncp.settings, "ollama_host", "http://remote.test:11434")
|
||||
monkeypatch.setattr(ncp, "kill_port", lambda port: killed_ports.append(port) or False)
|
||||
monkeypatch.setattr(
|
||||
ncp, "kill_matching", lambda patterns, force=False: killed_patterns.extend(patterns) or 0
|
||||
)
|
||||
|
||||
ncp.stop_ollama()
|
||||
ncp.cmd_kill()
|
||||
|
||||
assert 11434 not in killed_ports
|
||||
assert "ollama serve" not in killed_patterns
|
||||
Reference in New Issue
Block a user