Add optional Nanobot plugin controls (#4396)
* feat: add optional nanobot features * test: update azure install hint expectation * fix: validate optional feature extras maintainer edit: verify requested dependency extras before treating optional features as installed, propagate restart state from feature enablement, and align docs with the new plugins enable command. * fix: bound optional feature installs maintainer edit: make optional feature installs time out as a normal install failure instead of leaving the WebUI or CLI action waiting indefinitely. * feat: slim optional channel dependencies * fix: log optional install commands * fix(webui): gate remote feature installs * docs: clarify webhook plugin example * fix(webui): harden optional feature installs * fix: install optional deps without package fallback * fix(cli): refine plugin feature controls * fix(webui): count enabled nanobot features * fix(webui): allow slow feature install routes * fix(webui): allow disabling websocket channel * fix(plugins): simplify optional feature controls * fix(webui): polish apps catalog states * fix(webui): confirm nanobot support installs * fix(webui): polish nanobot install dialog * fix(webui): suppress empty websocket handshakes * fix(webui): clarify apps plugin summary * fix(webui): localize workspace access copy * fix(plugins): polish optional feature controls (#4691) --------- Co-authored-by: Xubin Ren <52506698+Re-bin@users.noreply.github.com>
This commit is contained in:
@@ -348,6 +348,42 @@ def test_install_dispatches_safe_pip_and_installs_skill(
|
||||
assert 'run_cli_app` tool with `name="gimp"' in skill.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_run_argv_logs_command_exit_and_output(
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
from nanobot.apps.cli import service as cli_service
|
||||
|
||||
manager = _manager(tmp_path)
|
||||
records: list[str] = []
|
||||
|
||||
class _Logger:
|
||||
def info(self, message: str, *args: object) -> None:
|
||||
records.append(message.format(*args))
|
||||
|
||||
def fake_run(
|
||||
argv: list[str],
|
||||
*,
|
||||
capture_output: bool,
|
||||
text: bool,
|
||||
timeout: int,
|
||||
) -> subprocess.CompletedProcess[str]:
|
||||
assert capture_output is True
|
||||
assert text is True
|
||||
assert timeout == 5
|
||||
return subprocess.CompletedProcess(argv, 0, stdout="installed ok", stderr="")
|
||||
|
||||
monkeypatch.setattr(cli_service, "logger", _Logger())
|
||||
monkeypatch.setattr(cli_service.subprocess, "run", fake_run)
|
||||
|
||||
result = manager._run_argv(["python", "-m", "pip", "install", "sample"], timeout=5)
|
||||
|
||||
assert result.returncode == 0
|
||||
assert any(record.startswith("CLI Apps: running ") for record in records)
|
||||
assert any("command exited with code 0" in record for record in records)
|
||||
assert any("installed ok" in record for record in records)
|
||||
|
||||
|
||||
def test_install_records_available_cli_without_reinstalling(
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
|
||||
Reference in New Issue
Block a user