chore: import upstream snapshot with attribution
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
"""/fleet kill subcommand."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from collections.abc import Callable
|
||||
|
||||
from rich.console import Console
|
||||
from rich.markup import escape
|
||||
|
||||
from platform.analytics.events import Event
|
||||
from platform.analytics.provider import get_analytics
|
||||
from surfaces.interactive_shell.runtime import Session
|
||||
from surfaces.interactive_shell.ui import DIM, ERROR, HIGHLIGHT, WARNING
|
||||
from tools.system.fleet_monitoring.lifecycle import TerminateResult, terminate
|
||||
from tools.system.fleet_monitoring.registry import AgentRegistry
|
||||
|
||||
# Type alias for the optional confirmation callback (used for testing).
|
||||
_ConfirmFn = Callable[[str], str]
|
||||
|
||||
|
||||
def _cmd_agents_kill(
|
||||
session: Session,
|
||||
console: Console,
|
||||
args: list[str],
|
||||
*,
|
||||
confirm_fn: _ConfirmFn | None = None,
|
||||
) -> bool:
|
||||
"""Handle ``/fleet kill <pid> [--force]``.
|
||||
|
||||
Sends SIGTERM, waits up to 5 s, then escalates to SIGKILL.
|
||||
Asks for confirmation unless ``--force`` is present.
|
||||
Emits an ``agent_killed`` analytics event on success.
|
||||
"""
|
||||
force = "--force" in args
|
||||
positional = [a for a in args if a != "--force"]
|
||||
|
||||
if not positional:
|
||||
console.print(f"[{ERROR}]usage:[/] /fleet kill <pid> [--force]")
|
||||
session.mark_latest(ok=False, kind="slash")
|
||||
return True
|
||||
|
||||
raw_pid = positional[0]
|
||||
try:
|
||||
pid = int(raw_pid)
|
||||
except ValueError:
|
||||
console.print(f"[{ERROR}]invalid pid:[/] {escape(raw_pid)} is not an integer")
|
||||
session.mark_latest(ok=False, kind="slash")
|
||||
return True
|
||||
|
||||
if pid == os.getpid():
|
||||
console.print(f"[{ERROR}]refusing to kill the opensre process itself[/]")
|
||||
session.mark_latest(ok=False, kind="slash")
|
||||
return True
|
||||
|
||||
# Look up agent name from registry for friendlier output.
|
||||
registry = AgentRegistry()
|
||||
record = registry.get(pid)
|
||||
label = f"{record.name} (pid {pid})" if record else f"pid {pid}"
|
||||
|
||||
if not force:
|
||||
prompt_text = f"About to SIGTERM {label}. Confirm? [y/N] "
|
||||
if confirm_fn is not None:
|
||||
answer = confirm_fn(prompt_text)
|
||||
else:
|
||||
answer = console.input(prompt_text)
|
||||
if answer.strip().lower() not in ("y", "yes"):
|
||||
console.print(f"[{DIM}]aborted.[/]")
|
||||
return True
|
||||
|
||||
try:
|
||||
result: TerminateResult = terminate(pid)
|
||||
except ProcessLookupError:
|
||||
console.print(f"[{ERROR}]no such process:[/] pid {pid}")
|
||||
session.mark_latest(ok=False, kind="slash")
|
||||
return True
|
||||
except PermissionError:
|
||||
console.print(f"[{ERROR}]permission denied:[/] cannot signal pid {pid}")
|
||||
session.mark_latest(ok=False, kind="slash")
|
||||
return True
|
||||
|
||||
if result.exited:
|
||||
console.print(
|
||||
f"[{HIGHLIGHT}]Sent {result.signal_sent}. "
|
||||
f"Process exited after {result.elapsed_seconds:.1f}s.[/]"
|
||||
)
|
||||
else:
|
||||
console.print(
|
||||
f"[{WARNING}]Sent {result.signal_sent} but process may still be running "
|
||||
f"after {result.elapsed_seconds:.1f}s.[/]"
|
||||
)
|
||||
session.mark_latest(ok=False, kind="slash")
|
||||
|
||||
# Remove from the agent registry so `/fleet` no longer shows the dead PID.
|
||||
# Only forget when the process actually exited — otherwise it stays visible
|
||||
# for further monitoring or another kill attempt.
|
||||
if record is not None and result.exited:
|
||||
registry.forget(pid)
|
||||
|
||||
event = Event.AGENT_KILLED if result.exited else Event.AGENT_KILL_FAILED
|
||||
get_analytics().capture(
|
||||
event,
|
||||
{
|
||||
"pid": str(pid),
|
||||
"agent_name": record.name if record else "unknown",
|
||||
"signal": result.signal_sent,
|
||||
"exited": result.exited,
|
||||
"elapsed_seconds": str(round(result.elapsed_seconds, 2)),
|
||||
},
|
||||
)
|
||||
return True
|
||||
Reference in New Issue
Block a user