@@ -167,6 +167,59 @@ fn call_binary_server_tool_then_health(
167167 )
168168}
169169
170+ fn call_binary_server_tools (
171+ current_dir : & Path ,
172+ initialize_params : Value ,
173+ tool_calls : Vec < ( & str , Value ) > ,
174+ settle_ms : u64 ,
175+ ) -> Vec < Value > {
176+ let exe = server_binary ( ) ;
177+ let mut command = Command :: new ( & exe) ;
178+ command
179+ . current_dir ( current_dir)
180+ . stdin ( Stdio :: piped ( ) )
181+ . stdout ( Stdio :: piped ( ) )
182+ . stderr ( Stdio :: piped ( ) ) ;
183+ let mut child = command. spawn ( ) . unwrap ( ) ;
184+
185+ {
186+ let stdin = child. stdin . as_mut ( ) . unwrap ( ) ;
187+ writeln ! (
188+ stdin,
189+ "{}" ,
190+ json!( { "jsonrpc" : "2.0" , "id" : 1 , "method" : "initialize" , "params" : initialize_params} )
191+ )
192+ . unwrap ( ) ;
193+ writeln ! (
194+ stdin,
195+ "{}" ,
196+ json!( { "jsonrpc" : "2.0" , "method" : "notifications/initialized" } )
197+ )
198+ . unwrap ( ) ;
199+ stdin. flush ( ) . unwrap ( ) ;
200+ thread:: sleep ( Duration :: from_millis ( settle_ms) ) ;
201+
202+ for ( index, ( tool_name, tool_arguments) ) in tool_calls. into_iter ( ) . enumerate ( ) {
203+ writeln ! (
204+ stdin,
205+ "{}" ,
206+ json!( { "jsonrpc" : "2.0" , "id" : index + 2 , "method" : "tools/call" , "params" : { "name" : tool_name, "arguments" : tool_arguments} } )
207+ )
208+ . unwrap ( ) ;
209+ }
210+ }
211+
212+ let output = child. wait_with_output ( ) . unwrap ( ) ;
213+ let stdout = String :: from_utf8 ( output. stdout ) . unwrap ( ) ;
214+ stdout
215+ . lines ( )
216+ . filter ( |line| line. trim_start ( ) . starts_with ( '{' ) )
217+ . filter_map ( |line| serde_json:: from_str :: < Value > ( line) . ok ( ) )
218+ . filter ( |response| response. get ( "id" ) . and_then ( |v| v. as_i64 ( ) ) . unwrap_or ( 0 ) >= 2 )
219+ . map ( |response| decode_tool_rpc_response ( & response) )
220+ . collect ( )
221+ }
222+
170223fn decode_tool_rpc_response ( rpc : & Value ) -> Value {
171224 serde_json:: from_str (
172225 rpc. get ( "result" )
@@ -524,6 +577,69 @@ fn test_tool_call_auto_indexes_workspace_from_request_path() {
524577 ) ;
525578}
526579
580+ #[ test]
581+ fn test_relative_paths_can_target_sibling_workspace_after_active_child_changes ( ) {
582+ let current_dir = tempdir ( ) . unwrap ( ) ;
583+ let workspace = tempdir ( ) . unwrap ( ) ;
584+ let api_dir = workspace. path ( ) . join ( "workboardapi" ) ;
585+ let ui_dir = workspace. path ( ) . join ( "workboardui" ) ;
586+ let api_search_dir = api_dir. join ( "src/redmine-sync" ) ;
587+ let ui_search_dir = ui_dir. join ( "src/app/features/task-current" ) ;
588+ fs:: create_dir_all ( & api_search_dir) . unwrap ( ) ;
589+ fs:: create_dir_all ( & ui_search_dir) . unwrap ( ) ;
590+ fs:: write (
591+ api_dir. join ( "Cargo.toml" ) ,
592+ "[package]\n name = \" api\" \n version = \" 0.1.0\" \n " ,
593+ )
594+ . unwrap ( ) ;
595+ fs:: write ( ui_dir. join ( "package.json" ) , "{\" name\" :\" ui\" }\n " ) . unwrap ( ) ;
596+ fs:: write ( api_search_dir. join ( "import.rs" ) , "fn basicImport() {}\n " ) . unwrap ( ) ;
597+ fs:: write (
598+ ui_search_dir. join ( "import.ts" ) ,
599+ "export const basicImport = true;\n " ,
600+ )
601+ . unwrap ( ) ;
602+
603+ let responses = call_binary_server_tools (
604+ current_dir. path ( ) ,
605+ json ! ( {
606+ "workspaceFolders" : [
607+ { "uri" : file_uri_for_test( workspace. path( ) ) }
608+ ]
609+ } ) ,
610+ vec ! [
611+ ( "resolve_path" , json!( { "path" : api_dir. to_str( ) . unwrap( ) } ) ) ,
612+ (
613+ "text_search" ,
614+ json!( {
615+ "paths" : [
616+ "workboardapi/src/redmine-sync" ,
617+ "workboardui/src/app/features/task-current"
618+ ] ,
619+ "query" : "basicImport" ,
620+ "max_results" : 50 ,
621+ "context_lines" : 2
622+ } ) ,
623+ ) ,
624+ ] ,
625+ 300 ,
626+ ) ;
627+
628+ let text_search_result = responses. last ( ) . unwrap ( ) ;
629+ assert_eq ! (
630+ text_search_result
631+ . get( "total_returned" )
632+ . and_then( |v| v. as_u64( ) ) ,
633+ Some ( 2 )
634+ ) ;
635+ assert_eq ! (
636+ text_search_result
637+ . get( "files_searched" )
638+ . and_then( |v| v. as_u64( ) ) ,
639+ Some ( 2 )
640+ ) ;
641+ }
642+
527643#[ test]
528644fn test_tool_call_switches_active_workspace_context ( ) {
529645 let current_dir = tempdir ( ) . unwrap ( ) ;
0 commit comments