Split the node/contact list out of info into its own nodes tool
The info tool showed both the device config and the node/contact list. Move the list into a dedicated nodes tool (Device category, right after info) so each feature does one thing; info now shows identity and radio config only. - nodes tool renders this node + contacts with the path-hash prefix highlighted, reading self-info + contacts + path-hash mode directly. - info drops the contacts read and nodes_table render (and its contacts summary field); the nodes_table widget and its test are unchanged. - README: add a Node list feature row. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
1036ff52f6
commit
2cd0fce032
3 files changed
+73
-18
No files matched your search
@@ -13,6 +13,7 @@ turned into interactive HTML visualizations.
|
||||
| --- | --- | --- |
|
||||
| **Trace** | ✅ skeleton | Run repeated path traces to a target and aggregate per-hop SNR. |
|
||||
| **Device info** | ✅ skeleton | Show the connected companion device's identity and radio config. |
|
||||
| **Node list** | ✅ working | List this node and its known contacts — full public keys with the path-hash prefix highlighted. |
|
||||
| **Device config** | ✅ working | View and change every setting (name, radio, behavior, experimental), with TOML backup/restore, channels, and gated destructive ops. |
|
||||
| **Device discovery** | ✅ working | Enumerate serial devices, pick one interactively, and remember the last good default. |
|
||||
| **History / DB** | ✅ skeleton | Every tool execution and measurement is persisted and queryable. |
|
||||
|
||||
+9
-18
@@ -1,4 +1,4 @@
|
||||
"""The ``info`` tool: show the connected companion device's identity and contacts."""
|
||||
"""The ``info`` tool: show the connected companion device's identity and radio config."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -12,46 +12,37 @@ from .base import Tool, ToolResult, register
|
||||
|
||||
@register
|
||||
class InfoTool(Tool):
|
||||
"""Display device identity, radio configuration, and known contacts."""
|
||||
"""Display device identity and radio configuration.
|
||||
|
||||
The known-contacts list lives in the separate ``nodes`` tool.
|
||||
"""
|
||||
|
||||
name = "info"
|
||||
help = "Show device identity, radio config, and contacts."
|
||||
help = "Show device identity and radio config."
|
||||
category = "Device"
|
||||
order = 10
|
||||
|
||||
async def run(self, ctx: AppContext, params: dict[str, Any]) -> ToolResult:
|
||||
"""Query the device and render its full configuration and contacts.
|
||||
"""Query the device and render its full configuration.
|
||||
|
||||
Args:
|
||||
ctx: Shared application context.
|
||||
params: Unused.
|
||||
|
||||
Returns:
|
||||
A :class:`ToolResult` summarizing device name and contact count.
|
||||
A :class:`ToolResult` summarizing the device name.
|
||||
"""
|
||||
from ..core.device_config import build_snapshot
|
||||
from ..ui.config_editor import render_config
|
||||
from ..ui.widgets import nodes_table
|
||||
|
||||
device = await ctx.device()
|
||||
snapshot = await build_snapshot(device)
|
||||
custom = await device.get_custom_vars()
|
||||
contacts = await device.get_contacts()
|
||||
|
||||
# Render every current setting with a short explanation of each.
|
||||
render_config(ctx.console, snapshot, custom)
|
||||
|
||||
# List our own node (first, highlighted) and contacts, each with its full key and
|
||||
# the path-hash prefix — the slice a forced path addresses — highlighted.
|
||||
mode = snapshot.get("path_hash_mode")
|
||||
prefix_bytes = (mode + 1) if isinstance(mode, int) and 0 <= mode <= 3 else 0
|
||||
self_name = str(snapshot.get("name") or "this node")
|
||||
self_key = str(snapshot.get("public_key") or "")
|
||||
ctx.console.print(nodes_table(self_name, self_key, contacts, prefix_bytes))
|
||||
|
||||
return ToolResult(
|
||||
summary={"name": snapshot.get("name"), "contacts": len(contacts)},
|
||||
)
|
||||
return ToolResult(summary={"name": snapshot.get("name")})
|
||||
|
||||
def register_cli(self, app: typer.Typer) -> None:
|
||||
"""Register the ``info`` subcommand.
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
"""The ``nodes`` tool: list this node and the contacts it knows about."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
import typer
|
||||
|
||||
from ..context import AppContext
|
||||
from .base import Tool, ToolResult, register
|
||||
|
||||
|
||||
@register
|
||||
class NodesTool(Tool):
|
||||
"""List this node and its known contacts, each with its path-hash prefix."""
|
||||
|
||||
name = "nodes"
|
||||
help = "List this node and known contacts (full keys, path-hash prefix highlighted)."
|
||||
category = "Device"
|
||||
order = 12
|
||||
|
||||
async def run(self, ctx: AppContext, params: dict[str, Any]) -> ToolResult:
|
||||
"""Query the device and render the node/contact list.
|
||||
|
||||
Args:
|
||||
ctx: Shared application context.
|
||||
params: Unused.
|
||||
|
||||
Returns:
|
||||
A :class:`ToolResult` summarizing the number of known contacts.
|
||||
"""
|
||||
from ..ui.widgets import nodes_table
|
||||
|
||||
device = await ctx.device()
|
||||
info = await device.get_self_info()
|
||||
contacts = await device.get_contacts()
|
||||
|
||||
# The path-hash prefix — the leading slice of a key a forced path addresses — is
|
||||
# ``mode + 1`` bytes wide; highlight it in every key. The mode is an optional read,
|
||||
# so fall back to no highlighting when the firmware doesn't report it.
|
||||
try:
|
||||
mode = await device.get_path_hash_mode()
|
||||
except Exception: # noqa: BLE001 - optional read; absence just skips highlighting
|
||||
mode = None
|
||||
prefix_bytes = (mode + 1) if isinstance(mode, int) and 0 <= mode <= 3 else 0
|
||||
|
||||
self_name = str(info.get("name") or "this node")
|
||||
self_key = str(info.get("public_key") or "")
|
||||
ctx.console.print(nodes_table(self_name, self_key, contacts, prefix_bytes))
|
||||
|
||||
return ToolResult(summary={"contacts": len(contacts)})
|
||||
|
||||
def register_cli(self, app: typer.Typer) -> None:
|
||||
"""Register the ``nodes`` subcommand.
|
||||
|
||||
Args:
|
||||
app: The Typer application.
|
||||
"""
|
||||
from ..cli import run_tool_command
|
||||
|
||||
@app.command(name=self.name, help=self.help)
|
||||
def _nodes() -> None:
|
||||
run_tool_command(self, {})
|
||||
Reference in new issue
Block a user