From cbefa961242e8133f831895423bc043ab7ddac65 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Wed, 2 Sep 2026 19:22:13 -0700 Subject: [PATCH] refactor(gateway): fold pairing dir merge, bool-default table in GatewayConfig.from_dict --- gateway/channel_directory.py | 19 ++++++---------- gateway/config.py | 17 +++++++------- gateway/pairing.py | 44 ++++++++++++------------------------ 3 files changed, 31 insertions(+), 49 deletions(-) diff --git a/gateway/channel_directory.py b/gateway/channel_directory.py index 8d2fdd46e7..edac38888e 100644 --- a/gateway/channel_directory.py +++ b/gateway/channel_directory.py @@ -506,22 +506,17 @@ def format_directory_for_display(platforms: Optional[Dict[str, Any]] = None) -> f"{plat_name}:, or bare '{plat_name}' for the home channel)" ) elif plat_name == "discord": - # Group Discord channels by guild; DMs last. + # Group Discord channels by guild (sorted by name); DMs last, in discovery order. guilds: Dict[str, List] = {} dms: List = [] for ch in channels: - guild = ch.get("guild") - (guilds.setdefault(guild, []) if guild else dms).append(ch) - - for guild_name, guild_channels in sorted(guilds.items()): - lines.append(f"Discord ({guild_name}):") - lines.extend( - f" discord:{_channel_target_name(plat_name, ch)}" - for ch in sorted(guild_channels, key=lambda c: c["name"]) - ) + (guilds.setdefault(ch["guild"], []) if ch.get("guild") else dms).append(ch) + groups = [(f"Discord ({g}):", sorted(chs, key=lambda c: c["name"])) for g, chs in sorted(guilds.items())] if dms: - lines.append("Discord (DMs):") - lines.extend(f" discord:{_channel_target_name(plat_name, ch)}" for ch in dms) + groups.append(("Discord (DMs):", dms)) + for header, group in groups: + lines.append(header) + lines.extend(f" discord:{_channel_target_name(plat_name, ch)}" for ch in group) else: lines.append(f"{plat_name.title()}:") lines.extend(f" {plat_name}:{_channel_target_name(plat_name, ch)}" for ch in channels) diff --git a/gateway/config.py b/gateway/config.py index 04eac75dc2..c428da7be5 100644 --- a/gateway/config.py +++ b/gateway/config.py @@ -158,9 +158,7 @@ def coerce_systemd_watchdog_seconds( if parsed is None: logger.warning("Ignoring invalid %s (expected a positive integer)", key) return 0 - if parsed == 0: - return 0 - if not 0 < parsed <= _SYSTEMD_WATCHDOG_MAX_SECONDS: + if parsed and not 0 < parsed <= _SYSTEMD_WATCHDOG_MAX_SECONDS: logger.warning("Ignoring invalid %s (expected an integer from 1 to %d)", key, _SYSTEMD_WATCHDOG_MAX_SECONDS) return 0 return parsed @@ -562,6 +560,13 @@ _PLATFORM_CONNECTED_CHECKERS: dict[Platform, Callable[[PlatformConfig], bool]] = } +# Top-level bool-ish keys read verbatim (no nested ``gateway.`` fallback) with their defaults. +_TOPLEVEL_BOOL_DEFAULTS = { + "write_sessions_json": True, "always_log_local": True, "filter_silence_narration": True, + "group_sessions_per_user": True, "thread_sessions_per_user": False, +} + + @dataclass class GatewayConfig: """Main gateway configuration: platform connections, session policies, delivery settings.""" @@ -772,13 +777,9 @@ class GatewayConfig: reset_triggers=data.get("reset_triggers", ["/new", "/reset"]), quick_commands=_coerce_dict(data.get("quick_commands", {})), sessions_dir=Path(data["sessions_dir"]) if "sessions_dir" in data else get_hermes_home() / "sessions", - write_sessions_json=_coerce_bool(data.get("write_sessions_json"), True), - always_log_local=_coerce_bool(data.get("always_log_local"), True), - filter_silence_narration=_coerce_bool(data.get("filter_silence_narration"), True), + **{name: _coerce_bool(data.get(name), default) for name, default in _TOPLEVEL_BOOL_DEFAULTS.items()}, stt_enabled=_coerce_bool(stt_setting("stt_enabled", "enabled"), True), stt_echo_transcripts=_coerce_bool(stt_setting("stt_echo_transcripts", "echo_transcripts"), True), - group_sessions_per_user=_coerce_bool(data.get("group_sessions_per_user"), True), - thread_sessions_per_user=_coerce_bool(data.get("thread_sessions_per_user"), False), multiplex_profiles=_coerce_bool(multiplex_profiles, False), multiplex_profile_allowlist=pick("multiplex_profile_allowlist"), room_link_url=room_link_url if isinstance(room_link_url, str) else None, diff --git a/gateway/pairing.py b/gateway/pairing.py index a2e1110580..7fefdb017e 100644 --- a/gateway/pairing.py +++ b/gateway/pairing.py @@ -297,41 +297,27 @@ def _save_json_file(path: Path, data: dict) -> None: _secure_write(path, json.dumps(data, indent=2, ensure_ascii=False)) -def _merge_pairing_dir(active_dir: Path, alternate_dir: Path) -> None: +def _migrate_split_pairing_dirs(*, home: Optional[Path] = None, active: Optional[Path] = None) -> None: """Merge split legacy (``pairing``) / new (``platforms/pairing``) data into the active dir. - If both exist, approved users in the inactive location must not be - silently ignored (they would be asked for a fresh code). + If both exist, approved users in the inactive location must not be silently + ignored (they would be asked for a fresh code). Active data wins on key conflict. """ - if not alternate_dir.exists() or active_dir.resolve() == alternate_dir.resolve(): - return - active_dir.mkdir(parents=True, exist_ok=True) - for src in alternate_dir.glob("*.json"): - if not src.is_file(): - continue - dest = active_dir / src.name - merged = _load_json_file(src) - if not merged: - continue - current = _load_json_file(dest) - before = dict(current) - # Active data wins on key conflict; otherwise union the inactive data. - merged.update(current) - if merged != before: - _save_json_file(dest, merged) - - -def _migrate_split_pairing_dirs( - *, - home: Optional[Path] = None, - active: Optional[Path] = None, -) -> None: home = home or get_hermes_home() old_dir = home / "pairing" - new_dir = home / "platforms" / "pairing" active = active if active is not None else _default_pairing_dir() - alternate = new_dir if active.resolve() == old_dir.resolve() else old_dir - _merge_pairing_dir(active, alternate) + alternate = home / "platforms" / "pairing" if active.resolve() == old_dir.resolve() else old_dir + if not alternate.exists() or active.resolve() == alternate.resolve(): + return + active.mkdir(parents=True, exist_ok=True) + for src in alternate.glob("*.json"): + merged = _load_json_file(src) if src.is_file() else {} + if not merged: + continue + current = _load_json_file(active / src.name) + merged.update(current) + if merged != current: + _save_json_file(active / src.name, merged) def _secure_write(path: Path, data: str) -> None: