@@ -16,6 +16,7 @@ pub(crate) enum NavigationRetry {
1616pub ( crate ) struct WorkspaceHandoff {
1717 boot_url : Url ,
1818 workspace_url : Url ,
19+ launch_workspace_url : Option < Url > ,
1920 last_workspace_url : Option < Url > ,
2021 retry : NavigationRetry ,
2122 pending : bool ,
@@ -25,9 +26,13 @@ pub(crate) struct WorkspaceHandoff {
2526impl WorkspaceHandoff {
2627 const RETRY_INTERVAL : Duration = Duration :: from_secs ( 2 ) ;
2728 pub ( crate ) fn new ( boot_url : Url , workspace_url : Url , retry : NavigationRetry ) -> Self {
29+ let mut root = workspace_url. clone ( ) ;
30+ root. set_query ( None ) ;
31+ root. set_fragment ( None ) ;
2832 Self {
2933 boot_url,
30- workspace_url,
34+ workspace_url : root,
35+ launch_workspace_url : Some ( workspace_url) ,
3136 last_workspace_url : None ,
3237 retry,
3338 pending : false ,
@@ -36,10 +41,21 @@ impl WorkspaceHandoff {
3641 }
3742 pub ( crate ) fn reconnect ( & mut self ) {
3843 // Explicit runtime repair retains its established workspace-root handoff.
44+ self . launch_workspace_url = None ;
3945 self . last_workspace_url = None ;
4046 self . pending = true ;
4147 self . last_attempt = None ;
4248 }
49+ pub ( crate ) fn services_ready ( & mut self ) {
50+ // A normal launch consumes the saved selection once. Explicit runtime
51+ // repair still returns to the root; it must not replay an old selection.
52+ let launch = self . launch_workspace_url . take ( ) ;
53+ self . reconnect ( ) ;
54+ self . last_workspace_url = launch;
55+ }
56+ pub ( crate ) fn origin ( & self ) -> & Url {
57+ & self . workspace_url
58+ }
4359 pub ( crate ) fn page_reached ( & mut self , current : & Url ) {
4460 if current. origin ( ) == self . workspace_url . origin ( ) {
4561 self . last_workspace_url = Some ( current. clone ( ) ) ;
@@ -128,6 +144,26 @@ pub(crate) fn content_lost(webview: &tauri::Webview) {
128144mod tests {
129145 use super :: * ;
130146 #[ test]
147+ fn normal_launch_resumes_once_but_explicit_repair_keeps_its_root_handoff ( ) {
148+ let launch: Url = "http://127.0.0.1:49123/chat/?goalId=example&view=tasks"
149+ . parse ( )
150+ . unwrap ( ) ;
151+ let root: Url = "http://127.0.0.1:49123/chat/" . parse ( ) . unwrap ( ) ;
152+ let mut h = WorkspaceHandoff :: new (
153+ "tauri://localhost/" . parse ( ) . unwrap ( ) ,
154+ launch. clone ( ) ,
155+ NavigationRetry :: UntilNativeCommit ,
156+ ) ;
157+ assert ! ( !h. needs_navigation( Instant :: now( ) ) ) ;
158+ h. services_ready ( ) ;
159+ assert_eq ! ( h. destination( ) , & launch) ;
160+ h. page_reached ( & launch) ;
161+ h. reconnect ( ) ;
162+ assert_eq ! ( h. destination( ) , & root) ;
163+ h. services_ready ( ) ;
164+ assert_eq ! ( h. destination( ) , & root) ;
165+ }
166+ #[ test]
131167 fn failed_workspace_load_retries_until_a_native_commit ( ) {
132168 let boot: Url = "tauri://localhost/" . parse ( ) . unwrap ( ) ;
133169 let target: Url = "http://127.0.0.1:8767/chat/" . parse ( ) . unwrap ( ) ;
0 commit comments