diff --git a/astrbot/core/computer/booters/local.py b/astrbot/core/computer/booters/local.py index 30de507ba1..f3751e0a08 100644 --- a/astrbot/core/computer/booters/local.py +++ b/astrbot/core/computer/booters/local.py @@ -118,18 +118,29 @@ def _run() -> dict[str, Any]: # `command` is intentionally executed through the current shell so # local computer-use behavior matches existing tool semantics. # Safety relies on `_is_safe_command()` and the allowed-root checks. - result = subprocess.run( # noqa: S602 # nosemgrep: python.lang.security.audit.dangerous-subprocess-use-audit + proc = subprocess.Popen( # noqa: S602 # nosemgrep: python.lang.security.audit.dangerous-subprocess-use-audit command, shell=shell, cwd=working_dir, env=run_env, - timeout=timeout or 300, - capture_output=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, ) + try: + stdout, stderr = proc.communicate(timeout=timeout or 300) + except subprocess.TimeoutExpired: + if sys.platform == "win32": + import subprocess as _sp + _sp.run(["taskkill", "/F", "/T", "/PID", str(proc.pid)], + capture_output=True, timeout=5) + else: + proc.kill() + proc.wait() + raise return { - "stdout": _decode_shell_output(result.stdout), - "stderr": _decode_shell_output(result.stderr), - "exit_code": result.returncode, + "stdout": _decode_shell_output(stdout), + "stderr": _decode_shell_output(stderr), + "exit_code": proc.returncode, } return await asyncio.to_thread(_run)