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.5 KiB
Python
72 lines
2.5 KiB
Python
"""The ``advert`` tool: announce this node to the mesh, straight from the main menu.
|
|
|
|
Opens the Send advert flow (see :func:`meshterm.ui.config_editor.send_advert`) — a
|
|
zero-hop or flood advertisement, or this node's shareable contact card as a QR code.
|
|
A ``popup`` tool: the flow's prompts and result float over the still-pushed main menu
|
|
as modal dialogs (the quit-dialog pattern), so the everyday action stays a quick
|
|
in-place popup rather than a screen change.
|
|
|
|
Menu-only: the scripted equivalents are ``config advert`` and ``config share``, so no
|
|
duplicate subcommand is registered here (the same pattern as ``device-actions``).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Optional
|
|
|
|
import typer
|
|
|
|
from ..context import AppContext
|
|
from .base import Tool, ToolResult, register
|
|
|
|
|
|
@register
|
|
class SendAdvertTool(Tool):
|
|
"""Send a zero-hop or flood advert, or share this node's contact card."""
|
|
|
|
name = "advert"
|
|
title = "Send advert"
|
|
icon = "📡"
|
|
help = "Announce this node — zero-hop, flood, or QR"
|
|
category = "This node"
|
|
order = 40 # your own node announcing itself: a device action, not a view
|
|
popup = True # dialog-sized: float over the menu instead of replacing it
|
|
|
|
async def prompt_params(self, ctx: AppContext) -> Optional[dict[str, Any]]:
|
|
"""Run the interactive advert flow; there are never parameters to collect.
|
|
|
|
The flow presents its own result (the sent-advert note or the contact-card
|
|
view) before returning, so by the time the user backs out there is nothing
|
|
left for :meth:`run` to do — returning ``None`` tells the menu the invocation
|
|
is complete (the same pattern as the Device actions screen).
|
|
|
|
Args:
|
|
ctx: Shared application context.
|
|
|
|
Returns:
|
|
Always ``None``.
|
|
"""
|
|
from ..ui.config_editor import send_advert
|
|
|
|
await send_advert(ctx)
|
|
return None
|
|
|
|
async def run(self, ctx: AppContext, params: dict[str, Any]) -> ToolResult:
|
|
"""Nothing runs here: the advert is sent 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 — ``config advert`` / ``config share`` cover scripting.
|
|
|
|
Args:
|
|
app: The Typer application (untouched).
|
|
"""
|