Skip to content

Commit 6b6f6f5

Browse files
committed
🐛 fix(cli): use Rich startup header
Replace the Textual header experiment with a Rich panel header to avoid startup hangs. Keep MCP CLI typing improvements and header stubs in tests, and update CLI guidance to reflect the Rich-only header.
1 parent 13ef9cf commit 6b6f6f5

4 files changed

Lines changed: 36 additions & 15 deletions

File tree

meeseeks-cli/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Scope: this file applies to the `meeseeks-cli/` package only. It covers the term
1212
- Entry point: `meeseeks-cli/cli_master.py` (`run_cli`).
1313
- Rendering is **Rich**-based and printed via a single `Console` instance.
1414
- High-level sections:
15-
- Ready panel with model/base URL (within the same border).
15+
- Startup header panel plus a ready line with session info.
1616
- Action plan checklist (Panel + Text + Group).
1717
- Tool results as cards (Panel + Columns).
1818
- Response panel (Markdown in a bold border).

meeseeks-cli/cli_commands.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
from core.task_master import orchestrate_session # noqa: E402
2424
from core.token_budget import get_token_budget # noqa: E402
25-
from core.tool_registry import ToolRegistry, load_registry # noqa: E402
25+
from core.tool_registry import ToolRegistry, ToolSpec, load_registry # noqa: E402
2626

2727

2828
@dataclass(frozen=True)
@@ -275,8 +275,8 @@ def _refresh_mcp_registry(context: CommandContext) -> None:
275275

276276
def _maybe_select_mcp_specs(
277277
context: CommandContext,
278-
mcp_specs: list[object],
279-
) -> list[object] | None:
278+
mcp_specs: list[ToolSpec],
279+
) -> list[ToolSpec] | None:
280280
if context.prompt_func is None:
281281
return None
282282
dialogs = DialogFactory(console=context.console, prompt_func=context.prompt_func)
@@ -471,7 +471,7 @@ def _handle_model_wizard(
471471
def _render_mcp(
472472
console: Console,
473473
tool_registry: ToolRegistry,
474-
mcp_specs: list[object] | None = None,
474+
mcp_specs: list[ToolSpec] | None = None,
475475
) -> None:
476476
config_path = os.getenv("MESEEKS_MCP_CONFIG")
477477
if config_path and os.path.exists(config_path):

meeseeks-cli/cli_master.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from rich.console import Console, Group
1515
from rich.markdown import Markdown
1616
from rich.panel import Panel
17+
from rich.status import Status
1718
from rich.syntax import Syntax
1819
from rich.text import Text
1920

@@ -139,6 +140,22 @@ def _resolve_display_model(model_name: str | None) -> str:
139140
)
140141

141142

143+
def _render_startup_header(console: Console, title: str, subtitle: str) -> None:
144+
header = Text(title, style="bold cyan", justify="center")
145+
body = Group(
146+
header,
147+
Text(subtitle, style="dim", justify="center"),
148+
)
149+
console.print(
150+
Panel(
151+
body,
152+
box=box.HEAVY,
153+
border_style="cyan",
154+
padding=(0, 2),
155+
)
156+
)
157+
158+
142159
def run_cli(args: argparse.Namespace) -> int:
143160
"""Run the CLI application loop.
144161
@@ -161,12 +178,10 @@ def run_cli(args: argparse.Namespace) -> int:
161178
registry = get_registry()
162179

163180
base_url = os.getenv("OPENAI_API_BASE") or os.getenv("OPENAI_BASE_URL")
164-
ready_lines = [
165-
Text("Meeseeks CLI ready"),
166-
Text(f"Model: {_resolve_display_model(state.model_name)}", style="dim"),
167-
Text(f"Base URL: {base_url or '(not set)'}", style="dim"),
168-
]
169-
console.print(Panel(Group(*ready_lines), title="Meeseeks"))
181+
model_name = _resolve_display_model(state.model_name)
182+
subtitle = f"Model: {model_name} • Base URL: {base_url or '(not set)'}"
183+
_render_startup_header(console, "Meeseeks", subtitle)
184+
console.print("Meeseeks CLI ready")
170185
console.print(f"Session: {state.session_id}")
171186
console.print("Type /help for commands.\n")
172187

@@ -255,7 +270,7 @@ def _run_query(
255270
task_queue,
256271
tool_registry,
257272
highlight_latest=not bool(task_queue.task_result),
258-
verbose=args.verbose > 0,
273+
verbose=getattr(args, "verbose", 0) > 0,
259274
)
260275
if task_queue.task_result:
261276
console.print(
@@ -401,6 +416,7 @@ def _render_results_with_registry(
401416

402417

403418
def _format_tool_output(result: object, content_style: str | None) -> Text | Syntax:
419+
style = content_style or ""
404420
if isinstance(result, dict | list):
405421
return Syntax(
406422
json.dumps(result, indent=2, ensure_ascii=True),
@@ -422,15 +438,15 @@ def _format_tool_output(result: object, content_style: str | None) -> Text | Syn
422438
theme="ansi_dark",
423439
word_wrap=True,
424440
)
425-
return Text(result, style=content_style)
426-
return Text(str(result), style=content_style)
441+
return Text(result, style=style)
442+
return Text(str(result), style=style)
427443

428444

429445
def _build_cli_hook_manager(
430446
console: Console,
431447
tool_registry: ToolRegistry,
432448
) -> HookManager:
433-
status_holder: dict[str, object] = {}
449+
status_holder: dict[str, Status] = {}
434450
specs = _tool_specs_by_id(tool_registry)
435451

436452
def _start_spinner(action_step: ActionStep) -> ActionStep:

meeseeks-cli/tests/test_cli.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ def test_run_cli_single_query(monkeypatch, tmp_path):
221221
auto_approve=False,
222222
)
223223

224+
def fake_header(*args, **kwargs):
225+
return None
226+
224227
def fake_orchestrate(*args, **kwargs):
225228
step = ActionStep(
226229
action_consumer="home_assistant_tool",
@@ -231,6 +234,7 @@ def fake_orchestrate(*args, **kwargs):
231234
task_queue.task_result = "ok"
232235
return task_queue
233236

237+
monkeypatch.setattr("cli_master._render_startup_header", fake_header)
234238
monkeypatch.setattr("cli_master.orchestrate_session", fake_orchestrate)
235239
assert run_cli(args) == 0
236240

@@ -265,6 +269,7 @@ def prompt(self, *args, **kwargs):
265269
self.calls += 1
266270
return "/quit"
267271

272+
monkeypatch.setattr("cli_master._render_startup_header", lambda *args, **kwargs: None)
268273
monkeypatch.setattr("cli_master.FileHistory", DummyHistory)
269274
monkeypatch.setattr("cli_master.PromptSession", lambda *args, **kwargs: DummySession())
270275
assert run_cli(args) == 0

0 commit comments

Comments
 (0)