Files
MeshTerm/meshterm/tools/device_actions.py
T
Jean-Pierre MartineauandClaude Opus 5 71b16ec7b7 The annotations, imports, and dead locals answer to ruff
`ruff check --fix` over the whole tree, ahead of putting the linter in CI:
1977 mechanical fixes, overwhelmingly `Optional[X]` → `X | None` (1186 in the
package alone) and the quoted annotations that `from __future__ import
annotations` already made unnecessary, plus import sorting and unused imports.
Nothing here changes behaviour — the suite is 1885 green before and after.

Four findings were real rather than stylistic and are fixed by hand: a dead
`cells` range in `MapCanvas`, a dead slot dict in the heat-ladder test, a
`ProgressScreen` task handle nobody read, and a tab loop binding a `label` it
never used. The two `F821`s were quoted forward references to names imported
inside their function bodies — now declared under `TYPE_CHECKING`, which keeps
`test_performance`'s local import (it guards the startup import graph) while
letting the linter resolve the name.

412 findings remain and are deliberately untouched: they need a decision about
the rule, not an edit to the code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 17:26:12 -04:00

73 lines
2.5 KiB
Python

"""The ``device-actions`` tool: immediate operations on the companion device itself.
Opens the Device actions screen (see :func:`meshterm.ui.config_editor.device_actions`) —
clock sync, backup/restore, the identity key, reboot, and factory reset. Where the
sibling ``config`` tool *stages* value changes for review, everything here acts on the
box the moment it is confirmed, so the two concerns get their own menu entries and
screens. Sending an advert is not here: that everyday operation lives in its own
main-menu entry (the sibling ``advert`` tool — see :mod:`meshterm.tools.advert`).
Menu-only: every action already has a first-class scripted equivalent under the ``config``
CLI group (``config backup``, ``config restore``, ``config reboot``, ...), so no duplicate
subcommand is registered here.
"""
from __future__ import annotations
from typing import Any
import typer
from ..context import AppContext
from .base import Tool, ToolResult, register
@register
class DeviceActionsTool(Tool):
"""Run immediate device operations: clock, backup, identity key, reboot, reset."""
name = "device-actions"
title = "Device actions"
icon = "🔨"
help = "Clock, backup, identity key, reboot, reset"
category = "This node"
order = 30
async def prompt_params(self, ctx: AppContext) -> dict[str, Any] | None:
"""Run the interactive actions screen; there are never parameters to collect.
Each action executes and presents its result inside the screen itself, 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 backing
out of the config editor with nothing staged).
Args:
ctx: Shared application context.
Returns:
Always ``None``.
"""
from ..ui.config_editor import device_actions
await device_actions(ctx)
return None
async def run(self, ctx: AppContext, params: dict[str, Any]) -> ToolResult:
"""Nothing runs here: the actions execute 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 scripted equivalents live under ``config``.
Args:
app: The Typer application (untouched).
"""