@@ -330,6 +330,9 @@ fn determine_agent_source(
330330 LaunchMode :: App { .. } | LaunchMode :: Test { .. } => {
331331 Some ( crate :: ai:: ambient_agents:: AgentSource :: CloudMode )
332332 }
333+ // Proxy and Daemon are headless server processes that don't use the
334+ // agent subsystem.
335+ LaunchMode :: Proxy | LaunchMode :: Daemon => None ,
333336 }
334337}
335338
@@ -359,13 +362,24 @@ pub enum LaunchMode {
359362 driver : Box < Option < TestDriver > > ,
360363 is_integration_test : bool ,
361364 } ,
365+
366+ /// Remote server proxy — bridges SSH stdio to the daemon's Unix socket.
367+ /// This is a short-lived process that runs for the lifetime of an SSH session.
368+ Proxy ,
369+
370+ /// Remote server daemon — long-lived headless process serving remote
371+ /// connections via a Unix domain socket.
372+ Daemon ,
362373}
363374
364375impl LaunchMode {
365376 fn args ( & self ) -> Cow < ' _ , warp_cli:: AppArgs > {
366377 match self {
367378 LaunchMode :: App { args, .. } => Cow :: Borrowed ( args) ,
368- _ => Cow :: Owned ( warp_cli:: AppArgs :: default ( ) ) ,
379+ LaunchMode :: CommandLine { .. }
380+ | LaunchMode :: Test { .. }
381+ | LaunchMode :: Proxy
382+ | LaunchMode :: Daemon => Cow :: Owned ( warp_cli:: AppArgs :: default ( ) ) ,
369383 }
370384 }
371385
@@ -376,14 +390,20 @@ impl LaunchMode {
376390 is_integration_test,
377391 ..
378392 } => * is_integration_test,
379- _ => false ,
393+ LaunchMode :: App { .. }
394+ | LaunchMode :: CommandLine { .. }
395+ | LaunchMode :: Proxy
396+ | LaunchMode :: Daemon => false ,
380397 }
381398 }
382399
383400 fn take_test_driver ( & mut self ) -> Option < TestDriver > {
384401 match self {
385402 LaunchMode :: Test { driver, .. } => driver. take ( ) ,
386- _ => None ,
403+ LaunchMode :: App { .. }
404+ | LaunchMode :: CommandLine { .. }
405+ | LaunchMode :: Proxy
406+ | LaunchMode :: Daemon => None ,
387407 }
388408 }
389409
@@ -400,13 +420,19 @@ impl LaunchMode {
400420 LaunchMode :: App { .. } => ExecutionMode :: App ,
401421 LaunchMode :: CommandLine { .. } => ExecutionMode :: Sdk ,
402422 LaunchMode :: Test { .. } => ExecutionMode :: App ,
423+ // Proxy and Daemon don't use execution mode, but Sdk is the
424+ // closest match (headless, no GUI).
425+ LaunchMode :: Proxy | LaunchMode :: Daemon => ExecutionMode :: Sdk ,
403426 }
404427 }
405428
406429 fn is_sandboxed ( & self ) -> bool {
407430 match self {
408431 LaunchMode :: CommandLine { is_sandboxed, .. } => * is_sandboxed,
409- _ => false ,
432+ LaunchMode :: App { .. }
433+ | LaunchMode :: Test { .. }
434+ | LaunchMode :: Proxy
435+ | LaunchMode :: Daemon => false ,
410436 }
411437 }
412438
@@ -417,7 +443,8 @@ impl LaunchMode {
417443 CliCommand :: Agent ( AgentCommand :: Run ( args) ) => !args. gui ,
418444 _ => true ,
419445 } ,
420- _ => false ,
446+ LaunchMode :: Proxy | LaunchMode :: Daemon => true ,
447+ LaunchMode :: App { .. } | LaunchMode :: Test { .. } => false ,
421448 }
422449 }
423450
@@ -427,7 +454,8 @@ impl LaunchMode {
427454 LaunchMode :: CommandLine { command, .. } => {
428455 matches ! ( command, CliCommand :: Agent ( AgentCommand :: Run { .. } ) )
429456 }
430- _ => true ,
457+ LaunchMode :: App { .. } | LaunchMode :: Test { .. } => true ,
458+ LaunchMode :: Proxy | LaunchMode :: Daemon => false ,
431459 }
432460 }
433461
@@ -436,8 +464,59 @@ impl LaunchMode {
436464 pub ( crate ) fn crash_recovery_enabled ( & self ) -> bool {
437465 match self {
438466 LaunchMode :: App { .. } => true ,
439- LaunchMode :: CommandLine { .. } => false ,
440- LaunchMode :: Test { .. } => false ,
467+ LaunchMode :: CommandLine { .. }
468+ | LaunchMode :: Test { .. }
469+ | LaunchMode :: Proxy
470+ | LaunchMode :: Daemon => false ,
471+ }
472+ }
473+
474+ /// Whether Sentry / crash reporting should be initialized in `init_common`.
475+ fn needs_crash_reporting ( & self ) -> bool {
476+ match self {
477+ LaunchMode :: App { .. } => true ,
478+ LaunchMode :: CommandLine { .. } => true ,
479+ LaunchMode :: Test { .. } => true ,
480+ LaunchMode :: Daemon => true ,
481+ LaunchMode :: Proxy => false ,
482+ }
483+ }
484+
485+ /// Whether profiling and tracing should be initialized in `init_common`.
486+ fn needs_profiling ( & self ) -> bool {
487+ match self {
488+ LaunchMode :: App { .. } => true ,
489+ LaunchMode :: CommandLine { .. } => true ,
490+ LaunchMode :: Test { .. } => true ,
491+ LaunchMode :: Daemon => true ,
492+ LaunchMode :: Proxy => false ,
493+ }
494+ }
495+
496+ /// Whether this is a CLI-like mode (logs to file/stderr, not stdout).
497+ fn is_cli_like ( & self ) -> bool {
498+ match self {
499+ LaunchMode :: App { .. } | LaunchMode :: Test { .. } => false ,
500+ LaunchMode :: CommandLine { .. }
501+ | LaunchMode :: Proxy
502+ | LaunchMode :: Daemon => true ,
503+ }
504+ }
505+
506+ /// Log destination for this mode.
507+ fn log_destination ( & self ) -> Option < LogDestination > {
508+ match self {
509+ LaunchMode :: CommandLine { debug, .. } => {
510+ if * debug {
511+ Some ( LogDestination :: Stderr )
512+ } else {
513+ Some ( LogDestination :: File )
514+ }
515+ }
516+ // Proxy must log to stderr because stdout is the protocol channel.
517+ LaunchMode :: Proxy => Some ( LogDestination :: Stderr ) ,
518+ LaunchMode :: Daemon => Some ( LogDestination :: File ) ,
519+ LaunchMode :: App { .. } | LaunchMode :: Test { .. } => None ,
441520 }
442521 }
443522
@@ -560,10 +639,12 @@ pub fn run() -> Result<()> {
560639 }
561640 #[ cfg( not( target_family = "wasm" ) ) ]
562641 warp_cli:: Command :: Worker ( warp_cli:: WorkerCommand :: RemoteServerProxy ) => {
642+ init_common ( & LaunchMode :: Proxy , None ) ?;
563643 return crate :: remote_server:: run_proxy ( ) ;
564644 }
565645 #[ cfg( not( target_family = "wasm" ) ) ]
566646 warp_cli:: Command :: Worker ( warp_cli:: WorkerCommand :: RemoteServerDaemon ) => {
647+ init_common ( & LaunchMode :: Daemon , None ) ?;
567648 return crate :: remote_server:: run_daemon ( ) ;
568649 }
569650 #[ cfg( not( target_family = "wasm" ) ) ]
@@ -657,43 +738,41 @@ pub fn run_integration_test(driver: TestDriver) -> Result<()> {
657738 run_internal ( launch)
658739}
659740
660- /// Runs the app.
661- fn run_internal ( mut launch_mode : LaunchMode ) -> Result < ( ) > {
741+ /// Shared early initialization for **every** process type (app, CLI, proxy,
742+ /// daemon). Every step in this function runs for all modes, including
743+ /// lightweight ones like Proxy. Think carefully before adding here — if
744+ /// the step is only needed by the full app, add it to `run_internal`
745+ /// instead.
746+ fn init_common (
747+ launch_mode : & LaunchMode ,
748+ timer : Option < & mut IntervalTimer > ,
749+ ) -> Result < ( ) > {
662750 #[ cfg( windows) ]
663751 dynamic_libraries:: configure_library_loading ( ) ;
664752
665- profiling:: init ( ) ;
753+ if launch_mode. needs_profiling ( ) {
754+ profiling:: init ( ) ;
755+ }
666756
667757 // The `run` function already initializes feature flags, but ensure they're initialized here
668758 // for other entrypoints.
669759 init_feature_flags ( ) ;
670760
671- let mut timer = IntervalTimer :: new ( ) ;
672-
673761 #[ cfg( feature = "crash_reporting" ) ]
674- {
762+ if launch_mode . needs_crash_reporting ( ) {
675763 // Ensure that the main/root Sentry hub is initialized on the main
676764 // thread. PtySpawner creates a background thread to receive logs from
677765 // the terminal server process, and we don't want it to be the host of
678766 // the primary sentry::Hub.
679767 sentry:: Hub :: main ( ) ;
680768 }
681769
682- tracing :: init ( ) ? ;
683-
684- let is_cli = matches ! ( launch_mode , LaunchMode :: CommandLine { .. } ) ;
770+ if launch_mode . needs_profiling ( ) {
771+ tracing :: init ( ) ? ;
772+ }
685773
686- // Log to a file for CLI commands to not obscure the command output.
687- let log_destination = match & launch_mode {
688- LaunchMode :: CommandLine { debug, .. } => {
689- if * debug {
690- Some ( LogDestination :: Stderr )
691- } else {
692- Some ( LogDestination :: File )
693- }
694- }
695- _ => None ,
696- } ;
774+ let is_cli = launch_mode. is_cli_like ( ) ;
775+ let log_destination = launch_mode. log_destination ( ) ;
697776
698777 cfg_if:: cfg_if! {
699778 if #[ cfg( enable_crash_recovery) ] {
@@ -707,13 +786,32 @@ fn run_internal(mut launch_mode: LaunchMode) -> Result<()> {
707786 }
708787 }
709788
710- timer. mark_interval_end ( "LOG_FILE_SETUP_COMPLETE" ) ;
789+ if let Some ( timer) = timer {
790+ timer. mark_interval_end ( "LOG_FILE_SETUP_COMPLETE" ) ;
791+ }
711792
712793 // Adjust resource limits early, before doing other work, to ensure that
713794 // any children we spawn (like the terminal server) inherit our adjusted
714795 // rlimits.
715796 resource_limits:: adjust_resource_limits ( ) ;
716797
798+ // Configure rustls to use its default crypto provider. This MUST be called
799+ // before making any network requests that use TLS, otherwise rustls will
800+ // panic.
801+ #[ cfg( not( target_family = "wasm" ) ) ]
802+ rustls:: crypto:: aws_lc_rs:: default_provider ( )
803+ . install_default ( )
804+ . expect ( "must be able to initialize crypto provider for TLS support" ) ;
805+
806+ Ok ( ( ) )
807+ }
808+
809+ /// Runs the app.
810+ fn run_internal ( mut launch_mode : LaunchMode ) -> Result < ( ) > {
811+ let mut timer = IntervalTimer :: new ( ) ;
812+
813+ init_common ( & launch_mode, Some ( & mut timer) ) ?;
814+
717815 // For wasm builds we have this special case to parse out the intent
718816 // from the url that is used to visite the app on web.
719817 #[ cfg( target_family = "wasm" ) ]
@@ -785,14 +883,6 @@ fn run_internal(mut launch_mode: LaunchMode) -> Result<()> {
785883 #[ cfg( windows) ]
786884 command:: windows:: init ( ) ;
787885
788- // Configure rustls to use its default crypto provider. This MUST be called
789- // before making any network requests that use TLS, otherwise rustls will
790- // panic.
791- #[ cfg( not( target_family = "wasm" ) ) ]
792- rustls:: crypto:: aws_lc_rs:: default_provider ( )
793- . install_default ( )
794- . expect ( "must be able to initialize crypto provider for TLS support" ) ;
795-
796886 let private_preferences = settings:: init_private_user_preferences ( ) ;
797887 let ( public_preferences, startup_toml_parse_error) = settings:: init_public_user_preferences ( ) ;
798888
@@ -2280,6 +2370,12 @@ fn launch(ctx: &mut warpui::AppContext, app_state: Option<AppState>, launch_mode
22802370 }
22812371 }
22822372 }
2373+ // Proxy and Daemon never go through run_internal / launch; they call
2374+ // init_common directly and then their own entry points.
2375+ LaunchMode :: Proxy | LaunchMode :: Daemon => {
2376+ log:: error!( "Proxy/Daemon modes should not use the launch() path" ) ;
2377+ std:: process:: exit ( 1 ) ;
2378+ }
22832379 }
22842380}
22852381
0 commit comments