feat(cli): add theme option for interactive shell and enhance configuration - #2519
Conversation
Greptile code reviewThis repo uses Greptile for automated review. Before merge, aim for Confidence Score: 5/5 with zero unresolved review threads — see CONTRIBUTING.md. Run a review — add a PR comment with: Give it ~5-10 minutes (sometimes longer) for results, then fix feedback and re-trigger until you reach Confidence Score: 5/5. Optional: automate with the greploop skill. |
Greptile SummaryThis PR introduces a comprehensive theming system for the interactive shell, allowing users to select and persist one of nine color palettes via a
Confidence Score: 5/5Safe to merge; the theming system is well-isolated, the three-tier config resolution follows established patterns, and previous review concerns (session initialization, public drain function) have been addressed. The core theme selection, persistence, and live-refresh flows are correct and well-tested. The only finding is a style concern: app/cli/interactive_shell/command_registry/theme.py — imports private helpers from config.py that should be promoted to a public surface. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User
participant CLI as opensre CLI (--theme)
participant ReplConfig
participant ThemeModule as ui/theme.py
participant Session as ReplSession
participant PromptTK as prompt_toolkit
User->>CLI: opensre --theme blue
CLI->>ReplConfig: "load(cli_theme="blue")"
ReplConfig->>ThemeModule: set_active_theme("blue")
ThemeModule-->>ReplConfig: "CliTheme(name="blue")"
ReplConfig-->>CLI: "ReplConfig(theme="blue")"
CLI->>Session: ReplSession()
CLI->>ThemeModule: get_active_theme_name()
ThemeModule-->>CLI: "blue"
CLI->>Session: "session.active_theme_name = "blue""
CLI->>PromptTK: run_interactive(session)
User->>PromptTK: /theme green
PromptTK->>ThemeModule: set_active_theme("green")
PromptTK->>Session: "session.active_theme_name = "green""
PromptTK->>PromptTK: call_soon_threadsafe(refresh_prompt_theme)
PromptTK->>CLI: "_save_config({interactive: {theme: green}})"
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User
participant CLI as opensre CLI (--theme)
participant ReplConfig
participant ThemeModule as ui/theme.py
participant Session as ReplSession
participant PromptTK as prompt_toolkit
User->>CLI: opensre --theme blue
CLI->>ReplConfig: "load(cli_theme="blue")"
ReplConfig->>ThemeModule: set_active_theme("blue")
ThemeModule-->>ReplConfig: "CliTheme(name="blue")"
ReplConfig-->>CLI: "ReplConfig(theme="blue")"
CLI->>Session: ReplSession()
CLI->>ThemeModule: get_active_theme_name()
ThemeModule-->>CLI: "blue"
CLI->>Session: "session.active_theme_name = "blue""
CLI->>PromptTK: run_interactive(session)
User->>PromptTK: /theme green
PromptTK->>ThemeModule: set_active_theme("green")
PromptTK->>Session: "session.active_theme_name = "green""
PromptTK->>PromptTK: call_soon_threadsafe(refresh_prompt_theme)
PromptTK->>CLI: "_save_config({interactive: {theme: green}})"
Reviews (7): Last reviewed commit: "merge: resolve main into themee for them..." | Re-trigger Greptile |
| active_theme_name: str = "green" | ||
| """Interactive shell palette name for this REPL session (``/theme``, prompts).""" |
There was a problem hiding this comment.
active_theme_name not initialized from the configured theme
The field defaults to the hardcoded string "green" regardless of what theme was resolved during ReplConfig.load(). If the user has configured interactive.theme: blue (or OPENSRE_THEME=blue), any code reading session.active_theme_name before /theme is first invoked will see "green" instead of "blue". Since set_active_theme() is called during config load, the module-level global in ui/theme.py is already correct — the session field just needs to be initialized with get_active_theme_name() either at session creation or in the REPL startup path.
|
@greptile-apps review again |
|
@greptile-apps review again |
|
@greptile-apps review again |
|
@Devesh36 can you fix conflicts? also a demo for an e2e flow like till investigate? I want to see how the theme goes when the interaction is happening? pls add a video demo |
Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # app/cli/interactive_shell/command_registry/__init__.py # app/cli/interactive_shell/command_registry/help.py # app/cli/interactive_shell/prompting/prompt_surface.py # app/cli/interactive_shell/runtime/entrypoint.py # app/cli/interactive_shell/ui/__init__.py # app/cli/interactive_shell/ui/banner.py # app/cli/interactive_shell/ui/theme.py # tests/cli/interactive_shell/ui/test_banner.py
|
@Devesh36 @muddlebee this looks pretty cool, am merging this, cc @0xpaulx for visibility too. |
|
@greptile-apps review again |
|
@greptile-apps review again |
Integrate upstream refactors (banner_state, provider, tables, settings/diagnostics commands) while preserving dynamic theming: refresh_welcome_poster, ui_theme module references for live ANSI updates, and theme save/restore in banner_state. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@greptile-apps review again |
|
🌊 Merged. @Devesh36 is now permanently woven into git history. No take-backs. 😄 👋 Join us on Discord - OpenSRE : hang out, contribute, or hunt for features and issues. Everyone's welcome. |


This pull request introduces a comprehensive theming system for the interactive shell, allowing users to select and persist a color palette via CLI options, environment variables, configuration files, or a new
/themeslash command. It also improves configuration validation and enhances the user experience for theme selection and application. Additionally, there are minor improvements to code clarity and command output formatting.Interactive shell theming system:
--themeCLI option,OPENSRE_THEMEenvironment variable, andinteractive.themeconfig key, allowing users to select the shell color palette. Theme selection is validated and persisted, with a default of"green"if unset or invalid (app/cli/__main__.py,app/cli/interactive_shell/config/repl_config.py,app/cli/commands/config.py). [1] [2] [3] [4] [5] [6] [7] [8] [9]/themeslash command for interactive theme selection and persistence, including a TTY picker, tab-completion, and help integration (app/cli/interactive_shell/command_registry/theme.py,app/cli/interactive_shell/command_registry/__init__.py,app/cli/interactive_shell/command_registry/help.py,app/cli/interactive_shell/command_registry/slash_catalog.py). [1] [2] [3] [4] [5] [6]app/cli/interactive_shell/prompting/prompt_surface.py). [1] [2] [3] [4]Configuration and validation improvements:
interactive.theme, providing user-friendly error messages and fallback to defaults if invalid values are detected (app/cli/commands/config.py,app/cli/interactive_shell/config/repl_config.py). [1] [2]Minor improvements and refactoring:
app/cli/interactive_shell/command_registry/session_cmds.py). [1] [2] [3] [4] [5] [6]These changes provide a more customizable and user-friendly interactive shell experience.
