@@ -122,6 +122,11 @@ fn build_cli(registry: &Registry, external_clis: &[ExternalCli]) -> Command {
122122 . arg ( Arg :: new ( "site" ) . long ( "site" ) . help ( "Override site name" ) )
123123 . arg ( Arg :: new ( "ai" ) . long ( "ai" ) . action ( ArgAction :: SetTrue ) . help ( "Use AI (LLM) to analyze and generate adapter (requires ~/.opencli-rs/config.json)" ) ) ,
124124 )
125+ . subcommand (
126+ Command :: new ( "search" )
127+ . about ( "Search for existing adapters on autocli.ai" )
128+ . arg ( Arg :: new ( "url" ) . required ( true ) . help ( "URL to search adapters for" ) ) ,
129+ )
125130 . subcommand (
126131 Command :: new ( "auth" )
127132 . about ( "Authenticate with AutoCLI" ) ,
@@ -364,6 +369,84 @@ async fn main() {
364369 completion:: run_completion ( & mut app, shell) ;
365370 return ;
366371 }
372+ "search" => {
373+ let raw_url = site_matches. get_one :: < String > ( "url" ) . unwrap ( ) ;
374+ let url = if raw_url. starts_with ( "http://" ) || raw_url. starts_with ( "https://" ) {
375+ raw_url. clone ( )
376+ } else {
377+ format ! ( "https://{}" , raw_url)
378+ } ;
379+ let config = opencli_rs_ai:: load_config ( ) ;
380+ let token = match & config. autocli_token {
381+ Some ( t) => t. clone ( ) ,
382+ None => {
383+ eprintln ! ( "{}" , t( "❌ 未认证,请先运行: opencli-rs auth" , "❌ Not authenticated. Run first: opencli-rs auth" ) ) ;
384+ std:: process:: exit ( 1 ) ;
385+ }
386+ } ;
387+
388+ match search_existing_adapters ( & url, & token) . await {
389+ Ok ( matches) if !matches. is_empty ( ) => {
390+ let options: Vec < String > = matches. iter ( ) . map ( |m| {
391+ let tag = match m. match_type . as_str ( ) {
392+ "exact" => "[exact] " ,
393+ "partial" => "[partial]" ,
394+ "domain" => "[domain] " ,
395+ _ => "[other] " ,
396+ } ;
397+ let desc = if m. description . is_empty ( ) {
398+ String :: new ( )
399+ } else {
400+ format ! ( " - {}" , m. description)
401+ } ;
402+ let author = if m. author . is_empty ( ) {
403+ String :: new ( )
404+ } else {
405+ format ! ( " (by {})" , m. author)
406+ } ;
407+ format ! ( "{} {} {}{}{}" , tag, m. site_name, m. cmd_name, author, desc)
408+ } ) . collect ( ) ;
409+
410+ let selection = inquire:: Select :: new (
411+ t ( "找到以下配置,请选择:" , "Adapters found, please select:" ) ,
412+ options,
413+ ) . prompt ( ) ;
414+
415+ match selection {
416+ Ok ( chosen) => {
417+ let idx = matches. iter ( ) . position ( |m| {
418+ chosen. contains ( & m. cmd_name ) && chosen. contains ( & m. site_name )
419+ } ) ;
420+ if let Some ( i) = idx {
421+ let m = & matches[ i] ;
422+ let yaml_site = m. config . lines ( )
423+ . find ( |l| l. starts_with ( "site:" ) )
424+ . and_then ( |l| l. strip_prefix ( "site:" ) )
425+ . map ( |s| s. trim ( ) . trim_matches ( '"' ) . to_string ( ) )
426+ . unwrap_or_else ( || m. site_name . clone ( ) ) ;
427+ let yaml_name = m. config . lines ( )
428+ . find ( |l| l. starts_with ( "name:" ) )
429+ . and_then ( |l| l. strip_prefix ( "name:" ) )
430+ . map ( |s| s. trim ( ) . trim_matches ( '"' ) . to_string ( ) )
431+ . unwrap_or_else ( || m. cmd_name . clone ( ) ) ;
432+ save_adapter ( & yaml_site, & yaml_name, & m. config ) ;
433+ }
434+ }
435+ Err ( _) => {
436+ eprintln ! ( "{}" , t( "已取消" , "Cancelled" ) ) ;
437+ }
438+ }
439+ }
440+ Ok ( _) => {
441+ eprintln ! ( "{}" , t( "📭 未找到匹配的配置" , "📭 No matching adapters found" ) ) ;
442+ }
443+ Err ( e) => {
444+ eprintln ! ( "{}" , e) ;
445+ std:: process:: exit ( 1 ) ;
446+ }
447+ }
448+ return ;
449+ }
367450 "auth" => {
368451 // Open browser to get token
369452 let token_url = "https://autocli.ai/get-token" ;
@@ -577,7 +660,18 @@ async fn main() {
577660 } ) ;
578661 if let Some ( i) = idx {
579662 let m = & matches[ i] ;
580- save_adapter ( & m. site_name , & m. cmd_name , & m. config ) ;
663+ // Extract site and name from YAML config content, not server's display name
664+ let yaml_site = m. config . lines ( )
665+ . find ( |l| l. starts_with ( "site:" ) )
666+ . and_then ( |l| l. strip_prefix ( "site:" ) )
667+ . map ( |s| s. trim ( ) . trim_matches ( '"' ) . to_string ( ) )
668+ . unwrap_or_else ( || m. site_name . clone ( ) ) ;
669+ let yaml_name = m. config . lines ( )
670+ . find ( |l| l. starts_with ( "name:" ) )
671+ . and_then ( |l| l. strip_prefix ( "name:" ) )
672+ . map ( |s| s. trim ( ) . trim_matches ( '"' ) . to_string ( ) )
673+ . unwrap_or_else ( || m. cmd_name . clone ( ) ) ;
674+ save_adapter ( & yaml_site, & yaml_name, & m. config ) ;
581675 let _ = page. close ( ) . await ;
582676 return ;
583677 } else {
0 commit comments