1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
//! Param and response types for the headless agent-shell MCP tools.
//!
//! These drive the embedded rmux daemon (see [`crate::shells`]): spawn a
//! detached headless shell session, send stdin, capture the visible output, and
//! kill it. The whole module is gated on `feature = "shells"`.
//!
//! Split into its own file to keep `types.rs` under the 1000-line cap.
#![cfg(feature = "shells")]
use rmcp::schemars;
use serde::{Deserialize, Serialize};
use crate::path::RelPath;
/// One environment-variable override for a spawned shell, in `KEY` / `VALUE` form.
///
/// Modelled as a struct (rather than a raw `"K=V"` string) so the schema is
/// self-documenting and the values are not re-parsed.
#[derive(Debug, Clone, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ShellEnv {
/// Environment variable name.
pub key: String,
/// Environment variable value.
pub value: String,
}
/// Parameters for `shell_spawn`.
#[derive(Debug, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ShellSpawnParams {
/// Command line to run in the session's initial pane, interpreted by the
/// login shell (e.g. `bash -lc '<command>'`). Required.
pub command: String,
/// Optional repository-relative working directory for the spawned process.
/// Forward-slash separated, no leading `/`.
#[serde(default)]
pub cwd: Option<RelPath>,
/// Optional environment-variable overrides applied to the spawned process.
#[serde(default)]
pub env: Option<Vec<ShellEnv>>,
/// Optional human-readable title for the session (advisory; not used for
/// addressing — use the returned `session_id`).
#[serde(default)]
pub title: Option<String>,
}
/// Response from `shell_spawn`.
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub struct ShellSpawnResponse {
/// Stable basemind-minted identifier for the spawned session. Pass this to
/// `shell_send` / `shell_capture` / `shell_kill`.
pub session_id: String,
/// A `rmux attach -t <name>` command an operator can run in a terminal to
/// attach to (observe) the otherwise-headless session.
pub attach_command: String,
/// The comms room id coupling this session's parent and child agents, when the server was
/// built with comms enabled. The spawned child auto-joins it on startup; the parent (this
/// server) is already subscribed. `None` when comms is disabled.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub room_id: Option<String>,
/// The agent id assigned to the spawned child, derived from the parent + session, when comms
/// is enabled. `None` when comms is disabled.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub child_agent: Option<String>,
}
/// Parameters for `shell_send`.
#[derive(Debug, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ShellSendParams {
/// The `session_id` returned by `shell_spawn`.
pub session_id: String,
/// Text to write to the session's stdin.
pub text: String,
/// When `true` (default), a trailing newline is appended so the line is
/// executed. Set `false` to send a raw keystroke fragment without a return.
#[serde(default = "default_true")]
pub enter: bool,
}
fn default_true() -> bool {
true
}
/// Parameters for `shell_capture`.
#[derive(Debug, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ShellCaptureParams {
/// The `session_id` returned by `shell_spawn`.
pub session_id: String,
/// Optional cap on how many trailing (most-recent) non-blank lines of the
/// visible screen to return. Omit to return the whole visible screen.
#[serde(default)]
pub lines: Option<usize>,
}
/// Response from `shell_capture`.
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub struct ShellCaptureResponse {
/// The captured visible screen text (trailing blank lines trimmed).
pub text: String,
}
/// Parameters for `shell_kill`.
#[derive(Debug, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ShellKillParams {
/// The `session_id` returned by `shell_spawn`.
pub session_id: String,
}
/// Response from `shell_kill`.
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub struct ShellKillResponse {
/// The `session_id` that was targeted.
pub session_id: String,
/// `true` when a live session was terminated, `false` when it was already
/// gone (already exited or never existed).
pub killed: bool,
}
/// Parameters for `shell_broadcast`.
#[derive(Debug, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ShellBroadcastParams {
/// The `session_id`s (from `shell_spawn`) to deliver `text` to. Every id must
/// be a known, live session of this server; an unknown id fails the whole
/// broadcast without sending to any pane.
pub session_ids: Vec<String>,
/// Text to write to each session's stdin.
pub text: String,
/// When `true` (default), a trailing newline is appended so each line is
/// executed. Set `false` to send a raw keystroke fragment without a return.
#[serde(default = "default_true")]
pub enter: bool,
}
/// Response from `shell_broadcast`.
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub struct ShellBroadcastResponse {
/// The number of session panes that accepted the input.
pub delivered: usize,
}
/// Parameters for `shell_list`. Takes no arguments.
#[derive(Debug, Deserialize, Serialize, schemars::JsonSchema)]
pub struct ShellListParams {}
/// One session in a `shell_list` response.
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub struct ShellSessionView {
/// The basemind-minted `session_id` for this session.
pub session_id: String,
/// The underlying rmux session name.
pub name: String,
/// `true` when the daemon still reports this session as live, `false` when it
/// has exited but the mapping has not been forgotten yet.
pub alive: bool,
/// The agent that spawned this session, from the shared comms lineage. `None` when comms is
/// disabled or the session has no recorded parent (e.g. a top-level session).
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parent_agent: Option<String>,
/// The agent that owns this session, from the shared comms lineage. `None` when comms is
/// disabled.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub child_agent: Option<String>,
/// The session-scoped comms room the parent and child share, from the shared comms lineage.
/// `None` when comms is disabled.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub room_id: Option<String>,
}
/// Response from `shell_list`.
#[derive(Debug, Serialize, schemars::JsonSchema)]
pub struct ShellListResponse {
/// The sessions this server spawned, each flagged with its liveness.
pub sessions: Vec<ShellSessionView>,
}