@daemon.command()
@click.option("--host", default=None, help="Bind address.")
@click.option("--port", default=None, type=int, help="Port number.")
@click.option("-e", "--engine", "engine_key", default=None, help="Engine backend.")
@click.option("-m", "--model", "model_name", default=None, help="Default model.")
@click.option("-a", "--agent", "agent_name", default=None, help="Agent type.")
def start(
host: str | None,
port: int | None,
engine_key: str | None,
model_name: str | None,
agent_name: str | None,
) -> None:
"""Start the OpenJarvis server as a background daemon."""
console = Console(stderr=True)
existing = _read_pid()
if existing is not None:
console.print(f"[yellow]Server already running (PID {existing}).[/yellow]")
console.print("Use 'jarvis stop' to stop it first, or 'jarvis restart'.")
sys.exit(1)
config = load_config()
bind_host = host or config.server.host
bind_port = port or config.server.port
# Build command to run jarvis serve
cmd = [sys.executable, "-m", "openjarvis.cli", "serve"]
if host:
cmd.extend(["--host", host])
if port:
cmd.extend(["--port", str(port)])
if engine_key:
cmd.extend(["--engine", engine_key])
if model_name:
cmd.extend(["--model", model_name])
if agent_name:
cmd.extend(["--agent", agent_name])
# Start as background process, fully detached from the launching terminal.
#
# ``start_new_session`` is POSIX-only: CPython's Windows ``_execute_child``
# names the parameter ``unused_start_new_session`` and ignores it. Relying
# on it there leaves the server sharing its parent's console, so closing
# that console — or logging off — delivers CTRL_CLOSE_EVENT and kills the
# daemon. DETACHED_PROCESS gives it no console at all; the new process
# group additionally stops a Ctrl-C in the parent reaching it.
DEFAULT_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
log_fh = open(_LOG_FILE, "a") # noqa: SIM115
spawn_kwargs: dict = {}
if sys.platform == "win32":
spawn_kwargs["creationflags"] = (
subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP
)
else:
spawn_kwargs["start_new_session"] = True
proc = subprocess.Popen(
cmd,
stdout=log_fh,
stderr=log_fh,
**spawn_kwargs,
)
_write_pid(proc.pid)
console.print(
f"[green]OpenJarvis server started[/green] (PID {proc.pid})\n"
f" URL: http://{bind_host}:{bind_port}\n"
f" Log: {_LOG_FILE}"
)