Skip to content

Changelog

  • Centralized logging module β€” Moved sec_gemini/tui2/logging.py to sec_gemini/logging.py so all components (TUI, MCP server, BYOT CLI) share the same structured JSON logging infrastructure. Fixed _KwargsAdapter to store structured fields safely, avoiding LogRecord attribute collisions (e.g. name=).

  • BYOT: setup_byot_logging() β€” New convenience function for the standalone BYOT CLI. Writes rotating JSON to ~/.config/sec-gemini/logs/byot.log plus colored console output via Rich. Added --verbose CLI flag.

  • BYOT: dedicated log file β€” MCP server now writes BYOT logs to a separate byot.log via a namespace handler on secgemini.byot, in addition to mcp.log via the root logger.

  • MCP: BYOT observability tools β€” Added 3 new Layer 1 tools: get_byot_status (state, tools, hub URL, uptime, errors), list_byot_tools (focused tool listing), reload_byot (stop + restart with refreshed config). Added 2 debug tools: byot_log and byot_log_grep for inspecting BYOT logs.

  • MCP: mcp_reload sends ToolListChangedNotification β€” After re-registering tools, the client is notified so it re-fetches the tool list. New tools appear immediately without a server reconnect.

  • MCP: mcp_reload covers BYOT and tools modules β€” Added sec_gemini.byot.* and sec_gemini.tools.* to the reload list so BYOT code changes take effect without restarting the MCP server.

  • BYOT: structured logging β€” Converted byot/service.py and byot/client.py to use get_logger() with structured kwargs (tool_count=, hub_url=, job_id=) instead of %s formatting.

  • BYOT: better auth error reporting β€” Hub registration rejection now logs registration_rejected with hub URL and key prefix, and raises a more descriptive error message.

  • MCP: TUI lifecycle tools β€” Added tui_start, tui_stop, tui_status debug tools that launch/manage the TUI as a headless subprocess. Enables autonomous TUI debugging from Claude Code without manual terminal setup.

  • TUI: debug socket server β€” New DebugServer in tui2/debug_server.py exposes a Unix domain socket (~/.config/sec-gemini/debug.sock) when --debug is passed. Accepts JSON commands for screen inspection, widget queries, clicks, keypresses, and state dumps.

  • TUI: --debug and --headless CLI flags β€” sec-gemini run --debug starts the debug socket server; --headless runs without a terminal for MCP-managed sessions.

  • sec_gemini/backoff.py β€” ExponentialBackoff utility with full jitter for use in reconnection and retry logic.

  • 30 new unit tests covering dispatch routing, error handling, reconnection backoff, retry behavior, and session state management.

  • TUI: stream loop stops after terminal state β€” The message stream loop no longer re-subscribes every 30s after a session reaches COMPLETED, FAILED, CANCELED, or MAX_ATTEMPTS_EXCEEDED. Previously this caused the server to replay the entire message history indefinitely. The session VM now tracks status changes via a callback and sets COMPLETED on AGENT_IS_DONE receipt.

  • BYOT: idempotent start β€” start_byot() returns current tools when BYOT is already running instead of raising an error. Fixes the β€œBYOT already created” toast when creating a second session.

  • BYOT: hot-reload resilience β€” MCP status tools (get_byot_status, list_byot_tools) access raw service attributes to survive Pydantic class identity mismatches after mcp_reload(). ByotService.status() also converts tools to dicts before constructing ByotStatus.

  • Sessions: sorted newest-first β€” list_sessions() now returns sessions sorted by created_at descending in both the Backend and MCP tool layer.

  • MCP: mcp_reload now re-registers tools β€” Previously only reloaded modules without updating the registered tool closures. Now calls register_all_tools() and register_debug_tools() after reload so code changes take effect without restarting the MCP server.

  • MCP: TUI inspection tools use IPC β€” tui_screenshot, tui_get_screen, tui_query, tui_click, tui_type, tui_press, tui_get_state now communicate via the debug Unix socket instead of requiring an in-process app reference that was never set in standalone mode.

  • MCP: stale debug socket cleanup β€” tui_stop and MCP lifespan shutdown now remove the debug socket file to prevent stale socket issues.

  • Session: get() reuses cached sessions β€” ClientSessions.get() now returns the existing tracked session instead of always creating a fresh one, which was clobbering accumulated state (status, name, created_at).

  • Session: server-assigned names applied from stream β€” Added Session.handle_streamed_message() to pick up MESSAGE_TYPE_SESSION_NAME from server. SessionMessages now holds a reference to its parent Session and calls the handler before yielding messages.

  • Session: state reconciliation after reconnection β€” Added reconnect callback mechanism to RpcClient. ClientSessions registers _reconcile_state at bind time, calling list() after reconnection to resync all session state from the server.

  • Connection: improved message routing reliability β€” Message routing now uses strict request ID matching, ensuring reliable delivery and preventing misrouting or silent drops.

  • Connection: exponential backoff on reconnection β€” Replaced fixed 0.2s/1.0s reconnection delays with exponential backoff using full jitter (base=0.5s, max=30s, multiplier=2x). Prevents connection storms and server-side rate limiting during network instability.

  • Session: log warning on invalid status β€” update_from_event now logs a warning when it receives an unrecognized status string, instead of silently swallowing the ValueError.

  • Session: handle name and created_at from events β€” update_from_event now updates _name and _created_at when those fields are present in the event dict.

  • ClientSessions: handle session_not_found β€” _handle_server_message now handles session_not_found events by removing stale sessions from the local cache and logging a warning.

  • ClientSessions: log unknown session state changes β€” State change events for sessions not in the local registry now emit a debug log instead of being silently ignored.