fix(maestro): chain default-terminal into new-session instead of pre-set
ci / rust (push) Successful in 2m59s

CI e2e tests failed with "tmux exited with code 1: server exited
unexpectedly" because the startup `start-server \; set-option -g
default-terminal` call left an empty server that tmux's default
`exit-empty on` killed before the first `new-session` could attach.

Move the `set-option -g default-terminal tmux-256color` into the same
tmux command as `new-session` (chained with `;`) so a single tmux
invocation creates the server, sets the option, and spawns the pane.
The pane reads `default-terminal` at creation time, so chaining before
`new-session` still applies to the very first session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-27 06:56:29 +00:00
co-authored by Claude Opus 4.7
parent 080f961238
commit b1aa2e6eab
3 changed files with 20 additions and 29 deletions
-6
View File
@@ -121,12 +121,6 @@ async fn run(config_override: Option<PathBuf>) -> Result<(), Box<dyn Error>> {
let sidecar = SidecarStore::new(config.sidecar_dir());
let worktree_mgr = WorktreeManager::new(config.worktree_root.clone());
let tmux = Tmux::new();
// The pane process's TERM comes from tmux's `default-terminal`, which on
// most distros is `screen` (8 colors). Promote it so attach clients see
// 256-color output. NAP-252.
if let Err(e) = tmux.set_option_global("default-terminal", "tmux-256color") {
tracing::warn!(error = ?e, "failed to set tmux default-terminal — sessions may lack color");
}
let manager = SessionManager::new_with_replay(
config.daemon_id.clone(),
tmux,
+20 -19
View File
@@ -77,13 +77,17 @@ impl Tmux {
c
}
/// `tmux new-session -d -e TERM=xterm-256color -e COLORTERM=truecolor -s maestro-<id> -c <cwd> <command>`.
/// `tmux set-option -g default-terminal tmux-256color \; new-session -d -e TERM=xterm-256color -e COLORTERM=truecolor -s maestro-<id> -c <cwd> <command>`.
///
/// `command` is passed as a single shell-line argument to tmux, which
/// invokes it via `$SHELL -c`. The `-e TERM=…`/`COLORTERM=…` flags ensure
/// the spawned shell sees sensible color env vars even when `maestrod`
/// runs from a stripped systemd unit. Pair with [`Self::set_option_global`]
/// of `default-terminal` for true 256-color output in the pane.
/// invokes it via `$SHELL -c`. Two layers ensure attach clients see color:
/// the `-e TERM=…`/`COLORTERM=…` flags populate the spawned shell's env
/// even when `maestrod` runs from a stripped systemd unit, and the chained
/// `set-option -g default-terminal tmux-256color` overrides tmux's
/// distro-default `screen` (8-color) terminfo for the pane process. The
/// `set-option` is chained into the same tmux invocation because a
/// stand-alone server with no sessions exits immediately under tmux's
/// default `exit-empty on`.
pub fn new_session(&self, id: Uuid, cwd: &Path, command: &str) -> Result<(), TmuxError> {
let name = session_name(id);
let out = self
@@ -93,19 +97,6 @@ impl Tmux {
check(out)
}
/// `tmux start-server \; set-option -g <name> <value>`. Used on daemon
/// startup to set `default-terminal` to `tmux-256color` so the pane's
/// `TERM` is a 256-color terminfo entry (the distro default `screen` caps
/// at 8). The chained `start-server` makes the call work before any
/// session exists.
pub fn set_option_global(&self, name: &str, value: &str) -> Result<(), TmuxError> {
let out = self
.cmd()
.args(["start-server", ";", "set-option", "-g", name, value])
.output()?;
check(out)
}
/// `tmux kill-session -t maestro-<id>`.
pub fn kill_session(&self, id: Uuid) -> Result<(), TmuxError> {
let name = session_name(id);
@@ -224,6 +215,11 @@ pub fn session_name(id: Uuid) -> String {
/// can be asserted without invoking tmux.
fn new_session_args(name: &str, cwd: &Path, command: &str) -> Vec<OsString> {
vec![
OsString::from("set-option"),
OsString::from("-g"),
OsString::from("default-terminal"),
OsString::from("tmux-256color"),
OsString::from(";"),
OsString::from("new-session"),
OsString::from("-d"),
OsString::from("-e"),
@@ -254,12 +250,17 @@ mod tests {
use super::*;
#[test]
fn new_session_args_pass_256color_env() {
fn new_session_args_pass_256color_env_and_default_terminal() {
let args = new_session_args("maestro-abc", Path::new("/tmp/proj"), "sleep 30");
let strs: Vec<&str> = args.iter().map(|s| s.to_str().unwrap()).collect();
assert_eq!(
strs,
vec![
"set-option",
"-g",
"default-terminal",
"tmux-256color",
";",
"new-session",
"-d",
"-e",
-4
View File
@@ -123,10 +123,6 @@ fn new_session_sets_256color_env_and_default_terminal() {
let sink_path = sink.path().join("env.log");
let id = Uuid::new_v4();
fx.tmux
.set_option_global("default-terminal", "tmux-256color")
.expect("set default-terminal");
fx.tmux
.new_session(id, cwd.path(), "bash --noprofile --norc")
.expect("new_session");