tmux_mcp/views.rs
1//! What the tools answer with.
2//!
3//! Every tool returns one of these rather than a string, so the shape it
4//! promises is published as an output schema and the value arrives as
5//! structured content. An agent reads fields instead of parsing prose, and the
6//! doc comments here become the descriptions it reads while doing it.
7//!
8//! Lists are wrapped in a named object rather than returned bare. The protocol
9//! says structured content is an object, and a wrapper leaves somewhere to put
10//! a count or a cursor later without changing a shape callers already read.
11
12use serde::Serialize;
13
14use crate::caller::Relation;
15use crate::schema::ChannelWaitOutcomeSchema;
16
17/// One session, as the protocol sees it.
18#[derive(Debug, Serialize, schemars::JsonSchema)]
19pub struct SessionView {
20 /// The `$`-prefixed tmux identity.
21 pub id: String,
22 /// The session name, absent when tmux reported none.
23 pub name: String,
24 /// How many windows the session holds.
25 pub windows: u32,
26 /// Whether any client is attached.
27 pub attached: bool,
28}
29
30/// One window, as the protocol sees it.
31#[derive(Debug, Serialize, schemars::JsonSchema)]
32pub struct WindowView {
33 /// The `@`-prefixed tmux identity.
34 pub id: String,
35 /// The session this window was reached through.
36 pub session_id: String,
37 /// The window's index within that session.
38 pub index: i32,
39 /// The window name.
40 pub name: String,
41 /// How many panes the window holds.
42 pub panes: u32,
43 /// Whether this is the session's active window.
44 pub active: bool,
45 /// Whether more than one session links this window.
46 pub linked: bool,
47}
48
49/// One pane, as the protocol sees it.
50#[derive(Debug, Serialize, schemars::JsonSchema)]
51pub struct PaneView {
52 /// The `%`-prefixed tmux identity.
53 pub id: String,
54 /// The window that contains the pane.
55 pub window_id: String,
56 /// The command currently running.
57 pub command: Option<String>,
58 /// The pane's working directory.
59 pub path: Option<String>,
60 /// Whether this is the window's active pane.
61 pub active: bool,
62 /// Whether this is the pane the MCP server itself runs in.
63 ///
64 /// `self` only on a confirmed match of both socket and pane id; `other`
65 /// for every pane that is not, including one this crate cannot prove
66 /// either way; `unknown` when the server is not running inside tmux, so
67 /// the question has no answer.
68 pub caller: Relation,
69}
70
71/// Every session on the server.
72#[derive(Debug, Serialize, schemars::JsonSchema)]
73pub struct Sessions {
74 /// The sessions, in tmux's own order.
75 pub sessions: Vec<SessionView>,
76}
77
78/// Every window asked for.
79#[derive(Debug, Serialize, schemars::JsonSchema)]
80pub struct Windows {
81 /// The windows, in tmux's own order.
82 pub windows: Vec<WindowView>,
83}
84
85/// Every pane asked for.
86#[derive(Debug, Serialize, schemars::JsonSchema)]
87pub struct Panes {
88 /// The panes, in tmux's own order.
89 pub panes: Vec<PaneView>,
90}
91
92/// One pane inside a described window.
93#[derive(Debug, Serialize, schemars::JsonSchema)]
94pub struct BranchPane {
95 /// The `%`-prefixed tmux identity.
96 pub id: String,
97 /// The command currently running.
98 pub command: Option<String>,
99 /// Whether this is the window's active pane.
100 pub active: bool,
101}
102
103/// One window inside a described session.
104#[derive(Debug, Serialize, schemars::JsonSchema)]
105pub struct BranchWindow {
106 /// The `@`-prefixed tmux identity.
107 pub id: String,
108 /// The window's index within its session.
109 pub index: i32,
110 /// The window name.
111 pub name: String,
112 /// Whether this is the session's active window.
113 pub active: bool,
114 /// Whether more than one session links this window.
115 pub linked: bool,
116 /// The panes it holds.
117 pub panes: Vec<BranchPane>,
118}
119
120/// One session with everything under it.
121#[derive(Debug, Serialize, schemars::JsonSchema)]
122pub struct Branch {
123 /// The `$`-prefixed tmux identity.
124 pub id: String,
125 /// The session name.
126 pub name: String,
127 /// Whether any client is attached.
128 pub attached: bool,
129 /// The windows it holds.
130 pub windows: Vec<BranchWindow>,
131}
132
133/// The whole hierarchy, in one answer.
134#[derive(Debug, Serialize, schemars::JsonSchema)]
135pub struct Tree {
136 /// Every session, with its windows and their panes.
137 pub sessions: Vec<Branch>,
138}
139
140/// Whether tmux knew where the last command's output began.
141///
142/// Reported rather than inferred: an answer that fell back to the whole
143/// screen looks exactly like a command that printed a great deal.
144#[derive(Debug, Serialize, schemars::JsonSchema)]
145#[serde(rename_all = "snake_case")]
146pub enum Marks {
147 /// The prompt marks were there, so the text is one command's output.
148 Present,
149 /// tmux has the marks but this pane has none, because its shell does not
150 /// emit OSC 133. fish does; bash and zsh need shell integration. The
151 /// visible screen came back instead -- not the history, which would
152 /// answer a request for one command with everything the pane ever wrote.
153 Absent,
154 /// This tmux predates `capture-pane -F`, which arrived in 3.7. The
155 /// visible screen came back instead.
156 Unsupported,
157 /// The caller did not ask for the last command, so nothing was looked up.
158 NotAsked,
159}
160
161/// What a pane is showing.
162#[derive(Debug, Serialize, schemars::JsonSchema)]
163pub struct Capture {
164 /// The pane that was read.
165 pub pane: String,
166 /// The text, with lines separated by newlines.
167 pub text: String,
168 /// How many lines that is.
169 pub lines: usize,
170 /// Whether the text is one command's output, and why it is not.
171 pub marks: Marks,
172}
173
174/// A pane's contents and the state a capture leaves out.
175#[derive(Debug, Serialize, schemars::JsonSchema)]
176pub struct Snapshot {
177 /// The pane itself.
178 pub pane: PaneView,
179 /// How wide it is, in columns.
180 pub width: u32,
181 /// How tall it is, in rows.
182 pub height: u32,
183 /// Where the cursor sits, counting from the left.
184 pub cursor_x: Option<u32>,
185 /// Where the cursor sits, counting from the top.
186 pub cursor_y: Option<u32>,
187 /// Whether the pane is in a mode, where keys navigate rather than type.
188 pub in_mode: bool,
189 /// Which mode, when it is in one.
190 pub mode: Option<String>,
191 /// How far it is scrolled back, when it is in copy mode.
192 pub scroll_position: Option<i32>,
193 /// Whether the process in it has ended.
194 pub dead: bool,
195 /// What the pane is showing.
196 pub content: String,
197 /// How many lines of it are reported.
198 pub lines: usize,
199 /// How many older lines were dropped to honour `max_lines`.
200 pub dropped: usize,
201}
202
203/// One line of one pane that matched a search.
204#[derive(Debug, Serialize, schemars::JsonSchema)]
205pub struct MatchView {
206 /// The pane the line was found in.
207 pub pane: String,
208 /// The window that pane belongs to.
209 pub window_id: String,
210 /// Which line of the capture matched, counting from the top.
211 pub line: usize,
212 /// The line itself.
213 pub text: String,
214}
215
216/// Where a pattern was found.
217#[derive(Debug, Serialize, schemars::JsonSchema)]
218pub struct Matches {
219 /// Every matching line, in the order the panes were read.
220 pub matches: Vec<MatchView>,
221 /// How many panes were read to answer this.
222 pub panes_searched: usize,
223 /// Whether the match ceiling was reached, so there may be more.
224 pub capped: bool,
225}
226
227/// What a pane wrote since a cursor.
228#[derive(Debug, Serialize, schemars::JsonSchema)]
229pub struct Since {
230 /// The pane that was read.
231 pub pane: String,
232 /// The text, with escape sequences removed.
233 ///
234 /// After the first answer this is the raw output stream, not the rendered
235 /// screen: a line redrawn in place repeats. `capture_pane` shows the
236 /// screen.
237 pub text: String,
238 /// The cursor to pass back next time.
239 pub cursor: String,
240 /// Whether output between the previous cursor and this text was lost.
241 pub missed: bool,
242 /// Whether the pane has stopped writing for good.
243 pub closed: bool,
244 /// Whether this is the first answer, which reports the visible screen
245 /// rather than what is new.
246 pub first: bool,
247}
248
249/// The value of one tmux option.
250#[derive(Debug, Serialize, schemars::JsonSchema)]
251pub struct OptionValue {
252 /// The option name.
253 pub name: String,
254 /// Its value, absent when it has never been set at that scope.
255 pub value: Option<String>,
256}
257
258/// How a wait on a channel finished.
259#[derive(Debug, Serialize, schemars::JsonSchema)]
260pub struct ChannelWait {
261 /// The channel that was waited on.
262 pub channel: String,
263 /// `signalled` or `deadline`.
264 #[schemars(with = "ChannelWaitOutcomeSchema")]
265 pub outcome: String,
266}
267
268/// A channel that was signalled.
269#[derive(Debug, Serialize, schemars::JsonSchema)]
270pub struct ChannelSignal {
271 /// The channel that was signalled.
272 pub channel: String,
273}
274
275/// Keys that were sent.
276#[derive(Debug, Serialize, schemars::JsonSchema)]
277pub struct Sent {
278 /// The pane the caller targeted.
279 pub pane: String,
280 /// The effective configured recipient IDs observed before dispatch.
281 ///
282 /// Membership does not confirm delivery and may change after observation.
283 pub panes: Vec<String>,
284}
285
286/// A pane's size after being resized.
287#[derive(Debug, Serialize, schemars::JsonSchema)]
288pub struct Size {
289 /// The pane that was resized.
290 pub pane: String,
291 /// How wide it is now, in columns.
292 pub width: u32,
293 /// How tall it is now, in rows.
294 pub height: u32,
295}
296
297/// An object that was destroyed.
298#[derive(Debug, Serialize, schemars::JsonSchema)]
299pub struct Killed {
300 /// The id of what was destroyed.
301 pub id: String,
302}
303
304/// What tmux holds under one environment name.
305#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, schemars::JsonSchema)]
306#[serde(rename_all = "snake_case")]
307pub enum EnvironmentState {
308 /// tmux holds a value and hands it to processes it starts.
309 Set,
310 /// tmux removes the name from the environment of processes it starts.
311 Removed,
312}
313
314/// One tmux environment entry.
315#[derive(Debug, Serialize, schemars::JsonSchema)]
316pub struct EnvironmentEntry {
317 /// The variable name.
318 pub name: String,
319 /// Whether the name holds a value or is marked for removal.
320 pub state: EnvironmentState,
321 /// The value, only for a set variable whose name the operator allowed in
322 /// `LIBTMUX_ENVIRONMENT_VALUES` at startup.
323 pub value: Option<String>,
324 /// True for a set variable whose value was not returned because the
325 /// operator did not allow its name.
326 pub withheld: bool,
327}
328
329/// A tmux environment, server-wide or for one session.
330#[derive(Debug, Serialize, schemars::JsonSchema)]
331pub struct Environment {
332 /// The entries, in tmux's own order.
333 pub entries: Vec<EnvironmentEntry>,
334 /// The session the environment belongs to, or absent for the server's.
335 pub session: Option<String>,
336}
337
338/// One tmux hook.
339#[derive(Debug, Serialize, schemars::JsonSchema)]
340pub struct Hook {
341 /// The hook name, such as `pane-exited`.
342 pub name: String,
343 /// Its index, when the hook is an array.
344 pub index: Option<u32>,
345 /// The command tmux runs.
346 pub command: String,
347}
348
349/// The hooks set at one scope.
350#[derive(Debug, Serialize, schemars::JsonSchema)]
351pub struct Hooks {
352 /// The hooks, in tmux's own order.
353 pub hooks: Vec<Hook>,
354}
355
356/// A window whose layout was set.
357#[derive(Debug, Serialize, schemars::JsonSchema)]
358pub struct Layout {
359 /// The window that was arranged.
360 pub window: String,
361 /// The layout it now has, in tmux's own syntax.
362 pub layout: String,
363}
364
365/// A pane that was cleared, respawned, or retitled.
366#[derive(Debug, Serialize, schemars::JsonSchema)]
367pub struct PaneChanged {
368 /// The pane that changed.
369 pub pane: String,
370}
371
372/// Text that was pasted into a pane.
373#[derive(Debug, Serialize, schemars::JsonSchema)]
374pub struct Pasted {
375 /// The pane it went into.
376 pub pane: String,
377 /// How many bytes came from `text`, excluding optional Enter.
378 pub bytes: usize,
379}