MCPcopy Index your code
hub / github.com/GuDaStudio/codexmcp / run_shell_command

Function run_shell_command

src/codexmcp/server.py:29–105  ·  view source on GitHub ↗

Execute a command and stream its output line-by-line. Args: cmd: Command and arguments as a list (e.g., ["codex", "exec", "prompt"]) Yields: Output lines from the command

(cmd: list[str])

Source from the content-addressed store, hash-verified

27
28
29def run_shell_command(cmd: list[str]) -> Generator[str, None, None]:
30 """Execute a command and stream its output line-by-line.
31
32 Args:
33 cmd: Command and arguments as a list (e.g., ["codex", "exec", "prompt"])
34
35 Yields:
36 Output lines from the command
37 """
38 # On Windows, codex is exposed via a *.cmd shim. Use cmd.exe with /s so
39 # user prompts containing quotes/newlines aren't reinterpreted as shell syntax.
40 popen_cmd = cmd.copy()
41 codex_path = shutil.which('codex') or cmd[0]
42 popen_cmd[0] = codex_path
43
44 process = subprocess.Popen(
45 popen_cmd,
46 shell=False,
47 stdin=subprocess.DEVNULL,
48 stdout=subprocess.PIPE,
49 stderr=subprocess.STDOUT,
50 universal_newlines=True,
51 encoding='utf-8',
52 )
53
54 output_queue: queue.Queue[str | None] = queue.Queue()
55 GRACEFUL_SHUTDOWN_DELAY = 0.3
56
57 def is_turn_completed(line: str) -> bool:
58 """Check if the line indicates turn completion via JSON parsing."""
59 try:
60 data = json.loads(line)
61 return data.get("type") == "turn.completed"
62 except (json.JSONDecodeError, AttributeError, TypeError):
63 return False
64
65 def read_output() -> None:
66 """Read process output in a separate thread."""
67 if process.stdout:
68 for line in iter(process.stdout.readline, ""):
69 stripped = line.strip()
70 output_queue.put(stripped)
71 if is_turn_completed(stripped):
72 time.sleep(GRACEFUL_SHUTDOWN_DELAY)
73 process.terminate()
74 break
75 process.stdout.close()
76 output_queue.put(None)
77
78 thread = threading.Thread(target=read_output)
79 thread.start()
80
81 # Yield lines while process is running
82 while True:
83 try:
84 line = output_queue.get(timeout=0.5)
85 if line is None:
86 break

Callers 1

codexFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected