The label column is the widest tool title plus two cells of gap, which leaves the muted description 47 to work in. All 22 of them ran past it — "Act on the device itself — clock, backup, identity key, reboot, reset" needed 94 columns of terminal to say what 67 could. The row scrolled under ←→ rather than lying, but a description you have to scroll is a description nobody reads. Rewritten to fit: the subject moves into the title's shadow (the row already says Device actions, so the description just lists them), the parenthetical asides go, and the trailing clause that repeated the obvious goes with them. Widest row is now exactly 72. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
72 lines
2.4 KiB
Python
72 lines
2.4 KiB
Python
"""The ``dashboard`` tool: the live mesh overview, at the top of the Watch section.
|
|
|
|
Opens the full-screen dashboard (see :mod:`meshterm.ui.dashboard_screen`): the two-hour
|
|
all-packet activity chart with its pulse line, the session's traffic tallies by packet
|
|
class, and the window's RF health beside the radio's own live numbers. (The per-packet
|
|
stream is the Live feed tool, right below.) It leads the Watch section because it answers
|
|
the section's first question — *what's going on out there?* — before any specific tool
|
|
is reached for.
|
|
|
|
Menu-only: the dashboard is inherently live (it rides the event hub and repaints every
|
|
second), so there is no scripted one-shot to register — the ``monitor`` and ``contacts``
|
|
subcommands cover scripted inspection.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Optional
|
|
|
|
import typer
|
|
|
|
from ..context import AppContext
|
|
from .base import Tool, ToolResult, register
|
|
|
|
|
|
@register
|
|
class DashboardTool(Tool):
|
|
"""Watch everything going on on the mesh: activity, traffic, RF health."""
|
|
|
|
name = "dashboard"
|
|
title = "Dashboard"
|
|
icon = "📊"
|
|
help = "The mesh live — activity, traffic, RF health"
|
|
category = "Watch"
|
|
order = 10 # the section's overview, above the tools it summarizes
|
|
|
|
async def prompt_params(self, ctx: AppContext) -> Optional[dict[str, Any]]:
|
|
"""Run the live dashboard; there are never parameters to collect.
|
|
|
|
The screen presents everything itself and returns when dismissed, so
|
|
returning ``None`` tells the menu the invocation is complete (the same
|
|
pattern as the ``advert`` tool).
|
|
|
|
Args:
|
|
ctx: Shared application context.
|
|
|
|
Returns:
|
|
Always ``None``.
|
|
"""
|
|
from ..ui.dashboard_screen import open_dashboard
|
|
|
|
await open_dashboard(ctx)
|
|
return None
|
|
|
|
async def run(self, ctx: AppContext, params: dict[str, Any]) -> ToolResult:
|
|
"""Nothing runs here: the dashboard lives inside :meth:`prompt_params`.
|
|
|
|
Args:
|
|
ctx: Shared application context.
|
|
params: Unused.
|
|
|
|
Returns:
|
|
An empty :class:`ToolResult` (only reachable from a scripted call).
|
|
"""
|
|
return ToolResult(summary={})
|
|
|
|
def register_cli(self, app: typer.Typer) -> None:
|
|
"""Register no CLI command — the dashboard is a live, menu-only screen.
|
|
|
|
Args:
|
|
app: The Typer application (untouched).
|
|
"""
|