@@ -7,9 +7,10 @@ import {
77 downloadBinary ,
88 fetchLatestVersion ,
99 getArchitecture ,
10- getBinaryPath ,
1110 getOperatingSystem ,
12- installBinary ,
11+ getRemoveOldBinaryCommand ,
12+ installWithMigration ,
13+ type MigrationResult ,
1314 restartApplication ,
1415} from "@/lib/update.ts" ;
1516import { Message } from "./common/Message.tsx" ;
@@ -30,6 +31,7 @@ type UpdateState =
3031 | "downloading"
3132 | "installing"
3233 | "complete"
34+ | "migrated"
3335 | "error" ;
3436
3537type UpdateAction = "update" | "remind" | "skip" ;
@@ -66,6 +68,7 @@ export function UpdatePrompt({
6668 const [ downloadedBytes , setDownloadedBytes ] = useState < number > ( 0 ) ;
6769 const [ totalBytes , setTotalBytes ] = useState < number > ( 0 ) ;
6870 const [ updatePerformed , setUpdatePerformed ] = useState < boolean > ( false ) ;
71+ const [ migrationResult , setMigrationResult ] = useState < MigrationResult | null > ( null ) ;
6972
7073 useEffect ( ( ) => {
7174 const checkForUpdates = async ( ) => {
@@ -82,13 +85,15 @@ export function UpdatePrompt({
8285 if ( comparison <= 0 ) {
8386 const currentConfig = loadConfig ( ) ;
8487 currentConfig . skipVersion = undefined ;
88+
8589 saveConfig ( currentConfig ) ;
8690 setState ( "up_to_date" ) ;
8791 } else {
8892 setState ( "update_available" ) ;
8993 }
9094 } catch ( err ) {
9195 const errorMessage = err instanceof Error ? err . message : String ( err ) ;
96+
9297 setError ( errorMessage ) ;
9398 setState ( "error" ) ;
9499 }
@@ -101,15 +106,19 @@ export function UpdatePrompt({
101106 switch ( item . value ) {
102107 case "update" :
103108 await performUpdate ( ) ;
109+
104110 break ;
105111 case "skip" :
106112 if ( latestVersion ) {
107113 skipVersion ( latestVersion ) ;
108114 }
115+
109116 setState ( "complete" ) ;
117+
110118 break ;
111119 case "remind" :
112120 setState ( "complete" ) ;
121+
113122 break ;
114123 }
115124 } ;
@@ -135,11 +144,16 @@ export function UpdatePrompt({
135144 ) ;
136145
137146 setState ( "installing" ) ;
138- const targetPath = getBinaryPath ( ) ;
139- await installBinary ( binaryData , targetPath ) ;
147+ const result = await installWithMigration ( binaryData ) ;
148+ setMigrationResult ( result ) ;
140149
141150 setUpdatePerformed ( true ) ;
142- setState ( "complete" ) ;
151+
152+ if ( result . migrated ) {
153+ setState ( "migrated" ) ;
154+ } else {
155+ setState ( "complete" ) ;
156+ }
143157 } catch ( err ) {
144158 const errorMessage = err instanceof Error ? err . message : String ( err ) ;
145159 setError ( errorMessage ) ;
@@ -150,15 +164,18 @@ export function UpdatePrompt({
150164 useEffect ( ( ) => {
151165 if ( state === "complete" || state === "up_to_date" || state === "error" ) {
152166 const timeout = setTimeout ( ( ) => {
153- if ( state === "complete" && updatePerformed ) {
167+ if ( state === "complete" && updatePerformed && migrationResult ) {
168+ restartApplication ( migrationResult . newPath ) ;
169+ } else if ( state === "complete" && updatePerformed ) {
154170 restartApplication ( ) ;
155171 } else {
156172 handleExit ( ) ;
157173 }
158174 } , 2000 ) ;
175+
159176 return ( ) => clearTimeout ( timeout ) ;
160177 }
161- } , [ state , handleExit , updatePerformed ] ) ;
178+ } , [ state , handleExit , updatePerformed , migrationResult ] ) ;
162179
163180 const renderContent = ( ) => {
164181 switch ( state ) {
@@ -207,6 +224,40 @@ export function UpdatePrompt({
207224 case "installing" :
208225 return < Spinner label = "Installing..." /> ;
209226
227+ case "migrated" :
228+ return (
229+ < Box flexDirection = "column" gap = { 1 } >
230+ < Message type = "success" > Ralph updated successfully to { latestVersion } !</ Message >
231+ < Box flexDirection = "column" marginTop = { 1 } >
232+ < Text color = "yellow" bold >
233+ Installation location has changed
234+ </ Text >
235+ < Text > Ralph has been moved to: { migrationResult ?. newPath } </ Text >
236+ </ Box >
237+ { migrationResult ?. shellConfigPath && (
238+ < Box flexDirection = "column" marginTop = { 1 } >
239+ < Text > PATH has been updated in: { migrationResult . shellConfigPath } </ Text >
240+ < Text dimColor >
241+ Restart your terminal or run: source { migrationResult . shellConfigPath }
242+ </ Text >
243+ </ Box >
244+ ) }
245+ { migrationResult ?. oldPath && (
246+ < Box flexDirection = "column" marginTop = { 1 } >
247+ < Text color = "yellow" > Please remove the old installation:</ Text >
248+ < Box marginTop = { 1 } >
249+ < Text color = "cyan" bold >
250+ { getRemoveOldBinaryCommand ( migrationResult . oldPath ) }
251+ </ Text >
252+ </ Box >
253+ </ Box >
254+ ) }
255+ < Box marginTop = { 1 } >
256+ < Text dimColor > Press Ctrl+C to exit, then restart your terminal.</ Text >
257+ </ Box >
258+ </ Box >
259+ ) ;
260+
210261 case "complete" :
211262 return (
212263 < Box flexDirection = "column" gap = { 1 } >
0 commit comments