feat(cli): expose nanobot process identities

This commit is contained in:
Xubin Ren
2026-08-23 21:13:14 +08:00
parent 9807e9cf37
commit cfc1fae8b5
6 changed files with 137 additions and 2 deletions
+3
View File
@@ -6,6 +6,8 @@ import os
import sys
from contextlib import suppress
from nanobot.cli.process_identity import set_cli_process_identity
def _native_tui_candidate(args: list[str]) -> bool:
"""Return whether ``agent`` can start without the classic agent stack."""
@@ -34,6 +36,7 @@ def _configure_windows_console() -> None:
def main() -> None:
"""Dispatch native TUI startup without importing the complete CLI graph."""
set_cli_process_identity(sys.argv[1:])
_configure_windows_console()
if _native_tui_candidate(sys.argv[1:]):
import typer
+45
View File
@@ -0,0 +1,45 @@
"""Give nanobot processes recognizable operating-system names."""
from __future__ import annotations
import hashlib
import os
from pathlib import Path
from typing import Final
from setproctitle import setproctitle
_ROLES: Final = {"agent", "gateway", "webui"}
def set_cli_process_identity(args: list[str]) -> None:
"""Name this CLI process after the nanobot role it is running."""
if os.name == "nt":
# Windows process managers use the console launcher's executable name,
# which packaging already generates as ``nanobot.exe``.
return
role = args[0] if args and args[0] in _ROLES else None
setproctitle(f"nanobot-{role}" if role else "nanobot")
def named_executable(executable: str, *, name: str, directory: Path) -> str:
"""Return a stable POSIX symlink whose basename identifies a child process."""
if os.name == "nt":
return executable
try:
target = Path(executable).resolve(strict=True)
digest = hashlib.sha256(os.fsencode(target)).hexdigest()[:12]
link_dir = directory / digest
link = link_dir / name
link_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
if link.is_symlink() and link.resolve(strict=False) == target:
return str(link)
if link.exists():
return executable
pending = link.with_name(f".{name}.{os.getpid()}")
pending.unlink(missing_ok=True)
pending.symlink_to(target)
os.replace(pending, link)
except OSError:
return executable
return str(link)
+7 -1
View File
@@ -17,6 +17,7 @@ from pathlib import Path
from typing import TYPE_CHECKING, Any, cast
from nanobot import __version__
from nanobot.cli.process_identity import named_executable
from nanobot.cli.runtime_config import _model_display
from nanobot.cli.webui_support import (
_gateway_health_ready,
@@ -229,7 +230,12 @@ def _resolve_source_tui_command(source_dir: Path, bun: str) -> list[str]:
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")]
executable = named_executable(
bun,
name="nanobot-tui",
directory=get_data_dir() / "run" / "executables",
)
return [executable, str(source_dir / "src" / "index.ts")]
def _download_release_tui(asset: str) -> Path | None: