From 5171e0b37fbbd1cd1c036860296da8ab34ec5c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=B8ldrup?= <14809761+martinmoldrup@users.noreply.github.com> Date: Wed, 24 Sep 2025 21:00:43 +0200 Subject: [PATCH 1/4] Enhance command registration by adding rich_help_panel parameter for improved CLI help display --- pyproject.toml | 2 +- toolit/auto_loader.py | 5 +++-- toolit/create_apps_and_register.py | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 21ba8d6..4ba500e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,4 +62,4 @@ build-backend = "setuptools.build_meta" packages = ["toolit"] [tool.setuptools.package-data] -snappylapy = ["py.typed"] +toolit = ["py.typed"] diff --git a/toolit/auto_loader.py b/toolit/auto_loader.py index 0d36c59..f708820 100644 --- a/toolit/auto_loader.py +++ b/toolit/auto_loader.py @@ -56,7 +56,7 @@ def load_tools_from_plugins() -> list[FunctionType]: """Discover and return plugin commands via entry points.""" plugins = get_plugin_tools() for plugin in plugins: - register_command(plugin) + register_command(plugin, rich_help_panel="Commands from Plugins") return plugins @@ -83,7 +83,7 @@ def load_tools_from_folder(folder_path: pathlib.Path) -> list[FunctionType]: tool_groups: list[FunctionType] = get_items_from_folder(folder_path, tool_group_strategy) # Register each tool as a command for tool in tools: - register_command(tool) + register_command(tool, rich_help_panel="Commands Local Tools") return tools + tool_groups @@ -124,5 +124,6 @@ def get_plugin_tools() -> list[FunctionType]: plugins = [] for entry_point in importlib.metadata.entry_points().get("toolit_plugins", []): plugin_func: Any = entry_point.load() + plugin_func.__name__ = entry_point.name plugins.append(plugin_func) return plugins diff --git a/toolit/create_apps_and_register.py b/toolit/create_apps_and_register.py index e62770c..aaf7085 100644 --- a/toolit/create_apps_and_register.py +++ b/toolit/create_apps_and_register.py @@ -29,11 +29,11 @@ def initialize() -> None: """Welcome to the Toolit CLI.""" -def register_command(command_func: Callable[..., Any], name: str | None = None) -> None: +def register_command(command_func: Callable[..., Any], name: str | None = None, rich_help_panel: str|None = None) -> None: """Register an external command to the CLI and MCP server if available.""" if not callable(command_func): msg = f"Command function {command_func} is not callable." raise TypeError(msg) - app.command(name=name)(command_func) + app.command(name=name, rich_help_panel=rich_help_panel)(command_func) if mcp is not None: mcp.tool(name)(command_func) From 0b2dc1cb3c3c02059cc668cbc2ce964597e5a37a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=B8ldrup?= <14809761+martinmoldrup@users.noreply.github.com> Date: Wed, 24 Sep 2025 21:24:16 +0200 Subject: [PATCH 2/4] Create rich panel groups for what is coming from plugin and what is coming from project --- toolit/__init__.py | 4 ++-- toolit/auto_loader.py | 6 +++--- toolit/cli.py | 11 ++++++----- toolit/config.py | 2 +- toolit/constants.py | 7 +++++++ toolit/decorators.py | 2 +- 6 files changed, 20 insertions(+), 12 deletions(-) diff --git a/toolit/__init__.py b/toolit/__init__.py index 7f9e98b..94ba30f 100644 --- a/toolit/__init__.py +++ b/toolit/__init__.py @@ -1,7 +1,7 @@ """Public API for the package.""" -from .config import get_config_value -from .decorators import tool +from toolit.config import get_config_value +from toolit.decorators import tool __all__ = [ "get_config_value", diff --git a/toolit/auto_loader.py b/toolit/auto_loader.py index f708820..c25791f 100644 --- a/toolit/auto_loader.py +++ b/toolit/auto_loader.py @@ -13,7 +13,7 @@ import pathlib import importlib import importlib.metadata -from toolit.constants import MARKER_TOOL, ToolitTypesEnum +from toolit.constants import MARKER_TOOL, RichHelpPanelNames, ToolitTypesEnum from toolit.create_apps_and_register import register_command from types import FunctionType, ModuleType from typing import Any, Callable @@ -56,7 +56,7 @@ def load_tools_from_plugins() -> list[FunctionType]: """Discover and return plugin commands via entry points.""" plugins = get_plugin_tools() for plugin in plugins: - register_command(plugin, rich_help_panel="Commands from Plugins") + register_command(plugin, rich_help_panel=RichHelpPanelNames.NAME_OF_THE_RICH_GROUP_HELP_PANEL_PLUGINS) return plugins @@ -83,7 +83,7 @@ def load_tools_from_folder(folder_path: pathlib.Path) -> list[FunctionType]: tool_groups: list[FunctionType] = get_items_from_folder(folder_path, tool_group_strategy) # Register each tool as a command for tool in tools: - register_command(tool, rich_help_panel="Commands Local Tools") + register_command(tool, rich_help_panel=RichHelpPanelNames.NAME_OF_THE_RICH_GROUP_HELP_PANEL_PROJECT) return tools + tool_groups diff --git a/toolit/cli.py b/toolit/cli.py index 20570fd..9de4f58 100644 --- a/toolit/cli.py +++ b/toolit/cli.py @@ -1,12 +1,13 @@ """CLI entry point for the toolit package.""" -from .auto_loader import load_tools_from_folder, load_tools_from_plugins, register_command -from .config import load_devtools_folder -from .create_apps_and_register import app -from .create_tasks_json import create_vscode_tasks_json +from toolit.auto_loader import load_tools_from_folder, load_tools_from_plugins, register_command +from toolit.config import load_devtools_folder +from toolit.constants import RichHelpPanelNames +from toolit.create_apps_and_register import app +from toolit.create_tasks_json import create_vscode_tasks_json load_tools_from_folder(load_devtools_folder()) load_tools_from_plugins() -register_command(create_vscode_tasks_json) +register_command(create_vscode_tasks_json, rich_help_panel=RichHelpPanelNames.NAME_OF_THE_RICH_GROUP_HELP_PANEL_PLUGINS) if __name__ == "__main__": diff --git a/toolit/config.py b/toolit/config.py index 96b9c88..f4c3771 100644 --- a/toolit/config.py +++ b/toolit/config.py @@ -10,8 +10,8 @@ import toml import pathlib -from .constants import ConfigFileKeys from functools import lru_cache +from toolit.constants import ConfigFileKeys from typing import Callable, overload diff --git a/toolit/constants.py b/toolit/constants.py index a23cf88..d0423b2 100644 --- a/toolit/constants.py +++ b/toolit/constants.py @@ -5,6 +5,13 @@ MARKER_TOOL = "__toolit_tool_type__" +class RichHelpPanelNames: + """Namespace for the different rich help panel names.""" + + NAME_OF_THE_RICH_GROUP_HELP_PANEL_PROJECT = "Commands from Project" + NAME_OF_THE_RICH_GROUP_HELP_PANEL_PLUGINS = "Commands from Plugins" + + class ConfigFileKeys: """Namespace for the different configuration file keys for user configuration.""" diff --git a/toolit/decorators.py b/toolit/decorators.py index e0645e9..45ca993 100644 --- a/toolit/decorators.py +++ b/toolit/decorators.py @@ -1,6 +1,6 @@ """Decorator to tell if a function is a tool.""" -from .constants import MARKER_TOOL, ToolitTypesEnum +from toolit.constants import MARKER_TOOL, ToolitTypesEnum from typing import Any, Callable, TypeVar T = TypeVar("T", bound=Callable[..., Any]) From ed41f7b01e6a01ea19ded4b73f6d2d5a7344ffd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=B8ldrup?= <14809761+martinmoldrup@users.noreply.github.com> Date: Wed, 24 Sep 2025 21:26:38 +0200 Subject: [PATCH 3/4] Update changelog and version --- CHANGELOG.md | 3 +++ pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c3f470..44fd4fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ All notable changes to this project will be documented in this file. *NOTE:* Version 0.X.X might have breaking changes in bumps of the minor version number. This is because the project is still in early development and the API is not yet stable. It will still be marked clearly in the release notes. +## [0.5.0] - 24-09-2025 +- Improvements to the plugin system. Plugins can choose their own names and the plugins is show in a seperate section in the rich help panel. + ## [0.4.0] - 14-09-2025 - Add ability to customize configurations in a toolit.ini or pyproject.toml file in the project root. Makes the devtools folder configurable, and allows plugins to add their own configurations. diff --git a/pyproject.toml b/pyproject.toml index 4ba500e..cc57ec8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "toolit" -version = "0.4.0" +version = "0.5.0" description = "MCP Server, Typer CLI and vscode tasks in one, provides an easy way to configure your own DevTools and python scripts in a project." readme = "README.md" requires-python = ">=3.9" # mcp[cli] requires Python 3.10+ From a5fe801911a0cc9f63ef4e16547763ae61c84a78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=B8ldrup?= <14809761+martinmoldrup@users.noreply.github.com> Date: Wed, 24 Sep 2025 21:32:06 +0200 Subject: [PATCH 4/4] Fix review comments --- toolit/auto_loader.py | 4 ++-- toolit/cli.py | 2 +- toolit/constants.py | 4 ++-- toolit/create_apps_and_register.py | 6 +++++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/toolit/auto_loader.py b/toolit/auto_loader.py index c25791f..f6b14e8 100644 --- a/toolit/auto_loader.py +++ b/toolit/auto_loader.py @@ -56,7 +56,7 @@ def load_tools_from_plugins() -> list[FunctionType]: """Discover and return plugin commands via entry points.""" plugins = get_plugin_tools() for plugin in plugins: - register_command(plugin, rich_help_panel=RichHelpPanelNames.NAME_OF_THE_RICH_GROUP_HELP_PANEL_PLUGINS) + register_command(plugin, rich_help_panel=RichHelpPanelNames.PLUGINS_COMMANDS_PANEL) return plugins @@ -83,7 +83,7 @@ def load_tools_from_folder(folder_path: pathlib.Path) -> list[FunctionType]: tool_groups: list[FunctionType] = get_items_from_folder(folder_path, tool_group_strategy) # Register each tool as a command for tool in tools: - register_command(tool, rich_help_panel=RichHelpPanelNames.NAME_OF_THE_RICH_GROUP_HELP_PANEL_PROJECT) + register_command(tool, rich_help_panel=RichHelpPanelNames.PROJECT_COMMANDS_PANEL) return tools + tool_groups diff --git a/toolit/cli.py b/toolit/cli.py index 9de4f58..c21b83e 100644 --- a/toolit/cli.py +++ b/toolit/cli.py @@ -7,7 +7,7 @@ load_tools_from_folder(load_devtools_folder()) load_tools_from_plugins() -register_command(create_vscode_tasks_json, rich_help_panel=RichHelpPanelNames.NAME_OF_THE_RICH_GROUP_HELP_PANEL_PLUGINS) +register_command(create_vscode_tasks_json, rich_help_panel=RichHelpPanelNames.PLUGINS_COMMANDS_PANEL) if __name__ == "__main__": diff --git a/toolit/constants.py b/toolit/constants.py index d0423b2..6275efb 100644 --- a/toolit/constants.py +++ b/toolit/constants.py @@ -8,8 +8,8 @@ class RichHelpPanelNames: """Namespace for the different rich help panel names.""" - NAME_OF_THE_RICH_GROUP_HELP_PANEL_PROJECT = "Commands from Project" - NAME_OF_THE_RICH_GROUP_HELP_PANEL_PLUGINS = "Commands from Plugins" + PROJECT_COMMANDS_PANEL = "Commands from Project" + PLUGINS_COMMANDS_PANEL = "Commands from Plugins" class ConfigFileKeys: diff --git a/toolit/create_apps_and_register.py b/toolit/create_apps_and_register.py index aaf7085..4f4c46b 100644 --- a/toolit/create_apps_and_register.py +++ b/toolit/create_apps_and_register.py @@ -29,7 +29,11 @@ def initialize() -> None: """Welcome to the Toolit CLI.""" -def register_command(command_func: Callable[..., Any], name: str | None = None, rich_help_panel: str|None = None) -> None: +def register_command( + command_func: Callable[..., Any], + name: str | None = None, + rich_help_panel: str | None = None, +) -> None: """Register an external command to the CLI and MCP server if available.""" if not callable(command_func): msg = f"Command function {command_func} is not callable."