FrameBridge 0.3.4 corresponding-source release

Snapshot assembled only from the signed corresponding-source archive.
Source archive SHA-256: db91a270cdefc4be79056ed38a0b4a16747e1ab130592645eac40fa3809809df
This commit is contained in:
FrameBridge release automation committed 2026-10-29 11:53:40 -04:00
1 parent b8c9b713d8
commit cdd980e1eb
993 files changed
+255481 -1720

No files matched your search

@@ -0,0 +1 @@
"""POSIX-specific utilities for MCP."""
@@ -0,0 +1,60 @@
"""
POSIX-specific functionality for stdio client operations.
"""
import logging
import os
import signal
import anyio
from anyio.abc import Process
logger = logging.getLogger(__name__)
async def terminate_posix_process_tree(process: Process, timeout_seconds: float = 2.0) -> None:
"""
Terminate a process and all its children on POSIX systems.
Uses os.killpg() for atomic process group termination.
Args:
process: The process to terminate
timeout_seconds: Timeout in seconds before force killing (default: 2.0)
"""
pid = getattr(process, "pid", None) or getattr(getattr(process, "popen", None), "pid", None)
if not pid:
# No PID means there's no process to terminate - it either never started,
# already exited, or we have an invalid process object
return
try:
pgid = os.getpgid(pid)
os.killpg(pgid, signal.SIGTERM)
with anyio.move_on_after(timeout_seconds):
while True:
try:
# Check if process group still exists (signal 0 = check only)
os.killpg(pgid, 0)
await anyio.sleep(0.1)
except ProcessLookupError:
return
try:
os.killpg(pgid, signal.SIGKILL)
except ProcessLookupError:
pass
except (ProcessLookupError, PermissionError, OSError) as e:
logger.warning(f"Process group termination failed for PID {pid}: {e}, falling back to simple terminate")
try:
process.terminate()
with anyio.fail_after(timeout_seconds):
await process.wait()
except Exception:
logger.warning(f"Process termination failed for PID {pid}, attempting force kill")
try:
process.kill()
except Exception:
logger.exception(f"Failed to kill process {pid}")