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
//! # Module: session_cmd
//!
//! ## Spec
//! - `agent-doc session` — show the currently configured tmux session
//! - `agent-doc session set <name>` — update config.toml and migrate all registered
//! panes to the new session by moving the agent-doc window via `tmux move-window`.
//!
//! ## Agentic Contracts
//! - `show()` reads config.toml and prints the configured session (or "(none)").
//! - `set()` updates config.toml, moves the agent-doc window from the old session to the
//! new session, and updates registry window references. If the old session has no
//! agent-doc window, the command still updates config for future routing.
//! - Session names are not validated against live tmux sessions — tmux will error if the
//! target session doesn't exist, and we propagate that error.
//!
//! ## Evals
//! - show_prints_configured_session: config has tmux_session="5" → prints "5"
//! - show_prints_none_when_unconfigured: no config → prints "(none)"
//! - set_updates_config: set "3" → config.toml contains tmux_session="3"
use anyhow::{Context, Result};
use crate::{config, sessions::Tmux};
/// Show the currently configured tmux session.
pub fn show() -> Result<()> {
let session = config::project_tmux_session();
match session {
Some(s) => println!("{}", s),
None => println!("(none)"),
}
Ok(())
}
/// Set the tmux session and migrate all registered panes.
pub fn set(name: &str) -> Result<()> {
let tmux = Tmux::default_server();
let old_session = config::project_tmux_session();
// Update config first
config::update_project_tmux_session(name)?;
// Try to move the agent-doc window from old session to new session
if let Some(ref old) = old_session {
if old != name {
let source = format!("{}:agent-doc", old);
let output = tmux
.cmd()
.args(["move-window", "-s", &source, "-t", &format!("{}:", name)])
.output()
.context("failed to run tmux move-window")?;
if output.status.success() {
eprintln!(
"[session] moved agent-doc window from session '{}' to '{}'",
old, name
);
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
eprintln!(
"[session] could not move agent-doc window: {} (config updated, panes will route to '{}' on next claim/route)",
stderr.trim(), name
);
}
// Also try to move stash window if it exists
let stash_source = format!("{}:stash", old);
let stash_output = tmux
.cmd()
.args(["move-window", "-s", &stash_source, "-t", &format!("{}:", name)])
.output();
if let Ok(o) = stash_output
&& o.status.success()
{
eprintln!("[session] moved stash window to session '{}'", name);
}
} else {
eprintln!("[session] already configured to '{}'", name);
}
} else {
eprintln!("[session] configured tmux_session to '{}' (was unset)", name);
}
Ok(())
}