MCPcopy Index your code
hub / github.com/ChrisFeldmeier/OpenCodeRust / shell_exec

Function shell_exec

crates/opencode-session/src/prompt.rs:3310–3388  ·  view source on GitHub ↗

Execute a shell command in the session context (matching TS `SessionPrompt.shell`). Creates a user message + assistant message with a tool call part recording the shell execution and its output. The command is provided by the user through the session UI and is intentionally executed as-is.

(input: &ShellInput, session: &mut Session)

Source from the content-addressed store, hash-verified

3308/// the shell execution and its output. The command is provided by the user
3309/// through the session UI and is intentionally executed as-is.
3310pub async fn shell_exec(input: &ShellInput, session: &mut Session) -> anyhow::Result<String> {
3311 // Create synthetic user message
3312 let _user_msg = session.add_user_message("The following tool was executed by the user");
3313
3314 // Create assistant message with tool call
3315 let assistant_msg = session.add_assistant_message();
3316 let call_id = format!("call_{}", uuid::Uuid::new_v4());
3317 assistant_msg.add_tool_call(
3318 &call_id,
3319 "bash",
3320 serde_json::json!({ "command": input.command_str }),
3321 );
3322
3323 let invocation =
3324 resolve_shell_invocation(std::env::var("SHELL").ok().as_deref(), &input.command_str);
3325 let abort = input.abort.clone().unwrap_or_else(CancellationToken::new);
3326
3327 let mut command = tokio::process::Command::new(&invocation.program);
3328 command
3329 .args(&invocation.args)
3330 .stdout(std::process::Stdio::piped())
3331 .stderr(std::process::Stdio::piped());
3332
3333 let mut child = command.spawn()?;
3334 let mut stdout = String::new();
3335 let mut stderr = String::new();
3336
3337 let stdout_task = child.stdout.take().map(|mut pipe| {
3338 tokio::spawn(async move {
3339 let mut buf = Vec::new();
3340 let _ = pipe.read_to_end(&mut buf).await;
3341 String::from_utf8_lossy(&buf).to_string()
3342 })
3343 });
3344 let stderr_task = child.stderr.take().map(|mut pipe| {
3345 tokio::spawn(async move {
3346 let mut buf = Vec::new();
3347 let _ = pipe.read_to_end(&mut buf).await;
3348 String::from_utf8_lossy(&buf).to_string()
3349 })
3350 });
3351
3352 let mut aborted = false;
3353 tokio::select! {
3354 _ = child.wait() => {}
3355 _ = abort.cancelled() => {
3356 aborted = true;
3357 let _ = child.kill().await;
3358 let _ = child.wait().await;
3359 }
3360 }
3361
3362 if let Some(task) = stdout_task {
3363 if let Ok(out) = task.await {
3364 stdout = out;
3365 }
3366 }
3367 if let Some(task) = stderr_task {

Callers

nothing calls this directly

Calls 9

resolve_shell_invocationFunction · 0.85
newFunction · 0.85
add_tool_callMethod · 0.80
spawnMethod · 0.80
is_emptyMethod · 0.80
add_user_messageMethod · 0.45
add_assistant_messageMethod · 0.45
cloneMethod · 0.45
add_tool_resultMethod · 0.45

Tested by

no test coverage detected