exec

open suspend override fun exec(command: String, args: List<String> = emptyList()): ShellResult

Run command with args as a shell process. Returns stdout/stderr/exit. Implementations should NOT throw on non-zero exit codes — surface them via ShellResult.exitCode so tools can decide whether that's an error.

Throws ShellException only on infrastructure failures (binder down, permission denied, process spawn failed). Tools translate that into a shell_unavailable: <reason> MCP error.

Implementations should bound both wall-clock time (throwing ShellException.SpawnFailed on timeout, after killing the process) and captured output size (reporting ShellResult.outputTruncated), and must honour coroutine cancellation by killing the process.

Output format is implementation-dependent for binary commands. The Shizuku backend returns raw bytes (it reads process.inputStream directly). The libsu backend's Shell.Result.out is line-decoded UTF-8 — binary stdout (screencap -p, etc.) is corrupted through this path. Tools that produce binary stdout should call execBinary instead.