diff --git a/setup.py b/setup.py index e23374c3..90495cc4 100644 --- a/setup.py +++ b/setup.py @@ -5,6 +5,7 @@ import sys from datetime import date from pathlib import Path +import platform from setuptools import setup from setuptools.command.build_py import build_py @@ -110,6 +111,8 @@ def _compile_translations(): def _replace_release_date(): + if platform.system() == 'Darwin': + return content = INIT_PATH.read_text(encoding="utf-8") today = date.today().isoformat() content = re.sub( diff --git a/src/iac_code/__init__.py b/src/iac_code/__init__.py index 046ca0f3..22cf2787 100644 --- a/src/iac_code/__init__.py +++ b/src/iac_code/__init__.py @@ -1,2 +1,2 @@ __version__ = "0.2.0" -__release_date__ = "2026-05-20" +__release_date__ = "" diff --git a/src/iac_code/commands/auth.py b/src/iac_code/commands/auth.py index 842c392e..35c6c5c8 100644 --- a/src/iac_code/commands/auth.py +++ b/src/iac_code/commands/auth.py @@ -18,7 +18,6 @@ _save_yaml, get_active_provider_key, get_credentials_path, - get_llm_source, get_provider_config, get_settings_path, ) @@ -564,33 +563,15 @@ async def auth_command(context: "CommandContext | None" = None, **kwargs) -> str # immediately — _on_state_change may skip reinit when only the API key # changed but the model and provider config stayed the same. if context and hasattr(context, "repl") and context.repl: - context.repl._reinitialize_provider(context.repl.store.get_state().model) + repl = context.repl + repl._reinitialize_provider(repl.store.get_state().model) return result def _auth_flow(console, store) -> str | None: """Auth flow running inside alternate screen.""" - llm_source = get_llm_source() - if llm_source != "local": - lock_notice = _("LLM provider is locked by '{source}'. To change, modify llm_source in settings.yml.").format( - source=llm_source - ) - options = [_cloud_provider_display(p["name"]) for p in CLOUD_PROVIDERS] - idx = _select("{}\n\n{}".format(lock_notice, _("Select Cloud Provider")), options) - if idx is None: - return _("Auth cancelled") - provider = CLOUD_PROVIDERS[idx] - if provider["name"] == "aliyun": - result = _aliyun_auth_flow() - else: - result = _BACK - if isinstance(result, _BackSentinel): - return _("Auth cancelled") - return result - while True: - # Step 0: Select category categories = [ _("Configure LLM Provider"), _("Configure IaC Cloud Service"), @@ -605,7 +586,7 @@ def _auth_flow(console, store) -> str | None: result = _cloud_auth_flow(console) if isinstance(result, _BackSentinel): - continue # Go back to category selection + continue return result @@ -640,22 +621,49 @@ def _llm_auth_flow(console, store) -> str | None | _BackSentinel: provider_map: dict[str, LLMProvider] = {str(p["key_name"]): p for p in PROVIDERS} + from iac_code.config import PARTNER_SOURCES, get_llm_source + + num_partner_sources = len(PARTNER_SOURCES) + + current_llm_source = get_llm_source() + while True: - # Step 1: Select vendor group + # Step 1: Select vendor group (partner sources shown at the top) group_options: list[str] = [] group_default_idx = 0 + + for i, ps in enumerate(PARTNER_SOURCES): + label = ps["display_name"] + if current_llm_source == ps["key"]: + label += _(" (current)") + group_default_idx = i + group_options.append(label) + for i, (group_name, keys) in enumerate(provider_groups): label = _(group_name) if active_key_name in keys: label += _(" (current)") - group_default_idx = i + group_default_idx = i + num_partner_sources group_options.append(label) group_idx = _select(_("Select provider"), group_options, default_index=group_default_idx) if group_idx is None: return _BACK - group_name, group_keys = provider_groups[group_idx] + # Handle partner source selection + if group_idx < num_partner_sources: + partner = PARTNER_SOURCES[group_idx] + settings_path = get_settings_path() + config = _load_yaml(settings_path) + config.pop("activeProvider", None) + config["llm_source"] = partner["key"] + _save_yaml(settings_path, config) + return _("{status}: {provider}").format( + status=_("Configured"), + provider=partner["display_name"], + ) + + group_name, group_keys = provider_groups[group_idx - num_partner_sources] group_providers = [provider_map[k] for k in group_keys if k in provider_map] # Step 2: Select provider within group (skip if only one) diff --git a/src/iac_code/commands/clear.py b/src/iac_code/commands/clear.py index 21cf6f52..b1311610 100644 --- a/src/iac_code/commands/clear.py +++ b/src/iac_code/commands/clear.py @@ -13,6 +13,8 @@ async def clear_command(context=None, **kwargs) -> str: agent_loop = getattr(context.repl, "_agent_loop", None) if agent_loop: agent_loop.context_manager.reset() + if hasattr(context.repl, "_command_log"): + context.repl._command_log.clear() if context and hasattr(context, "console"): console = context.console diff --git a/src/iac_code/commands/model.py b/src/iac_code/commands/model.py index 94013c0f..caa7f7c4 100644 --- a/src/iac_code/commands/model.py +++ b/src/iac_code/commands/model.py @@ -46,9 +46,16 @@ async def model_command(context: "CommandContext | None" = None, args: list[str] """Switch or display current model.""" llm_source = get_llm_source() if llm_source != "local": - return _("Model selection is locked by '{source}'. To change, modify llm_source in settings.yml.").format( - source=llm_source - ) + from iac_code.config import PARTNER_SOURCES + + display_name = llm_source + for ps in PARTNER_SOURCES: + if ps["key"] == llm_source: + display_name = ps["display_name"] + break + return _( + "Model is managed by '{source}'. To change model, modify it in {source} or switch provider via /auth." + ).format(source=display_name) store = context.store if context else kwargs.get("store") args = args or [] diff --git a/src/iac_code/config.py b/src/iac_code/config.py index 7ece856b..d3424337 100644 --- a/src/iac_code/config.py +++ b/src/iac_code/config.py @@ -155,7 +155,14 @@ def _read(name: str) -> str | None: def get_llm_source() -> str: - """Return the LLM source: 'qwenpaw', 'local', or 'env'.""" + """Return the effective LLM source based on priority chain. + + Priority (highest to lowest): + 1. Environment variable (IAC_CODE_API_KEY) → "env" + 2. activeProvider in settings → "local" + 3. llm_source in settings → partner source value (e.g. "qwenpaw") + 4. Nothing → "local" + """ env = _get_env_overrides() if env["api_key"]: return "env" @@ -163,12 +170,20 @@ def get_llm_source() -> str: settings = _load_yaml(get_settings_path()) except Exception: return "local" + active = settings.get("activeProvider") + if isinstance(active, str) and active.strip(): + return "local" source = settings.get("llm_source") if isinstance(source, str) and source.strip(): return source.strip() return "local" +PARTNER_SOURCES: list[dict[str, str]] = [ + {"key": "qwenpaw", "display_name": "QwenPaw"}, +] + + # --------------------------------------------------------------------------- # Path helpers # --------------------------------------------------------------------------- diff --git a/src/iac_code/i18n/locales/de/LC_MESSAGES/messages.po b/src/iac_code/i18n/locales/de/LC_MESSAGES/messages.po index 34c42855..e2051d98 100644 --- a/src/iac_code/i18n/locales/de/LC_MESSAGES/messages.po +++ b/src/iac_code/i18n/locales/de/LC_MESSAGES/messages.po @@ -4,9 +4,9 @@ # msgid "" msgstr "" -"Project-Id-Version: iac-code 0.1.2\n" +"Project-Id-Version: iac-code 0.2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-05-18 18:09+0800\n" +"POT-Creation-Date: 2026-05-20 12:34+0800\n" "PO-Revision-Date: 2026-05-13 00:00+0000\n" "Last-Translator: \n" "Language: de\n" @@ -543,222 +543,217 @@ msgstr "Eine frühere Sitzung fortsetzen" msgid "[conversation id or search term]" msgstr "[Konversations-ID oder Suchbegriff]" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:836 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:844 #: src/iac_code/ui/core/prompt_input.py:505 msgid "Navigate" msgstr "Navigieren" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:368 -#: src/iac_code/commands/auth.py:402 src/iac_code/commands/auth.py:409 -#: src/iac_code/commands/auth.py:433 src/iac_code/commands/auth.py:836 -#: src/iac_code/commands/auth.py:1026 src/iac_code/ui/core/prompt_input.py:505 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:367 +#: src/iac_code/commands/auth.py:401 src/iac_code/commands/auth.py:408 +#: src/iac_code/commands/auth.py:432 src/iac_code/commands/auth.py:844 +#: src/iac_code/commands/auth.py:1034 src/iac_code/ui/core/prompt_input.py:505 msgid "Confirm" msgstr "Bestätigen" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:366 -#: src/iac_code/commands/auth.py:368 src/iac_code/commands/auth.py:402 -#: src/iac_code/commands/auth.py:409 src/iac_code/commands/auth.py:433 -#: src/iac_code/commands/auth.py:836 src/iac_code/commands/auth.py:921 -#: src/iac_code/commands/auth.py:1026 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:365 +#: src/iac_code/commands/auth.py:367 src/iac_code/commands/auth.py:401 +#: src/iac_code/commands/auth.py:408 src/iac_code/commands/auth.py:432 +#: src/iac_code/commands/auth.py:844 src/iac_code/commands/auth.py:929 +#: src/iac_code/commands/auth.py:1034 msgid "Back" msgstr "Zurück" -#: src/iac_code/commands/auth.py:366 +#: src/iac_code/commands/auth.py:365 msgid "Keep" msgstr "Behalten" -#: src/iac_code/commands/auth.py:366 +#: src/iac_code/commands/auth.py:365 msgid "Re-enter" msgstr "Erneut eingeben" -#: src/iac_code/commands/auth.py:508 src/iac_code/commands/auth.py:650 -#: src/iac_code/commands/auth.py:670 +#: src/iac_code/commands/auth.py:507 src/iac_code/commands/auth.py:638 +#: src/iac_code/commands/auth.py:645 src/iac_code/commands/auth.py:678 msgid " (current)" msgstr " (aktuell)" -#: src/iac_code/commands/auth.py:511 +#: src/iac_code/commands/auth.py:510 msgid "Custom model..." msgstr "Benutzerdefiniertes Modell …" -#: src/iac_code/commands/auth.py:514 +#: src/iac_code/commands/auth.py:513 #, python-brace-format msgid "Select model for {provider}" msgstr "Modell für {provider} auswählen" -#: src/iac_code/commands/auth.py:516 +#: src/iac_code/commands/auth.py:515 msgid "Select model" msgstr "Modell auswählen" -#: src/iac_code/commands/auth.py:524 +#: src/iac_code/commands/auth.py:523 msgid "Enter custom model name: " msgstr "Benutzerdefinierten Modellnamen eingeben: " -#: src/iac_code/commands/auth.py:550 +#: src/iac_code/commands/auth.py:549 msgid "Error: console not available" msgstr "Fehler: Konsole nicht verfügbar" #: src/iac_code/commands/auth.py:576 -#, python-brace-format -msgid "" -"LLM provider is locked by '{source}'. To change, modify llm_source in " -"settings.yml." -msgstr "" -"LLM-Anbieter ist durch '{source}' gesperrt. Zum Ändern passen Sie " -"llm_source in settings.yml an." - -#: src/iac_code/commands/auth.py:580 src/iac_code/commands/auth.py:780 -msgid "Select Cloud Provider" -msgstr "Cloud-Anbieter auswählen" - -#: src/iac_code/commands/auth.py:582 src/iac_code/commands/auth.py:589 -#: src/iac_code/commands/auth.py:600 src/iac_code/commands/auth.py:695 -#: src/iac_code/commands/auth.py:711 src/iac_code/commands/auth.py:789 -#: src/iac_code/commands/auth.py:962 src/iac_code/commands/auth.py:1003 -msgid "Auth cancelled" -msgstr "Authentifizierung abgebrochen" - -#: src/iac_code/commands/auth.py:595 msgid "Configure LLM Provider" msgstr "LLM-Anbieter konfigurieren" -#: src/iac_code/commands/auth.py:596 +#: src/iac_code/commands/auth.py:577 msgid "Configure IaC Cloud Service" msgstr "IaC-Cloud-Dienst konfigurieren" -#: src/iac_code/commands/auth.py:598 +#: src/iac_code/commands/auth.py:579 msgid "Select configuration type" msgstr "Konfigurationstyp auswählen" -#: src/iac_code/commands/auth.py:654 +#: src/iac_code/commands/auth.py:581 src/iac_code/commands/auth.py:703 +#: src/iac_code/commands/auth.py:719 src/iac_code/commands/auth.py:797 +#: src/iac_code/commands/auth.py:970 src/iac_code/commands/auth.py:1011 +msgid "Auth cancelled" +msgstr "Authentifizierung abgebrochen" + +#: src/iac_code/commands/auth.py:649 msgid "Select provider" msgstr "Anbieter auswählen" -#: src/iac_code/commands/auth.py:675 src/iac_code/commands/auth.py:764 +#: src/iac_code/commands/auth.py:661 +#, python-brace-format +msgid "{status}: {provider}" +msgstr "{status}: {provider}" + +#: src/iac_code/commands/auth.py:662 src/iac_code/commands/auth.py:751 +msgid "Configured" +msgstr "Konfiguriert" + +#: src/iac_code/commands/auth.py:683 src/iac_code/commands/auth.py:772 #, python-brace-format msgid "Select provider — {group}" msgstr "Anbieter auswählen — {group}" -#: src/iac_code/commands/auth.py:688 +#: src/iac_code/commands/auth.py:696 #, python-brace-format msgid "Configure {provider}" msgstr "{provider} konfigurieren" -#: src/iac_code/commands/auth.py:704 +#: src/iac_code/commands/auth.py:712 #, python-brace-format msgid "Enter API key for {provider}" msgstr "API-Key für {provider} eingeben" -#: src/iac_code/commands/auth.py:742 +#: src/iac_code/commands/auth.py:750 #, python-brace-format msgid "{status}: {provider} / {model}" msgstr "{status}: {provider} / {model}" -#: src/iac_code/commands/auth.py:743 -msgid "Configured" -msgstr "Konfiguriert" - -#: src/iac_code/commands/auth.py:750 src/iac_code/commands/auth.py:771 +#: src/iac_code/commands/auth.py:758 src/iac_code/commands/auth.py:779 msgid "Alibaba Cloud" msgstr "Alibaba Cloud" -#: src/iac_code/commands/auth.py:751 src/iac_code/providers/registry.py:423 +#: src/iac_code/commands/auth.py:759 src/iac_code/providers/registry.py:423 msgid "ZhiPu AI" msgstr "ZhiPu AI" -#: src/iac_code/commands/auth.py:752 +#: src/iac_code/commands/auth.py:760 msgid "Kimi" msgstr "Kimi" -#: src/iac_code/commands/auth.py:753 +#: src/iac_code/commands/auth.py:761 msgid "MiniMax" msgstr "MiniMax" -#: src/iac_code/commands/auth.py:754 src/iac_code/providers/registry.py:425 +#: src/iac_code/commands/auth.py:762 src/iac_code/providers/registry.py:425 msgid "Volcengine" msgstr "Volcengine" -#: src/iac_code/commands/auth.py:755 +#: src/iac_code/commands/auth.py:763 msgid "SiliconFlow" msgstr "SiliconFlow" -#: src/iac_code/commands/auth.py:756 src/iac_code/providers/registry.py:416 +#: src/iac_code/commands/auth.py:764 src/iac_code/providers/registry.py:416 msgid "DeepSeek" msgstr "DeepSeek" -#: src/iac_code/commands/auth.py:757 src/iac_code/providers/registry.py:414 +#: src/iac_code/commands/auth.py:765 src/iac_code/providers/registry.py:414 msgid "OpenAI" msgstr "OpenAI" -#: src/iac_code/commands/auth.py:758 src/iac_code/providers/registry.py:415 +#: src/iac_code/commands/auth.py:766 src/iac_code/providers/registry.py:415 msgid "Anthropic" msgstr "Anthropic" -#: src/iac_code/commands/auth.py:759 src/iac_code/providers/registry.py:418 +#: src/iac_code/commands/auth.py:767 src/iac_code/providers/registry.py:418 msgid "Google Gemini" msgstr "Google Gemini" -#: src/iac_code/commands/auth.py:760 src/iac_code/providers/registry.py:431 +#: src/iac_code/commands/auth.py:768 src/iac_code/providers/registry.py:431 msgid "Azure OpenAI" msgstr "Azure OpenAI" -#: src/iac_code/commands/auth.py:761 src/iac_code/providers/registry.py:430 +#: src/iac_code/commands/auth.py:769 src/iac_code/providers/registry.py:430 msgid "OpenRouter" msgstr "OpenRouter" -#: src/iac_code/commands/auth.py:762 +#: src/iac_code/commands/auth.py:770 msgid "Local" msgstr "Lokal" -#: src/iac_code/commands/auth.py:763 +#: src/iac_code/commands/auth.py:771 msgid "Compatible" msgstr "Kompatibel" -#: src/iac_code/commands/auth.py:796 +#: src/iac_code/commands/auth.py:788 +msgid "Select Cloud Provider" +msgstr "Cloud-Anbieter auswählen" + +#: src/iac_code/commands/auth.py:804 msgid "Credential" msgstr "Anmeldedaten" -#: src/iac_code/commands/auth.py:797 src/iac_code/commands/auth.py:894 -#: src/iac_code/commands/auth.py:999 src/iac_code/ui/renderer.py:418 +#: src/iac_code/commands/auth.py:805 src/iac_code/commands/auth.py:902 +#: src/iac_code/commands/auth.py:1007 src/iac_code/ui/renderer.py:418 msgid "Region" msgstr "Region" -#: src/iac_code/commands/auth.py:799 +#: src/iac_code/commands/auth.py:807 msgid "Configure Alibaba Cloud" msgstr "Alibaba Cloud konfigurieren" -#: src/iac_code/commands/auth.py:882 +#: src/iac_code/commands/auth.py:890 msgid "Current configuration" msgstr "Aktuelle Konfiguration" -#: src/iac_code/commands/auth.py:884 +#: src/iac_code/commands/auth.py:892 msgid "Mode" msgstr "Modus" -#: src/iac_code/commands/auth.py:891 +#: src/iac_code/commands/auth.py:899 msgid "(not set)" msgstr "(nicht gesetzt)" -#: src/iac_code/commands/auth.py:908 +#: src/iac_code/commands/auth.py:916 msgid "Configure Alibaba Cloud credentials" msgstr "Alibaba Cloud-Anmeldedaten konfigurieren" -#: src/iac_code/commands/auth.py:921 +#: src/iac_code/commands/auth.py:929 msgid "Reconfigure credential" msgstr "Anmeldedaten neu konfigurieren" -#: src/iac_code/commands/auth.py:934 +#: src/iac_code/commands/auth.py:942 msgid "Select credential type" msgstr "Anmeldedatentyp auswählen" -#: src/iac_code/commands/auth.py:984 +#: src/iac_code/commands/auth.py:992 msgid "Configured: Alibaba Cloud credentials saved to ~/.iac-code" msgstr "Konfiguriert: Alibaba Cloud-Anmeldedaten unter ~/.iac-code gespeichert" -#: src/iac_code/commands/auth.py:991 +#: src/iac_code/commands/auth.py:999 msgid "Configure Alibaba Cloud region" msgstr "Alibaba Cloud-Region konfigurieren" -#: src/iac_code/commands/auth.py:1017 +#: src/iac_code/commands/auth.py:1025 msgid "Configured: Alibaba Cloud region saved to ~/.iac-code" msgstr "Konfiguriert: Alibaba Cloud-Region unter ~/.iac-code gespeichert" @@ -791,8 +786,8 @@ msgstr "Der Befehl debug erfordert einen Kontext." msgid "No active session." msgstr "Keine aktive Sitzung." -#: src/iac_code/commands/effort.py:54 src/iac_code/commands/model.py:88 -#: src/iac_code/commands/model.py:92 +#: src/iac_code/commands/effort.py:54 src/iac_code/commands/model.py:95 +#: src/iac_code/commands/model.py:99 msgid "No configured providers. Run /auth first." msgstr "Keine konfigurierten Anbieter. Führen Sie zuerst /auth aus." @@ -854,26 +849,26 @@ msgstr "Befehlsvorschläge anzeigen" msgid "Exit" msgstr "Beenden" -#: src/iac_code/commands/model.py:49 +#: src/iac_code/commands/model.py:57 #, python-brace-format msgid "" -"Model selection is locked by '{source}'. To change, modify llm_source in " -"settings.yml." +"Model is managed by '{source}'. To change model, modify it in {source} or" +" switch provider via /auth." msgstr "" -"Modellauswahl ist durch '{source}' gesperrt. Zum Ändern passen Sie " -"llm_source in settings.yml an." +"Das Modell wird von '{source}' verwaltet. Ändern Sie es in {source} oder " +"wechseln Sie den Provider über /auth." -#: src/iac_code/commands/model.py:81 src/iac_code/commands/model.py:136 +#: src/iac_code/commands/model.py:88 src/iac_code/commands/model.py:143 #, python-brace-format msgid "Model switched to: {model}" msgstr "Modell gewechselt auf: {model}" -#: src/iac_code/commands/model.py:85 +#: src/iac_code/commands/model.py:92 #, python-brace-format msgid "Current model: {model}" msgstr "Aktuelles Modell: {model}" -#: src/iac_code/commands/model.py:111 +#: src/iac_code/commands/model.py:118 #, python-brace-format msgid "Kept model as {model}" msgstr "Modell beibehalten: {model}" @@ -1590,23 +1585,23 @@ msgstr "ROS Stack" msgid "CloudStackInstances" msgstr "CloudStackInstances" -#: src/iac_code/ui/banner.py:64 +#: src/iac_code/ui/banner.py:68 msgid "Your AI-powered Infrastructure as Code assistant" msgstr "Ihr KI-gestützter Infrastructure-as-Code-Assistent" -#: src/iac_code/ui/banner.py:88 +#: src/iac_code/ui/banner.py:92 msgid "Welcome back" msgstr "Willkommen zurück" -#: src/iac_code/ui/banner.py:94 +#: src/iac_code/ui/banner.py:98 msgid "Session" msgstr "Sitzung" -#: src/iac_code/ui/banner.py:104 +#: src/iac_code/ui/banner.py:108 msgid "Debug mode" msgstr "Debug-Modus" -#: src/iac_code/ui/banner.py:105 +#: src/iac_code/ui/banner.py:109 msgid "Log file" msgstr "Protokolldatei" @@ -1703,23 +1698,23 @@ msgstr "Nein, immer \"{rule}\" ablehnen (diese Sitzung)" msgid "No, always reject this tool" msgstr "Nein, dieses Tool immer ablehnen" -#: src/iac_code/ui/repl.py:353 +#: src/iac_code/ui/repl.py:354 msgid "Press Ctrl+C again to exit." msgstr "Drücken Sie erneut Ctrl+C zum Beenden." -#: src/iac_code/ui/repl.py:373 +#: src/iac_code/ui/repl.py:374 msgid "Interrupted." msgstr "Unterbrochen." -#: src/iac_code/ui/repl.py:410 +#: src/iac_code/ui/repl.py:411 msgid "Goodbye!" msgstr "Auf Wiedersehen!" -#: src/iac_code/ui/repl.py:411 +#: src/iac_code/ui/repl.py:412 msgid "Resume this session with:" msgstr "Diese Sitzung fortsetzen mit:" -#: src/iac_code/ui/repl.py:444 +#: src/iac_code/ui/repl.py:445 msgid "No image in clipboard." msgstr "Kein Bild in der Zwischenablage." @@ -1730,22 +1725,22 @@ msgstr "" "Unknown command: /{name}. Type /help for available commands.Unbekannter " "Befehl: /{name}. Geben Sie /help für verfügbare Befehle ein." -#: src/iac_code/ui/repl.py:608 src/iac_code/ui/repl.py:640 +#: src/iac_code/ui/repl.py:609 src/iac_code/ui/repl.py:654 #, python-brace-format msgid "Command error: {error}" msgstr "Befehlsfehler: {error}" -#: src/iac_code/ui/repl.py:615 +#: src/iac_code/ui/repl.py:616 #, python-brace-format msgid "Command has no handler: {name}" msgstr "Kein Handler für Befehl: {name}" -#: src/iac_code/ui/repl.py:835 +#: src/iac_code/ui/repl.py:889 #, python-brace-format msgid "Session not found: {session_id}" msgstr "Sitzung nicht gefunden: {session_id}" -#: src/iac_code/ui/repl.py:854 +#: src/iac_code/ui/repl.py:908 #, python-brace-format msgid "" "This session belongs to a different directory.\n" @@ -1756,19 +1751,19 @@ msgstr "" "Zum Fortsetzen ausführen:\n" " {cmd}" -#: src/iac_code/ui/repl.py:893 +#: src/iac_code/ui/repl.py:947 msgid "This conversation is from a different directory." msgstr "Diese Konversation stammt aus einem anderen Verzeichnis." -#: src/iac_code/ui/repl.py:895 +#: src/iac_code/ui/repl.py:949 msgid "To resume, run:" msgstr "Zum Fortsetzen ausführen:" -#: src/iac_code/ui/repl.py:900 +#: src/iac_code/ui/repl.py:954 msgid "(Command copied to clipboard)" msgstr "(Befehl in die Zwischenablage kopiert)" -#: src/iac_code/ui/repl.py:1057 +#: src/iac_code/ui/repl.py:1111 #, python-brace-format msgid "" "Current model {model} does not support image input. Use /model to switch " @@ -1777,12 +1772,12 @@ msgstr "" "Das aktuelle Modell {model} unterstützt keine Bildeingabe. Verwenden Sie " "/model, um zu einem Vision-fähigen Modell zu wechseln." -#: src/iac_code/ui/repl.py:1066 +#: src/iac_code/ui/repl.py:1120 #, python-brace-format msgid "Image error: {err}" msgstr "Bildfehler: {err}" -#: src/iac_code/ui/repl.py:1083 +#: src/iac_code/ui/repl.py:1137 msgid "" "Failed to persist image to cache; it will only exist in memory for this " "turn." @@ -1988,3 +1983,15 @@ msgstr "vor {n} Tag{s}" #~ msgid "tree-sitter not available" #~ msgstr "tree-sitter not available" +#~ msgid "" +#~ "LLM provider is locked by '{source}'." +#~ " To change, modify llm_source in " +#~ "settings.yml." +#~ msgstr "" +#~ "LLM-Anbieter ist durch '{source}' " +#~ "gesperrt. Zum Ändern passen Sie " +#~ "llm_source in settings.yml an." + +#~ msgid "Provider switched: {status}" +#~ msgstr "Provider gewechselt: {status}" + diff --git a/src/iac_code/i18n/locales/es/LC_MESSAGES/messages.po b/src/iac_code/i18n/locales/es/LC_MESSAGES/messages.po index e610b30b..8f18a8e1 100644 --- a/src/iac_code/i18n/locales/es/LC_MESSAGES/messages.po +++ b/src/iac_code/i18n/locales/es/LC_MESSAGES/messages.po @@ -4,9 +4,9 @@ # msgid "" msgstr "" -"Project-Id-Version: iac-code 0.1.2\n" +"Project-Id-Version: iac-code 0.2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-05-18 18:09+0800\n" +"POT-Creation-Date: 2026-05-20 12:34+0800\n" "PO-Revision-Date: 2026-05-13 00:00+0000\n" "Last-Translator: \n" "Language: es\n" @@ -544,222 +544,217 @@ msgstr "Reanudar una sesión anterior" msgid "[conversation id or search term]" msgstr "[id de conversación o término de búsqueda]" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:836 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:844 #: src/iac_code/ui/core/prompt_input.py:505 msgid "Navigate" msgstr "Navegar" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:368 -#: src/iac_code/commands/auth.py:402 src/iac_code/commands/auth.py:409 -#: src/iac_code/commands/auth.py:433 src/iac_code/commands/auth.py:836 -#: src/iac_code/commands/auth.py:1026 src/iac_code/ui/core/prompt_input.py:505 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:367 +#: src/iac_code/commands/auth.py:401 src/iac_code/commands/auth.py:408 +#: src/iac_code/commands/auth.py:432 src/iac_code/commands/auth.py:844 +#: src/iac_code/commands/auth.py:1034 src/iac_code/ui/core/prompt_input.py:505 msgid "Confirm" msgstr "Confirmar" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:366 -#: src/iac_code/commands/auth.py:368 src/iac_code/commands/auth.py:402 -#: src/iac_code/commands/auth.py:409 src/iac_code/commands/auth.py:433 -#: src/iac_code/commands/auth.py:836 src/iac_code/commands/auth.py:921 -#: src/iac_code/commands/auth.py:1026 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:365 +#: src/iac_code/commands/auth.py:367 src/iac_code/commands/auth.py:401 +#: src/iac_code/commands/auth.py:408 src/iac_code/commands/auth.py:432 +#: src/iac_code/commands/auth.py:844 src/iac_code/commands/auth.py:929 +#: src/iac_code/commands/auth.py:1034 msgid "Back" msgstr "Atrás" -#: src/iac_code/commands/auth.py:366 +#: src/iac_code/commands/auth.py:365 msgid "Keep" msgstr "Conservar" -#: src/iac_code/commands/auth.py:366 +#: src/iac_code/commands/auth.py:365 msgid "Re-enter" msgstr "Volver a introducir" -#: src/iac_code/commands/auth.py:508 src/iac_code/commands/auth.py:650 -#: src/iac_code/commands/auth.py:670 +#: src/iac_code/commands/auth.py:507 src/iac_code/commands/auth.py:638 +#: src/iac_code/commands/auth.py:645 src/iac_code/commands/auth.py:678 msgid " (current)" msgstr " (actual)" -#: src/iac_code/commands/auth.py:511 +#: src/iac_code/commands/auth.py:510 msgid "Custom model..." msgstr "Modelo personalizado..." -#: src/iac_code/commands/auth.py:514 +#: src/iac_code/commands/auth.py:513 #, python-brace-format msgid "Select model for {provider}" msgstr "Seleccionar modelo para {provider}" -#: src/iac_code/commands/auth.py:516 +#: src/iac_code/commands/auth.py:515 msgid "Select model" msgstr "Seleccionar modelo" -#: src/iac_code/commands/auth.py:524 +#: src/iac_code/commands/auth.py:523 msgid "Enter custom model name: " msgstr "Introduzca el nombre del modelo personalizado: " -#: src/iac_code/commands/auth.py:550 +#: src/iac_code/commands/auth.py:549 msgid "Error: console not available" msgstr "Error: la consola no está disponible" #: src/iac_code/commands/auth.py:576 -#, python-brace-format -msgid "" -"LLM provider is locked by '{source}'. To change, modify llm_source in " -"settings.yml." -msgstr "" -"El proveedor LLM está bloqueado por '{source}'. Para cambiar, modifique " -"llm_source en settings.yml." - -#: src/iac_code/commands/auth.py:580 src/iac_code/commands/auth.py:780 -msgid "Select Cloud Provider" -msgstr "Seleccionar proveedor de cloud" - -#: src/iac_code/commands/auth.py:582 src/iac_code/commands/auth.py:589 -#: src/iac_code/commands/auth.py:600 src/iac_code/commands/auth.py:695 -#: src/iac_code/commands/auth.py:711 src/iac_code/commands/auth.py:789 -#: src/iac_code/commands/auth.py:962 src/iac_code/commands/auth.py:1003 -msgid "Auth cancelled" -msgstr "Autenticación cancelada" - -#: src/iac_code/commands/auth.py:595 msgid "Configure LLM Provider" msgstr "Configurar proveedor LLM" -#: src/iac_code/commands/auth.py:596 +#: src/iac_code/commands/auth.py:577 msgid "Configure IaC Cloud Service" msgstr "Configurar servicio cloud IaC" -#: src/iac_code/commands/auth.py:598 +#: src/iac_code/commands/auth.py:579 msgid "Select configuration type" msgstr "Seleccionar tipo de configuración" -#: src/iac_code/commands/auth.py:654 +#: src/iac_code/commands/auth.py:581 src/iac_code/commands/auth.py:703 +#: src/iac_code/commands/auth.py:719 src/iac_code/commands/auth.py:797 +#: src/iac_code/commands/auth.py:970 src/iac_code/commands/auth.py:1011 +msgid "Auth cancelled" +msgstr "Autenticación cancelada" + +#: src/iac_code/commands/auth.py:649 msgid "Select provider" msgstr "Seleccionar proveedor" -#: src/iac_code/commands/auth.py:675 src/iac_code/commands/auth.py:764 +#: src/iac_code/commands/auth.py:661 +#, python-brace-format +msgid "{status}: {provider}" +msgstr "{status}: {provider}" + +#: src/iac_code/commands/auth.py:662 src/iac_code/commands/auth.py:751 +msgid "Configured" +msgstr "Configurado" + +#: src/iac_code/commands/auth.py:683 src/iac_code/commands/auth.py:772 #, python-brace-format msgid "Select provider — {group}" msgstr "Seleccionar proveedor — {group}" -#: src/iac_code/commands/auth.py:688 +#: src/iac_code/commands/auth.py:696 #, python-brace-format msgid "Configure {provider}" msgstr "Configurar {provider}" -#: src/iac_code/commands/auth.py:704 +#: src/iac_code/commands/auth.py:712 #, python-brace-format msgid "Enter API key for {provider}" msgstr "Introduzca la API key para {provider}" -#: src/iac_code/commands/auth.py:742 +#: src/iac_code/commands/auth.py:750 #, python-brace-format msgid "{status}: {provider} / {model}" msgstr "{status}: {provider} / {model}" -#: src/iac_code/commands/auth.py:743 -msgid "Configured" -msgstr "Configurado" - -#: src/iac_code/commands/auth.py:750 src/iac_code/commands/auth.py:771 +#: src/iac_code/commands/auth.py:758 src/iac_code/commands/auth.py:779 msgid "Alibaba Cloud" msgstr "Alibaba Cloud" -#: src/iac_code/commands/auth.py:751 src/iac_code/providers/registry.py:423 +#: src/iac_code/commands/auth.py:759 src/iac_code/providers/registry.py:423 msgid "ZhiPu AI" msgstr "ZhiPu AI" -#: src/iac_code/commands/auth.py:752 +#: src/iac_code/commands/auth.py:760 msgid "Kimi" msgstr "Kimi" -#: src/iac_code/commands/auth.py:753 +#: src/iac_code/commands/auth.py:761 msgid "MiniMax" msgstr "MiniMax" -#: src/iac_code/commands/auth.py:754 src/iac_code/providers/registry.py:425 +#: src/iac_code/commands/auth.py:762 src/iac_code/providers/registry.py:425 msgid "Volcengine" msgstr "Volcengine" -#: src/iac_code/commands/auth.py:755 +#: src/iac_code/commands/auth.py:763 msgid "SiliconFlow" msgstr "SiliconFlow" -#: src/iac_code/commands/auth.py:756 src/iac_code/providers/registry.py:416 +#: src/iac_code/commands/auth.py:764 src/iac_code/providers/registry.py:416 msgid "DeepSeek" msgstr "DeepSeek" -#: src/iac_code/commands/auth.py:757 src/iac_code/providers/registry.py:414 +#: src/iac_code/commands/auth.py:765 src/iac_code/providers/registry.py:414 msgid "OpenAI" msgstr "OpenAI" -#: src/iac_code/commands/auth.py:758 src/iac_code/providers/registry.py:415 +#: src/iac_code/commands/auth.py:766 src/iac_code/providers/registry.py:415 msgid "Anthropic" msgstr "Anthropic" -#: src/iac_code/commands/auth.py:759 src/iac_code/providers/registry.py:418 +#: src/iac_code/commands/auth.py:767 src/iac_code/providers/registry.py:418 msgid "Google Gemini" msgstr "Google Gemini" -#: src/iac_code/commands/auth.py:760 src/iac_code/providers/registry.py:431 +#: src/iac_code/commands/auth.py:768 src/iac_code/providers/registry.py:431 msgid "Azure OpenAI" msgstr "Azure OpenAI" -#: src/iac_code/commands/auth.py:761 src/iac_code/providers/registry.py:430 +#: src/iac_code/commands/auth.py:769 src/iac_code/providers/registry.py:430 msgid "OpenRouter" msgstr "OpenRouter" -#: src/iac_code/commands/auth.py:762 +#: src/iac_code/commands/auth.py:770 msgid "Local" msgstr "Local" -#: src/iac_code/commands/auth.py:763 +#: src/iac_code/commands/auth.py:771 msgid "Compatible" msgstr "Compatible" -#: src/iac_code/commands/auth.py:796 +#: src/iac_code/commands/auth.py:788 +msgid "Select Cloud Provider" +msgstr "Seleccionar proveedor de cloud" + +#: src/iac_code/commands/auth.py:804 msgid "Credential" msgstr "Credencial" -#: src/iac_code/commands/auth.py:797 src/iac_code/commands/auth.py:894 -#: src/iac_code/commands/auth.py:999 src/iac_code/ui/renderer.py:418 +#: src/iac_code/commands/auth.py:805 src/iac_code/commands/auth.py:902 +#: src/iac_code/commands/auth.py:1007 src/iac_code/ui/renderer.py:418 msgid "Region" msgstr "Región" -#: src/iac_code/commands/auth.py:799 +#: src/iac_code/commands/auth.py:807 msgid "Configure Alibaba Cloud" msgstr "Configurar Alibaba Cloud" -#: src/iac_code/commands/auth.py:882 +#: src/iac_code/commands/auth.py:890 msgid "Current configuration" msgstr "Configuración actual" -#: src/iac_code/commands/auth.py:884 +#: src/iac_code/commands/auth.py:892 msgid "Mode" msgstr "Modo" -#: src/iac_code/commands/auth.py:891 +#: src/iac_code/commands/auth.py:899 msgid "(not set)" msgstr "(sin definir)" -#: src/iac_code/commands/auth.py:908 +#: src/iac_code/commands/auth.py:916 msgid "Configure Alibaba Cloud credentials" msgstr "Configurar credenciales de Alibaba Cloud" -#: src/iac_code/commands/auth.py:921 +#: src/iac_code/commands/auth.py:929 msgid "Reconfigure credential" msgstr "Reconfigurar la credencial" -#: src/iac_code/commands/auth.py:934 +#: src/iac_code/commands/auth.py:942 msgid "Select credential type" msgstr "Seleccionar tipo de credencial" -#: src/iac_code/commands/auth.py:984 +#: src/iac_code/commands/auth.py:992 msgid "Configured: Alibaba Cloud credentials saved to ~/.iac-code" msgstr "Configurado: credenciales de Alibaba Cloud guardadas en ~/.iac-code" -#: src/iac_code/commands/auth.py:991 +#: src/iac_code/commands/auth.py:999 msgid "Configure Alibaba Cloud region" msgstr "Configurar la región de Alibaba Cloud" -#: src/iac_code/commands/auth.py:1017 +#: src/iac_code/commands/auth.py:1025 msgid "Configured: Alibaba Cloud region saved to ~/.iac-code" msgstr "Configurado: región de Alibaba Cloud guardada en ~/.iac-code" @@ -792,8 +787,8 @@ msgstr "El comando debug requiere un contexto." msgid "No active session." msgstr "No hay ninguna sesión activa." -#: src/iac_code/commands/effort.py:54 src/iac_code/commands/model.py:88 -#: src/iac_code/commands/model.py:92 +#: src/iac_code/commands/effort.py:54 src/iac_code/commands/model.py:95 +#: src/iac_code/commands/model.py:99 msgid "No configured providers. Run /auth first." msgstr "No hay proveedores configurados. Ejecute /auth primero." @@ -855,26 +850,26 @@ msgstr "Mostrar sugerencias de comandos" msgid "Exit" msgstr "Salir" -#: src/iac_code/commands/model.py:49 +#: src/iac_code/commands/model.py:57 #, python-brace-format msgid "" -"Model selection is locked by '{source}'. To change, modify llm_source in " -"settings.yml." +"Model is managed by '{source}'. To change model, modify it in {source} or" +" switch provider via /auth." msgstr "" -"La selección de modelo está bloqueada por '{source}'. Para cambiar, " -"modifique llm_source en settings.yml." +"El modelo es gestionado por '{source}'. Para cambiarlo, modifíquelo en " +"{source} o cambie de proveedor mediante /auth." -#: src/iac_code/commands/model.py:81 src/iac_code/commands/model.py:136 +#: src/iac_code/commands/model.py:88 src/iac_code/commands/model.py:143 #, python-brace-format msgid "Model switched to: {model}" msgstr "Modelo cambiado a: {model}" -#: src/iac_code/commands/model.py:85 +#: src/iac_code/commands/model.py:92 #, python-brace-format msgid "Current model: {model}" msgstr "Modelo actual: {model}" -#: src/iac_code/commands/model.py:111 +#: src/iac_code/commands/model.py:118 #, python-brace-format msgid "Kept model as {model}" msgstr "Se mantiene el modelo como {model}" @@ -1590,23 +1585,23 @@ msgstr "ROS Stack" msgid "CloudStackInstances" msgstr "CloudStackInstances" -#: src/iac_code/ui/banner.py:64 +#: src/iac_code/ui/banner.py:68 msgid "Your AI-powered Infrastructure as Code assistant" msgstr "Su asistente de infraestructura como código con IA" -#: src/iac_code/ui/banner.py:88 +#: src/iac_code/ui/banner.py:92 msgid "Welcome back" msgstr "Bienvenido de nuevo" -#: src/iac_code/ui/banner.py:94 +#: src/iac_code/ui/banner.py:98 msgid "Session" msgstr "Sesión" -#: src/iac_code/ui/banner.py:104 +#: src/iac_code/ui/banner.py:108 msgid "Debug mode" msgstr "Modo depuración" -#: src/iac_code/ui/banner.py:105 +#: src/iac_code/ui/banner.py:109 msgid "Log file" msgstr "Archivo de registro" @@ -1703,23 +1698,23 @@ msgstr "No, siempre denegar \"{rule}\" (esta sesión)" msgid "No, always reject this tool" msgstr "No, rechazar siempre esta herramienta" -#: src/iac_code/ui/repl.py:353 +#: src/iac_code/ui/repl.py:354 msgid "Press Ctrl+C again to exit." msgstr "Pulse Ctrl+C de nuevo para salir." -#: src/iac_code/ui/repl.py:373 +#: src/iac_code/ui/repl.py:374 msgid "Interrupted." msgstr "Interrumpido." -#: src/iac_code/ui/repl.py:410 +#: src/iac_code/ui/repl.py:411 msgid "Goodbye!" msgstr "¡Hasta luego!" -#: src/iac_code/ui/repl.py:411 +#: src/iac_code/ui/repl.py:412 msgid "Resume this session with:" msgstr "Para reanudar esta sesión, ejecute:" -#: src/iac_code/ui/repl.py:444 +#: src/iac_code/ui/repl.py:445 msgid "No image in clipboard." msgstr "No hay ninguna imagen en el portapapeles." @@ -1731,22 +1726,22 @@ msgstr "" "command: /{name}. Type /help for available commands.Comando desconocido: " "/{name}. Escriba /help para ver los comandos disponibles." -#: src/iac_code/ui/repl.py:608 src/iac_code/ui/repl.py:640 +#: src/iac_code/ui/repl.py:609 src/iac_code/ui/repl.py:654 #, python-brace-format msgid "Command error: {error}" msgstr "Error de comando: {error}" -#: src/iac_code/ui/repl.py:615 +#: src/iac_code/ui/repl.py:616 #, python-brace-format msgid "Command has no handler: {name}" msgstr "El comando no tiene controlador: {name}" -#: src/iac_code/ui/repl.py:835 +#: src/iac_code/ui/repl.py:889 #, python-brace-format msgid "Session not found: {session_id}" msgstr "Sesión no encontrada: {session_id}" -#: src/iac_code/ui/repl.py:854 +#: src/iac_code/ui/repl.py:908 #, python-brace-format msgid "" "This session belongs to a different directory.\n" @@ -1757,19 +1752,19 @@ msgstr "" "Para reanudar, ejecute:\n" " {cmd}" -#: src/iac_code/ui/repl.py:893 +#: src/iac_code/ui/repl.py:947 msgid "This conversation is from a different directory." msgstr "Esta conversación procede de otro directorio." -#: src/iac_code/ui/repl.py:895 +#: src/iac_code/ui/repl.py:949 msgid "To resume, run:" msgstr "Para reanudar, ejecute:" -#: src/iac_code/ui/repl.py:900 +#: src/iac_code/ui/repl.py:954 msgid "(Command copied to clipboard)" msgstr "(Comando copiado al portapapeles)" -#: src/iac_code/ui/repl.py:1057 +#: src/iac_code/ui/repl.py:1111 #, python-brace-format msgid "" "Current model {model} does not support image input. Use /model to switch " @@ -1778,12 +1773,12 @@ msgstr "" "El modelo actual {model} no admite entrada de imágenes. Usa /model para " "cambiar a un modelo con capacidad de visión." -#: src/iac_code/ui/repl.py:1066 +#: src/iac_code/ui/repl.py:1120 #, python-brace-format msgid "Image error: {err}" msgstr "Error de imagen: {err}" -#: src/iac_code/ui/repl.py:1083 +#: src/iac_code/ui/repl.py:1137 msgid "" "Failed to persist image to cache; it will only exist in memory for this " "turn." @@ -1989,3 +1984,15 @@ msgstr "hace {n} día{s}" #~ msgid "tree-sitter not available" #~ msgstr "tree-sitter not available" +#~ msgid "" +#~ "LLM provider is locked by '{source}'." +#~ " To change, modify llm_source in " +#~ "settings.yml." +#~ msgstr "" +#~ "El proveedor LLM está bloqueado por " +#~ "'{source}'. Para cambiar, modifique llm_source" +#~ " en settings.yml." + +#~ msgid "Provider switched: {status}" +#~ msgstr "Provider cambiado: {status}" + diff --git a/src/iac_code/i18n/locales/fr/LC_MESSAGES/messages.po b/src/iac_code/i18n/locales/fr/LC_MESSAGES/messages.po index b021d3ee..33f1a912 100644 --- a/src/iac_code/i18n/locales/fr/LC_MESSAGES/messages.po +++ b/src/iac_code/i18n/locales/fr/LC_MESSAGES/messages.po @@ -4,9 +4,9 @@ # msgid "" msgstr "" -"Project-Id-Version: iac-code 0.1.2\n" +"Project-Id-Version: iac-code 0.2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-05-18 18:09+0800\n" +"POT-Creation-Date: 2026-05-20 12:34+0800\n" "PO-Revision-Date: 2026-05-13 00:00+0000\n" "Last-Translator: \n" "Language: fr\n" @@ -540,225 +540,220 @@ msgstr "Reprendre une session précédente" msgid "[conversation id or search term]" msgstr "[identifiant de conversation ou terme de recherche]" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:836 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:844 #: src/iac_code/ui/core/prompt_input.py:505 msgid "Navigate" msgstr "Naviguer" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:368 -#: src/iac_code/commands/auth.py:402 src/iac_code/commands/auth.py:409 -#: src/iac_code/commands/auth.py:433 src/iac_code/commands/auth.py:836 -#: src/iac_code/commands/auth.py:1026 src/iac_code/ui/core/prompt_input.py:505 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:367 +#: src/iac_code/commands/auth.py:401 src/iac_code/commands/auth.py:408 +#: src/iac_code/commands/auth.py:432 src/iac_code/commands/auth.py:844 +#: src/iac_code/commands/auth.py:1034 src/iac_code/ui/core/prompt_input.py:505 msgid "Confirm" msgstr "Confirmer" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:366 -#: src/iac_code/commands/auth.py:368 src/iac_code/commands/auth.py:402 -#: src/iac_code/commands/auth.py:409 src/iac_code/commands/auth.py:433 -#: src/iac_code/commands/auth.py:836 src/iac_code/commands/auth.py:921 -#: src/iac_code/commands/auth.py:1026 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:365 +#: src/iac_code/commands/auth.py:367 src/iac_code/commands/auth.py:401 +#: src/iac_code/commands/auth.py:408 src/iac_code/commands/auth.py:432 +#: src/iac_code/commands/auth.py:844 src/iac_code/commands/auth.py:929 +#: src/iac_code/commands/auth.py:1034 msgid "Back" msgstr "Retour" -#: src/iac_code/commands/auth.py:366 +#: src/iac_code/commands/auth.py:365 msgid "Keep" msgstr "Conserver" -#: src/iac_code/commands/auth.py:366 +#: src/iac_code/commands/auth.py:365 msgid "Re-enter" msgstr "Saisir à nouveau" -#: src/iac_code/commands/auth.py:508 src/iac_code/commands/auth.py:650 -#: src/iac_code/commands/auth.py:670 +#: src/iac_code/commands/auth.py:507 src/iac_code/commands/auth.py:638 +#: src/iac_code/commands/auth.py:645 src/iac_code/commands/auth.py:678 msgid " (current)" msgstr " (actuel)" -#: src/iac_code/commands/auth.py:511 +#: src/iac_code/commands/auth.py:510 msgid "Custom model..." msgstr "Modèle personnalisé…" -#: src/iac_code/commands/auth.py:514 +#: src/iac_code/commands/auth.py:513 #, python-brace-format msgid "Select model for {provider}" msgstr "Sélectionner le modèle pour {provider}" -#: src/iac_code/commands/auth.py:516 +#: src/iac_code/commands/auth.py:515 msgid "Select model" msgstr "Sélectionner le modèle" -#: src/iac_code/commands/auth.py:524 +#: src/iac_code/commands/auth.py:523 msgid "Enter custom model name: " msgstr "Saisir le nom du modèle personnalisé : " -#: src/iac_code/commands/auth.py:550 +#: src/iac_code/commands/auth.py:549 msgid "Error: console not available" msgstr "Erreur : console indisponible" #: src/iac_code/commands/auth.py:576 -#, python-brace-format -msgid "" -"LLM provider is locked by '{source}'. To change, modify llm_source in " -"settings.yml." -msgstr "" -"Le fournisseur LLM est verrouillé par '{source}'. Pour changer, modifiez " -"llm_source dans settings.yml." - -#: src/iac_code/commands/auth.py:580 src/iac_code/commands/auth.py:780 -msgid "Select Cloud Provider" -msgstr "Sélectionner le fournisseur cloud" - -#: src/iac_code/commands/auth.py:582 src/iac_code/commands/auth.py:589 -#: src/iac_code/commands/auth.py:600 src/iac_code/commands/auth.py:695 -#: src/iac_code/commands/auth.py:711 src/iac_code/commands/auth.py:789 -#: src/iac_code/commands/auth.py:962 src/iac_code/commands/auth.py:1003 -msgid "Auth cancelled" -msgstr "Authentification annulée" - -#: src/iac_code/commands/auth.py:595 msgid "Configure LLM Provider" msgstr "Configurer le fournisseur LLM" -#: src/iac_code/commands/auth.py:596 +#: src/iac_code/commands/auth.py:577 msgid "Configure IaC Cloud Service" msgstr "Configurer le service cloud IaC" -#: src/iac_code/commands/auth.py:598 +#: src/iac_code/commands/auth.py:579 msgid "Select configuration type" msgstr "Sélectionner le type de configuration" -#: src/iac_code/commands/auth.py:654 +#: src/iac_code/commands/auth.py:581 src/iac_code/commands/auth.py:703 +#: src/iac_code/commands/auth.py:719 src/iac_code/commands/auth.py:797 +#: src/iac_code/commands/auth.py:970 src/iac_code/commands/auth.py:1011 +msgid "Auth cancelled" +msgstr "Authentification annulée" + +#: src/iac_code/commands/auth.py:649 msgid "Select provider" msgstr "Sélectionner le fournisseur" -#: src/iac_code/commands/auth.py:675 src/iac_code/commands/auth.py:764 +#: src/iac_code/commands/auth.py:661 +#, python-brace-format +msgid "{status}: {provider}" +msgstr "{status} : {provider}" + +#: src/iac_code/commands/auth.py:662 src/iac_code/commands/auth.py:751 +msgid "Configured" +msgstr "Configuré" + +#: src/iac_code/commands/auth.py:683 src/iac_code/commands/auth.py:772 #, python-brace-format msgid "Select provider — {group}" msgstr "Sélectionner le fournisseur — {group}" -#: src/iac_code/commands/auth.py:688 +#: src/iac_code/commands/auth.py:696 #, python-brace-format msgid "Configure {provider}" msgstr "Configurer {provider}" -#: src/iac_code/commands/auth.py:704 +#: src/iac_code/commands/auth.py:712 #, python-brace-format msgid "Enter API key for {provider}" msgstr "Saisir la clé API pour {provider}" -#: src/iac_code/commands/auth.py:742 +#: src/iac_code/commands/auth.py:750 #, python-brace-format msgid "{status}: {provider} / {model}" msgstr "{status} : {provider} / {model}" -#: src/iac_code/commands/auth.py:743 -msgid "Configured" -msgstr "Configuré" - -#: src/iac_code/commands/auth.py:750 src/iac_code/commands/auth.py:771 +#: src/iac_code/commands/auth.py:758 src/iac_code/commands/auth.py:779 msgid "Alibaba Cloud" msgstr "Alibaba Cloud" -#: src/iac_code/commands/auth.py:751 src/iac_code/providers/registry.py:423 +#: src/iac_code/commands/auth.py:759 src/iac_code/providers/registry.py:423 msgid "ZhiPu AI" msgstr "ZhiPu AI" -#: src/iac_code/commands/auth.py:752 +#: src/iac_code/commands/auth.py:760 msgid "Kimi" msgstr "Kimi" -#: src/iac_code/commands/auth.py:753 +#: src/iac_code/commands/auth.py:761 msgid "MiniMax" msgstr "MiniMax" -#: src/iac_code/commands/auth.py:754 src/iac_code/providers/registry.py:425 +#: src/iac_code/commands/auth.py:762 src/iac_code/providers/registry.py:425 msgid "Volcengine" msgstr "Volcengine" -#: src/iac_code/commands/auth.py:755 +#: src/iac_code/commands/auth.py:763 msgid "SiliconFlow" msgstr "SiliconFlow" -#: src/iac_code/commands/auth.py:756 src/iac_code/providers/registry.py:416 +#: src/iac_code/commands/auth.py:764 src/iac_code/providers/registry.py:416 msgid "DeepSeek" msgstr "DeepSeek" -#: src/iac_code/commands/auth.py:757 src/iac_code/providers/registry.py:414 +#: src/iac_code/commands/auth.py:765 src/iac_code/providers/registry.py:414 msgid "OpenAI" msgstr "OpenAI" -#: src/iac_code/commands/auth.py:758 src/iac_code/providers/registry.py:415 +#: src/iac_code/commands/auth.py:766 src/iac_code/providers/registry.py:415 msgid "Anthropic" msgstr "Anthropic" -#: src/iac_code/commands/auth.py:759 src/iac_code/providers/registry.py:418 +#: src/iac_code/commands/auth.py:767 src/iac_code/providers/registry.py:418 msgid "Google Gemini" msgstr "Google Gemini" -#: src/iac_code/commands/auth.py:760 src/iac_code/providers/registry.py:431 +#: src/iac_code/commands/auth.py:768 src/iac_code/providers/registry.py:431 msgid "Azure OpenAI" msgstr "Azure OpenAI" -#: src/iac_code/commands/auth.py:761 src/iac_code/providers/registry.py:430 +#: src/iac_code/commands/auth.py:769 src/iac_code/providers/registry.py:430 msgid "OpenRouter" msgstr "OpenRouter" -#: src/iac_code/commands/auth.py:762 +#: src/iac_code/commands/auth.py:770 msgid "Local" msgstr "Local" -#: src/iac_code/commands/auth.py:763 +#: src/iac_code/commands/auth.py:771 msgid "Compatible" msgstr "Compatible" -#: src/iac_code/commands/auth.py:796 +#: src/iac_code/commands/auth.py:788 +msgid "Select Cloud Provider" +msgstr "Sélectionner le fournisseur cloud" + +#: src/iac_code/commands/auth.py:804 msgid "Credential" msgstr "Identifiants" -#: src/iac_code/commands/auth.py:797 src/iac_code/commands/auth.py:894 -#: src/iac_code/commands/auth.py:999 src/iac_code/ui/renderer.py:418 +#: src/iac_code/commands/auth.py:805 src/iac_code/commands/auth.py:902 +#: src/iac_code/commands/auth.py:1007 src/iac_code/ui/renderer.py:418 msgid "Region" msgstr "Région" -#: src/iac_code/commands/auth.py:799 +#: src/iac_code/commands/auth.py:807 msgid "Configure Alibaba Cloud" msgstr "Configurer Alibaba Cloud" -#: src/iac_code/commands/auth.py:882 +#: src/iac_code/commands/auth.py:890 msgid "Current configuration" msgstr "Configuration actuelle" -#: src/iac_code/commands/auth.py:884 +#: src/iac_code/commands/auth.py:892 msgid "Mode" msgstr "Mode" -#: src/iac_code/commands/auth.py:891 +#: src/iac_code/commands/auth.py:899 msgid "(not set)" msgstr "(non défini)" -#: src/iac_code/commands/auth.py:908 +#: src/iac_code/commands/auth.py:916 msgid "Configure Alibaba Cloud credentials" msgstr "Configurer les identifiants Alibaba Cloud" -#: src/iac_code/commands/auth.py:921 +#: src/iac_code/commands/auth.py:929 msgid "Reconfigure credential" msgstr "Reconfigurer les identifiants" -#: src/iac_code/commands/auth.py:934 +#: src/iac_code/commands/auth.py:942 msgid "Select credential type" msgstr "Sélectionner le type d’identifiants" -#: src/iac_code/commands/auth.py:984 +#: src/iac_code/commands/auth.py:992 msgid "Configured: Alibaba Cloud credentials saved to ~/.iac-code" msgstr "" "Configured: Alibaba Cloud credentials saved to ~/.iac-codeConfigured: " "Alibaba Cloud credentials saved to ~/.iac-codeConfiguration effectuée : " "identifiants Alibaba Cloud enregistrés dans ~/.iac-code" -#: src/iac_code/commands/auth.py:991 +#: src/iac_code/commands/auth.py:999 msgid "Configure Alibaba Cloud region" msgstr "Configurer la région Alibaba Cloud" -#: src/iac_code/commands/auth.py:1017 +#: src/iac_code/commands/auth.py:1025 msgid "Configured: Alibaba Cloud region saved to ~/.iac-code" msgstr "" "Configured: Alibaba Cloud region saved to ~/.iac-codeConfigured: Alibaba " @@ -794,8 +789,8 @@ msgstr "La commande debug nécessite un contexte." msgid "No active session." msgstr "Aucune session active." -#: src/iac_code/commands/effort.py:54 src/iac_code/commands/model.py:88 -#: src/iac_code/commands/model.py:92 +#: src/iac_code/commands/effort.py:54 src/iac_code/commands/model.py:95 +#: src/iac_code/commands/model.py:99 msgid "No configured providers. Run /auth first." msgstr "Aucun fournisseur configuré. Exécutez d’abord /auth." @@ -857,26 +852,26 @@ msgstr "Afficher les suggestions de commandes" msgid "Exit" msgstr "Quitter" -#: src/iac_code/commands/model.py:49 +#: src/iac_code/commands/model.py:57 #, python-brace-format msgid "" -"Model selection is locked by '{source}'. To change, modify llm_source in " -"settings.yml." +"Model is managed by '{source}'. To change model, modify it in {source} or" +" switch provider via /auth." msgstr "" -"La sélection du modèle est verrouillée par '{source}'. Pour changer, " -"modifiez llm_source dans settings.yml." +"Le modèle est géré par '{source}'. Pour changer le modèle, modifiez-le " +"dans {source} ou changez de fournisseur via /auth." -#: src/iac_code/commands/model.py:81 src/iac_code/commands/model.py:136 +#: src/iac_code/commands/model.py:88 src/iac_code/commands/model.py:143 #, python-brace-format msgid "Model switched to: {model}" msgstr "Modèle défini sur : {model}" -#: src/iac_code/commands/model.py:85 +#: src/iac_code/commands/model.py:92 #, python-brace-format msgid "Current model: {model}" msgstr "Modèle actuel : {model}" -#: src/iac_code/commands/model.py:111 +#: src/iac_code/commands/model.py:118 #, python-brace-format msgid "Kept model as {model}" msgstr "Modèle conservé : {model}" @@ -1590,23 +1585,23 @@ msgstr "ROS Stack" msgid "CloudStackInstances" msgstr "CloudStackInstances" -#: src/iac_code/ui/banner.py:64 +#: src/iac_code/ui/banner.py:68 msgid "Your AI-powered Infrastructure as Code assistant" msgstr "Votre assistant Infrastructure as Code assisté par IA" -#: src/iac_code/ui/banner.py:88 +#: src/iac_code/ui/banner.py:92 msgid "Welcome back" msgstr "Bon retour" -#: src/iac_code/ui/banner.py:94 +#: src/iac_code/ui/banner.py:98 msgid "Session" msgstr "Session" -#: src/iac_code/ui/banner.py:104 +#: src/iac_code/ui/banner.py:108 msgid "Debug mode" msgstr "Mode debug" -#: src/iac_code/ui/banner.py:105 +#: src/iac_code/ui/banner.py:109 msgid "Log file" msgstr "Fichier journal" @@ -1705,23 +1700,23 @@ msgstr "Non, toujours refuser \"{rule}\" (cette session)" msgid "No, always reject this tool" msgstr "Non, toujours refuser cet outil" -#: src/iac_code/ui/repl.py:353 +#: src/iac_code/ui/repl.py:354 msgid "Press Ctrl+C again to exit." msgstr "Appuyez de nouveau sur Ctrl+C pour quitter." -#: src/iac_code/ui/repl.py:373 +#: src/iac_code/ui/repl.py:374 msgid "Interrupted." msgstr "Interrompu." -#: src/iac_code/ui/repl.py:410 +#: src/iac_code/ui/repl.py:411 msgid "Goodbye!" msgstr "Au revoir !" -#: src/iac_code/ui/repl.py:411 +#: src/iac_code/ui/repl.py:412 msgid "Resume this session with:" msgstr "Pour reprendre cette session :" -#: src/iac_code/ui/repl.py:444 +#: src/iac_code/ui/repl.py:445 msgid "No image in clipboard." msgstr "Aucune image dans le presse-papiers." @@ -1732,22 +1727,22 @@ msgstr "" "Unknown command: /{name}. Type /help for available commands.Commande " "inconnue : /{name}. Saisissez /help pour la liste des commandes." -#: src/iac_code/ui/repl.py:608 src/iac_code/ui/repl.py:640 +#: src/iac_code/ui/repl.py:609 src/iac_code/ui/repl.py:654 #, python-brace-format msgid "Command error: {error}" msgstr "Erreur de commande : {error}" -#: src/iac_code/ui/repl.py:615 +#: src/iac_code/ui/repl.py:616 #, python-brace-format msgid "Command has no handler: {name}" msgstr "Aucun gestionnaire pour la commande : {name}" -#: src/iac_code/ui/repl.py:835 +#: src/iac_code/ui/repl.py:889 #, python-brace-format msgid "Session not found: {session_id}" msgstr "Session introuvable : {session_id}" -#: src/iac_code/ui/repl.py:854 +#: src/iac_code/ui/repl.py:908 #, python-brace-format msgid "" "This session belongs to a different directory.\n" @@ -1758,19 +1753,19 @@ msgstr "" "Pour la reprendre, exécutez :\n" " {cmd}" -#: src/iac_code/ui/repl.py:893 +#: src/iac_code/ui/repl.py:947 msgid "This conversation is from a different directory." msgstr "Cette conversation provient d’un autre répertoire." -#: src/iac_code/ui/repl.py:895 +#: src/iac_code/ui/repl.py:949 msgid "To resume, run:" msgstr "Pour reprendre, exécutez :" -#: src/iac_code/ui/repl.py:900 +#: src/iac_code/ui/repl.py:954 msgid "(Command copied to clipboard)" msgstr "(Commande copiée dans le presse-papiers)" -#: src/iac_code/ui/repl.py:1057 +#: src/iac_code/ui/repl.py:1111 #, python-brace-format msgid "" "Current model {model} does not support image input. Use /model to switch " @@ -1779,12 +1774,12 @@ msgstr "" "Le modèle actuel {model} ne prend pas en charge l’entrée d’image. " "Utilisez /model pour passer à un modèle compatible vision." -#: src/iac_code/ui/repl.py:1066 +#: src/iac_code/ui/repl.py:1120 #, python-brace-format msgid "Image error: {err}" msgstr "Erreur d’image : {err}" -#: src/iac_code/ui/repl.py:1083 +#: src/iac_code/ui/repl.py:1137 msgid "" "Failed to persist image to cache; it will only exist in memory for this " "turn." @@ -1975,3 +1970,15 @@ msgstr "il y a {n} jour{s}" #~ msgid "tree-sitter not available" #~ msgstr "tree-sitter not available" +#~ msgid "" +#~ "LLM provider is locked by '{source}'." +#~ " To change, modify llm_source in " +#~ "settings.yml." +#~ msgstr "" +#~ "Le fournisseur LLM est verrouillé par" +#~ " '{source}'. Pour changer, modifiez " +#~ "llm_source dans settings.yml." + +#~ msgid "Provider switched: {status}" +#~ msgstr "Provider changé : {status}" + diff --git a/src/iac_code/i18n/locales/ja/LC_MESSAGES/messages.po b/src/iac_code/i18n/locales/ja/LC_MESSAGES/messages.po index 974c9fa1..d17fde4e 100644 --- a/src/iac_code/i18n/locales/ja/LC_MESSAGES/messages.po +++ b/src/iac_code/i18n/locales/ja/LC_MESSAGES/messages.po @@ -4,9 +4,9 @@ # msgid "" msgstr "" -"Project-Id-Version: iac-code 0.1.2\n" +"Project-Id-Version: iac-code 0.2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-05-18 18:09+0800\n" +"POT-Creation-Date: 2026-05-20 12:34+0800\n" "PO-Revision-Date: 2026-05-13 00:00+0000\n" "Last-Translator: \n" "Language: ja\n" @@ -523,224 +523,219 @@ msgstr "以前のセッションを再開します" msgid "[conversation id or search term]" msgstr "[会話 ID または検索語]" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:836 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:844 #: src/iac_code/ui/core/prompt_input.py:505 msgid "Navigate" msgstr "移動" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:368 -#: src/iac_code/commands/auth.py:402 src/iac_code/commands/auth.py:409 -#: src/iac_code/commands/auth.py:433 src/iac_code/commands/auth.py:836 -#: src/iac_code/commands/auth.py:1026 src/iac_code/ui/core/prompt_input.py:505 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:367 +#: src/iac_code/commands/auth.py:401 src/iac_code/commands/auth.py:408 +#: src/iac_code/commands/auth.py:432 src/iac_code/commands/auth.py:844 +#: src/iac_code/commands/auth.py:1034 src/iac_code/ui/core/prompt_input.py:505 msgid "Confirm" msgstr "確認" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:366 -#: src/iac_code/commands/auth.py:368 src/iac_code/commands/auth.py:402 -#: src/iac_code/commands/auth.py:409 src/iac_code/commands/auth.py:433 -#: src/iac_code/commands/auth.py:836 src/iac_code/commands/auth.py:921 -#: src/iac_code/commands/auth.py:1026 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:365 +#: src/iac_code/commands/auth.py:367 src/iac_code/commands/auth.py:401 +#: src/iac_code/commands/auth.py:408 src/iac_code/commands/auth.py:432 +#: src/iac_code/commands/auth.py:844 src/iac_code/commands/auth.py:929 +#: src/iac_code/commands/auth.py:1034 msgid "Back" msgstr "戻る" -#: src/iac_code/commands/auth.py:366 +#: src/iac_code/commands/auth.py:365 msgid "Keep" msgstr "維持" -#: src/iac_code/commands/auth.py:366 +#: src/iac_code/commands/auth.py:365 msgid "Re-enter" msgstr "再入力" -#: src/iac_code/commands/auth.py:508 src/iac_code/commands/auth.py:650 -#: src/iac_code/commands/auth.py:670 +#: src/iac_code/commands/auth.py:507 src/iac_code/commands/auth.py:638 +#: src/iac_code/commands/auth.py:645 src/iac_code/commands/auth.py:678 msgid " (current)" msgstr " (現在)" -#: src/iac_code/commands/auth.py:511 +#: src/iac_code/commands/auth.py:510 msgid "Custom model..." msgstr "カスタムモデル…" -#: src/iac_code/commands/auth.py:514 +#: src/iac_code/commands/auth.py:513 #, python-brace-format msgid "Select model for {provider}" msgstr "{provider} のモデルを選択してください" -#: src/iac_code/commands/auth.py:516 +#: src/iac_code/commands/auth.py:515 msgid "Select model" msgstr "モデルを選択" -#: src/iac_code/commands/auth.py:524 +#: src/iac_code/commands/auth.py:523 msgid "Enter custom model name: " msgstr "カスタムモデル名を入力してください:" -#: src/iac_code/commands/auth.py:550 +#: src/iac_code/commands/auth.py:549 msgid "Error: console not available" msgstr "エラー:コンソールを使用できません" #: src/iac_code/commands/auth.py:576 -#, python-brace-format -msgid "" -"LLM provider is locked by '{source}'. To change, modify llm_source in " -"settings.yml." -msgstr "" -"LLM プロバイダーは '{source}' によりロックされています。変更するには settings.yml の llm_source " -"を修正してください。" - -#: src/iac_code/commands/auth.py:580 src/iac_code/commands/auth.py:780 -msgid "Select Cloud Provider" -msgstr "クラウドプロバイダーを選択" - -#: src/iac_code/commands/auth.py:582 src/iac_code/commands/auth.py:589 -#: src/iac_code/commands/auth.py:600 src/iac_code/commands/auth.py:695 -#: src/iac_code/commands/auth.py:711 src/iac_code/commands/auth.py:789 -#: src/iac_code/commands/auth.py:962 src/iac_code/commands/auth.py:1003 -msgid "Auth cancelled" -msgstr "認証をキャンセルしました" - -#: src/iac_code/commands/auth.py:595 msgid "Configure LLM Provider" msgstr "LLM プロバイダーを設定" -#: src/iac_code/commands/auth.py:596 +#: src/iac_code/commands/auth.py:577 msgid "Configure IaC Cloud Service" msgstr "IaC クラウドサービスを設定" -#: src/iac_code/commands/auth.py:598 +#: src/iac_code/commands/auth.py:579 msgid "Select configuration type" msgstr "設定の種類を選択" -#: src/iac_code/commands/auth.py:654 +#: src/iac_code/commands/auth.py:581 src/iac_code/commands/auth.py:703 +#: src/iac_code/commands/auth.py:719 src/iac_code/commands/auth.py:797 +#: src/iac_code/commands/auth.py:970 src/iac_code/commands/auth.py:1011 +msgid "Auth cancelled" +msgstr "認証をキャンセルしました" + +#: src/iac_code/commands/auth.py:649 msgid "Select provider" msgstr "プロバイダーを選択" -#: src/iac_code/commands/auth.py:675 src/iac_code/commands/auth.py:764 +#: src/iac_code/commands/auth.py:661 +#, python-brace-format +msgid "{status}: {provider}" +msgstr "{status}:{provider}" + +#: src/iac_code/commands/auth.py:662 src/iac_code/commands/auth.py:751 +msgid "Configured" +msgstr "設定済み" + +#: src/iac_code/commands/auth.py:683 src/iac_code/commands/auth.py:772 #, python-brace-format msgid "Select provider — {group}" msgstr "プロバイダーを選択 — {group}" -#: src/iac_code/commands/auth.py:688 +#: src/iac_code/commands/auth.py:696 #, python-brace-format msgid "Configure {provider}" msgstr "{provider} を設定" -#: src/iac_code/commands/auth.py:704 +#: src/iac_code/commands/auth.py:712 #, python-brace-format msgid "Enter API key for {provider}" msgstr "{provider} の API key を入力してください" -#: src/iac_code/commands/auth.py:742 +#: src/iac_code/commands/auth.py:750 #, python-brace-format msgid "{status}: {provider} / {model}" msgstr "{status}:{provider} / {model}" -#: src/iac_code/commands/auth.py:743 -msgid "Configured" -msgstr "設定済み" - -#: src/iac_code/commands/auth.py:750 src/iac_code/commands/auth.py:771 +#: src/iac_code/commands/auth.py:758 src/iac_code/commands/auth.py:779 msgid "Alibaba Cloud" msgstr "Alibaba Cloud" -#: src/iac_code/commands/auth.py:751 src/iac_code/providers/registry.py:423 +#: src/iac_code/commands/auth.py:759 src/iac_code/providers/registry.py:423 msgid "ZhiPu AI" msgstr "ZhiPu AI" -#: src/iac_code/commands/auth.py:752 +#: src/iac_code/commands/auth.py:760 msgid "Kimi" msgstr "Kimi" -#: src/iac_code/commands/auth.py:753 +#: src/iac_code/commands/auth.py:761 msgid "MiniMax" msgstr "MiniMax" -#: src/iac_code/commands/auth.py:754 src/iac_code/providers/registry.py:425 +#: src/iac_code/commands/auth.py:762 src/iac_code/providers/registry.py:425 msgid "Volcengine" msgstr "Volcengine" -#: src/iac_code/commands/auth.py:755 +#: src/iac_code/commands/auth.py:763 msgid "SiliconFlow" msgstr "SiliconFlow" -#: src/iac_code/commands/auth.py:756 src/iac_code/providers/registry.py:416 +#: src/iac_code/commands/auth.py:764 src/iac_code/providers/registry.py:416 msgid "DeepSeek" msgstr "DeepSeek" -#: src/iac_code/commands/auth.py:757 src/iac_code/providers/registry.py:414 +#: src/iac_code/commands/auth.py:765 src/iac_code/providers/registry.py:414 msgid "OpenAI" msgstr "OpenAI" -#: src/iac_code/commands/auth.py:758 src/iac_code/providers/registry.py:415 +#: src/iac_code/commands/auth.py:766 src/iac_code/providers/registry.py:415 msgid "Anthropic" msgstr "Anthropic" -#: src/iac_code/commands/auth.py:759 src/iac_code/providers/registry.py:418 +#: src/iac_code/commands/auth.py:767 src/iac_code/providers/registry.py:418 msgid "Google Gemini" msgstr "Google Gemini" -#: src/iac_code/commands/auth.py:760 src/iac_code/providers/registry.py:431 +#: src/iac_code/commands/auth.py:768 src/iac_code/providers/registry.py:431 msgid "Azure OpenAI" msgstr "Azure OpenAI" -#: src/iac_code/commands/auth.py:761 src/iac_code/providers/registry.py:430 +#: src/iac_code/commands/auth.py:769 src/iac_code/providers/registry.py:430 msgid "OpenRouter" msgstr "OpenRouter" -#: src/iac_code/commands/auth.py:762 +#: src/iac_code/commands/auth.py:770 msgid "Local" msgstr "ローカル" -#: src/iac_code/commands/auth.py:763 +#: src/iac_code/commands/auth.py:771 msgid "Compatible" msgstr "互換モード" -#: src/iac_code/commands/auth.py:796 +#: src/iac_code/commands/auth.py:788 +msgid "Select Cloud Provider" +msgstr "クラウドプロバイダーを選択" + +#: src/iac_code/commands/auth.py:804 msgid "Credential" msgstr "クレデンシャル" -#: src/iac_code/commands/auth.py:797 src/iac_code/commands/auth.py:894 -#: src/iac_code/commands/auth.py:999 src/iac_code/ui/renderer.py:418 +#: src/iac_code/commands/auth.py:805 src/iac_code/commands/auth.py:902 +#: src/iac_code/commands/auth.py:1007 src/iac_code/ui/renderer.py:418 msgid "Region" msgstr "リージョン" -#: src/iac_code/commands/auth.py:799 +#: src/iac_code/commands/auth.py:807 msgid "Configure Alibaba Cloud" msgstr "Alibaba Cloud を設定" -#: src/iac_code/commands/auth.py:882 +#: src/iac_code/commands/auth.py:890 msgid "Current configuration" msgstr "現在の設定" -#: src/iac_code/commands/auth.py:884 +#: src/iac_code/commands/auth.py:892 msgid "Mode" msgstr "モード" -#: src/iac_code/commands/auth.py:891 +#: src/iac_code/commands/auth.py:899 msgid "(not set)" msgstr "(未設定)" -#: src/iac_code/commands/auth.py:908 +#: src/iac_code/commands/auth.py:916 msgid "Configure Alibaba Cloud credentials" msgstr "Alibaba Cloud のクレデンシャルを設定" -#: src/iac_code/commands/auth.py:921 +#: src/iac_code/commands/auth.py:929 msgid "Reconfigure credential" msgstr "クレデンシャルを再設定" -#: src/iac_code/commands/auth.py:934 +#: src/iac_code/commands/auth.py:942 msgid "Select credential type" msgstr "クレデンシャルの種類を選択" -#: src/iac_code/commands/auth.py:984 +#: src/iac_code/commands/auth.py:992 msgid "Configured: Alibaba Cloud credentials saved to ~/.iac-code" msgstr "" "Configured: Alibaba Cloud credentials saved to ~/.iac-code設定しました:Alibaba " "Cloud のクレデンシャルを ~/.iac-code に保存しました" -#: src/iac_code/commands/auth.py:991 +#: src/iac_code/commands/auth.py:999 msgid "Configure Alibaba Cloud region" msgstr "Alibaba Cloud のリージョンを設定" -#: src/iac_code/commands/auth.py:1017 +#: src/iac_code/commands/auth.py:1025 msgid "Configured: Alibaba Cloud region saved to ~/.iac-code" msgstr "設定しました:Alibaba Cloud のリージョンを ~/.iac-code に保存しました" @@ -773,8 +768,8 @@ msgstr "debug コマンドにはコンテキストが必要です。" msgid "No active session." msgstr "アクティブなセッションがありません。" -#: src/iac_code/commands/effort.py:54 src/iac_code/commands/model.py:88 -#: src/iac_code/commands/model.py:92 +#: src/iac_code/commands/effort.py:54 src/iac_code/commands/model.py:95 +#: src/iac_code/commands/model.py:99 msgid "No configured providers. Run /auth first." msgstr "設定済みのプロバイダーがありません。先に /auth を実行してください。" @@ -836,24 +831,26 @@ msgstr "コマンド候補を表示" msgid "Exit" msgstr "終了" -#: src/iac_code/commands/model.py:49 +#: src/iac_code/commands/model.py:57 #, python-brace-format msgid "" -"Model selection is locked by '{source}'. To change, modify llm_source in " -"settings.yml." -msgstr "モデル選択は '{source}' によりロックされています。変更するには settings.yml の llm_source を修正してください。" +"Model is managed by '{source}'. To change model, modify it in {source} or" +" switch provider via /auth." +msgstr "" +"モデルは '{source}' によって管理されています。モデルを変更するには {source} で調整するか、/auth " +"で別のプロバイダーに切り替えてください。" -#: src/iac_code/commands/model.py:81 src/iac_code/commands/model.py:136 +#: src/iac_code/commands/model.py:88 src/iac_code/commands/model.py:143 #, python-brace-format msgid "Model switched to: {model}" msgstr "モデルを {model} に切り替えました" -#: src/iac_code/commands/model.py:85 +#: src/iac_code/commands/model.py:92 #, python-brace-format msgid "Current model: {model}" msgstr "現在のモデル:{model}" -#: src/iac_code/commands/model.py:111 +#: src/iac_code/commands/model.py:118 #, python-brace-format msgid "Kept model as {model}" msgstr "モデルを {model} のままにしました" @@ -1555,23 +1552,23 @@ msgstr "ROS スタック" msgid "CloudStackInstances" msgstr "CloudStackInstances" -#: src/iac_code/ui/banner.py:64 +#: src/iac_code/ui/banner.py:68 msgid "Your AI-powered Infrastructure as Code assistant" msgstr "あなたの AI 駆動の Infrastructure as Code アシスタントです" -#: src/iac_code/ui/banner.py:88 +#: src/iac_code/ui/banner.py:92 msgid "Welcome back" msgstr "おかえりなさい" -#: src/iac_code/ui/banner.py:94 +#: src/iac_code/ui/banner.py:98 msgid "Session" msgstr "セッション" -#: src/iac_code/ui/banner.py:104 +#: src/iac_code/ui/banner.py:108 msgid "Debug mode" msgstr "デバッグモード" -#: src/iac_code/ui/banner.py:105 +#: src/iac_code/ui/banner.py:109 msgid "Log file" msgstr "ログファイル" @@ -1668,23 +1665,23 @@ msgstr "いいえ、常に \"{rule}\" を拒否(このセッション)" msgid "No, always reject this tool" msgstr "いいえ、このツールは常に拒否" -#: src/iac_code/ui/repl.py:353 +#: src/iac_code/ui/repl.py:354 msgid "Press Ctrl+C again to exit." msgstr "終了するには Ctrl+C をもう一度押してください。" -#: src/iac_code/ui/repl.py:373 +#: src/iac_code/ui/repl.py:374 msgid "Interrupted." msgstr "中断しました。" -#: src/iac_code/ui/repl.py:410 +#: src/iac_code/ui/repl.py:411 msgid "Goodbye!" msgstr "さようなら。" -#: src/iac_code/ui/repl.py:411 +#: src/iac_code/ui/repl.py:412 msgid "Resume this session with:" msgstr "このセッションを再開するには次を実行してください:" -#: src/iac_code/ui/repl.py:444 +#: src/iac_code/ui/repl.py:445 msgid "No image in clipboard." msgstr "クリップボードに画像がありません。" @@ -1695,22 +1692,22 @@ msgstr "" "Unknown command: /{name}. Type /help for available " "commands.不明なコマンドです:/{name}。利用可能なコマンドは /help を入力してください。" -#: src/iac_code/ui/repl.py:608 src/iac_code/ui/repl.py:640 +#: src/iac_code/ui/repl.py:609 src/iac_code/ui/repl.py:654 #, python-brace-format msgid "Command error: {error}" msgstr "コマンドエラー:{error}" -#: src/iac_code/ui/repl.py:615 +#: src/iac_code/ui/repl.py:616 #, python-brace-format msgid "Command has no handler: {name}" msgstr "ハンドラーがないコマンドです:{name}" -#: src/iac_code/ui/repl.py:835 +#: src/iac_code/ui/repl.py:889 #, python-brace-format msgid "Session not found: {session_id}" msgstr "セッションが見つかりません:{session_id}" -#: src/iac_code/ui/repl.py:854 +#: src/iac_code/ui/repl.py:908 #, python-brace-format msgid "" "This session belongs to a different directory.\n" @@ -1721,31 +1718,31 @@ msgstr "" "再開するには次を実行してください:\n" " {cmd}" -#: src/iac_code/ui/repl.py:893 +#: src/iac_code/ui/repl.py:947 msgid "This conversation is from a different directory." msgstr "この会話は別のディレクトリ由来です。" -#: src/iac_code/ui/repl.py:895 +#: src/iac_code/ui/repl.py:949 msgid "To resume, run:" msgstr "再開するには次を実行してください:" -#: src/iac_code/ui/repl.py:900 +#: src/iac_code/ui/repl.py:954 msgid "(Command copied to clipboard)" msgstr "(コマンドをクリップボードにコピーしました)" -#: src/iac_code/ui/repl.py:1057 +#: src/iac_code/ui/repl.py:1111 #, python-brace-format msgid "" "Current model {model} does not support image input. Use /model to switch " "to a vision-capable model." msgstr "現在のモデル {model} は画像入力をサポートしていません。/model を使用してビジョン対応モデルに切り替えてください。" -#: src/iac_code/ui/repl.py:1066 +#: src/iac_code/ui/repl.py:1120 #, python-brace-format msgid "Image error: {err}" msgstr "画像エラー:{err}" -#: src/iac_code/ui/repl.py:1083 +#: src/iac_code/ui/repl.py:1137 msgid "" "Failed to persist image to cache; it will only exist in memory for this " "turn." @@ -1949,3 +1946,14 @@ msgstr "{n} 日{s}前" #~ msgid "tree-sitter not available" #~ msgstr "tree-sitter not available" +#~ msgid "" +#~ "LLM provider is locked by '{source}'." +#~ " To change, modify llm_source in " +#~ "settings.yml." +#~ msgstr "" +#~ "LLM プロバイダーは '{source}' によりロックされています。変更するには " +#~ "settings.yml の llm_source を修正してください。" + +#~ msgid "Provider switched: {status}" +#~ msgstr "Provider が切り替わりました: {status}" + diff --git a/src/iac_code/i18n/locales/pt/LC_MESSAGES/messages.po b/src/iac_code/i18n/locales/pt/LC_MESSAGES/messages.po index 881ca83d..064cd1d4 100644 --- a/src/iac_code/i18n/locales/pt/LC_MESSAGES/messages.po +++ b/src/iac_code/i18n/locales/pt/LC_MESSAGES/messages.po @@ -4,9 +4,9 @@ # msgid "" msgstr "" -"Project-Id-Version: iac-code 0.1.2\n" +"Project-Id-Version: iac-code 0.2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-05-18 18:09+0800\n" +"POT-Creation-Date: 2026-05-20 12:34+0800\n" "PO-Revision-Date: 2026-05-13 00:00+0000\n" "Last-Translator: \n" "Language: pt\n" @@ -537,222 +537,217 @@ msgstr "Retomar uma sessão anterior" msgid "[conversation id or search term]" msgstr "[ID da conversa ou termo de busca]" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:836 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:844 #: src/iac_code/ui/core/prompt_input.py:505 msgid "Navigate" msgstr "Navegar" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:368 -#: src/iac_code/commands/auth.py:402 src/iac_code/commands/auth.py:409 -#: src/iac_code/commands/auth.py:433 src/iac_code/commands/auth.py:836 -#: src/iac_code/commands/auth.py:1026 src/iac_code/ui/core/prompt_input.py:505 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:367 +#: src/iac_code/commands/auth.py:401 src/iac_code/commands/auth.py:408 +#: src/iac_code/commands/auth.py:432 src/iac_code/commands/auth.py:844 +#: src/iac_code/commands/auth.py:1034 src/iac_code/ui/core/prompt_input.py:505 msgid "Confirm" msgstr "Confirmar" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:366 -#: src/iac_code/commands/auth.py:368 src/iac_code/commands/auth.py:402 -#: src/iac_code/commands/auth.py:409 src/iac_code/commands/auth.py:433 -#: src/iac_code/commands/auth.py:836 src/iac_code/commands/auth.py:921 -#: src/iac_code/commands/auth.py:1026 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:365 +#: src/iac_code/commands/auth.py:367 src/iac_code/commands/auth.py:401 +#: src/iac_code/commands/auth.py:408 src/iac_code/commands/auth.py:432 +#: src/iac_code/commands/auth.py:844 src/iac_code/commands/auth.py:929 +#: src/iac_code/commands/auth.py:1034 msgid "Back" msgstr "Voltar" -#: src/iac_code/commands/auth.py:366 +#: src/iac_code/commands/auth.py:365 msgid "Keep" msgstr "Manter" -#: src/iac_code/commands/auth.py:366 +#: src/iac_code/commands/auth.py:365 msgid "Re-enter" msgstr "Digitar novamente" -#: src/iac_code/commands/auth.py:508 src/iac_code/commands/auth.py:650 -#: src/iac_code/commands/auth.py:670 +#: src/iac_code/commands/auth.py:507 src/iac_code/commands/auth.py:638 +#: src/iac_code/commands/auth.py:645 src/iac_code/commands/auth.py:678 msgid " (current)" msgstr " (atual)" -#: src/iac_code/commands/auth.py:511 +#: src/iac_code/commands/auth.py:510 msgid "Custom model..." msgstr "Modelo personalizado..." -#: src/iac_code/commands/auth.py:514 +#: src/iac_code/commands/auth.py:513 #, python-brace-format msgid "Select model for {provider}" msgstr "Selecionar modelo para {provider}" -#: src/iac_code/commands/auth.py:516 +#: src/iac_code/commands/auth.py:515 msgid "Select model" msgstr "Selecionar modelo" -#: src/iac_code/commands/auth.py:524 +#: src/iac_code/commands/auth.py:523 msgid "Enter custom model name: " msgstr "Informe o nome do modelo personalizado: " -#: src/iac_code/commands/auth.py:550 +#: src/iac_code/commands/auth.py:549 msgid "Error: console not available" msgstr "Erro: console indisponível" #: src/iac_code/commands/auth.py:576 -#, python-brace-format -msgid "" -"LLM provider is locked by '{source}'. To change, modify llm_source in " -"settings.yml." -msgstr "" -"O provedor LLM está bloqueado por '{source}'. Para alterar, modifique " -"llm_source em settings.yml." - -#: src/iac_code/commands/auth.py:580 src/iac_code/commands/auth.py:780 -msgid "Select Cloud Provider" -msgstr "Selecionar provedor de nuvem" - -#: src/iac_code/commands/auth.py:582 src/iac_code/commands/auth.py:589 -#: src/iac_code/commands/auth.py:600 src/iac_code/commands/auth.py:695 -#: src/iac_code/commands/auth.py:711 src/iac_code/commands/auth.py:789 -#: src/iac_code/commands/auth.py:962 src/iac_code/commands/auth.py:1003 -msgid "Auth cancelled" -msgstr "Autenticação cancelada" - -#: src/iac_code/commands/auth.py:595 msgid "Configure LLM Provider" msgstr "Configurar provedor LLM" -#: src/iac_code/commands/auth.py:596 +#: src/iac_code/commands/auth.py:577 msgid "Configure IaC Cloud Service" msgstr "Configurar serviço de nuvem IaC" -#: src/iac_code/commands/auth.py:598 +#: src/iac_code/commands/auth.py:579 msgid "Select configuration type" msgstr "Selecionar tipo de configuração" -#: src/iac_code/commands/auth.py:654 +#: src/iac_code/commands/auth.py:581 src/iac_code/commands/auth.py:703 +#: src/iac_code/commands/auth.py:719 src/iac_code/commands/auth.py:797 +#: src/iac_code/commands/auth.py:970 src/iac_code/commands/auth.py:1011 +msgid "Auth cancelled" +msgstr "Autenticação cancelada" + +#: src/iac_code/commands/auth.py:649 msgid "Select provider" msgstr "Selecionar provedor" -#: src/iac_code/commands/auth.py:675 src/iac_code/commands/auth.py:764 +#: src/iac_code/commands/auth.py:661 +#, python-brace-format +msgid "{status}: {provider}" +msgstr "{status}: {provider}" + +#: src/iac_code/commands/auth.py:662 src/iac_code/commands/auth.py:751 +msgid "Configured" +msgstr "Configurado" + +#: src/iac_code/commands/auth.py:683 src/iac_code/commands/auth.py:772 #, python-brace-format msgid "Select provider — {group}" msgstr "Selecionar provedor — {group}" -#: src/iac_code/commands/auth.py:688 +#: src/iac_code/commands/auth.py:696 #, python-brace-format msgid "Configure {provider}" msgstr "Configurar {provider}" -#: src/iac_code/commands/auth.py:704 +#: src/iac_code/commands/auth.py:712 #, python-brace-format msgid "Enter API key for {provider}" msgstr "Informe a API key para {provider}" -#: src/iac_code/commands/auth.py:742 +#: src/iac_code/commands/auth.py:750 #, python-brace-format msgid "{status}: {provider} / {model}" msgstr "{status}: {provider} / {model}" -#: src/iac_code/commands/auth.py:743 -msgid "Configured" -msgstr "Configurado" - -#: src/iac_code/commands/auth.py:750 src/iac_code/commands/auth.py:771 +#: src/iac_code/commands/auth.py:758 src/iac_code/commands/auth.py:779 msgid "Alibaba Cloud" msgstr "Alibaba Cloud" -#: src/iac_code/commands/auth.py:751 src/iac_code/providers/registry.py:423 +#: src/iac_code/commands/auth.py:759 src/iac_code/providers/registry.py:423 msgid "ZhiPu AI" msgstr "ZhiPu AI" -#: src/iac_code/commands/auth.py:752 +#: src/iac_code/commands/auth.py:760 msgid "Kimi" msgstr "Kimi" -#: src/iac_code/commands/auth.py:753 +#: src/iac_code/commands/auth.py:761 msgid "MiniMax" msgstr "MiniMax" -#: src/iac_code/commands/auth.py:754 src/iac_code/providers/registry.py:425 +#: src/iac_code/commands/auth.py:762 src/iac_code/providers/registry.py:425 msgid "Volcengine" msgstr "Volcengine" -#: src/iac_code/commands/auth.py:755 +#: src/iac_code/commands/auth.py:763 msgid "SiliconFlow" msgstr "SiliconFlow" -#: src/iac_code/commands/auth.py:756 src/iac_code/providers/registry.py:416 +#: src/iac_code/commands/auth.py:764 src/iac_code/providers/registry.py:416 msgid "DeepSeek" msgstr "DeepSeek" -#: src/iac_code/commands/auth.py:757 src/iac_code/providers/registry.py:414 +#: src/iac_code/commands/auth.py:765 src/iac_code/providers/registry.py:414 msgid "OpenAI" msgstr "OpenAI" -#: src/iac_code/commands/auth.py:758 src/iac_code/providers/registry.py:415 +#: src/iac_code/commands/auth.py:766 src/iac_code/providers/registry.py:415 msgid "Anthropic" msgstr "Anthropic" -#: src/iac_code/commands/auth.py:759 src/iac_code/providers/registry.py:418 +#: src/iac_code/commands/auth.py:767 src/iac_code/providers/registry.py:418 msgid "Google Gemini" msgstr "Google Gemini" -#: src/iac_code/commands/auth.py:760 src/iac_code/providers/registry.py:431 +#: src/iac_code/commands/auth.py:768 src/iac_code/providers/registry.py:431 msgid "Azure OpenAI" msgstr "Azure OpenAI" -#: src/iac_code/commands/auth.py:761 src/iac_code/providers/registry.py:430 +#: src/iac_code/commands/auth.py:769 src/iac_code/providers/registry.py:430 msgid "OpenRouter" msgstr "OpenRouter" -#: src/iac_code/commands/auth.py:762 +#: src/iac_code/commands/auth.py:770 msgid "Local" msgstr "Local" -#: src/iac_code/commands/auth.py:763 +#: src/iac_code/commands/auth.py:771 msgid "Compatible" msgstr "Compatível" -#: src/iac_code/commands/auth.py:796 +#: src/iac_code/commands/auth.py:788 +msgid "Select Cloud Provider" +msgstr "Selecionar provedor de nuvem" + +#: src/iac_code/commands/auth.py:804 msgid "Credential" msgstr "Credencial" -#: src/iac_code/commands/auth.py:797 src/iac_code/commands/auth.py:894 -#: src/iac_code/commands/auth.py:999 src/iac_code/ui/renderer.py:418 +#: src/iac_code/commands/auth.py:805 src/iac_code/commands/auth.py:902 +#: src/iac_code/commands/auth.py:1007 src/iac_code/ui/renderer.py:418 msgid "Region" msgstr "Região" -#: src/iac_code/commands/auth.py:799 +#: src/iac_code/commands/auth.py:807 msgid "Configure Alibaba Cloud" msgstr "Configurar Alibaba Cloud" -#: src/iac_code/commands/auth.py:882 +#: src/iac_code/commands/auth.py:890 msgid "Current configuration" msgstr "Configuração atual" -#: src/iac_code/commands/auth.py:884 +#: src/iac_code/commands/auth.py:892 msgid "Mode" msgstr "Modo" -#: src/iac_code/commands/auth.py:891 +#: src/iac_code/commands/auth.py:899 msgid "(not set)" msgstr "(não definido)" -#: src/iac_code/commands/auth.py:908 +#: src/iac_code/commands/auth.py:916 msgid "Configure Alibaba Cloud credentials" msgstr "Configurar credenciais da Alibaba Cloud" -#: src/iac_code/commands/auth.py:921 +#: src/iac_code/commands/auth.py:929 msgid "Reconfigure credential" msgstr "Reconfigurar credencial" -#: src/iac_code/commands/auth.py:934 +#: src/iac_code/commands/auth.py:942 msgid "Select credential type" msgstr "Selecionar tipo de credencial" -#: src/iac_code/commands/auth.py:984 +#: src/iac_code/commands/auth.py:992 msgid "Configured: Alibaba Cloud credentials saved to ~/.iac-code" msgstr "Configurado: credenciais da Alibaba Cloud salvas em ~/.iac-code" -#: src/iac_code/commands/auth.py:991 +#: src/iac_code/commands/auth.py:999 msgid "Configure Alibaba Cloud region" msgstr "Configurar região da Alibaba Cloud" -#: src/iac_code/commands/auth.py:1017 +#: src/iac_code/commands/auth.py:1025 msgid "Configured: Alibaba Cloud region saved to ~/.iac-code" msgstr "Configurado: região da Alibaba Cloud salva em ~/.iac-code" @@ -785,8 +780,8 @@ msgstr "O comando debug requer um contexto." msgid "No active session." msgstr "Nenhuma sessão ativa." -#: src/iac_code/commands/effort.py:54 src/iac_code/commands/model.py:88 -#: src/iac_code/commands/model.py:92 +#: src/iac_code/commands/effort.py:54 src/iac_code/commands/model.py:95 +#: src/iac_code/commands/model.py:99 msgid "No configured providers. Run /auth first." msgstr "Nenhum provedor configurado. Execute /auth primeiro." @@ -848,26 +843,26 @@ msgstr "Mostrar sugestões de comando" msgid "Exit" msgstr "Sair" -#: src/iac_code/commands/model.py:49 +#: src/iac_code/commands/model.py:57 #, python-brace-format msgid "" -"Model selection is locked by '{source}'. To change, modify llm_source in " -"settings.yml." +"Model is managed by '{source}'. To change model, modify it in {source} or" +" switch provider via /auth." msgstr "" -"A seleção de modelo está bloqueada por '{source}'. Para alterar, " -"modifique llm_source em settings.yml." +"O modelo é gerenciado por '{source}'. Para alterá-lo, modifique em " +"{source} ou troque de provedor via /auth." -#: src/iac_code/commands/model.py:81 src/iac_code/commands/model.py:136 +#: src/iac_code/commands/model.py:88 src/iac_code/commands/model.py:143 #, python-brace-format msgid "Model switched to: {model}" msgstr "Modelo alterado para: {model}" -#: src/iac_code/commands/model.py:85 +#: src/iac_code/commands/model.py:92 #, python-brace-format msgid "Current model: {model}" msgstr "Modelo atual: {model}" -#: src/iac_code/commands/model.py:111 +#: src/iac_code/commands/model.py:118 #, python-brace-format msgid "Kept model as {model}" msgstr "Modelo mantido como {model}" @@ -1579,23 +1574,23 @@ msgstr "ROS Stack" msgid "CloudStackInstances" msgstr "CloudStackInstances" -#: src/iac_code/ui/banner.py:64 +#: src/iac_code/ui/banner.py:68 msgid "Your AI-powered Infrastructure as Code assistant" msgstr "Seu assistente de Infrastructure as Code com IA" -#: src/iac_code/ui/banner.py:88 +#: src/iac_code/ui/banner.py:92 msgid "Welcome back" msgstr "Bem-vindo de volta" -#: src/iac_code/ui/banner.py:94 +#: src/iac_code/ui/banner.py:98 msgid "Session" msgstr "Sessão" -#: src/iac_code/ui/banner.py:104 +#: src/iac_code/ui/banner.py:108 msgid "Debug mode" msgstr "Modo debug" -#: src/iac_code/ui/banner.py:105 +#: src/iac_code/ui/banner.py:109 msgid "Log file" msgstr "Arquivo de log" @@ -1692,23 +1687,23 @@ msgstr "Não, sempre negar \"{rule}\" (esta sessão)" msgid "No, always reject this tool" msgstr "Não, sempre rejeitar esta ferramenta" -#: src/iac_code/ui/repl.py:353 +#: src/iac_code/ui/repl.py:354 msgid "Press Ctrl+C again to exit." msgstr "Pressione Ctrl+C novamente para sair." -#: src/iac_code/ui/repl.py:373 +#: src/iac_code/ui/repl.py:374 msgid "Interrupted." msgstr "Interrompido." -#: src/iac_code/ui/repl.py:410 +#: src/iac_code/ui/repl.py:411 msgid "Goodbye!" msgstr "Até logo!" -#: src/iac_code/ui/repl.py:411 +#: src/iac_code/ui/repl.py:412 msgid "Resume this session with:" msgstr "Para retomar esta sessão, execute:" -#: src/iac_code/ui/repl.py:444 +#: src/iac_code/ui/repl.py:445 msgid "No image in clipboard." msgstr "Nenhuma imagem na área de transferência." @@ -1717,22 +1712,22 @@ msgstr "Nenhuma imagem na área de transferência." msgid "Unknown command: /{name}. Type /help for available commands." msgstr "Comando desconhecido: /{name}. Digite /help para ver os comandos." -#: src/iac_code/ui/repl.py:608 src/iac_code/ui/repl.py:640 +#: src/iac_code/ui/repl.py:609 src/iac_code/ui/repl.py:654 #, python-brace-format msgid "Command error: {error}" msgstr "Erro de comando: {error}" -#: src/iac_code/ui/repl.py:615 +#: src/iac_code/ui/repl.py:616 #, python-brace-format msgid "Command has no handler: {name}" msgstr "Comando sem tratador: {name}" -#: src/iac_code/ui/repl.py:835 +#: src/iac_code/ui/repl.py:889 #, python-brace-format msgid "Session not found: {session_id}" msgstr "Sessão não encontrada: {session_id}" -#: src/iac_code/ui/repl.py:854 +#: src/iac_code/ui/repl.py:908 #, python-brace-format msgid "" "This session belongs to a different directory.\n" @@ -1743,19 +1738,19 @@ msgstr "" "Para retomar, execute:\n" " {cmd}" -#: src/iac_code/ui/repl.py:893 +#: src/iac_code/ui/repl.py:947 msgid "This conversation is from a different directory." msgstr "Esta conversa é de outro diretório." -#: src/iac_code/ui/repl.py:895 +#: src/iac_code/ui/repl.py:949 msgid "To resume, run:" msgstr "Para retomar, execute:" -#: src/iac_code/ui/repl.py:900 +#: src/iac_code/ui/repl.py:954 msgid "(Command copied to clipboard)" msgstr "(Comando copiado para a área de transferência)" -#: src/iac_code/ui/repl.py:1057 +#: src/iac_code/ui/repl.py:1111 #, python-brace-format msgid "" "Current model {model} does not support image input. Use /model to switch " @@ -1764,12 +1759,12 @@ msgstr "" "O modelo atual {model} não suporta entrada de imagem. Use /model para " "alternar para um modelo com capacidade de visão." -#: src/iac_code/ui/repl.py:1066 +#: src/iac_code/ui/repl.py:1120 #, python-brace-format msgid "Image error: {err}" msgstr "Erro de imagem: {err}" -#: src/iac_code/ui/repl.py:1083 +#: src/iac_code/ui/repl.py:1137 msgid "" "Failed to persist image to cache; it will only exist in memory for this " "turn." @@ -1960,3 +1955,15 @@ msgstr "há {n} dia{s}" #~ msgid "tree-sitter not available" #~ msgstr "tree-sitter not available" +#~ msgid "" +#~ "LLM provider is locked by '{source}'." +#~ " To change, modify llm_source in " +#~ "settings.yml." +#~ msgstr "" +#~ "O provedor LLM está bloqueado por " +#~ "'{source}'. Para alterar, modifique llm_source" +#~ " em settings.yml." + +#~ msgid "Provider switched: {status}" +#~ msgstr "Provider alterado: {status}" + diff --git a/src/iac_code/i18n/locales/zh/LC_MESSAGES/messages.po b/src/iac_code/i18n/locales/zh/LC_MESSAGES/messages.po index 7a918612..5ee1eca5 100644 --- a/src/iac_code/i18n/locales/zh/LC_MESSAGES/messages.po +++ b/src/iac_code/i18n/locales/zh/LC_MESSAGES/messages.po @@ -4,9 +4,9 @@ # msgid "" msgstr "" -"Project-Id-Version: iac-code 0.1.2\n" +"Project-Id-Version: iac-code 0.2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-05-18 18:09+0800\n" +"POT-Creation-Date: 2026-05-20 12:34+0800\n" "PO-Revision-Date: 2026-04-02 00:00+0000\n" "Last-Translator: \n" "Language: zh\n" @@ -519,220 +519,217 @@ msgstr "恢复之前的会话" msgid "[conversation id or search term]" msgstr "[会话 ID 或搜索词]" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:836 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:844 #: src/iac_code/ui/core/prompt_input.py:505 msgid "Navigate" msgstr "导航" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:368 -#: src/iac_code/commands/auth.py:402 src/iac_code/commands/auth.py:409 -#: src/iac_code/commands/auth.py:433 src/iac_code/commands/auth.py:836 -#: src/iac_code/commands/auth.py:1026 src/iac_code/ui/core/prompt_input.py:505 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:367 +#: src/iac_code/commands/auth.py:401 src/iac_code/commands/auth.py:408 +#: src/iac_code/commands/auth.py:432 src/iac_code/commands/auth.py:844 +#: src/iac_code/commands/auth.py:1034 src/iac_code/ui/core/prompt_input.py:505 msgid "Confirm" msgstr "确认" -#: src/iac_code/commands/auth.py:246 src/iac_code/commands/auth.py:366 -#: src/iac_code/commands/auth.py:368 src/iac_code/commands/auth.py:402 -#: src/iac_code/commands/auth.py:409 src/iac_code/commands/auth.py:433 -#: src/iac_code/commands/auth.py:836 src/iac_code/commands/auth.py:921 -#: src/iac_code/commands/auth.py:1026 +#: src/iac_code/commands/auth.py:245 src/iac_code/commands/auth.py:365 +#: src/iac_code/commands/auth.py:367 src/iac_code/commands/auth.py:401 +#: src/iac_code/commands/auth.py:408 src/iac_code/commands/auth.py:432 +#: src/iac_code/commands/auth.py:844 src/iac_code/commands/auth.py:929 +#: src/iac_code/commands/auth.py:1034 msgid "Back" msgstr "返回" -#: src/iac_code/commands/auth.py:366 +#: src/iac_code/commands/auth.py:365 msgid "Keep" msgstr "保留" -#: src/iac_code/commands/auth.py:366 +#: src/iac_code/commands/auth.py:365 msgid "Re-enter" msgstr "重新输入" -#: src/iac_code/commands/auth.py:508 src/iac_code/commands/auth.py:650 -#: src/iac_code/commands/auth.py:670 +#: src/iac_code/commands/auth.py:507 src/iac_code/commands/auth.py:638 +#: src/iac_code/commands/auth.py:645 src/iac_code/commands/auth.py:678 msgid " (current)" msgstr " (当前)" -#: src/iac_code/commands/auth.py:511 +#: src/iac_code/commands/auth.py:510 msgid "Custom model..." msgstr "自定义模型..." -#: src/iac_code/commands/auth.py:514 +#: src/iac_code/commands/auth.py:513 #, python-brace-format msgid "Select model for {provider}" msgstr "为 {provider} 选择模型" -#: src/iac_code/commands/auth.py:516 +#: src/iac_code/commands/auth.py:515 msgid "Select model" msgstr "选择模型" -#: src/iac_code/commands/auth.py:524 +#: src/iac_code/commands/auth.py:523 msgid "Enter custom model name: " msgstr "输入自定义模型名称:" -#: src/iac_code/commands/auth.py:550 +#: src/iac_code/commands/auth.py:549 msgid "Error: console not available" msgstr "错误:控制台不可用" #: src/iac_code/commands/auth.py:576 -#, python-brace-format -msgid "" -"LLM provider is locked by '{source}'. To change, modify llm_source in " -"settings.yml." -msgstr "LLM 提供商已被 '{source}' 锁定。如需修改,请调整 settings.yml 中的 llm_source 配置。" - -#: src/iac_code/commands/auth.py:580 src/iac_code/commands/auth.py:780 -msgid "Select Cloud Provider" -msgstr "选择云服务商" - -#: src/iac_code/commands/auth.py:582 src/iac_code/commands/auth.py:589 -#: src/iac_code/commands/auth.py:600 src/iac_code/commands/auth.py:695 -#: src/iac_code/commands/auth.py:711 src/iac_code/commands/auth.py:789 -#: src/iac_code/commands/auth.py:962 src/iac_code/commands/auth.py:1003 -msgid "Auth cancelled" -msgstr "认证已取消" - -#: src/iac_code/commands/auth.py:595 msgid "Configure LLM Provider" msgstr "配置 LLM 提供商" -#: src/iac_code/commands/auth.py:596 +#: src/iac_code/commands/auth.py:577 msgid "Configure IaC Cloud Service" msgstr "配置 IaC 云服务" -#: src/iac_code/commands/auth.py:598 +#: src/iac_code/commands/auth.py:579 msgid "Select configuration type" msgstr "选择配置类型" -#: src/iac_code/commands/auth.py:654 +#: src/iac_code/commands/auth.py:581 src/iac_code/commands/auth.py:703 +#: src/iac_code/commands/auth.py:719 src/iac_code/commands/auth.py:797 +#: src/iac_code/commands/auth.py:970 src/iac_code/commands/auth.py:1011 +msgid "Auth cancelled" +msgstr "认证已取消" + +#: src/iac_code/commands/auth.py:649 msgid "Select provider" msgstr "选择提供商" -#: src/iac_code/commands/auth.py:675 src/iac_code/commands/auth.py:764 +#: src/iac_code/commands/auth.py:661 +#, python-brace-format +msgid "{status}: {provider}" +msgstr "{status}:{provider}" + +#: src/iac_code/commands/auth.py:662 src/iac_code/commands/auth.py:751 +msgid "Configured" +msgstr "已配置" + +#: src/iac_code/commands/auth.py:683 src/iac_code/commands/auth.py:772 #, python-brace-format msgid "Select provider — {group}" msgstr "选择提供商 — {group}" -#: src/iac_code/commands/auth.py:688 +#: src/iac_code/commands/auth.py:696 #, python-brace-format msgid "Configure {provider}" msgstr "配置 {provider}" -#: src/iac_code/commands/auth.py:704 +#: src/iac_code/commands/auth.py:712 #, python-brace-format msgid "Enter API key for {provider}" msgstr "为 {provider} 输入 API 密钥" -#: src/iac_code/commands/auth.py:742 +#: src/iac_code/commands/auth.py:750 #, python-brace-format msgid "{status}: {provider} / {model}" msgstr "{status}:{provider} / {model}" -#: src/iac_code/commands/auth.py:743 -msgid "Configured" -msgstr "已配置" - -#: src/iac_code/commands/auth.py:750 src/iac_code/commands/auth.py:771 +#: src/iac_code/commands/auth.py:758 src/iac_code/commands/auth.py:779 msgid "Alibaba Cloud" msgstr "阿里云" -#: src/iac_code/commands/auth.py:751 src/iac_code/providers/registry.py:423 +#: src/iac_code/commands/auth.py:759 src/iac_code/providers/registry.py:423 msgid "ZhiPu AI" msgstr "智谱 AI" -#: src/iac_code/commands/auth.py:752 +#: src/iac_code/commands/auth.py:760 msgid "Kimi" msgstr "Kimi" -#: src/iac_code/commands/auth.py:753 +#: src/iac_code/commands/auth.py:761 msgid "MiniMax" msgstr "MiniMax" -#: src/iac_code/commands/auth.py:754 src/iac_code/providers/registry.py:425 +#: src/iac_code/commands/auth.py:762 src/iac_code/providers/registry.py:425 msgid "Volcengine" msgstr "火山引擎" -#: src/iac_code/commands/auth.py:755 +#: src/iac_code/commands/auth.py:763 msgid "SiliconFlow" msgstr "硅基流动" -#: src/iac_code/commands/auth.py:756 src/iac_code/providers/registry.py:416 +#: src/iac_code/commands/auth.py:764 src/iac_code/providers/registry.py:416 msgid "DeepSeek" msgstr "DeepSeek" -#: src/iac_code/commands/auth.py:757 src/iac_code/providers/registry.py:414 +#: src/iac_code/commands/auth.py:765 src/iac_code/providers/registry.py:414 msgid "OpenAI" msgstr "OpenAI" -#: src/iac_code/commands/auth.py:758 src/iac_code/providers/registry.py:415 +#: src/iac_code/commands/auth.py:766 src/iac_code/providers/registry.py:415 msgid "Anthropic" msgstr "Anthropic" -#: src/iac_code/commands/auth.py:759 src/iac_code/providers/registry.py:418 +#: src/iac_code/commands/auth.py:767 src/iac_code/providers/registry.py:418 msgid "Google Gemini" msgstr "Google Gemini" -#: src/iac_code/commands/auth.py:760 src/iac_code/providers/registry.py:431 +#: src/iac_code/commands/auth.py:768 src/iac_code/providers/registry.py:431 msgid "Azure OpenAI" msgstr "Azure OpenAI" -#: src/iac_code/commands/auth.py:761 src/iac_code/providers/registry.py:430 +#: src/iac_code/commands/auth.py:769 src/iac_code/providers/registry.py:430 msgid "OpenRouter" msgstr "OpenRouter" -#: src/iac_code/commands/auth.py:762 +#: src/iac_code/commands/auth.py:770 msgid "Local" msgstr "本地模型" -#: src/iac_code/commands/auth.py:763 +#: src/iac_code/commands/auth.py:771 msgid "Compatible" msgstr "兼容模式" -#: src/iac_code/commands/auth.py:796 +#: src/iac_code/commands/auth.py:788 +msgid "Select Cloud Provider" +msgstr "选择云服务商" + +#: src/iac_code/commands/auth.py:804 msgid "Credential" msgstr "凭证" -#: src/iac_code/commands/auth.py:797 src/iac_code/commands/auth.py:894 -#: src/iac_code/commands/auth.py:999 src/iac_code/ui/renderer.py:418 +#: src/iac_code/commands/auth.py:805 src/iac_code/commands/auth.py:902 +#: src/iac_code/commands/auth.py:1007 src/iac_code/ui/renderer.py:418 msgid "Region" msgstr "地域" -#: src/iac_code/commands/auth.py:799 +#: src/iac_code/commands/auth.py:807 msgid "Configure Alibaba Cloud" msgstr "配置阿里云" -#: src/iac_code/commands/auth.py:882 +#: src/iac_code/commands/auth.py:890 msgid "Current configuration" msgstr "当前配置" -#: src/iac_code/commands/auth.py:884 +#: src/iac_code/commands/auth.py:892 msgid "Mode" msgstr "模式" -#: src/iac_code/commands/auth.py:891 +#: src/iac_code/commands/auth.py:899 msgid "(not set)" msgstr "(未设置)" -#: src/iac_code/commands/auth.py:908 +#: src/iac_code/commands/auth.py:916 msgid "Configure Alibaba Cloud credentials" msgstr "配置阿里云凭证" -#: src/iac_code/commands/auth.py:921 +#: src/iac_code/commands/auth.py:929 msgid "Reconfigure credential" msgstr "重新配置凭证" -#: src/iac_code/commands/auth.py:934 +#: src/iac_code/commands/auth.py:942 msgid "Select credential type" msgstr "选择凭证类型" -#: src/iac_code/commands/auth.py:984 +#: src/iac_code/commands/auth.py:992 msgid "Configured: Alibaba Cloud credentials saved to ~/.iac-code" msgstr "已配置:阿里云凭证已保存到 ~/.iac-code" -#: src/iac_code/commands/auth.py:991 +#: src/iac_code/commands/auth.py:999 msgid "Configure Alibaba Cloud region" msgstr "配置阿里云地域" -#: src/iac_code/commands/auth.py:1017 +#: src/iac_code/commands/auth.py:1025 msgid "Configured: Alibaba Cloud region saved to ~/.iac-code" msgstr "已配置:阿里云地域已保存到 ~/.iac-code" @@ -765,8 +762,8 @@ msgstr "调试命令需要上下文。" msgid "No active session." msgstr "没有活动的会话。" -#: src/iac_code/commands/effort.py:54 src/iac_code/commands/model.py:88 -#: src/iac_code/commands/model.py:92 +#: src/iac_code/commands/effort.py:54 src/iac_code/commands/model.py:95 +#: src/iac_code/commands/model.py:99 msgid "No configured providers. Run /auth first." msgstr "没有已配置的提供商。请先运行 /auth。" @@ -828,24 +825,24 @@ msgstr "显示命令建议" msgid "Exit" msgstr "退出" -#: src/iac_code/commands/model.py:49 +#: src/iac_code/commands/model.py:57 #, python-brace-format msgid "" -"Model selection is locked by '{source}'. To change, modify llm_source in " -"settings.yml." -msgstr "模型选择已被 '{source}' 锁定。如需修改,请调整 settings.yml 中的 llm_source 配置。" +"Model is managed by '{source}'. To change model, modify it in {source} or" +" switch provider via /auth." +msgstr "模型由 '{source}' 管理。如需修改模型,请在 {source} 中调整,或通过 /auth 切换其他 Provider。" -#: src/iac_code/commands/model.py:81 src/iac_code/commands/model.py:136 +#: src/iac_code/commands/model.py:88 src/iac_code/commands/model.py:143 #, python-brace-format msgid "Model switched to: {model}" msgstr "模型已切换为:{model}" -#: src/iac_code/commands/model.py:85 +#: src/iac_code/commands/model.py:92 #, python-brace-format msgid "Current model: {model}" msgstr "当前模型:{model}" -#: src/iac_code/commands/model.py:111 +#: src/iac_code/commands/model.py:118 #, python-brace-format msgid "Kept model as {model}" msgstr "保持模型为 {model}" @@ -1542,23 +1539,23 @@ msgstr "ROS 资源栈" msgid "CloudStackInstances" msgstr "云资源栈实例" -#: src/iac_code/ui/banner.py:64 +#: src/iac_code/ui/banner.py:68 msgid "Your AI-powered Infrastructure as Code assistant" msgstr "您的 AI 驱动的基础设施即代码助手" -#: src/iac_code/ui/banner.py:88 +#: src/iac_code/ui/banner.py:92 msgid "Welcome back" msgstr "欢迎回来" -#: src/iac_code/ui/banner.py:94 +#: src/iac_code/ui/banner.py:98 msgid "Session" msgstr "会话" -#: src/iac_code/ui/banner.py:104 +#: src/iac_code/ui/banner.py:108 msgid "Debug mode" msgstr "调试模式" -#: src/iac_code/ui/banner.py:105 +#: src/iac_code/ui/banner.py:109 msgid "Log file" msgstr "日志文件" @@ -1655,23 +1652,23 @@ msgstr "否,始终拒绝 \"{rule}\"(本次会话)" msgid "No, always reject this tool" msgstr "否,始终拒绝此工具" -#: src/iac_code/ui/repl.py:353 +#: src/iac_code/ui/repl.py:354 msgid "Press Ctrl+C again to exit." msgstr "再次按 Ctrl+C 退出。" -#: src/iac_code/ui/repl.py:373 +#: src/iac_code/ui/repl.py:374 msgid "Interrupted." msgstr "已中断。" -#: src/iac_code/ui/repl.py:410 +#: src/iac_code/ui/repl.py:411 msgid "Goodbye!" msgstr "再见!" -#: src/iac_code/ui/repl.py:411 +#: src/iac_code/ui/repl.py:412 msgid "Resume this session with:" msgstr "恢复此会话请运行:" -#: src/iac_code/ui/repl.py:444 +#: src/iac_code/ui/repl.py:445 msgid "No image in clipboard." msgstr "剪贴板中没有图像。" @@ -1680,22 +1677,22 @@ msgstr "剪贴板中没有图像。" msgid "Unknown command: /{name}. Type /help for available commands." msgstr "未知命令:/{name}。输入 /help 查看可用命令。" -#: src/iac_code/ui/repl.py:608 src/iac_code/ui/repl.py:640 +#: src/iac_code/ui/repl.py:609 src/iac_code/ui/repl.py:654 #, python-brace-format msgid "Command error: {error}" msgstr "命令错误:{error}" -#: src/iac_code/ui/repl.py:615 +#: src/iac_code/ui/repl.py:616 #, python-brace-format msgid "Command has no handler: {name}" msgstr "命令没有处理器:{name}" -#: src/iac_code/ui/repl.py:835 +#: src/iac_code/ui/repl.py:889 #, python-brace-format msgid "Session not found: {session_id}" msgstr "会话不存在:{session_id}" -#: src/iac_code/ui/repl.py:854 +#: src/iac_code/ui/repl.py:908 #, python-brace-format msgid "" "This session belongs to a different directory.\n" @@ -1706,31 +1703,31 @@ msgstr "" "请运行以下命令恢复:\n" " {cmd}" -#: src/iac_code/ui/repl.py:893 +#: src/iac_code/ui/repl.py:947 msgid "This conversation is from a different directory." msgstr "该会话来自另一个目录。" -#: src/iac_code/ui/repl.py:895 +#: src/iac_code/ui/repl.py:949 msgid "To resume, run:" msgstr "请运行以下命令恢复:" -#: src/iac_code/ui/repl.py:900 +#: src/iac_code/ui/repl.py:954 msgid "(Command copied to clipboard)" msgstr "(命令已复制到剪贴板)" -#: src/iac_code/ui/repl.py:1057 +#: src/iac_code/ui/repl.py:1111 #, python-brace-format msgid "" "Current model {model} does not support image input. Use /model to switch " "to a vision-capable model." msgstr "当前模型 {model} 不支持图像输入。请使用 /model 切换到支持视觉的模型。" -#: src/iac_code/ui/repl.py:1066 +#: src/iac_code/ui/repl.py:1120 #, python-brace-format msgid "Image error: {err}" msgstr "图像错误:{err}" -#: src/iac_code/ui/repl.py:1083 +#: src/iac_code/ui/repl.py:1137 msgid "" "Failed to persist image to cache; it will only exist in memory for this " "turn." @@ -1934,3 +1931,12 @@ msgstr "{n} 天前" #~ msgid "tree-sitter not available" #~ msgstr "tree-sitter 不可用" +#~ msgid "" +#~ "LLM provider is locked by '{source}'." +#~ " To change, modify llm_source in " +#~ "settings.yml." +#~ msgstr "LLM 提供商已被 '{source}' 锁定。如需修改,请调整 settings.yml 中的 llm_source 配置。" + +#~ msgid "Provider switched: {status}" +#~ msgstr "Provider 已切换: {status}" + diff --git a/src/iac_code/ui/banner.py b/src/iac_code/ui/banner.py index a687f589..67bf9c06 100644 --- a/src/iac_code/ui/banner.py +++ b/src/iac_code/ui/banner.py @@ -28,12 +28,16 @@ def _get_provider_display() -> str: """Get the active provider display name from settings.""" try: - from iac_code.config import get_active_provider_key, get_provider_config + from iac_code.config import PARTNER_SOURCES, get_active_provider_key, get_llm_source, get_provider_config from iac_code.i18n import _ from iac_code.providers.registry import PROVIDER_REGISTRY key = get_active_provider_key() if not key: + llm_source = get_llm_source() + for ps in PARTNER_SOURCES: + if ps["key"] == llm_source: + return ps["display_name"] return "" desc = PROVIDER_REGISTRY.get(key) if desc: @@ -91,7 +95,7 @@ def render_welcome_banner(model: str, cwd: str, session_id: str | None = None) - Text(), Text(f" {model_display}", style="dim") if model_display else Text(), Text(f" {cwd_display}", style="dim"), - Text(f" {_('Session')}: {session_id}", style="dim") if session_id else Text(), + Text(" {}: {}".format(_("Session"), session_id), style="dim") if session_id else Text(), ] from iac_code.utils.log import is_debug_enabled diff --git a/src/iac_code/ui/repl.py b/src/iac_code/ui/repl.py index 2463dc1c..e5bbb6af 100644 --- a/src/iac_code/ui/repl.py +++ b/src/iac_code/ui/repl.py @@ -125,6 +125,7 @@ def __init__( self._resume_messages = self._load_resume_messages(resume_session_id) self._task_manager = TaskManager() self._notification_queue = NotificationQueue() + self._command_log: list[tuple[str, str, int, bool]] = [] memory_dir = str(get_config_dir() / "memory") self._memory_manager = MemoryManager(memory_dir=memory_dir) @@ -580,10 +581,10 @@ async def _handle_command(self, user_input: str) -> None: name, args = self.command_registry.parse(user_input) cmd = self.command_registry.get(name) if cmd is None: - self.renderer.print_system_message( - _("Unknown command: /{name}. Type /help for available commands.").format(name=name), - style="red", - ) + error_msg = _("Unknown command: /{name}. Type /help for available commands.").format(name=name) + msg_count = len(self._agent_loop.context_manager.get_messages()) + self._command_log.append((user_input, error_msg, msg_count, True)) + self.renderer.print_system_message(error_msg, style="red") return if isinstance(cmd, PromptCommand): @@ -616,6 +617,10 @@ async def _handle_command(self, user_input: str) -> None: style="red", ) return + from iac_code.config import get_active_provider_key + + prev_model = self.store.get_state().model + prev_provider_key = get_active_provider_key() try: handler_call = cmd.handler( context=context, @@ -632,7 +637,16 @@ async def _handle_command(self, user_input: str) -> None: else: result = await handler_call if result: - self.renderer.print_command_result(user_input, result) + msg_count = len(self._agent_loop.context_manager.get_messages()) + self._command_log.append((user_input, result, msg_count, False)) + # Re-render banner when model/provider actually switched + new_state = self.store.get_state() + new_provider_key = get_active_provider_key() + if new_state.model != prev_model or new_provider_key != prev_provider_key: + self._refresh_banner() + else: + if result: + self.renderer.print_command_result(user_input, result) except ExitREPLError: raise except Exception as exc: @@ -641,6 +655,46 @@ async def _handle_command(self, user_input: str) -> None: style="red", ) + def _refresh_banner(self) -> None: + """Clear screen and re-render the welcome banner, then replay history with commands.""" + self.console.file.write("\033[H\033[2J\033[3J") + self.console.file.flush() + state = self.store.get_state() + self.console.print(render_welcome_banner(state.model, state.cwd, session_id=self._session_id)) + messages = self._agent_loop.context_manager.get_messages() + if not messages and not self._command_log: + return + # Build ordered list of (position, commands) for interleaving + cmd_at: dict[int, list[tuple[str, str, bool]]] = {} + for cmd_input, cmd_result, at, is_error in self._command_log: + cmd_at.setdefault(at, []).append((cmd_input, cmd_result, is_error)) + # Find split points where commands need to be inserted + split_points = sorted(cmd_at.keys()) + # Replay messages in segments, inserting commands between segments + prev = 0 + has_output = False + for point in split_points: + if point > prev and prev < len(messages): + if has_output: + self.console.print() + self.renderer.replay_history(messages[prev : min(point, len(messages))]) + has_output = True + for cmd_input, cmd_result, is_error in cmd_at[point]: + if has_output: + self.console.print() + self.renderer.print_user_message(cmd_input) + if is_error: + self.renderer.print_system_message(cmd_result, style="red") + else: + self.renderer.print_command_result(cmd_input, cmd_result) + has_output = True + prev = max(prev, point) + # Replay remaining messages after last command + if prev < len(messages): + if has_output: + self.console.print() + self.renderer.replay_history(messages[prev:]) + # ------------------------------------------------------------------ # Chat handling # ------------------------------------------------------------------ diff --git a/tests/commands/test_auth_flows.py b/tests/commands/test_auth_flows.py index e553f625..77ab90c5 100644 --- a/tests/commands/test_auth_flows.py +++ b/tests/commands/test_auth_flows.py @@ -139,7 +139,7 @@ def test_back_at_sub_provider_returns_to_group(self, monkeypatch): def select_side_effect(title, options, default_index=0): call_count["select"] += 1 if call_count["select"] == 1: - return 0 # Alibaba Cloud group (multiple items) + return 1 # Alibaba Cloud group (multiple items), after partner sources if call_count["select"] == 2: return None # Esc at sub-provider → back to group return None # Esc at group → _BACK @@ -154,8 +154,10 @@ def test_back_at_api_key_input_loops_to_group_select(self, monkeypatch): def select_side_effect(title, options, default_index=0): call_count["select"] += 1 - if call_count["select"] <= 2: - return 0 # group + sub-provider + if call_count["select"] == 1: + return 1 # Alibaba Cloud group (after partner sources) + if call_count["select"] == 2: + return 0 # sub-provider return None # Esc → _BACK monkeypatch.setattr("iac_code.commands.auth._select", select_side_effect) @@ -166,8 +168,16 @@ def select_side_effect(title, options, default_index=0): assert call_count["select"] == 3 def test_cancel_at_api_key_input_returns_cancelled(self, monkeypatch): - # _select always returns 0 → Alibaba Cloud group → DashScope provider - monkeypatch.setattr("iac_code.commands.auth._select", lambda title, options, default_index=0: 0) + # _select returns 1 for group (Alibaba Cloud, after partner sources) then 0 for sub-provider + call_count = {"n": 0} + + def select_side_effect(title, options, default_index=0): + call_count["n"] += 1 + if call_count["n"] == 1: + return 1 # Alibaba Cloud group (after partner sources) + return 0 # DashScope provider + + monkeypatch.setattr("iac_code.commands.auth._select", select_side_effect) monkeypatch.setattr("iac_code.commands.auth._load_existing_key", lambda key_name: None) monkeypatch.setattr("iac_code.commands.auth._input_masked", lambda *a, **kw: None) result = _llm_auth_flow(MagicMock(), MagicMock()) @@ -196,8 +206,16 @@ def select_side_effect(title, options, default_index=0): assert call_count["select"] == 2 # group + group again (no sub-provider step) def test_successful_config_saves_and_returns_string(self, monkeypatch): - # _select always returns 0 → Alibaba Cloud → DashScope (first sub-provider) - monkeypatch.setattr("iac_code.commands.auth._select", lambda title, options, default_index=0: 0) + # _select returns 1 for group (Alibaba Cloud, after partner sources) then 0 for sub-provider + call_count = {"n": 0} + + def select_side_effect(title, options, default_index=0): + call_count["n"] += 1 + if call_count["n"] == 1: + return 1 # Alibaba Cloud group (after partner sources) + return 0 # DashScope (first sub-provider) + + monkeypatch.setattr("iac_code.commands.auth._select", select_side_effect) monkeypatch.setattr("iac_code.commands.auth._load_existing_key", lambda key_name: None) monkeypatch.setattr("iac_code.commands.auth._input_masked", lambda *a, **kw: "test-api-key") monkeypatch.setattr( @@ -373,45 +391,86 @@ def test_region_flow_creates_new_credential_when_missing(self, monkeypatch): class TestAuthLlmSourceLock: - def test_auth_flow_locked_shows_cloud_select_with_lock_notice(self, monkeypatch): - """When llm_source is 'qwenpaw', _auth_flow shows lock notice in _select title.""" - titles_seen = [] + def test_auth_flow_always_shows_category_selection(self, monkeypatch): + """_auth_flow always shows category selection regardless of llm_source.""" + monkeypatch.setattr("iac_code.commands.auth._select", lambda title, options, default_index=0: None) + result = _auth_flow(MagicMock(), MagicMock()) + assert "cancel" in result.lower() + + def test_auth_flow_llm_branch_works_with_qwenpaw_source(self, monkeypatch): + """Even with qwenpaw source, user can access LLM config.""" + call_count = {"n": 0} def fake_select(title, options, default_index=0): - titles_seen.append(title) - return 0 # select first cloud provider (aliyun) + call_count["n"] += 1 + if call_count["n"] == 1: + return 0 # LLM branch + return None - monkeypatch.setattr("iac_code.commands.auth.get_llm_source", lambda: "qwenpaw") monkeypatch.setattr("iac_code.commands.auth._select", fake_select) - monkeypatch.setattr("iac_code.commands.auth._aliyun_auth_flow", lambda: "cloud done") + monkeypatch.setattr("iac_code.commands.auth._llm_auth_flow", lambda c, s: "llm-done") result = _auth_flow(MagicMock(), MagicMock()) - assert result == "cloud done" - assert any("qwenpaw" in t for t in titles_seen) + assert result == "llm-done" + - def test_auth_flow_locked_env_shows_lock_notice(self, monkeypatch): - """When llm_source is 'env', lock notice mentions 'env'.""" - titles_seen = [] +class TestPartnerSourceInLlmFlow: + def test_partner_source_shown_at_top_of_list(self, monkeypatch): + """QwenPaw should appear as the first option in provider group selection.""" + options_seen = [] def fake_select(title, options, default_index=0): - titles_seen.append(title) - return 0 + options_seen.extend(options) + return None # Esc - monkeypatch.setattr("iac_code.commands.auth.get_llm_source", lambda: "env") monkeypatch.setattr("iac_code.commands.auth._select", fake_select) - monkeypatch.setattr("iac_code.commands.auth._aliyun_auth_flow", lambda: "cloud done") - _auth_flow(MagicMock(), MagicMock()) - assert any("env" in t for t in titles_seen) + monkeypatch.setattr("iac_code.commands.auth.get_active_provider_key", lambda: None) + result = _llm_auth_flow(MagicMock(), MagicMock()) + assert result is _BACK + assert len(options_seen) > 0 + assert "QwenPaw" in options_seen[0] - def test_auth_flow_locked_escape_returns_cancelled(self, monkeypatch): - """When locked and user presses Esc, return cancelled.""" - monkeypatch.setattr("iac_code.commands.auth.get_llm_source", lambda: "qwenpaw") - monkeypatch.setattr("iac_code.commands.auth._select", lambda title, options, default_index=0: None) - result = _auth_flow(MagicMock(), MagicMock()) - assert "cancel" in result.lower() + def test_selecting_partner_source_clears_active_provider(self, monkeypatch, iac_home): + """Selecting QwenPaw clears activeProvider and sets llm_source.""" + from iac_code.config import _load_yaml - def test_auth_flow_normal_when_local(self, monkeypatch): - """When llm_source is 'local', _auth_flow shows category selection as usual.""" - monkeypatch.setattr("iac_code.commands.auth.get_llm_source", lambda: "local") - monkeypatch.setattr("iac_code.commands.auth._select", lambda title, options, default_index=0: None) - result = _auth_flow(MagicMock(), MagicMock()) - assert "cancel" in result.lower() + settings_path = iac_home / ".iac-code" / "settings.yml" + settings_path.parent.mkdir(parents=True, exist_ok=True) + settings_path.write_text("activeProvider: dashscope\nproviders:\n dashscope:\n model: qwen-plus\n") + + monkeypatch.setattr("iac_code.commands.auth.get_settings_path", lambda: settings_path) + + call_count = {"n": 0} + + def fake_select(title, options, default_index=0): + call_count["n"] += 1 + if call_count["n"] == 1: + return 0 # Select first option (QwenPaw) + return None + + monkeypatch.setattr("iac_code.commands.auth._select", fake_select) + monkeypatch.setattr("iac_code.commands.auth.get_active_provider_key", lambda: "dashscope") + _llm_auth_flow(MagicMock(), MagicMock()) + + config = _load_yaml(settings_path) + assert "activeProvider" not in config + assert config.get("llm_source") == "qwenpaw" + # providers dict preserved + assert "dashscope" in config.get("providers", {}) + + def test_selecting_partner_source_returns_configured_message(self, monkeypatch, iac_home): + """Selecting QwenPaw returns a success message.""" + settings_path = iac_home / ".iac-code" / "settings.yml" + settings_path.parent.mkdir(parents=True, exist_ok=True) + settings_path.write_text("") + + monkeypatch.setattr("iac_code.commands.auth.get_settings_path", lambda: settings_path) + + def fake_select(title, options, default_index=0): + return 0 # Select QwenPaw + + monkeypatch.setattr("iac_code.commands.auth._select", fake_select) + monkeypatch.setattr("iac_code.commands.auth.get_active_provider_key", lambda: None) + result = _llm_auth_flow(MagicMock(), MagicMock()) + + assert isinstance(result, str) + assert "QwenPaw" in result diff --git a/tests/commands/test_config_llm_source.py b/tests/commands/test_config_llm_source.py new file mode 100644 index 00000000..1073a60b --- /dev/null +++ b/tests/commands/test_config_llm_source.py @@ -0,0 +1,57 @@ +"""Tests for get_llm_source() priority chain.""" + +import pytest + +from iac_code.config import get_llm_source + + +@pytest.fixture(autouse=True) +def iac_home(tmp_path, monkeypatch): + monkeypatch.setenv("HOME", str(tmp_path)) + (tmp_path / ".iac-code").mkdir() + return tmp_path + + +class TestGetLlmSource: + def test_env_api_key_returns_env(self, monkeypatch, iac_home): + """Env var takes highest priority.""" + monkeypatch.setenv("IAC_CODE_API_KEY", "sk-test") + assert get_llm_source() == "env" + + def test_active_provider_returns_local(self, iac_home): + """activeProvider present -> 'local' regardless of llm_source.""" + settings_path = iac_home / ".iac-code" / "settings.yml" + settings_path.write_text("llm_source: qwenpaw\nactiveProvider: dashscope\n") + assert get_llm_source() == "local" + + def test_no_active_provider_with_llm_source_returns_source(self, iac_home): + """No activeProvider but llm_source set -> return llm_source value.""" + settings_path = iac_home / ".iac-code" / "settings.yml" + settings_path.write_text("llm_source: qwenpaw\n") + assert get_llm_source() == "qwenpaw" + + def test_no_active_provider_no_llm_source_returns_local(self, iac_home): + """Nothing configured -> 'local'.""" + settings_path = iac_home / ".iac-code" / "settings.yml" + settings_path.write_text("") + assert get_llm_source() == "local" + + def test_active_provider_empty_string_treated_as_absent(self, iac_home): + """Empty-string activeProvider is treated as absent.""" + settings_path = iac_home / ".iac-code" / "settings.yml" + settings_path.write_text("llm_source: qwenpaw\nactiveProvider: ''\n") + assert get_llm_source() == "qwenpaw" + + def test_env_overrides_active_provider(self, monkeypatch, iac_home): + """Env var wins even when activeProvider exists.""" + monkeypatch.setenv("IAC_CODE_API_KEY", "sk-test") + settings_path = iac_home / ".iac-code" / "settings.yml" + settings_path.write_text("activeProvider: dashscope\n") + assert get_llm_source() == "env" + + def test_settings_file_missing_returns_local(self, iac_home): + """No settings file -> 'local'.""" + settings_path = iac_home / ".iac-code" / "settings.yml" + if settings_path.exists(): + settings_path.unlink() + assert get_llm_source() == "local" diff --git a/tests/commands/test_model.py b/tests/commands/test_model.py index 5d73443c..bc76c921 100644 --- a/tests/commands/test_model.py +++ b/tests/commands/test_model.py @@ -18,24 +18,24 @@ async def test_model_locked_when_qwenpaw(self, monkeypatch): store = MagicMock() context = MagicMock(store=store) result = await model_command(context=context) - assert "locked" in result.lower() - assert "qwenpaw" in result + assert "QwenPaw" in result + assert "/auth" in result async def test_model_locked_when_env(self, monkeypatch): monkeypatch.setattr("iac_code.commands.model.get_llm_source", lambda: "env") store = MagicMock() context = MagicMock(store=store) result = await model_command(context=context) - assert "locked" in result.lower() assert "env" in result + assert "/auth" in result async def test_model_locked_with_args(self, monkeypatch): monkeypatch.setattr("iac_code.commands.model.get_llm_source", lambda: "qwenpaw") store = MagicMock() context = MagicMock(store=store) result = await model_command(context=context, args=["gpt-4"]) - assert "locked" in result.lower() - assert "qwenpaw" in result + assert "QwenPaw" in result + assert "/auth" in result async def test_model_not_locked_when_local(self, monkeypatch): monkeypatch.setattr("iac_code.commands.model.get_llm_source", lambda: "local")