synaps_cli/tools/shell/
send.rs1use serde_json::{json, Value};
4use crate::{Result, RuntimeError};
5use crate::tools::{Tool, ToolContext};
6
7pub struct ShellSendTool;
8
9#[async_trait::async_trait]
10impl Tool for ShellSendTool {
11 fn name(&self) -> &str { "shell_send" }
12
13 fn description(&self) -> &str {
14 "Send input to an active shell session. Returns the output produced after sending the input. The input is sent exactly as received after JSON parsing — a JSON string containing \\n will send an actual newline (Enter key). Use \\x03 for Ctrl-C, \\x04 for Ctrl-D."
15 }
16
17 fn parameters(&self) -> Value {
18 json!({
19 "type": "object",
20 "properties": {
21 "session_id": {
22 "type": "string",
23 "description": "Session ID from shell_start"
24 },
25 "input": {
26 "type": "string",
27 "description": "Text to send to the shell. Use \\n for Enter, \\x03 for Ctrl-C, \\x04 for Ctrl-D"
28 },
29 "timeout_ms": {
30 "type": "integer",
31 "description": "Override readiness timeout for this send (ms)"
32 }
33 },
34 "required": ["session_id", "input"]
35 })
36 }
37
38 async fn execute(&self, params: Value, ctx: ToolContext) -> Result<String> {
39 let mgr = ctx.capabilities.session_manager.as_ref()
40 .ok_or_else(|| RuntimeError::Tool("Shell sessions not available".into()))?;
41
42 let session_id = params["session_id"].as_str()
43 .ok_or_else(|| RuntimeError::Tool("Missing session_id parameter".into()))?;
44 let input = params["input"].as_str()
45 .ok_or_else(|| RuntimeError::Tool("Missing input parameter".into()))?;
46 let timeout_ms = params["timeout_ms"].as_u64();
47
48 let result = mgr.send_input(session_id, input, timeout_ms, ctx.channels.tx_delta.as_ref()).await?;
49
50 if result.status == "active" {
51 Ok(result.output)
52 } else {
53 let mut out = result.output;
54 out.push_str(&format!("\n[{}]", result.status));
55 Ok(out)
56 }
57 }
58}