@@ -82,13 +82,16 @@ def print_phase_header(
8282 "anthropic" : "claude-sonnet-4-6" ,
8383 "ollama" : "llama3.2" ,
8484 "litellm" : "groq/llama-3.1-70b-versatile" ,
85+ "free-code" : "claude-sonnet-4-6" ,
8586}
8687
8788_PROVIDER_ENV : dict [str , str ] = {
8889 "gemini" : "GEMINI_API_KEY" ,
8990 "openai" : "OPENAI_API_KEY" ,
9091 "anthropic" : "ANTHROPIC_API_KEY" ,
9192 "ollama" : "OLLAMA_BASE_URL" ,
93+ # free-code uses FREE_CODE_BASE_URL (optional — defaults to http://localhost:3180)
94+ "free-code" : "FREE_CODE_BASE_URL" ,
9295}
9396
9497_PROVIDER_SIGNUP : dict [str , str ] = {
@@ -98,6 +101,9 @@ def print_phase_header(
98101 "ollama" : "https://ollama.com/download" ,
99102}
100103
104+ # Providers that require no API key — always considered available
105+ _NO_KEY_PROVIDERS : set [str ] = {"free-code" }
106+
101107
102108# ---------------------------------------------------------------------------
103109# .env persistence — save/load API keys in .repowise/.env
@@ -220,10 +226,13 @@ def interactive_mode_select(console: Console) -> str:
220226
221227
222228def _detect_provider_status () -> dict [str , str ]:
223- """Return {provider: env_var_name} for providers whose key is set."""
229+ """Return {provider: env_var_name} for providers whose key is set or that need no key ."""
224230 status : dict [str , str ] = {}
225231 for prov , env_var in _PROVIDER_ENV .items ():
226- if prov == "gemini" :
232+ if prov in _NO_KEY_PROVIDERS :
233+ # No-key providers are always considered available
234+ status [prov ] = env_var
235+ elif prov == "gemini" :
227236 if os .environ .get ("GEMINI_API_KEY" ) or os .environ .get ("GOOGLE_API_KEY" ):
228237 status [prov ] = env_var
229238 elif os .environ .get (env_var ):
@@ -258,12 +267,19 @@ def interactive_provider_select(
258267 table .add_column ("Default Model" , style = "dim" )
259268
260269 for idx , prov in enumerate (providers , 1 ):
261- status_text = f"[{ OK } ]✓ API key set[/]" if prov in detected else "[dim]✗ no key[/dim]"
270+ if prov in _NO_KEY_PROVIDERS :
271+ status_text = f"[{ OK } ]✓ no key needed[/]"
272+ elif prov in detected :
273+ status_text = f"[{ OK } ]✓ API key set[/]"
274+ else :
275+ status_text = "[dim]✗ no key[/dim]"
262276 default_model = _PROVIDER_DEFAULTS .get (prov , "" )
263277 # Mark gemini as recommended
264278 label = prov
265279 if prov == "gemini" :
266280 label = f"{ prov } [dim](recommended)[/dim]"
281+ elif prov == "free-code" :
282+ label = f"{ prov } [dim](local Claude proxy)[/dim]"
267283 table .add_row (f"[{ idx } ]" , label , status_text , default_model )
268284
269285 console .print ()
@@ -288,7 +304,7 @@ def interactive_provider_select(
288304 chosen = providers [int (chosen_idx ) - 1 ]
289305
290306 # --- inline API key entry if missing ---
291- if chosen not in detected :
307+ if chosen not in detected and chosen not in _NO_KEY_PROVIDERS :
292308 env_var = _PROVIDER_ENV [chosen ]
293309 signup_url = _PROVIDER_SIGNUP .get (chosen , "" )
294310 console .print ()
@@ -300,6 +316,14 @@ def interactive_provider_select(
300316 if not key :
301317 console .print (f" [{ WARN } ]Skipped. Please select another provider.[/]" )
302318 return interactive_provider_select (console , model_flag , repo_path = repo_path )
319+ elif chosen == "free-code" :
320+ base_url = os .environ .get ("FREE_CODE_BASE_URL" , "http://localhost:3180" )
321+ console .print ()
322+ console .print (f" [dim]free-code serve endpoint: [cyan]{ base_url } [/cyan][/dim]" )
323+ console .print (
324+ " [dim]Make sure [bold]claude serve[/bold] is running before starting analysis.[/dim]"
325+ )
326+ console .print ()
303327
304328 # --- model ---
305329 default_model = _PROVIDER_DEFAULTS .get (chosen , "" )
0 commit comments