From 85fc82a606e646fcbcb9e36ee760aa926b1f90bb Mon Sep 17 00:00:00 2001 From: Jean-Pierre Martineau Date: Sat, 11 Jul 2026 03:35:00 -0400 Subject: [PATCH] Regroup the menu: Mesh, Device management, Tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Messaging becomes Mesh and takes in Nodes (between Channels and Map — the "who's out there" view) and Send advert (last in section: its one action, after its views), so everything mesh-wide lives under one heading. Device becomes Device management and keeps the box-level tools; Diagnostics becomes Tools. Co-Authored-By: Claude Fable 5 --- meshterm/tools/advert.py | 4 ++-- meshterm/tools/base.py | 11 ++++++----- meshterm/tools/channels.py | 2 +- meshterm/tools/chat.py | 2 +- meshterm/tools/config.py | 2 +- meshterm/tools/device_actions.py | 2 +- meshterm/tools/devices.py | 2 +- meshterm/tools/info.py | 2 +- meshterm/tools/map.py | 2 +- meshterm/tools/monitor.py | 2 +- meshterm/tools/nodes.py | 4 ++-- meshterm/tools/trace.py | 4 ++-- meshterm/tools/tx_optimize.py | 2 +- 13 files changed, 21 insertions(+), 20 deletions(-) diff --git a/meshterm/tools/advert.py b/meshterm/tools/advert.py index 6cd7a0b..984844d 100644 --- a/meshterm/tools/advert.py +++ b/meshterm/tools/advert.py @@ -28,8 +28,8 @@ class SendAdvertTool(Tool): title = "Send advert" icon = "📡" help = "Announce this node to the mesh — zero-hop, flood, or share as QR" - category = "Device" - order = 10 # right after Device actions, before Device info + category = "Mesh" + order = 40 # the section's one action, after its views popup = True # dialog-sized: float over the menu instead of replacing it async def prompt_params(self, ctx: AppContext) -> Optional[dict[str, Any]]: diff --git a/meshterm/tools/base.py b/meshterm/tools/base.py index 5e383e5..5ac7d7b 100644 --- a/meshterm/tools/base.py +++ b/meshterm/tools/base.py @@ -149,10 +149,11 @@ class Tool(ABC): _REGISTRY: dict[str, Tool] = {} -#: Explicit menu ordering for tool categories. Messaging (Chat + Channels) leads because it -#: holds the first-class, everyday features; the rest follow in a natural workflow order. -#: Categories not listed here sort last, alphabetically, so a new category still appears. -_CATEGORY_ORDER = ["Messaging", "Device", "Diagnostics"] +#: Explicit menu ordering for tool categories. Mesh leads because it holds the +#: first-class, everyday features (chat, channels, the nodes and map views, adverts); +#: the rest follow in a natural workflow order. Categories not listed here sort last, +#: alphabetically, so a new category still appears. +_CATEGORY_ORDER = ["Mesh", "Device management", "Tools"] def _category_rank(category: str) -> int: @@ -187,7 +188,7 @@ def register(cls: type[Tool]) -> type[Tool]: def all_tools() -> list[Tool]: """Return all registered tools sorted by category rank, then order, then name. - Categories are ordered by :data:`_CATEGORY_ORDER` (Messaging first), so the first-class + Categories are ordered by :data:`_CATEGORY_ORDER` (Mesh first), so the first-class Chat and Channels tools lead the menu; within a category, ``order`` then ``name`` break ties. diff --git a/meshterm/tools/channels.py b/meshterm/tools/channels.py index 6fb6ecc..c11fbfd 100644 --- a/meshterm/tools/channels.py +++ b/meshterm/tools/channels.py @@ -38,7 +38,7 @@ class ChannelsTool(Tool): title = "Channels" icon = "📻" help = "Create, join, and share mesh channels (with QR codes)" - category = "Messaging" + category = "Mesh" order = 20 async def run(self, ctx: AppContext, params: dict[str, Any]) -> ToolResult: diff --git a/meshterm/tools/chat.py b/meshterm/tools/chat.py index eab2625..0b3a7a1 100644 --- a/meshterm/tools/chat.py +++ b/meshterm/tools/chat.py @@ -46,7 +46,7 @@ class ChatTool(Tool): title = "Chat" icon = "💬" help = "Channel and direct messaging — live chat, with stored history" - category = "Messaging" + category = "Mesh" order = 10 async def prompt_params(self, ctx: AppContext) -> Optional[dict[str, Any]]: diff --git a/meshterm/tools/config.py b/meshterm/tools/config.py index 784a93d..971f818 100644 --- a/meshterm/tools/config.py +++ b/meshterm/tools/config.py @@ -38,7 +38,7 @@ class ConfigTool(Tool): title = "Device configuration" icon = "🔧" help = "View and change device settings — identity, radio, tuning, …" - category = "Device" + category = "Device management" order = 8 async def prompt_params(self, ctx: AppContext) -> Optional[dict[str, Any]]: diff --git a/meshterm/tools/device_actions.py b/meshterm/tools/device_actions.py index 7fa05de..c012a53 100644 --- a/meshterm/tools/device_actions.py +++ b/meshterm/tools/device_actions.py @@ -32,7 +32,7 @@ class DeviceActionsTool(Tool): title = "Device actions" icon = "🔨" help = "Act on the device itself — advert, backup, identity key, reboot, reset" - category = "Device" + category = "Device management" order = 9 async def prompt_params(self, ctx: AppContext) -> Optional[dict[str, Any]]: diff --git a/meshterm/tools/devices.py b/meshterm/tools/devices.py index 305ad29..c8551cc 100644 --- a/meshterm/tools/devices.py +++ b/meshterm/tools/devices.py @@ -41,7 +41,7 @@ class DevicesTool(Tool): name = "devices" title = "Devices" help = "List attached serial and Bluetooth devices, flagging likely companions" - category = "Device" + category = "Device management" order = 5 menu_visible = False # CLI-only: a startup diagnostic with no place in a connected session diff --git a/meshterm/tools/info.py b/meshterm/tools/info.py index a72fbcd..628dc91 100644 --- a/meshterm/tools/info.py +++ b/meshterm/tools/info.py @@ -28,7 +28,7 @@ class InfoTool(Tool): title = "Device info" icon = "📋" help = "Show device status, identity, and radio config" - category = "Device" + category = "Device management" order = 11 # after Send advert (10), which slots in behind Device actions async def run(self, ctx: AppContext, params: dict[str, Any]) -> ToolResult: diff --git a/meshterm/tools/map.py b/meshterm/tools/map.py index 267e7d0..d678600 100644 --- a/meshterm/tools/map.py +++ b/meshterm/tools/map.py @@ -37,7 +37,7 @@ class MapTool(Tool): title = "Map" icon = "🌍" help = "Show mesh nodes on a street map (pannable; repeaters highlighted)" - category = "Messaging" + category = "Mesh" order = 30 async def run(self, ctx: AppContext, params: dict[str, Any]) -> ToolResult: diff --git a/meshterm/tools/monitor.py b/meshterm/tools/monitor.py index 06eb44c..310b920 100644 --- a/meshterm/tools/monitor.py +++ b/meshterm/tools/monitor.py @@ -38,7 +38,7 @@ class MonitorTool(Tool): title = "Monitor" icon = "🎧" help = "Capture overheard packets live for a while and summarize them" - category = "Diagnostics" + category = "Tools" order = 20 menu_visible = False # recording is always on; in the menu the header/Nodes/Map show it diff --git a/meshterm/tools/nodes.py b/meshterm/tools/nodes.py index abc3e65..7b35094 100644 --- a/meshterm/tools/nodes.py +++ b/meshterm/tools/nodes.py @@ -18,8 +18,8 @@ class NodesTool(Tool): title = "Nodes" icon = "👥" help = "List this node and known contacts (last heard, packets, type, key)" - category = "Device" - order = 12 + category = "Mesh" + order = 25 # between Channels and Map: the "who's out there" view async def run(self, ctx: AppContext, params: dict[str, Any]) -> ToolResult: """Query the device and render the node/contact list. diff --git a/meshterm/tools/trace.py b/meshterm/tools/trace.py index aae6a04..39c6467 100644 --- a/meshterm/tools/trace.py +++ b/meshterm/tools/trace.py @@ -50,7 +50,7 @@ class TraceTool(Tool): title = "Trace target" icon = "🎯" help = "Trace a target over a mirrored route and watch per-hop SNR" - category = "Diagnostics" + category = "Tools" order = 10 async def prompt_params(self, ctx: AppContext) -> Optional[dict[str, Any]]: @@ -225,7 +225,7 @@ class TracePathTool(Tool): title = "Trace path" icon = "👣" help = "Walk a hand-composed route — out and back your way" - category = "Diagnostics" + category = "Tools" order = 11 async def prompt_params(self, ctx: AppContext) -> Optional[dict[str, Any]]: diff --git a/meshterm/tools/tx_optimize.py b/meshterm/tools/tx_optimize.py index c3fc683..c0fdfc5 100644 --- a/meshterm/tools/tx_optimize.py +++ b/meshterm/tools/tx_optimize.py @@ -39,7 +39,7 @@ class TxOptimizeTool(Tool): title = "TX optimize" icon = "📶" help = "Tune a remote node's TX power for the best signal at a target" - category = "Diagnostics" + category = "Tools" order = 15 # right after Trace, its measurement sibling async def prompt_params(self, ctx: AppContext) -> Optional[dict[str, Any]]: