@@ -35,85 +35,68 @@ pub fn run_with_tmux(file: &Path, tmux: &Tmux, pane: Option<&str>) -> Result<()>
3535 if updated_content != content {
3636 std:: fs:: write ( file, & updated_content)
3737 . with_context ( || format ! ( "failed to write {}" , file. display( ) ) ) ?;
38- eprintln ! ( "Generated session UUID: {}" , session_id) ;
38+ eprintln ! ( "[route] Generated session UUID: {}" , session_id) ;
3939 }
4040
41- // Compute the file path to send (relative to cwd)
4241 let file_path = file. to_string_lossy ( ) ;
43-
44- // Look up pane for this session
4542 let registered = sessions:: lookup ( & session_id) ?;
4643
44+ // Step 1: Check if registered pane is alive
4745 if let Some ( ref registered_pane) = registered {
4846 if tmux. pane_alive ( registered_pane) {
49- // Pane is alive — send the command
50- let command = format ! ( "/agent-doc {}" , file_path) ;
51- tmux. send_keys ( registered_pane, & command) ?;
52- if let Err ( e) = tmux. select_pane ( registered_pane) {
53- eprintln ! ( "warning: failed to focus pane {}: {}" , registered_pane, e) ;
54- }
55- eprintln ! ( "Sent /agent-doc {} → pane {}" , file_path, registered_pane) ;
56- return Ok ( ( ) ) ;
57- }
58- // Pane is dead — try lazy claim
59- let target_pane = pane
60- . map ( |p| p. to_string ( ) )
61- . or_else ( || tmux. active_pane ( TMUX_SESSION_NAME ) ) ;
62- if let Some ( new_pane) = target_pane
63- && tmux. pane_alive ( & new_pane)
64- {
65- eprintln ! (
66- "Pane {} is dead, lazy-claiming to pane {}" ,
67- registered_pane, new_pane
68- ) ;
69- sessions:: register ( & session_id, & new_pane, & file_path) ?;
70- let command = format ! ( "/agent-doc {}" , file_path) ;
71- tmux. send_keys ( & new_pane, & command) ?;
72- if let Err ( e) = tmux. select_pane ( & new_pane) {
73- eprintln ! ( "warning: failed to focus pane {}: {}" , new_pane, e) ;
74- }
75- eprintln ! ( "Sent /agent-doc {} → pane {}" , file_path, new_pane) ;
76- sync_after_claim ( tmux, & new_pane) ;
77- return Ok ( ( ) ) ;
47+ eprintln ! ( "[route] Pane {} is alive" , registered_pane) ;
48+ return send_command ( tmux, registered_pane, & file_path) ;
7849 }
79- eprintln ! ( "Pane {} is dead, auto-starting... " , registered_pane) ;
50+ eprintln ! ( "[route] Pane {} is dead" , registered_pane) ;
8051 } else {
81- // No registered pane — try lazy claim
82- let target_pane = pane
83- . map ( |p| p. to_string ( ) )
84- . or_else ( || tmux. active_pane ( TMUX_SESSION_NAME ) ) ;
85- if let Some ( new_pane) = target_pane
86- && tmux. pane_alive ( & new_pane)
87- {
88- eprintln ! (
89- "No pane registered for session {}, lazy-claiming to pane {}" ,
90- & session_id[ ..std:: cmp:: min( 8 , session_id. len( ) ) ] ,
91- new_pane
92- ) ;
93- sessions:: register ( & session_id, & new_pane, & file_path) ?;
94- let command = format ! ( "/agent-doc {}" , file_path) ;
95- tmux. send_keys ( & new_pane, & command) ?;
96- if let Err ( e) = tmux. select_pane ( & new_pane) {
97- eprintln ! ( "warning: failed to focus pane {}: {}" , new_pane, e) ;
98- }
99- eprintln ! ( "Sent /agent-doc {} → pane {}" , file_path, new_pane) ;
100- sync_after_claim ( tmux, & new_pane) ;
101- return Ok ( ( ) ) ;
102- }
10352 eprintln ! (
104- "No pane registered for session {}, auto-starting... " ,
53+ "[route] No pane registered for session {}" ,
10554 & session_id[ ..std:: cmp:: min( 8 , session_id. len( ) ) ]
10655 ) ;
10756 }
10857
109- // Auto-start cascade (can be disabled for testing)
58+ // Step 2: Try lazy claim to an active pane
59+ if let Some ( new_pane) = find_target_pane ( tmux, pane) {
60+ let reason = if registered. is_some ( ) {
61+ "dead pane"
62+ } else {
63+ "no registration"
64+ } ;
65+ eprintln ! ( "[route] Lazy-claiming to pane {} ({})" , new_pane, reason) ;
66+ sessions:: register ( & session_id, & new_pane, & file_path) ?;
67+ send_command ( tmux, & new_pane, & file_path) ?;
68+ sync_after_claim ( tmux, & new_pane) ;
69+ return Ok ( ( ) ) ;
70+ }
71+
72+ // Step 3: Auto-start a new Claude session
73+ eprintln ! ( "[route] No active pane found, auto-starting..." ) ;
11074 if std:: env:: var ( "AGENT_DOC_NO_AUTOSTART" ) . is_ok ( ) {
11175 anyhow:: bail!( "auto-start skipped (AGENT_DOC_NO_AUTOSTART set)" ) ;
11276 }
11377 auto_start ( tmux, file, & session_id, & file_path) ?;
11478 Ok ( ( ) )
11579}
11680
81+ /// Send `/agent-doc <file>` to a pane and focus it.
82+ fn send_command ( tmux : & Tmux , pane : & str , file_path : & str ) -> Result < ( ) > {
83+ let command = format ! ( "/agent-doc {}" , file_path) ;
84+ tmux. send_keys ( pane, & command) ?;
85+ if let Err ( e) = tmux. select_pane ( pane) {
86+ eprintln ! ( "[route] warning: failed to focus pane {}: {}" , pane, e) ;
87+ }
88+ eprintln ! ( "[route] Sent /agent-doc {} → pane {}" , file_path, pane) ;
89+ Ok ( ( ) )
90+ }
91+
92+ /// Find an active target pane for lazy claiming.
93+ fn find_target_pane ( tmux : & Tmux , explicit_pane : Option < & str > ) -> Option < String > {
94+ let target = explicit_pane
95+ . map ( |p| p. to_string ( ) )
96+ . or_else ( || tmux. active_pane ( TMUX_SESSION_NAME ) ) ;
97+ target. filter ( |p| tmux. pane_alive ( p) )
98+ }
99+
117100/// Auto-start a new Claude session in tmux.
118101///
119102/// Cascade:
@@ -138,7 +121,7 @@ fn auto_start(tmux: &Tmux, file: &Path, session_id: &str, file_path: &str) -> Re
138121 && active != new_pane
139122 && let Err ( e) = tmux. join_pane ( & new_pane, & active, "-dh" )
140123 {
141- eprintln ! ( "warning: join_pane failed ({} → {}): {}" , new_pane, active, e) ;
124+ eprintln ! ( "[route] warning: join_pane failed ({} → {}): {}" , new_pane, active, e) ;
142125 }
143126
144127 // Register immediately so subsequent route calls find this pane
@@ -149,13 +132,13 @@ fn auto_start(tmux: &Tmux, file: &Path, session_id: &str, file_path: &str) -> Re
149132 tmux. send_keys ( & new_pane, & start_cmd) ?;
150133
151134 eprintln ! (
152- "Started Claude for {} in pane {} (session {})" ,
135+ "[route] Started Claude for {} in pane {} (session {})" ,
153136 file_path,
154137 new_pane,
155138 & session_id[ ..std:: cmp:: min( 8 , session_id. len( ) ) ]
156139 ) ;
157140 eprintln ! (
158- "Wait for Claude to start, then run `agent-doc route {}` again to send the command." ,
141+ "[route] Wait for Claude to start, then run `agent-doc route {}` again to send the command." ,
159142 file_path
160143 ) ;
161144
@@ -191,14 +174,14 @@ fn sync_after_claim(tmux: &Tmux, pane_id: &str) {
191174 . collect ( ) ;
192175
193176 if window_files. len ( ) < 2 {
194- return ; // Single file — no layout sync needed
177+ return ; // 0 or 1 files — no layout sync needed
195178 }
196179
197180 // Call sync with all files as a single column
198181 let col_args = vec ! [ window_files. join( "," ) ] ;
199182 if let Err ( e) = sync:: run ( & col_args, Some ( & window_id) , None ) {
200- eprintln ! ( "warning: post-claim sync failed: {}" , e) ;
183+ eprintln ! ( "[route] warning: post-claim sync failed: {}" , e) ;
201184 } else {
202- eprintln ! ( "Auto-synced {} files in window {}" , window_files. len( ) , window_id) ;
185+ eprintln ! ( "[route] Auto-synced {} files in window {}" , window_files. len( ) , window_id) ;
203186 }
204187}
0 commit comments