feat: enable remote SDK and resilient device orchestration
This commit is contained in:
1 parent
3cc711df51
commit
ddfa420945
110 files changed
+14450
-12954
No files matched your search
@@ -17,6 +17,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
import time
|
||||
from typing import Annotated
|
||||
import webbrowser
|
||||
|
||||
@@ -25,8 +26,8 @@ from rich.panel import Panel
|
||||
from rich.table import Table
|
||||
import typer
|
||||
|
||||
from artemis.interfaces.cli.commands.ui import ui_command
|
||||
from artemis.runtime.daemon_client import spawn_daemon
|
||||
from artemis.interfaces.cli.commands.ui import ensure_showcase_built, ui_command
|
||||
from artemis.runtime.daemon_client import daemon_log_path, is_daemon_running, spawn_daemon
|
||||
from artemis.runtime.server_lifecycle import (
|
||||
find_server_pids,
|
||||
get_server_status,
|
||||
@@ -55,8 +56,15 @@ def _format_uptime(seconds: float | None) -> str:
|
||||
def restart_command(
|
||||
host: Annotated[
|
||||
str,
|
||||
typer.Option("--host", "-H", help="Bind host address for the UI server."),
|
||||
] = "0.0.0.0",
|
||||
typer.Option(
|
||||
"--host",
|
||||
"-H",
|
||||
help=(
|
||||
"Bind host address for the UI server. Defaults to loopback; for remote "
|
||||
"access prefer a Tailscale/SSH tunnel over a wide bind."
|
||||
),
|
||||
),
|
||||
] = "127.0.0.1",
|
||||
port: Annotated[
|
||||
int,
|
||||
typer.Option("--port", "-p", help="Port to run the unified UI server on."),
|
||||
@@ -86,14 +94,23 @@ def restart_command(
|
||||
daemon: Annotated[
|
||||
bool,
|
||||
typer.Option(
|
||||
"--daemon",
|
||||
"-d",
|
||||
help="Run the new server as a detached background process instead of foreground.",
|
||||
"--daemon/--foreground",
|
||||
"-d/-F",
|
||||
help=(
|
||||
"Run the new server as a detached background daemon (default) or attached "
|
||||
"to the current terminal. The daemon is launched via 'python -m' so the "
|
||||
"console-script executable is never pinned by a long-lived server "
|
||||
"(which would block 'uv sync' reinstalls on Windows)."
|
||||
),
|
||||
),
|
||||
] = False,
|
||||
] = True,
|
||||
) -> None:
|
||||
"""Restart the Artemis Web UI server, terminating any existing instance on the port."""
|
||||
console.print()
|
||||
if reload and daemon:
|
||||
# uvicorn auto-reload requires an attached terminal session.
|
||||
console.print(" [dim]βΉ --reload requested: switching to foreground mode.[/dim]")
|
||||
daemon = False
|
||||
console.print(
|
||||
Panel(
|
||||
f"[bold cyan]π Artemis Server Restart[/bold cyan]\n"
|
||||
@@ -111,7 +128,7 @@ def restart_command(
|
||||
else:
|
||||
console.print(f" [dim]βΉ No active Artemis server found on port {port}.[/dim]")
|
||||
|
||||
success, msg, stopped_pids = stop_server(port=port, force=force, timeout=4.0)
|
||||
success, msg, stopped_pids = stop_server(port=port, force=force, timeout=12.0)
|
||||
if stopped_pids:
|
||||
console.print(f" [green]β {msg}[/green]\n")
|
||||
elif not success:
|
||||
@@ -122,23 +139,54 @@ def restart_command(
|
||||
# 2. Launch fresh server instance
|
||||
local_url = f"http://localhost:{port}"
|
||||
if daemon:
|
||||
console.print(f" [cyan]π Starting Artemis in detached background daemon mode...[/cyan]")
|
||||
ensure_showcase_built(console)
|
||||
console.print(" [cyan]π Starting Artemis in detached background daemon mode...[/cyan]")
|
||||
proc = spawn_daemon(host=host, port=port)
|
||||
if proc:
|
||||
if not proc:
|
||||
console.print(" [red]β Failed to spawn background daemon.[/red]\n")
|
||||
raise typer.Exit(code=1)
|
||||
|
||||
# Wait until the daemon answers HTTP before declaring success (cold
|
||||
# start includes DB/trace initialization and can take tens of seconds).
|
||||
ready = False
|
||||
deadline = time.monotonic() + 60.0
|
||||
while time.monotonic() < deadline:
|
||||
if is_daemon_running(host="127.0.0.1", port=port, timeout=0.5):
|
||||
ready = True
|
||||
break
|
||||
if proc.poll() is not None:
|
||||
# Parent exited: either it crashed, or it handed the socket off
|
||||
# to a child worker. Give the worker a short grace period.
|
||||
grace = time.monotonic() + 5.0
|
||||
while time.monotonic() < grace:
|
||||
if is_daemon_running(host="127.0.0.1", port=port, timeout=0.5):
|
||||
ready = True
|
||||
break
|
||||
time.sleep(0.3)
|
||||
break
|
||||
time.sleep(0.3)
|
||||
|
||||
log_path = daemon_log_path(port)
|
||||
if ready:
|
||||
console.print(
|
||||
f" [bold green]β Artemis server running in background (PID: {proc.pid})[/bold green]\n"
|
||||
f" π [cyan]{local_url}[/cyan]\n"
|
||||
f" π οΈ [cyan]{local_url}/admin[/cyan]\n"
|
||||
f" π [dim]Logs: {log_path}[/dim]\n"
|
||||
f" [dim]π‘ Stop with [bold]artemis stop[/bold]; run in-terminal with [bold]artemis restart --foreground[/bold].[/dim]\n"
|
||||
)
|
||||
if open_browser:
|
||||
webbrowser.open(local_url)
|
||||
else:
|
||||
console.print(" [red]β Failed to spawn background daemon.[/red]\n")
|
||||
console.print(
|
||||
f" [red]β Background daemon did not become ready on port {port}.[/red]\n"
|
||||
f" π [dim]Check logs: {log_path}[/dim]\n"
|
||||
)
|
||||
raise typer.Exit(code=1)
|
||||
return
|
||||
|
||||
# Default foreground mode
|
||||
console.print(f" [cyan]π Launching unified Artemis Showcase UI in current terminal...[/cyan]\n")
|
||||
# Foreground mode (--foreground / --reload)
|
||||
console.print(" [cyan]π Launching unified Artemis Showcase UI in current terminal...[/cyan]\n")
|
||||
ui_command(host=host, port=port, open_browser=open_browser, reload=reload)
|
||||
|
||||
|
||||
@@ -165,7 +213,7 @@ def stop_command(
|
||||
else:
|
||||
console.print(f" [dim]Scanning port {port}...[/dim]")
|
||||
|
||||
success, msg, stopped_pids = stop_server(port=port, force=force, timeout=4.0)
|
||||
success, msg, stopped_pids = stop_server(port=port, force=force, timeout=12.0)
|
||||
if stopped_pids:
|
||||
console.print(
|
||||
Panel(
|
||||
|
||||
Reference in new issue
Block a user