@@ -5,13 +5,15 @@ use rustix::fs::{
55 FlockOperation ,
66 flock,
77} ;
8+ use serde_json:: Value ;
89use tokio:: fs;
910use tracing:: debug;
1011
1112const KIRO_MIGRATION_KEY : & str = "migration.kiro.completed" ;
12- const MIGRATION_TIMEOUT_SECS : u64 = 10 ;
13+ const MIGRATION_TIMEOUT_SECS : u64 = 60 ;
1314
1415pub async fn migrate_if_needed ( ) -> Result < bool > {
16+ let start = std:: time:: Instant :: now ( ) ;
1517 let status = detect_migration ( ) . await ?;
1618
1719 match status {
@@ -54,7 +56,7 @@ pub async fn migrate_if_needed() -> Result<bool> {
5456 debug ! ( "Marking migration as completed" ) ;
5557 mark_migration_completed ( ) ?;
5658
57- debug ! ( "Migration completed successfully" ) ;
59+ debug ! ( "Migration completed successfully in {:?}" , start . elapsed ( ) ) ;
5860 Ok ( true )
5961}
6062
@@ -116,6 +118,106 @@ async fn copy_essential_files(src: &std::path::Path, dst: &std::path::Path) -> R
116118 }
117119 }
118120
121+ // Copy global files from home directory
122+ copy_global_config_files ( ) ?;
123+
124+ Ok ( ( ) )
125+ }
126+
127+ fn copy_global_config_files ( ) -> Result < ( ) > {
128+ let home_dir = fig_util:: directories:: home_dir ( ) ?;
129+ let kiro_dir = home_dir. join ( ".kiro" ) ;
130+ let legacy_amazonq_dir = home_dir. join ( ".aws/amazonq" ) ;
131+
132+ let src_dir = if legacy_amazonq_dir. exists ( ) {
133+ & legacy_amazonq_dir
134+ } else {
135+ return Ok ( ( ) ) ;
136+ } ;
137+
138+ // Use fig_data_dir for knowledge_bases and cli-checkouts
139+ let data_dir = fig_util:: directories:: fig_data_dir ( ) ?;
140+
141+ let files_to_copy = [
142+ // copy to home/.kiro
143+ ( "cli-agents" , kiro_dir. join ( "agents" ) ) ,
144+ ( "prompts" , kiro_dir. join ( "prompts" ) ) ,
145+ ( ".cli_bash_history" , kiro_dir. join ( ".cli_bash_history" ) ) ,
146+ // copy to data-dir
147+ ( "cli-checkouts" , data_dir. join ( "cli-checkouts" ) ) ,
148+ ( "knowledge_bases" , data_dir. join ( "knowledge_bases" ) ) ,
149+ ] ;
150+
151+ for ( src_subpath, dst_path) in files_to_copy {
152+ let src_path = src_dir. join ( src_subpath) ;
153+
154+ if src_path. exists ( ) {
155+ if let Some ( parent) = dst_path. parent ( ) {
156+ std:: fs:: create_dir_all ( parent) ?;
157+ }
158+
159+ if src_path. is_dir ( ) {
160+ debug ! ( "Copying directory {} to {}" , src_path. display( ) , dst_path. display( ) ) ;
161+ dircpy:: copy_dir ( & src_path, & dst_path) ?;
162+ } else {
163+ debug ! ( "Copying file {} to {}" , src_path. display( ) , dst_path. display( ) ) ;
164+ std:: fs:: copy ( & src_path, & dst_path) ?;
165+ }
166+ }
167+ }
168+
169+ // Handle mcp.json separately with merging
170+ let src_mcp = src_dir. join ( "mcp.json" ) ;
171+ let dst_mcp = kiro_dir. join ( "settings/mcp.json" ) ;
172+ if src_mcp. exists ( ) {
173+ merge_mcp_json ( & src_mcp, & dst_mcp) ?;
174+ }
175+
176+ Ok ( ( ) )
177+ }
178+
179+ fn merge_mcp_json ( src_path : & std:: path:: Path , dst_path : & std:: path:: Path ) -> Result < ( ) > {
180+ if let Some ( parent) = dst_path. parent ( ) {
181+ std:: fs:: create_dir_all ( parent) ?;
182+ }
183+
184+ let src_content = std:: fs:: read_to_string ( src_path) ?;
185+ let src_json = match serde_json:: from_str :: < Value > ( & src_content) {
186+ Ok ( json) => json,
187+ Err ( _) => {
188+ debug ! ( "Invalid JSON in source mcp.json, leaving destination unchanged" ) ;
189+ return Ok ( ( ) ) ;
190+ } ,
191+ } ;
192+
193+ let merged_json = if dst_path. exists ( ) {
194+ let dst_content = std:: fs:: read_to_string ( dst_path) ?;
195+ match serde_json:: from_str :: < Value > ( & dst_content) {
196+ Ok ( mut dst_json) => {
197+ if let ( Some ( src_servers) , Some ( dst_servers) ) = (
198+ src_json. get ( "mcpServers" ) . and_then ( |v| v. as_object ( ) ) ,
199+ dst_json. get_mut ( "mcpServers" ) . and_then ( |v| v. as_object_mut ( ) ) ,
200+ ) {
201+ for ( key, value) in src_servers {
202+ if !dst_servers. contains_key ( key) {
203+ dst_servers. insert ( key. clone ( ) , value. clone ( ) ) ;
204+ }
205+ }
206+ }
207+ dst_json
208+ } ,
209+ Err ( _) => {
210+ debug ! ( "Invalid JSON in destination mcp.json, overwriting with source" ) ;
211+ src_json
212+ } ,
213+ }
214+ } else {
215+ src_json
216+ } ;
217+
218+ let merged_content = serde_json:: to_string_pretty ( & merged_json) ?;
219+ std:: fs:: write ( dst_path, merged_content) ?;
220+ debug ! ( "Merged mcp.json to {}" , dst_path. display( ) ) ;
119221 Ok ( ( ) )
120222}
121223
0 commit comments