@@ -438,11 +438,7 @@ def interactive_setup(self) -> bool:
438438 required_vars = self .get_required_env_vars ()
439439 existing_vars = self .load_existing_env ()
440440 missing_required , missing_optional = self .check_missing_env_vars ()
441-
442- if not missing_required and not missing_optional :
443- console .print ("[green]✅ All environment variables are already configured![/green]" )
444- return True
445-
441+
446442 # Show what we need to configure
447443 if missing_required :
448444 console .print (f"[yellow]Missing { len (missing_required )} required variables:[/yellow]" )
@@ -526,55 +522,101 @@ def interactive_setup(self) -> bool:
526522 console .print (f"[green]Auto-detected GKE cluster: { auto_cluster } [/green]" )
527523 updated_vars ['TARGET_GKE_CLUSTER_NAME' ] = auto_cluster
528524
529- # Configure missing required variables
530- for var_name in missing_required :
531- if var_name in updated_vars :
532- continue # Already auto-detected
533-
525+ # Configure all variables (allow updating existing ones)
526+ changes_made = False
527+ all_required_vars = [ var for var in required_vars . keys () if required_vars [ var ][ 'required' ]]
528+
529+ for var_name in all_required_vars :
534530 config = required_vars [var_name ]
535531
536- # Special handling for PROVIDER - show as a choice menu
532+ # Special handling for PROVIDER - show as a choice menu with current value
537533 if var_name == "PROVIDER" :
534+ current_provider = existing_vars .get ("PROVIDER" , "" )
535+
538536 console .print (f"\n [cyan]LLM Provider Selection[/cyan]" )
539- console .print ("Which LLM provider would you like to use?" )
540- console .print (" 1. Anthropic (Claude)" )
541- console .print (" 2. Google (Gemini)" )
537+ if current_provider :
538+ console .print (f"Current: { current_provider } " )
539+ console .print ("Which LLM provider would you like to use?" )
540+ console .print (" 1. Anthropic (Claude)" )
541+ console .print (" 2. Google (Gemini)" )
542+ console .print (" 3. Keep current" )
543+
544+ choice = Prompt .ask ("Choose provider" , choices = ["1" , "2" , "3" ], default = "3" )
545+ else :
546+ console .print ("Which LLM provider would you like to use?" )
547+ console .print (" 1. Anthropic (Claude)" )
548+ console .print (" 2. Google (Gemini)" )
549+
550+ choice = Prompt .ask ("Choose provider" , choices = ["1" , "2" ], default = "1" )
542551
543- choice = Prompt .ask ("Choose provider" , choices = ["1" , "2" ], default = "1" )
544552 if choice == "1" :
545- updated_vars ["PROVIDER" ] = "anthropic"
546- console .print ("[green]Selected: Anthropic (Claude)[/green]" )
547- else :
548- updated_vars ["PROVIDER" ] = "google"
549- console .print ("[green]Selected: Google (Gemini)[/green]" )
553+ new_provider = "anthropic"
554+ elif choice == "2" :
555+ new_provider = "google"
556+ else : # choice == "3" (keep current)
557+ new_provider = current_provider
558+
559+ if new_provider != current_provider :
560+ changes_made = True
561+ console .print (f"[green]Selected: { new_provider } [/green]" )
562+ elif current_provider :
563+ console .print (f"[green]Keeping: { current_provider } [/green]" )
564+
565+ updated_vars ["PROVIDER" ] = new_provider
550566 continue
551567
568+ # Get current value or provide defaults
569+ current_value = existing_vars .get (var_name , "" )
570+ if not current_value :
571+ # Provide defaults for first-time setup
572+ if var_name == "MODEL" :
573+ if updated_vars .get ("PROVIDER" ) == "anthropic" :
574+ current_value = "claude-3-7-sonnet-latest"
575+ elif updated_vars .get ("PROVIDER" ) == "google" :
576+ current_value = "gemini-1.5-pro"
577+ elif var_name == "MAX_TOKENS" :
578+ current_value = "4000"
579+ elif var_name == "PROJECT_ROOT" :
580+ current_value = "src" if self .minimal else "."
581+ elif var_name == "GITHUB_ORGANISATION" and self .minimal :
582+ current_value = "fuzzylabs"
583+ elif var_name == "GITHUB_REPO_NAME" and self .minimal :
584+ current_value = "microservices-demo"
585+ elif var_name == "DEV_BEARER_TOKEN" :
586+ current_value = "dev_token_" + str (hash ("sre-agent" ))[:8 ]
587+
552588 console .print (f"\n [cyan]{ var_name } [/cyan] ({ config ['description' ]} )" )
553589
554- # Provide defaults for some variables
555- default_value = ""
556- if var_name == "MODEL" :
557- if updated_vars .get ("PROVIDER" ) == "anthropic" :
558- default_value = "claude-3-5-sonnet-20241022"
559- elif updated_vars .get ("PROVIDER" ) == "google" :
560- default_value = "gemini-1.5-pro"
561- elif var_name == "MAX_TOKENS" :
562- default_value = "4000"
563- elif var_name == "PROJECT_ROOT" :
564- default_value = "src" if self .minimal else "."
565- elif var_name == "GITHUB_ORGANISATION" and self .minimal :
566- default_value = "fuzzylabs"
567- elif var_name == "GITHUB_REPO_NAME" and self .minimal :
568- default_value = "microservices-demo"
569- elif var_name == "DEV_BEARER_TOKEN" :
570- default_value = "dev_token_" + str (hash ("sre-agent" ))[:8 ]
590+ # Smart prompt text based on whether value exists
591+ if current_value :
592+ # Show current value (masked if sensitive)
593+ if config ['sensitive' ]:
594+ if len (current_value ) > 6 :
595+ display_value = f"{ current_value [:3 ]} ...{ current_value [- 3 :]} "
596+ else :
597+ display_value = "*" * len (current_value )
598+ else :
599+ display_value = current_value
600+
601+ console .print (f"Current: { display_value } " )
602+ prompt_text = f"Enter { var_name } or press Enter to keep current"
603+ else :
604+ prompt_text = f"Enter { var_name } "
571605
572606 if config ['sensitive' ]:
573- value = Prompt .ask (f"Enter { var_name } " , default = default_value , password = True )
607+ # Don't use default for password fields to avoid showing sensitive data
608+ value = Prompt .ask (prompt_text , password = True )
609+ if not value : # User pressed Enter without typing
610+ value = current_value
574611 else :
575- value = Prompt .ask (f"Enter { var_name } " , default = default_value )
576- if value :
612+ value = Prompt .ask (prompt_text , default = current_value )
613+
614+ # Track changes
615+ if value != current_value :
616+ changes_made = True
577617 updated_vars [var_name ] = value
618+ elif current_value :
619+ updated_vars [var_name ] = current_value
578620 elif config ['required' ]:
579621 # For required variables, empty values are not allowed
580622 console .print (f"[red]❌ { var_name } is required and cannot be empty[/red]" )
@@ -587,19 +629,37 @@ def interactive_setup(self) -> bool:
587629 if selected_provider == "google" :
588630 api_key_var = "GEMINI_API_KEY"
589631
590- if api_key_var not in updated_vars or not updated_vars [api_key_var ]:
591- console .print (f"\n [cyan]{ api_key_var } [/cyan] (Required for { selected_provider } provider)" )
592- if selected_provider == "anthropic" :
593- console .print ("Get your API key from: https://console.anthropic.com/" )
594- elif selected_provider == "google" :
595- console .print ("Get your API key from: https://aistudio.google.com/app/apikey" )
596-
597- api_key = Prompt .ask (f"Enter { api_key_var } " , password = True )
598- if api_key :
599- updated_vars [api_key_var ] = api_key
600- else :
601- console .print (f"[red]❌ { api_key_var } is required for the selected provider[/red]" )
602- return False
632+ # Handle API key with smart prompting
633+ current_api_key = existing_vars .get (api_key_var , "" )
634+
635+ console .print (f"\n [cyan]{ api_key_var } [/cyan] (Required for { selected_provider } provider)" )
636+ if selected_provider == "anthropic" :
637+ console .print ("Get your API key from: https://console.anthropic.com/" )
638+ elif selected_provider == "google" :
639+ console .print ("Get your API key from: https://aistudio.google.com/app/apikey" )
640+
641+ if current_api_key :
642+ # Show masked current value
643+ masked_key = f"{ current_api_key [:3 ]} ...{ current_api_key [- 3 :]} " if len (current_api_key ) > 6 else "*" * len (current_api_key )
644+ console .print (f"Current: { masked_key } " )
645+ prompt_text = f"Enter { api_key_var } or press Enter to keep current"
646+ else :
647+ prompt_text = f"Enter { api_key_var } "
648+
649+ # Don't use default for password fields to avoid showing sensitive data
650+ api_key = Prompt .ask (prompt_text , password = True )
651+ if not api_key : # User pressed Enter without typing
652+ api_key = current_api_key
653+
654+ # Track changes for API key
655+ if api_key != current_api_key :
656+ changes_made = True
657+ updated_vars [api_key_var ] = api_key
658+ elif current_api_key :
659+ updated_vars [api_key_var ] = current_api_key
660+ elif not api_key :
661+ console .print (f"[red]❌ { api_key_var } is required for the selected provider[/red]" )
662+ return False
603663
604664 # Ask about optional variables (skip API keys and Slack vars)
605665 optional_vars_to_configure = [
@@ -644,14 +704,18 @@ def interactive_setup(self) -> bool:
644704 elif selected_provider == "google" and "ANTHROPIC_API_KEY" not in updated_vars :
645705 updated_vars ["ANTHROPIC_API_KEY" ] = ""
646706
647- # Save to .env file
648- try :
649- self .save_env_file (updated_vars )
650- console .print (f"\n [green]✅ Environment variables saved to { self .env_file } [/green]" )
707+ # Save to .env file only if changes were made
708+ if changes_made :
709+ try :
710+ self .save_env_file (updated_vars )
711+ console .print (f"\n [green]✅ Environment variables updated and saved to { self .env_file } [/green]" )
712+ return True
713+ except Exception as e :
714+ console .print (f"[red]❌ Failed to save .env file: { e } [/red]" )
715+ return False
716+ else :
717+ console .print (f"\n [green]✅ No changes made - { self .env_file } unchanged[/green]" )
651718 return True
652- except Exception as e :
653- console .print (f"[red]❌ Failed to save .env file: { e } [/red]" )
654- return False
655719
656720 def save_env_file (self , env_vars : Dict [str , str ]) -> None :
657721 """Save environment variables to .env file."""
0 commit comments