Skip to content

feat(cli): add theme option for interactive shell and enhance configuration#2519

Open
Devesh36 wants to merge 5 commits into
Tracer-Cloud:mainfrom
Devesh36:themee
Open

feat(cli): add theme option for interactive shell and enhance configuration#2519
Devesh36 wants to merge 5 commits into
Tracer-Cloud:mainfrom
Devesh36:themee

Conversation

@Devesh36
Copy link
Copy Markdown
Collaborator

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 /theme slash 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:

  • Added support for a --theme CLI option, OPENSRE_THEME environment variable, and interactive.theme config 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]
  • Introduced a /theme slash 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]
  • Updated prompt rendering and UI code to use the active theme dynamically, ensuring prompt-toolkit and color codes reflect the selected palette (app/cli/interactive_shell/prompting/prompt_surface.py). [1] [2] [3] [4]

Configuration and validation improvements:

  • Enhanced config validation for 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:

  • Improved code clarity and output formatting in session commands and welcome poster refresh logic (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.
Screenshot 2026-05-25 at 7 56 58 PM

Screenshot 2026-05-25 at 7 58 06 PM

@github-actions
Copy link
Copy Markdown
Contributor

Greptile code review

This 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:

@greptile review

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.

Comment thread app/cli/interactive_shell/ui/banner.py Fixed
Comment thread app/cli/interactive_shell/ui/choice_menu.py Fixed
Comment thread app/cli/interactive_shell/ui/rendering.py Fixed
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 25, 2026

Greptile Summary

This PR adds a comprehensive theming system to the interactive shell, allowing users to pick a color palette via --theme CLI flag, OPENSRE_THEME env var, interactive.theme config key, or the new /theme slash command. It also initializes session.active_theme_name from the resolved config at startup (fixing the previous thread concern) and makes drain_stale_cpr_bytes public so the theme command can import it cleanly.

  • Theme resolution: ReplConfig.load() now resolves theme via three-tier priority (CLI > env > file > default) with validation and warnings for invalid values; set_active_theme() is called once during load to populate the module-level ANSI globals.
  • /theme slash command: New interactive picker with tab-completion and persistence to ~/.opensre/config.yml; TTY guard is correctly scoped to the picker branch, not the direct-arg branch.
  • Session initialization: repl_main() now sets session.active_theme_name = get_active_theme_name() after the config is loaded, so the session field matches the actual active palette from startup.

Confidence Score: 5/5

Safe to merge — the theming feature is well-contained, all three config tiers resolve correctly, and the previous issues (session field initialization, TTY guard ordering, private import) are all addressed.

The three-tier theme resolution path is tested end-to-end, the lazy _LazyRichStyle tokens resolve at render time so no stale colours can leak, and session.active_theme_name is now seeded from get_active_theme_name() immediately after config load. The only remaining findings are minor maintenance concerns that carry no current runtime risk.

The hardcoded theme list in app/cli/main.py will require a manual update every time a theme is added to or removed from THEME_REGISTRY.

Important Files Changed

Filename Overview
app/cli/main.py Adds --theme Click option with hardcoded choices (duplicate of THEME_REGISTRY); moves ReplConfig import to module level for subcommand path; the interactive and subcommand paths now each call ReplConfig.load() exactly once.
app/cli/interactive_shell/command_registry/theme.py New /theme slash command; if args: branch correctly precedes TTY guard; uses public drain_stale_cpr_bytes from loop.py; persists selection to config file and refreshes prompt style via call_soon_threadsafe.
app/cli/interactive_shell/config/repl_config.py Three-tier theme resolution added; env/file paths log warnings for invalid values; CLI path has no explicit validation (safe because click.Choice already validates), but no warning is emitted if an invalid programmatic cli_theme is passed.
app/cli/interactive_shell/runtime/session.py active_theme_name defaults to green but is immediately overwritten in repl_main() via get_active_theme_name(), so no mismatch at runtime.
app/cli/interactive_shell/runtime/entrypoint.py Now sets session.active_theme_name = get_active_theme_name() after config is loaded, fixing the previously noted mismatch between the session field and the module-level global.
app/cli/interactive_shell/ui/theme.py New CliTheme dataclass and THEME_REGISTRY; lazy _LazyRichStyle tokens resolve against active palette at render time; set_active_theme populates all ANSI globals.
app/cli/commands/config.py Added interactive.theme to _SUPPORTED_KEYS; _coerce_value now validates theme names against list_theme_names() and raises UsageError on invalid input.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[opensre CLI invoked] --> B{subcommand?}
    B -- no, TTY --> C[ReplConfig.load\ncli_theme + env + file]
    B -- no, non-TTY --> D[render_landing]
    B -- yes --> E[ReplConfig.load\ncli_theme only\nfor theme side-effect]
    C --> F[set_active_theme\nmodule globals updated]
    E --> F
    F --> G[run_repl]
    G --> H[repl_main]
    H --> I[session.active_theme_name =\nget_active_theme_name]
    I --> J[REPL loop]
    J --> K{/theme command}
    K -- with arg --> L[validate & apply theme]
    K -- no arg + TTY --> M[interactive picker]
    M --> L
    L --> N[set_active_theme]
    N --> O[persist to config.yml]
    O --> P[call_soon_threadsafe\nrefresh_prompt_theme]
    O --> Q[refresh_welcome_poster\nwith theme_notice]
Loading

Reviews (3): Last reviewed commit: "fix(cli): resolve CodeQL findings and th..." | Re-trigger Greptile

Comment thread app/cli/__main__.py
Comment thread app/cli/interactive_shell/command_registry/theme.py Outdated
Comment thread app/cli/interactive_shell/command_registry/theme.py
Comment on lines +104 to +105
active_theme_name: str = "green"
"""Interactive shell palette name for this REPL session (``/theme``, prompts)."""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

@Devesh36
Copy link
Copy Markdown
Collaborator Author

@greptile-apps review again

@Devesh36
Copy link
Copy Markdown
Collaborator Author

@greptile-apps review again

@Devesh36 Devesh36 requested a review from 0xpaulx May 27, 2026 11:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants