@@ -139,8 +139,9 @@ async fn run_wizard(app: &AppContext, args: InitArgs) -> Result<()> {
139139 ) ) ;
140140 }
141141 output. line ( format ! (
142- "\n Found {} git repo(s) " ,
142+ "\n Found {} {} " ,
143143 style( repos. len( ) ) . cyan( ) . bold( ) ,
144+ style( git_repository_count_label( repos. len( ) ) ) . dim( ) ,
144145 ) ) ;
145146 let selected_repos = prompt_repo_selection ( 1 , & repos, existing_config_repos. as_deref ( ) ) ?;
146147
@@ -171,7 +172,11 @@ async fn run_wizard(app: &AppContext, args: InitArgs) -> Result<()> {
171172 } else if args. no_watch {
172173 false
173174 } else {
174- prompt_yes_no ( 5 , "Enable auto-reindex on repository changes?" , false ) ?
175+ prompt_yes_no (
176+ 5 ,
177+ "Watch for repository changes and re-index automatically?" ,
178+ false ,
179+ ) ?
175180 } ;
176181
177182 write_default_config_with_repos ( app, & args, & selected_repos, existing_config. as_ref ( ) ) ?;
@@ -222,15 +227,15 @@ fn write_default_config_with_repos(
222227
223228 if repos. is_empty ( ) {
224229 bail ! (
225- "No git repositories found under {}" ,
230+ "No Git repositories found under {}. " ,
226231 app. workspace_path. display( )
227232 ) ;
228233 }
229234
230235 let configured_repos = materialize_repo_config ( repos, existing_config) ;
231236 let config = match existing_config {
232237 Some ( existing) => GatherStepConfig {
233- allow_listed_repos : existing . allow_listed_repos . clone ( ) ,
238+ allow_listed_repos : retain_allow_listed_repos_for_selected ( existing , & configured_repos ) ,
234239 repos : configured_repos,
235240 github : existing. github . clone ( ) ,
236241 jira : existing. jira . clone ( ) ,
@@ -273,21 +278,41 @@ fn materialize_repo_config(
273278 repos
274279 . iter ( )
275280 . map ( |repo| {
276- existing_by_path
277- . get ( repo. relative_path . as_str ( ) )
278- . or_else ( || existing_by_name. get ( repo. name . as_str ( ) ) )
279- . map_or_else (
280- || RepoConfig {
281- name : repo. name . clone ( ) ,
282- path : repo. relative_path . clone ( ) ,
283- depth : None ,
284- } ,
285- |existing| ( * existing) . clone ( ) ,
286- )
281+ if let Some ( existing) = existing_by_path. get ( repo. relative_path . as_str ( ) ) {
282+ return ( * existing) . clone ( ) ;
283+ }
284+ if let Some ( existing) = existing_by_name. get ( repo. name . as_str ( ) ) {
285+ return RepoConfig {
286+ name : existing. name . clone ( ) ,
287+ path : repo. relative_path . clone ( ) ,
288+ depth : existing. depth ,
289+ } ;
290+ }
291+ RepoConfig {
292+ name : repo. name . clone ( ) ,
293+ path : repo. relative_path . clone ( ) ,
294+ depth : None ,
295+ }
287296 } )
288297 . collect ( )
289298}
290299
300+ fn retain_allow_listed_repos_for_selected (
301+ existing_config : & GatherStepConfig ,
302+ selected_repos : & [ RepoConfig ] ,
303+ ) -> Vec < String > {
304+ let selected_names = selected_repos
305+ . iter ( )
306+ . map ( |repo| repo. name . as_str ( ) )
307+ . collect :: < BTreeSet < _ > > ( ) ;
308+ existing_config
309+ . allow_listed_repos
310+ . iter ( )
311+ . filter ( |repo_name| selected_names. contains ( repo_name. as_str ( ) ) )
312+ . cloned ( )
313+ . collect ( )
314+ }
315+
291316fn emit_config_summary (
292317 app : & AppContext ,
293318 config_path : & Path ,
@@ -317,7 +342,7 @@ fn emit_config_summary(
317342 output. line ( format ! (
318343 " {} {}" ,
319344 style( payload. repo_count) . cyan( ) . bold( ) ,
320- style( "configured repository(ies)" ) . dim( )
345+ style( repository_count_label ( payload . repo_count ) ) . dim( )
321346 ) ) ;
322347 for repo in payload. repos {
323348 output. line ( format ! (
@@ -332,9 +357,9 @@ fn emit_config_summary(
332357
333358fn emit_setup_complete ( output : & crate :: app:: Output ) {
334359 output. line ( format ! (
335- "\n {} Gather Step is ready. Start planning with your agent, for example : {}. Docs: {}" ,
360+ "\n {} Gather Step is ready. Start planning with your agent. Example : {}. Docs: {}" ,
336361 style( "✓ Setup complete." ) . green( ) . bold( ) ,
337- style( "\" Start planning for Task A, use gather-step\" " ) . cyan( ) ,
362+ style( "\" Start planning your next task with gather-step\" " ) . cyan( ) ,
338363 style( "https://gatherstep.dev/reference/mcp-tools/" ) . underlined( )
339364 ) ) ;
340365}
@@ -361,6 +386,22 @@ fn discovered_repos_from_config(config: &GatherStepConfig) -> Vec<DiscoveredRepo
361386 . collect ( )
362387}
363388
389+ fn repository_count_label ( count : usize ) -> & ' static str {
390+ if count == 1 {
391+ "configured repository"
392+ } else {
393+ "configured repositories"
394+ }
395+ }
396+
397+ fn git_repository_count_label ( count : usize ) -> & ' static str {
398+ if count == 1 {
399+ "Git repository"
400+ } else {
401+ "Git repositories"
402+ }
403+ }
404+
364405fn prompt_yes_no ( step : usize , message : & str , default : bool ) -> Result < bool > {
365406 let suffix = if default { "[Y/n]" } else { "[y/N]" } ;
366407 let mut stdout = io:: stdout ( ) . lock ( ) ;
@@ -412,7 +453,7 @@ fn prompt_repo_selection(
412453 existing_config_repos : Option < & [ DiscoveredRepo ] > ,
413454) -> Result < Vec < DiscoveredRepo > > {
414455 if repos. is_empty ( ) {
415- bail ! ( "No git repositories found under the workspace" ) ;
456+ bail ! ( "No Git repositories found under the workspace. " ) ;
416457 }
417458
418459 let default_names = existing_config_repos. map ( |repos| {
@@ -502,7 +543,7 @@ fn prompt_repo_selection(
502543 }
503544
504545 if selected. is_empty ( ) {
505- bail ! ( "select at least one repository before continuing" ) ;
546+ bail ! ( "Select at least one repository before continuing. " ) ;
506547 }
507548
508549 Ok ( selected
@@ -707,7 +748,12 @@ mod tests {
707748
708749 use pretty_assertions:: assert_eq;
709750
710- use super :: discover_git_repos;
751+ use gather_step_core:: { DepthLevel , GatherStepConfig , IndexingConfig , RepoConfig } ;
752+
753+ use super :: {
754+ DiscoveredRepo , discover_git_repos, materialize_repo_config,
755+ retain_allow_listed_repos_for_selected,
756+ } ;
711757
712758 static TEMP_COUNTER : AtomicU64 = AtomicU64 :: new ( 0 ) ;
713759
@@ -788,4 +834,65 @@ mod tests {
788834 ]
789835 ) ;
790836 }
837+
838+ #[ test]
839+ fn repo_config_merge_filters_allow_list_to_selected_repos ( ) {
840+ let existing = GatherStepConfig {
841+ allow_listed_repos : vec ! [ "api" . to_owned( ) , "web" . to_owned( ) ] ,
842+ repos : vec ! [
843+ RepoConfig {
844+ name: "api" . to_owned( ) ,
845+ path: "apps/api" . to_owned( ) ,
846+ depth: Some ( DepthLevel :: Level2 ) ,
847+ } ,
848+ RepoConfig {
849+ name: "web" . to_owned( ) ,
850+ path: "apps/web" . to_owned( ) ,
851+ depth: Some ( DepthLevel :: Level1 ) ,
852+ } ,
853+ ] ,
854+ github : None ,
855+ jira : None ,
856+ indexing : IndexingConfig :: default ( ) ,
857+ } ;
858+ let selected = vec ! [ DiscoveredRepo {
859+ name: "api" . to_owned( ) ,
860+ relative_path: "apps/api" . to_owned( ) ,
861+ } ] ;
862+ let merged = materialize_repo_config ( & selected, Some ( & existing) ) ;
863+
864+ assert_eq ! (
865+ retain_allow_listed_repos_for_selected( & existing, & merged) ,
866+ vec![ "api" . to_owned( ) ]
867+ ) ;
868+ }
869+
870+ #[ test]
871+ fn repo_config_name_match_keeps_discovered_path ( ) {
872+ let existing = GatherStepConfig {
873+ allow_listed_repos : Vec :: new ( ) ,
874+ repos : vec ! [ RepoConfig {
875+ name: "api" . to_owned( ) ,
876+ path: "old/api" . to_owned( ) ,
877+ depth: Some ( DepthLevel :: Level2 ) ,
878+ } ] ,
879+ github : None ,
880+ jira : None ,
881+ indexing : IndexingConfig :: default ( ) ,
882+ } ;
883+ let selected = vec ! [ DiscoveredRepo {
884+ name: "api" . to_owned( ) ,
885+ relative_path: "new/api" . to_owned( ) ,
886+ } ] ;
887+ let merged = materialize_repo_config ( & selected, Some ( & existing) ) ;
888+
889+ assert_eq ! (
890+ merged,
891+ vec![ RepoConfig {
892+ name: "api" . to_owned( ) ,
893+ path: "new/api" . to_owned( ) ,
894+ depth: Some ( DepthLevel :: Level2 ) ,
895+ } ]
896+ ) ;
897+ }
791898}
0 commit comments