@@ -235,15 +235,17 @@ impl FfiHost {
235235 environment : Vec < ( String , String ) > ,
236236 args : Vec < String > ,
237237 ) -> Result < Self , Error > {
238- let entrypoint = std:: fs:: canonicalize ( entrypoint) . map_err ( |e| {
239- Error :: with_message (
240- ErrorKind :: InvalidConfig ,
241- format ! (
242- "failed to resolve in-process CLI entrypoint '{}': {e}" ,
243- entrypoint. display( )
244- ) ,
245- )
246- } ) ?;
238+ let entrypoint = std:: fs:: canonicalize ( entrypoint)
239+ . map ( path_for_child_process)
240+ . map_err ( |e| {
241+ Error :: with_message (
242+ ErrorKind :: InvalidConfig ,
243+ format ! (
244+ "failed to resolve in-process CLI entrypoint '{}': {e}" ,
245+ entrypoint. display( )
246+ ) ,
247+ )
248+ } ) ?;
247249 let library_path =
248250 std:: fs:: canonicalize ( resolve_library_path ( & entrypoint) ?) . map_err ( |e| {
249251 Error :: with_message (
@@ -491,6 +493,33 @@ fn resolve_library_path(entrypoint: &Path) -> Result<PathBuf, Error> {
491493 ) )
492494}
493495
496+ #[ cfg( windows) ]
497+ fn path_for_child_process ( path : PathBuf ) -> PathBuf {
498+ use std:: ffi:: OsString ;
499+ use std:: os:: windows:: ffi:: { OsStrExt , OsStringExt } ;
500+
501+ const VERBATIM_PREFIX : & [ u16 ] = & [ b'\\' as u16 , b'\\' as u16 , b'?' as u16 , b'\\' as u16 ] ;
502+ const UNC_PREFIX : & [ u16 ] = & [ b'U' as u16 , b'N' as u16 , b'C' as u16 , b'\\' as u16 ] ;
503+
504+ let encoded: Vec < u16 > = path. as_os_str ( ) . encode_wide ( ) . collect ( ) ;
505+ let Some ( stripped) = encoded. strip_prefix ( VERBATIM_PREFIX ) else {
506+ return path;
507+ } ;
508+ let normalized = if let Some ( unc_path) = stripped. strip_prefix ( UNC_PREFIX ) {
509+ let mut result = vec ! [ b'\\' as u16 , b'\\' as u16 ] ;
510+ result. extend_from_slice ( unc_path) ;
511+ result
512+ } else {
513+ stripped. to_vec ( )
514+ } ;
515+ PathBuf :: from ( OsString :: from_wide ( & normalized) )
516+ }
517+
518+ #[ cfg( not( windows) ) ]
519+ fn path_for_child_process ( path : PathBuf ) -> PathBuf {
520+ path
521+ }
522+
494523fn build_argv_json ( entrypoint : & Path , extra_args : & [ String ] ) -> Vec < u8 > {
495524 // A `.js` entrypoint (dev / dist-cli) is launched via node; the packaged
496525 // single-file CLI binary embeds its own Node and is invoked directly.
@@ -563,6 +592,19 @@ mod tests {
563592 ) ;
564593 }
565594
595+ #[ cfg( windows) ]
596+ #[ test]
597+ fn child_process_path_removes_windows_verbatim_prefix ( ) {
598+ assert_eq ! (
599+ path_for_child_process( PathBuf :: from( r"\\?\D:\a\copilot-sdk\index.js" ) ) ,
600+ PathBuf :: from( r"D:\a\copilot-sdk\index.js" )
601+ ) ;
602+ assert_eq ! (
603+ path_for_child_process( PathBuf :: from( r"\\?\UNC\server\share\copilot-sdk\index.js" ) ) ,
604+ PathBuf :: from( r"\\server\share\copilot-sdk\index.js" )
605+ ) ;
606+ }
607+
566608 #[ test]
567609 fn environment_is_omitted_when_empty ( ) {
568610 assert_eq ! ( build_env_json( & [ ] ) , None ) ;
0 commit comments