fix(tui): require the native interactive client
This commit is contained in:
+14
-10
@@ -83,18 +83,21 @@ def agent(
|
||||
theme = theme.strip().lower()
|
||||
if theme not in {"auto", "dark", "light"}:
|
||||
raise typer.BadParameter("must be auto, dark, or light", param_hint="--theme")
|
||||
native_tui = (
|
||||
message is None
|
||||
and not classic
|
||||
and markdown
|
||||
and not logs
|
||||
and sys.stdin.isatty()
|
||||
and sys.stdout.isatty()
|
||||
)
|
||||
native_tui = message is None and not classic
|
||||
if native_tui:
|
||||
from nanobot.cli.tui_launcher import TuiUnavailableError, launch_tui
|
||||
from nanobot.config.loader import get_config_path
|
||||
|
||||
if not sys.stdin.isatty() or not sys.stdout.isatty():
|
||||
raise typer.BadParameter(
|
||||
"the native TUI requires an interactive terminal; use --message for "
|
||||
"one-shot input or --classic for the legacy prompt",
|
||||
param_hint="terminal",
|
||||
)
|
||||
if not markdown:
|
||||
raise typer.BadParameter("--no-markdown requires --classic", param_hint="--no-markdown")
|
||||
if logs:
|
||||
raise typer.BadParameter("--logs requires --classic", param_hint="--logs")
|
||||
try:
|
||||
exit_code = launch_tui(
|
||||
runtime_config,
|
||||
@@ -104,8 +107,9 @@ def agent(
|
||||
theme=theme,
|
||||
)
|
||||
except TuiUnavailableError as exc:
|
||||
console.print(f"[yellow]Native TUI unavailable: {exc}[/yellow]")
|
||||
console.print("[dim]Falling back to the classic prompt.[/dim]")
|
||||
console.print(f"[red]Native TUI unavailable: {exc}[/red]")
|
||||
console.print("[dim]Use `nanobot agent --classic` only if you want the old prompt.[/dim]")
|
||||
raise typer.Exit(1) from exc
|
||||
else:
|
||||
if exit_code:
|
||||
raise typer.Exit(exit_code)
|
||||
|
||||
@@ -123,11 +123,7 @@ def _resolve_tui_command() -> list[str]:
|
||||
source_dir = Path(__file__).resolve().parents[2] / "tui"
|
||||
bun = shutil.which("bun")
|
||||
if bun and (source_dir / "package.json").is_file():
|
||||
if not (source_dir / "node_modules" / "@opentui" / "core").is_dir():
|
||||
raise TuiUnavailableError(
|
||||
f"TUI dependencies are missing; run `bun install --cwd {source_dir}`"
|
||||
)
|
||||
return [bun, str(source_dir / "src" / "index.ts")]
|
||||
return _resolve_source_tui_command(source_dir, bun)
|
||||
|
||||
downloaded = _download_release_tui(asset)
|
||||
if downloaded is not None:
|
||||
@@ -139,6 +135,25 @@ def _resolve_tui_command() -> list[str]:
|
||||
)
|
||||
|
||||
|
||||
def _resolve_source_tui_command(source_dir: Path, bun: str) -> list[str]:
|
||||
dependency = source_dir / "node_modules" / "@opentui" / "core"
|
||||
try:
|
||||
install = subprocess.run(
|
||||
[bun, "install", "--frozen-lockfile"],
|
||||
cwd=source_dir,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
except OSError as exc:
|
||||
raise TuiUnavailableError(f"could not install TUI dependencies: {exc}") from exc
|
||||
if install.returncode != 0 or not dependency.is_dir():
|
||||
detail = (install.stderr or install.stdout).strip().splitlines()
|
||||
suffix = f": {detail[-1]}" if detail else ""
|
||||
raise TuiUnavailableError(f"could not install TUI dependencies{suffix}")
|
||||
return [bun, str(source_dir / "src" / "index.ts")]
|
||||
|
||||
|
||||
def _download_release_tui(asset: str) -> Path | None:
|
||||
"""Install the version-matched release sidecar into nanobot's data directory."""
|
||||
if os.environ.get("NANOBOT_TUI_NO_DOWNLOAD") == "1":
|
||||
|
||||
Reference in New Issue
Block a user