@innvisor/conny-ai 9.8.0 β†’ 9.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.8.2 - 2026-06-02
4
+
5
+ - persisted the language selected in `conny init` so the rest of the CLI loads it automatically
6
+ - made `conny_i18n` read the saved workspace language on startup
7
+ - kept the `conny init` banner unchanged while aligning other launch paths to the same brand
8
+
9
+ ## 9.8.1 - 2026-06-02
10
+
11
+ - made `conny` open the guided setup flow by default instead of the old help banner
12
+ - removed the default launcher banner from the primary `conny` path
13
+ - aligned the TUI version display with `package.json`
14
+
3
15
  ## 9.8.0 - 2026-06-02
4
16
 
5
17
  - blocked first-contact setup for unknown chats until a valid activation token is provided
package/conny_app.py CHANGED
@@ -285,7 +285,7 @@ def main():
285
285
  if first_run() and not (len(sys.argv)>1 and sys.argv[1] in ("help","--help","-h","-v","--version")):
286
286
  onboard()
287
287
  if len(sys.argv) <= 1:
288
- cmd_help()
288
+ cmd_new()
289
289
  else:
290
290
  route(sys.argv[1], " ".join(sys.argv[2:]))
291
291
 
package/conny_i18n.py CHANGED
@@ -5,6 +5,9 @@ Supported languages: es, en, pt, fr, de
5
5
  """
6
6
 
7
7
  from __future__ import annotations
8
+ import json
9
+ import os
10
+ from pathlib import Path
8
11
  from typing import Dict, Optional
9
12
  from dataclasses import dataclass
10
13
 
@@ -20,6 +23,79 @@ SUPPORTED_LANGUAGES = {
20
23
  DEFAULT_LANGUAGE = "es"
21
24
 
22
25
 
26
+ def _workspace_config_path() -> Path:
27
+ explicit = os.environ.get("CONNY_WORKSPACE_CONFIG")
28
+ if explicit:
29
+ return Path(explicit)
30
+ conny_home = os.environ.get("CONNY_HOME")
31
+ if conny_home:
32
+ return Path(conny_home) / "config.json"
33
+ return Path.home() / ".conny" / "config.json"
34
+
35
+
36
+ def _extract_language(payload: object) -> str:
37
+ if not isinstance(payload, dict):
38
+ return ""
39
+ candidates = [
40
+ payload.get("language"),
41
+ payload.get("ui_language"),
42
+ payload.get("locale"),
43
+ ]
44
+ for nested_key in ("agent", "meta"):
45
+ nested = payload.get(nested_key)
46
+ if isinstance(nested, dict):
47
+ candidates.append(nested.get("language"))
48
+ candidates.append(nested.get("ui_language"))
49
+ candidates.append(nested.get("locale"))
50
+ for value in candidates:
51
+ if isinstance(value, str) and value in SUPPORTED_LANGUAGES:
52
+ return value
53
+ return ""
54
+
55
+
56
+ def _load_persisted_language() -> str:
57
+ for candidate in (
58
+ os.environ.get("CONNY_LANG"),
59
+ os.environ.get("CONNY_UI_LANG"),
60
+ os.environ.get("CONNY_INIT_LANG"),
61
+ ):
62
+ if candidate in SUPPORTED_LANGUAGES:
63
+ return candidate
64
+ path = _workspace_config_path()
65
+ try:
66
+ if path.exists():
67
+ payload = json.loads(path.read_text(encoding="utf-8"))
68
+ lang = _extract_language(payload)
69
+ if lang:
70
+ return lang
71
+ except Exception:
72
+ pass
73
+ return DEFAULT_LANGUAGE
74
+
75
+
76
+ def _persist_language(lang: str) -> None:
77
+ if lang not in SUPPORTED_LANGUAGES:
78
+ return
79
+ os.environ["CONNY_LANG"] = lang
80
+ os.environ["CONNY_UI_LANG"] = lang
81
+ try:
82
+ path = _workspace_config_path()
83
+ path.parent.mkdir(parents=True, exist_ok=True)
84
+ payload = {}
85
+ if path.exists():
86
+ try:
87
+ payload = json.loads(path.read_text(encoding="utf-8"))
88
+ if not isinstance(payload, dict):
89
+ payload = {}
90
+ except Exception:
91
+ payload = {}
92
+ payload["language"] = lang
93
+ payload["ui_language"] = lang
94
+ path.write_text(json.dumps(payload, indent=2, ensure_ascii=False), encoding="utf-8")
95
+ except Exception:
96
+ pass
97
+
98
+
23
99
  @dataclass
24
100
  class TranslationSet:
25
101
  ui: Dict[str, str]
@@ -523,7 +599,9 @@ _TRANSLATIONS: Dict[str, TranslationSet] = {
523
599
 
524
600
 
525
601
  class I18n:
526
- def __init__(self, lang: str = DEFAULT_LANGUAGE):
602
+ def __init__(self, lang: str = None):
603
+ if lang is None:
604
+ lang = _load_persisted_language()
527
605
  self.lang = lang if lang in _TRANSLATIONS else DEFAULT_LANGUAGE
528
606
  self._cache: Dict[str, str] = {}
529
607
 
@@ -576,6 +654,7 @@ def get_i18n() -> I18n:
576
654
 
577
655
  def set_language(lang: str) -> None:
578
656
  _global_i18n.set_lang(lang)
657
+ _persist_language(lang)
579
658
 
580
659
 
581
660
  def t(key: str, category: str = "ui") -> str:
@@ -616,4 +695,4 @@ LANGUAGE_MENU = {
616
695
  "pt": "πŸ‡§πŸ‡· PortuguΓͺs",
617
696
  "fr": "πŸ‡«πŸ‡· FranΓ§ais",
618
697
  "de": "πŸ‡©πŸ‡ͺ Deutsch",
619
- }
698
+ }
package/conny_init.py CHANGED
@@ -214,6 +214,25 @@ def validate_api_key(provider, key):
214
214
  return True
215
215
 
216
216
 
217
+ def _persist_language(lang: str) -> None:
218
+ try:
219
+ workspace_config_path = Path(os.environ.get("CONNY_WORKSPACE_CONFIG", str(CONNY_HOME / "config.json")))
220
+ workspace_config_path.parent.mkdir(parents=True, exist_ok=True)
221
+ payload = {}
222
+ if workspace_config_path.exists():
223
+ try:
224
+ payload = json.loads(workspace_config_path.read_text(encoding="utf-8"))
225
+ if not isinstance(payload, dict):
226
+ payload = {}
227
+ except Exception:
228
+ payload = {}
229
+ payload["language"] = lang
230
+ payload["ui_language"] = lang
231
+ workspace_config_path.write_text(json.dumps(payload, indent=2, ensure_ascii=False), encoding="utf-8")
232
+ except Exception:
233
+ pass
234
+
235
+
217
236
  def _next_available_port() -> int:
218
237
  existing_ports = []
219
238
  if INSTANCES_DIR.exists():
@@ -379,6 +398,7 @@ def run_wizard():
379
398
  lang = LANGUAGES[i][0]
380
399
  global CURRENT_LANG
381
400
  CURRENT_LANG = lang
401
+ _persist_language(lang)
382
402
 
383
403
  # 1. Identity
384
404
  clear()
package/conny_tui.py CHANGED
@@ -30,6 +30,13 @@ CONNY_DIR = os.getenv("CONNY_DIR", str(Path(__file__).resolve().parent))
30
30
  INSTANCES_DIR = os.getenv("INSTANCES_DIR", str(Path.home() / "conny-instances"))
31
31
  CLI_SCRIPT = os.getenv("CONNY_CLI", str(Path(__file__).resolve().parent / "conny_cli.py"))
32
32
 
33
+ try:
34
+ _package_path = Path(CONNY_DIR) / "package.json"
35
+ if _package_path.exists():
36
+ VERSION = json.loads(_package_path.read_text(encoding="utf-8")).get("version", VERSION)
37
+ except Exception:
38
+ pass
39
+
33
40
  # ── Colores curses (Γ­ndices de par) ─────────────────────────────────────────
34
41
  CP_LOGO1 = 1 # Rosa β€” letras CONNY (gradiente lΓ­nea 1)
35
42
  CP_LOGO2 = 10 # Rosa claro (gradiente lΓ­nea 2)
package/npm/conny.js CHANGED
@@ -518,10 +518,8 @@ if (isHelp) {
518
518
  process.exit(0);
519
519
  }
520
520
 
521
- if (!isJson && process.stdout.isTTY) {
522
- printBanner();
523
- }
521
+ const launchArgs = args.length === 0 ? ["new"] : args;
524
522
 
525
- if (!execConny(args)) {
523
+ if (!execConny(launchArgs)) {
526
524
  fail(`No pude iniciar Conny desde ${connyHome}`);
527
525
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@innvisor/conny-ai",
3
- "version": "9.8.0",
3
+ "version": "9.8.2",
4
4
  "description": "Open-source CLI and runtime for building Conny AI receptionist agents on WhatsApp and Telegram.",
5
5
  "license": "MIT",
6
6
  "author": "Santiago Rubio",
@@ -109,4 +109,4 @@
109
109
  "figlet": "^1.11.0",
110
110
  "ora": "^5.4.1"
111
111
  }
112
- }
112
+ }