Skip to content

Commit 95bd1a5

Browse files
committed
Fix approval UX and enforce exact managed tmux session targeting
1 parent ffa5a92 commit 95bd1a5

13 files changed

Lines changed: 207 additions & 56 deletions

File tree

src/app/approval.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ use buddy::ui::render::RenderSink;
99
use buddy::ui::theme::{self, ThemeToken};
1010
use crossterm::style::{Color, Stylize};
1111

12+
/// Default number of command lines shown in approval preview mode.
13+
const APPROVAL_PREVIEW_LINES: usize = 5;
14+
1215
/// Build the target label used in approval prompts.
1316
pub(crate) fn approval_prompt_actor(
1417
ssh_target: Option<&str>,
@@ -35,6 +38,7 @@ pub(crate) fn render_shell_approval_request(
3538
renderer: &dyn RenderSink,
3639
actor: &str,
3740
command: &str,
41+
expanded: bool,
3842
risk: Option<&str>,
3943
why: Option<&str>,
4044
) {
@@ -57,7 +61,19 @@ pub(crate) fn render_shell_approval_request(
5761
eprintln!(" {reason}");
5862
}
5963
}
60-
renderer.approval_block(&format_approval_command_block(command));
64+
let (command_text, truncated_lines) = if expanded {
65+
(command.to_string(), 0)
66+
} else {
67+
approval_command_preview(command, APPROVAL_PREVIEW_LINES)
68+
};
69+
let mut block = format_approval_command_block(&command_text);
70+
if truncated_lines > 0 {
71+
block.push('\n');
72+
block.push_str(&format!(
73+
" ...{truncated_lines} more lines... (press 'e' to expand)"
74+
));
75+
}
76+
renderer.approval_block(&block);
6177
}
6278

6379
/// Map risk metadata to a display label/style.
@@ -94,6 +110,24 @@ pub(crate) fn format_approval_command_block(command: &str) -> String {
94110
out
95111
}
96112

113+
/// Build a line-limited preview for approval command rendering.
114+
pub(crate) fn approval_command_preview(command: &str, max_lines: usize) -> (String, usize) {
115+
if max_lines == 0 {
116+
return (String::new(), command.lines().count());
117+
}
118+
let lines = command.lines().collect::<Vec<_>>();
119+
if lines.len() <= max_lines {
120+
return (command.to_string(), 0);
121+
}
122+
let preview = lines
123+
.iter()
124+
.take(max_lines)
125+
.copied()
126+
.collect::<Vec<_>>()
127+
.join("\n");
128+
(preview, lines.len() - max_lines)
129+
}
130+
97131
/// Convert CLI-side approval decision into runtime command decision.
98132
pub(crate) fn runtime_approval_decision(decision: ApprovalDecision) -> RuntimeApprovalDecision {
99133
match decision {
@@ -166,4 +200,22 @@ mod tests {
166200
let block = format_approval_command_block("echo 1\necho 2");
167201
assert_eq!(block, "$ echo 1\n echo 2");
168202
}
203+
204+
#[test]
205+
fn approval_command_preview_limits_to_configured_lines() {
206+
// Preview mode should cap output to the first N lines and report remaining lines.
207+
let (preview, remaining) =
208+
approval_command_preview("a\nb\nc\nd\ne\nf\ng", APPROVAL_PREVIEW_LINES);
209+
assert_eq!(preview, "a\nb\nc\nd\ne");
210+
assert_eq!(remaining, 2);
211+
}
212+
213+
#[test]
214+
fn approval_command_preview_keeps_short_commands_intact() {
215+
// Commands with <= max preview lines should remain unchanged.
216+
let (preview, remaining) =
217+
approval_command_preview("echo 1\necho 2", APPROVAL_PREVIEW_LINES);
218+
assert_eq!(preview, "echo 1\necho 2");
219+
assert_eq!(remaining, 0);
220+
}
169221
}

src/app/repl_mode.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ pub(crate) async fn run_repl_mode(inputs: ReplModeInputs<'_>) -> i32 {
194194
set_progress_enabled(true);
195195
}
196196

197-
if let Some(approval) = pending_approval.take() {
197+
if let Some(mut approval) = pending_approval.take() {
198198
// Approval input mode temporarily replaces normal prompt handling.
199199
let approval_actor = approval_prompt_actor(
200200
cli_args.ssh.as_deref(),
@@ -206,6 +206,7 @@ pub(crate) async fn run_repl_mode(inputs: ReplModeInputs<'_>) -> i32 {
206206
renderer,
207207
&approval_actor,
208208
&approval.command,
209+
approval.expanded,
209210
approval.risk.as_deref(),
210211
approval.why.as_deref(),
211212
);
@@ -250,6 +251,11 @@ pub(crate) async fn run_repl_mode(inputs: ReplModeInputs<'_>) -> i32 {
250251

251252
let approval_input = approval_input.trim();
252253
eprintln!();
254+
if matches!(approval_input.to_ascii_lowercase().as_str(), "e" | "expand") {
255+
approval.expanded = !approval.expanded;
256+
pending_approval = Some(approval);
257+
continue;
258+
}
253259
if let Some(decision) = parse_approval_decision(approval_input) {
254260
// Direct y/n responses resolve the pending runtime approval.
255261
let task_id = approval.task_id;
@@ -320,7 +326,7 @@ pub(crate) async fn run_repl_mode(inputs: ReplModeInputs<'_>) -> i32 {
320326
}
321327

322328
renderer.warn(
323-
"Approval required. Reply with y/yes or n/no. You can also use /ps, /kill <id>, /timeout <dur> [id], /approve <mode>, /status, /context, /compact.",
329+
"Approval required. Reply with y/yes, n/no, or e/expand. You can also use /ps, /kill <id>, /timeout <dur> [id], /approve <mode>, /status, /context, /compact.",
324330
);
325331
pending_approval = Some(approval);
326332
continue;

src/repl/task_state.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ pub struct PendingApproval {
7272
pub privesc: Option<bool>,
7373
/// Optional human-readable rationale for why approval is required.
7474
pub why: Option<String>,
75+
/// Whether the full command is expanded in the approval UI.
76+
pub expanded: bool,
7577
}
7678

7779
/// Cached runtime context usage displayed by REPL status prompt.

src/runtime/approvals.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub(super) fn handle_approval_request(
7474
RuntimeEvent::Task(TaskEvent::WaitingApproval {
7575
task: active_task.task_ref.clone(),
7676
approval_id: approval_id.clone(),
77-
command: truncate_preview(request.command(), 140),
77+
command: request.command().to_string(),
7878
risk: request
7979
.metadata()
8080
.map(|meta| meta.risk().as_str().to_string()),

src/runtime/schema.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ pub enum TaskEvent {
267267
task: TaskRef,
268268
/// Identifier required for approve/deny command.
269269
approval_id: String,
270-
/// Truncated command preview awaiting approval.
270+
/// Full command awaiting approval.
271271
command: String,
272272
/// Optional risk classification.
273273
#[serde(skip_serializing_if = "Option::is_none")]

src/templates/system_prompt.snapshot.local.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ before running commands. If there is no usable shell prompt, do not run
6464
`run_shell`; explain what is blocking the pane and offer safe recovery with
6565
`tmux_send_keys`.
6666

67+
Shared-terminal advantage: in the managed shared tmux pane, it is acceptable to
68+
use `sudo` or other commands that may require a password or explicit human
69+
interaction. The user can intervene directly in that same shared terminal when
70+
needed, then you can continue.
71+
6772
## Tool Choice Quick Guide
6873
- Use `run_shell` to execute shell commands and gather command output.
6974
- Use `tmux_capture_pane` to observe in-progress or interactive terminal state.

src/templates/system_prompt.template

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ before running commands. If there is no usable shell prompt, do not run
6464
`run_shell`; explain what is blocking the pane and offer safe recovery with
6565
`tmux_send_keys`.
6666

67+
Shared-terminal advantage: in the managed shared tmux pane, it is acceptable to
68+
use `sudo` or other commands that may require a password or explicit human
69+
interaction. The user can intervene directly in that same shared terminal when
70+
needed, then you can continue.
71+
6772
## Tool Choice Quick Guide
6873
- Use `run_shell` to execute shell commands and gather command output.
6974
- Use `tmux_capture_pane` to observe in-progress or interactive terminal state.

src/tmux/management.rs

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ if [ -z \"$SESSION\" ] || [ -z \"$PANE\" ]; then\n\
140140
echo \"tmux target not found; omit target/session/pane to use the default shared pane, or create one with tmux_create_pane\" >&2\n\
141141
exit 1\n\
142142
fi\n\
143-
SESSION_MANAGED=\"$(tmux show-options -v -t \"$SESSION\" {TMUX_MANAGED_OPTION} 2>/dev/null || true)\"\n\
144-
SESSION_OWNER=\"$(tmux show-options -v -t \"$SESSION\" {TMUX_OWNER_OPTION} 2>/dev/null || true)\"\n\
143+
SESSION_MANAGED=\"$(tmux show-options -v -t \"=$SESSION\" {TMUX_MANAGED_OPTION} 2>/dev/null || true)\"\n\
144+
SESSION_OWNER=\"$(tmux show-options -v -t \"=$SESSION\" {TMUX_OWNER_OPTION} 2>/dev/null || true)\"\n\
145145
if [ \"$SESSION_MANAGED\" != \"1\" ] || [ \"$SESSION_OWNER\" != \"$OWNER\" ]; then\n\
146146
echo \"tmux session '$SESSION' is not managed by this buddy instance\" >&2\n\
147147
exit 1\n\
@@ -177,9 +177,9 @@ PANE_TITLE='{TMUX_PANE_TITLE}'\n\
177177
MAX_SESSIONS={max_sessions}\n\
178178
COUNT=\"$(tmux list-sessions -F '#{{session_name}}\\t#{{@buddy_managed}}\\t#{{@buddy_owner}}' 2>/dev/null | awk -F '\\t' -v owner=\"$OWNER\" '$2==\"1\" && $3==owner {{c++}} END {{print c+0}}')\"\n\
179179
CREATED=0\n\
180-
if tmux has-session -t \"$SESSION\" 2>/dev/null; then\n\
181-
SESSION_MANAGED=\"$(tmux show-options -v -t \"$SESSION\" {TMUX_MANAGED_OPTION} 2>/dev/null || true)\"\n\
182-
SESSION_OWNER=\"$(tmux show-options -v -t \"$SESSION\" {TMUX_OWNER_OPTION} 2>/dev/null || true)\"\n\
180+
if tmux has-session -t \"=$SESSION\" 2>/dev/null; then\n\
181+
SESSION_MANAGED=\"$(tmux show-options -v -t \"=$SESSION\" {TMUX_MANAGED_OPTION} 2>/dev/null || true)\"\n\
182+
SESSION_OWNER=\"$(tmux show-options -v -t \"=$SESSION\" {TMUX_OWNER_OPTION} 2>/dev/null || true)\"\n\
183183
if [ \"$SESSION_MANAGED\" != \"1\" ] || [ \"$SESSION_OWNER\" != \"$OWNER\" ]; then\n\
184184
echo \"tmux session '$SESSION' exists but is not managed by this buddy instance\" >&2\n\
185185
exit 1\n\
@@ -192,16 +192,16 @@ else\n\
192192
tmux new-session -d -s \"$SESSION\" -n \"$WINDOW\"\n\
193193
CREATED=1\n\
194194
fi\n\
195-
if ! tmux list-windows -t \"$SESSION\" -F '#{{window_name}}' | grep -Fx -- \"$WINDOW\" >/dev/null 2>&1; then\n\
196-
tmux new-window -d -t \"$SESSION\" -n \"$WINDOW\"\n\
195+
if ! tmux list-windows -t \"=$SESSION\" -F '#{{window_name}}' | grep -Fx -- \"$WINDOW\" >/dev/null 2>&1; then\n\
196+
tmux new-window -d -t \"=$SESSION\" -n \"$WINDOW\"\n\
197197
fi\n\
198198
PANE=\"$(tmux list-panes -a -F '#{{session_name}}\\t#{{pane_id}}\\t#{{pane_title}}' | awk -F '\\t' -v session=\"$SESSION\" -v pane_title=\"$PANE_TITLE\" '$1==session && $3==pane_title {{print $2; exit}}')\"\n\
199199
if [ -z \"$PANE\" ]; then\n\
200-
PANE=\"$(tmux list-panes -t \"$SESSION:$WINDOW\" -F '#{{pane_id}}' | head -n1)\"\n\
200+
PANE=\"$(tmux list-panes -t \"=$SESSION:$WINDOW\" -F '#{{pane_id}}' | head -n1)\"\n\
201201
tmux select-pane -t \"$PANE\" -T \"$PANE_TITLE\" >/dev/null 2>&1 || true\n\
202202
fi\n\
203-
tmux set-option -q -t \"$SESSION\" {TMUX_MANAGED_OPTION} 1\n\
204-
tmux set-option -q -t \"$SESSION\" {TMUX_OWNER_OPTION} \"$OWNER\"\n\
203+
tmux set-option -q -t \"=$SESSION\" {TMUX_MANAGED_OPTION} 1\n\
204+
tmux set-option -q -t \"=$SESSION\" {TMUX_OWNER_OPTION} \"$OWNER\"\n\
205205
tmux set-option -q -p -t \"$PANE\" {TMUX_MANAGED_OPTION} 1\n\
206206
tmux set-option -q -p -t \"$PANE\" {TMUX_OWNER_OPTION} \"$OWNER\"\n\
207207
printf '%s\\n%s\\n%s' \"$SESSION\" \"$PANE\" \"$CREATED\"\n"
@@ -228,12 +228,12 @@ SESSION={session_q}\n\
228228
PANE_TITLE={pane_q}\n\
229229
WINDOW='{TMUX_WINDOW_NAME}'\n\
230230
MAX_PANES={max_panes}\n\
231-
if ! tmux has-session -t \"$SESSION\" 2>/dev/null; then\n\
231+
if ! tmux has-session -t \"=$SESSION\" 2>/dev/null; then\n\
232232
echo \"tmux session '$SESSION' was not found\" >&2\n\
233233
exit 1\n\
234234
fi\n\
235-
SESSION_MANAGED=\"$(tmux show-options -v -t \"$SESSION\" {TMUX_MANAGED_OPTION} 2>/dev/null || true)\"\n\
236-
SESSION_OWNER=\"$(tmux show-options -v -t \"$SESSION\" {TMUX_OWNER_OPTION} 2>/dev/null || true)\"\n\
235+
SESSION_MANAGED=\"$(tmux show-options -v -t \"=$SESSION\" {TMUX_MANAGED_OPTION} 2>/dev/null || true)\"\n\
236+
SESSION_OWNER=\"$(tmux show-options -v -t \"=$SESSION\" {TMUX_OWNER_OPTION} 2>/dev/null || true)\"\n\
237237
if [ \"$SESSION_MANAGED\" != \"1\" ] || [ \"$SESSION_OWNER\" != \"$OWNER\" ]; then\n\
238238
echo \"tmux session '$SESSION' is not managed by this buddy instance\" >&2\n\
239239
exit 1\n\
@@ -246,10 +246,10 @@ if [ -z \"$PANE\" ]; then\n\
246246
echo \"managed tmux pane limit reached in session '$SESSION' ($COUNT/$MAX_PANES)\" >&2\n\
247247
exit 1\n\
248248
fi\n\
249-
if ! tmux list-windows -t \"$SESSION\" -F '#{{window_name}}' | grep -Fx -- \"$WINDOW\" >/dev/null 2>&1; then\n\
250-
tmux new-window -d -t \"$SESSION\" -n \"$WINDOW\"\n\
249+
if ! tmux list-windows -t \"=$SESSION\" -F '#{{window_name}}' | grep -Fx -- \"$WINDOW\" >/dev/null 2>&1; then\n\
250+
tmux new-window -d -t \"=$SESSION\" -n \"$WINDOW\"\n\
251251
fi\n\
252-
PANE=\"$(tmux split-window -d -P -F '#{{pane_id}}' -t \"$SESSION:$WINDOW\")\"\n\
252+
PANE=\"$(tmux split-window -d -P -F '#{{pane_id}}' -t \"=$SESSION:$WINDOW\")\"\n\
253253
tmux select-pane -t \"$PANE\" -T \"$PANE_TITLE\" >/dev/null 2>&1 || true\n\
254254
tmux set-option -q -p -t \"$PANE\" {TMUX_MANAGED_OPTION} 1\n\
255255
tmux set-option -q -p -t \"$PANE\" {TMUX_OWNER_OPTION} \"$OWNER\"\n\
@@ -278,12 +278,12 @@ OWNER={owner_q}\n\
278278
SESSION={session_q}\n\
279279
PANE_TITLE={pane_q}\n\
280280
DEFAULT_SESSION={default_session_q}\n\
281-
if ! tmux has-session -t \"$SESSION\" 2>/dev/null; then\n\
281+
if ! tmux has-session -t \"=$SESSION\" 2>/dev/null; then\n\
282282
echo \"tmux session '$SESSION' was not found\" >&2\n\
283283
exit 1\n\
284284
fi\n\
285-
SESSION_MANAGED=\"$(tmux show-options -v -t \"$SESSION\" {TMUX_MANAGED_OPTION} 2>/dev/null || true)\"\n\
286-
SESSION_OWNER=\"$(tmux show-options -v -t \"$SESSION\" {TMUX_OWNER_OPTION} 2>/dev/null || true)\"\n\
285+
SESSION_MANAGED=\"$(tmux show-options -v -t \"=$SESSION\" {TMUX_MANAGED_OPTION} 2>/dev/null || true)\"\n\
286+
SESSION_OWNER=\"$(tmux show-options -v -t \"=$SESSION\" {TMUX_OWNER_OPTION} 2>/dev/null || true)\"\n\
287287
if [ \"$SESSION_MANAGED\" != \"1\" ] || [ \"$SESSION_OWNER\" != \"$OWNER\" ]; then\n\
288288
echo \"tmux session '$SESSION' is not managed by this buddy instance\" >&2\n\
289289
exit 1\n\
@@ -327,17 +327,17 @@ if [ \"$SESSION\" = \"$DEFAULT_SESSION\" ]; then\n\
327327
echo \"cannot kill default managed tmux session\" >&2\n\
328328
exit 1\n\
329329
fi\n\
330-
if ! tmux has-session -t \"$SESSION\" 2>/dev/null; then\n\
330+
if ! tmux has-session -t \"=$SESSION\" 2>/dev/null; then\n\
331331
echo \"tmux session '$SESSION' was not found\" >&2\n\
332332
exit 1\n\
333333
fi\n\
334-
SESSION_MANAGED=\"$(tmux show-options -v -t \"$SESSION\" {TMUX_MANAGED_OPTION} 2>/dev/null || true)\"\n\
335-
SESSION_OWNER=\"$(tmux show-options -v -t \"$SESSION\" {TMUX_OWNER_OPTION} 2>/dev/null || true)\"\n\
334+
SESSION_MANAGED=\"$(tmux show-options -v -t \"=$SESSION\" {TMUX_MANAGED_OPTION} 2>/dev/null || true)\"\n\
335+
SESSION_OWNER=\"$(tmux show-options -v -t \"=$SESSION\" {TMUX_OWNER_OPTION} 2>/dev/null || true)\"\n\
336336
if [ \"$SESSION_MANAGED\" != \"1\" ] || [ \"$SESSION_OWNER\" != \"$OWNER\" ]; then\n\
337337
echo \"tmux session '$SESSION' is not managed by this buddy instance\" >&2\n\
338338
exit 1\n\
339339
fi\n\
340-
tmux kill-session -t \"$SESSION\"\n\
340+
tmux kill-session -t \"=$SESSION\"\n\
341341
printf '%s' \"$SESSION\"\n"
342342
))
343343
}
@@ -467,4 +467,24 @@ mod tests {
467467
resolve_managed_target_script("buddy-agent-mo", "buddy-agent-mo", &selector).unwrap();
468468
assert!(script.contains("TARGET=''"));
469469
}
470+
471+
#[test]
472+
fn lifecycle_scripts_use_exact_session_targets() {
473+
// Exact `=$SESSION` targeting avoids accidental prefix matching
474+
// (for example, resolving `buddy-agent-mo` to `buddy-agent-mo-default-repair`).
475+
let create = create_managed_session_script("buddy-agent-mo", "buddy-agent-mo", 1);
476+
assert!(create.contains("tmux has-session -t \"=$SESSION\""));
477+
assert!(create.contains("tmux list-windows -t \"=$SESSION\""));
478+
assert!(create.contains("tmux set-option -q -t \"=$SESSION\""));
479+
480+
let pane =
481+
create_managed_pane_script("buddy-agent-mo", "buddy-agent-mo", None, "worker", 5)
482+
.unwrap();
483+
assert!(pane.contains("tmux has-session -t \"=$SESSION\""));
484+
assert!(pane.contains("-t \"=$SESSION:$WINDOW\""));
485+
486+
let kill_session =
487+
kill_managed_session_script("buddy-agent-mo", "buddy-agent-mo", "worker").unwrap();
488+
assert!(kill_session.contains("tmux kill-session -t \"=$SESSION\""));
489+
}
470490
}

src/tmux/pane.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,26 @@ SESSION={session_q}\n\
2424
WINDOW={window_q}\n\
2525
PANE_TITLE={pane_title_q}\n\
2626
CREATED=0\n\
27-
if tmux has-session -t \"$SESSION\" 2>/dev/null; then\n\
27+
if tmux has-session -t \"=$SESSION\" 2>/dev/null; then\n\
2828
:\n\
2929
else\n\
3030
tmux new-session -d -s \"$SESSION\" -n \"$WINDOW\"\n\
3131
CREATED=1\n\
3232
fi\n\
33-
if ! tmux list-windows -t \"$SESSION\" -F '#{{window_name}}' | grep -Fx -- \"$WINDOW\" >/dev/null 2>&1; then\n\
34-
tmux new-window -d -t \"$SESSION\" -n \"$WINDOW\"\n\
33+
if ! tmux list-windows -t \"=$SESSION\" -F '#{{window_name}}' | grep -Fx -- \"$WINDOW\" >/dev/null 2>&1; then\n\
34+
tmux new-window -d -t \"=$SESSION\" -n \"$WINDOW\"\n\
3535
CREATED=1\n\
3636
fi\n\
37-
PANE=\"$(tmux list-panes -t \"$SESSION:$WINDOW\" -F '#{{pane_id}}\\t#{{pane_title}}' | awk -F '\\t' '$2==\"'\"$PANE_TITLE\"'\" {{print $1; exit}}')\"\n\
37+
PANE=\"$(tmux list-panes -t \"=$SESSION:$WINDOW\" -F '#{{pane_id}}\\t#{{pane_title}}' | awk -F '\\t' '$2==\"'\"$PANE_TITLE\"'\" {{print $1; exit}}')\"\n\
3838
if [ -z \"$PANE\" ]; then\n\
3939
if [ \"$CREATED\" = \"1\" ]; then\n\
40-
PANE=\"$(tmux list-panes -t \"$SESSION:$WINDOW\" -F '#{{pane_id}}' | head -n1)\"\n\
40+
PANE=\"$(tmux list-panes -t \"=$SESSION:$WINDOW\" -F '#{{pane_id}}' | head -n1)\"\n\
4141
else\n\
42-
PANE_COUNT=\"$(tmux list-panes -t \"$SESSION:$WINDOW\" -F '#{{pane_id}}' | wc -l | tr -d '[:space:]')\"\n\
42+
PANE_COUNT=\"$(tmux list-panes -t \"=$SESSION:$WINDOW\" -F '#{{pane_id}}' | wc -l | tr -d '[:space:]')\"\n\
4343
if [ \"$PANE_COUNT\" = \"1\" ]; then\n\
44-
PANE=\"$(tmux list-panes -t \"$SESSION:$WINDOW\" -F '#{{pane_id}}' | head -n1)\"\n\
44+
PANE=\"$(tmux list-panes -t \"=$SESSION:$WINDOW\" -F '#{{pane_id}}' | head -n1)\"\n\
4545
else\n\
46-
PANE=\"$(tmux split-window -d -P -F '#{{pane_id}}' -t \"$SESSION:$WINDOW\")\"\n\
46+
PANE=\"$(tmux split-window -d -P -F '#{{pane_id}}' -t \"=$SESSION:$WINDOW\")\"\n\
4747
CREATED=1\n\
4848
fi\n\
4949
fi\n\
@@ -73,8 +73,8 @@ fn mark_managed_tmux_entities_script(
7373
SESSION={session_q}\n\
7474
PANE={pane_q}\n\
7575
OWNER={owner_q}\n\
76-
tmux set-option -q -t \"$SESSION\" @buddy_managed 1\n\
77-
tmux set-option -q -t \"$SESSION\" @buddy_owner \"$OWNER\"\n\
76+
tmux set-option -q -t \"=$SESSION\" @buddy_managed 1\n\
77+
tmux set-option -q -t \"=$SESSION\" @buddy_owner \"$OWNER\"\n\
7878
tmux set-option -q -p -t \"$PANE\" @buddy_managed 1\n\
7979
tmux set-option -q -p -t \"$PANE\" @buddy_owner \"$OWNER\"\n"
8080
)
@@ -171,8 +171,9 @@ mod tests {
171171
assert!(script.contains("CREATED=0"));
172172
assert!(script.contains("CREATED=1"));
173173
assert!(script.contains("tmux new-session -d -s \"$SESSION\" -n \"$WINDOW\""));
174-
assert!(script.contains("tmux new-window -d -t \"$SESSION\" -n \"$WINDOW\""));
175-
assert!(script.contains("tmux split-window -d -P -F '#{pane_id}' -t \"$SESSION:$WINDOW\""));
174+
assert!(script.contains("tmux has-session -t \"=$SESSION\""));
175+
assert!(script.contains("tmux new-window -d -t \"=$SESSION\" -n \"$WINDOW\""));
176+
assert!(script.contains("tmux split-window -d -P -F '#{pane_id}' -t \"=$SESSION:$WINDOW\""));
176177
assert!(script.contains("tmux select-pane -t \"$PANE\" -T \"$PANE_TITLE\""));
177178
}
178179

0 commit comments

Comments
 (0)