janito 3.3.0__py3-none-any.whl → 3.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- janito/cli/cli_commands/list_plugins.py +48 -52
- janito/cli/core/getters.py +0 -3
- janito/cli/main_cli.py +12 -9
- janito/drivers/openai/driver.py +0 -1
- janito/drivers/zai/driver.py +0 -1
- janito/hello.txt +0 -0
- janito/llm/auth_utils.py +5 -14
- janito/plugins/__init__.py +7 -18
- janito/{plugins_backup_20250825_070018 → plugins}/auto_loader_fixed.py +11 -12
- janito/plugins/base.py +152 -57
- janito/plugins/builtin.py +1 -15
- janito/{plugins_backup_20250825_070018 → plugins}/core_adapter.py +9 -11
- janito/plugins/core_loader.py +34 -58
- janito/{plugin_system_backup_20250825_070018/core_loader.py → plugins/core_loader_fixed.py} +26 -45
- janito/plugins/discovery.py +3 -3
- janito/tools/__init__.py +7 -31
- janito/tools/adapters/__init__.py +1 -6
- janito/tools/adapters/local/__init__.py +70 -7
- janito/{plugins_backup_20250825_070018/tools → tools/adapters/local}/ask_user.py +3 -3
- janito/{plugins_backup_20250825_070018/tools → tools/adapters/local}/create_file.py +4 -4
- janito/{plugins/core/filemanager/tools → tools/adapters/local}/delete_text_in_file.py +0 -1
- janito/{plugins_backup_20250825_070018/tools → tools/adapters/local}/fetch_url.py +3 -3
- janito/{plugins_backup_20250825_070018/tools → tools/adapters/local}/replace_text_in_file.py +4 -4
- janito/{plugins_backup_20250825_070018/tools → tools/adapters/local}/show_image.py +6 -15
- janito/{plugins/core/imagedisplay/tools → tools/adapters/local}/show_image_grid.py +5 -13
- janito/tools/base.py +1 -31
- janito/tools/function_adapter.py +16 -127
- janito/tools/tool_base.py +114 -142
- janito/tools/tools_schema.py +6 -12
- {janito-3.3.0.dist-info → janito-3.4.0.dist-info}/METADATA +2 -1
- janito-3.4.0.dist-info/RECORD +264 -0
- janito/cli/cli_commands/check_tools.py +0 -212
- janito/plugin_system_backup_20250825_070018/__init__.py +0 -10
- janito/plugin_system_backup_20250825_070018/base.py +0 -155
- janito/plugin_system_backup_20250825_070018/core_loader_fixed.py +0 -149
- janito/plugins/__main__.py +0 -85
- janito/plugins/core/__init__.py +0 -7
- janito/plugins/core/codeanalyzer/__init__.py +0 -43
- janito/plugins/core/filemanager/__init__.py +0 -124
- janito/plugins/core/filemanager/tools/copy_file.py +0 -111
- janito/plugins/core/filemanager/tools/create_directory.py +0 -97
- janito/plugins/core/filemanager/tools/create_file.py +0 -111
- janito/plugins/core/filemanager/tools/replace_text_in_file.py +0 -270
- janito/plugins/core/imagedisplay/__init__.py +0 -14
- janito/plugins/core/imagedisplay/plugin.py +0 -51
- janito/plugins/core/imagedisplay/tools/__init__.py +0 -1
- janito/plugins/core/imagedisplay/tools/show_image.py +0 -83
- janito/plugins/core/system/__init__.py +0 -23
- janito/plugins/dev/__init__.py +0 -7
- janito/plugins/dev/pythondev/__init__.py +0 -37
- janito/plugins/dev/visualization/__init__.py +0 -23
- janito/plugins/example_plugin.py +0 -108
- janito/plugins/ui/__init__.py +0 -7
- janito/plugins/ui/userinterface/__init__.py +0 -16
- janito/plugins/ui/userinterface/tools/ask_user.py +0 -110
- janito/plugins/web/__init__.py +0 -7
- janito/plugins/web/webtools/__init__.py +0 -33
- janito/plugins/web/webtools/tools/fetch_url.py +0 -458
- janito/plugins_backup_20250825_070018/__init__.py +0 -36
- janito/plugins_backup_20250825_070018/builtin.py +0 -102
- janito/plugins_backup_20250825_070018/config.py +0 -84
- janito/plugins_backup_20250825_070018/core/__init__.py +0 -7
- janito/plugins_backup_20250825_070018/core/codeanalyzer/__init__.py +0 -43
- janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/get_file_outline/__init__.py +0 -1
- janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/get_file_outline/core.py +0 -122
- janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/get_file_outline/java_outline.py +0 -47
- janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/get_file_outline/markdown_outline.py +0 -14
- janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/get_file_outline/python_outline.py +0 -303
- janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/get_file_outline/search_outline.py +0 -36
- janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/search_text/__init__.py +0 -1
- janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/search_text/core.py +0 -205
- janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/search_text/match_lines.py +0 -67
- janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/search_text/pattern_utils.py +0 -73
- janito/plugins_backup_20250825_070018/core/codeanalyzer/tools/search_text/traverse_directory.py +0 -145
- janito/plugins_backup_20250825_070018/core/filemanager/__init__.py +0 -124
- janito/plugins_backup_20250825_070018/core/filemanager/tools/create_file.py +0 -87
- janito/plugins_backup_20250825_070018/core/filemanager/tools/delete_text_in_file.py +0 -135
- janito/plugins_backup_20250825_070018/core/filemanager/tools/find_files.py +0 -143
- janito/plugins_backup_20250825_070018/core/filemanager/tools/move_file.py +0 -131
- janito/plugins_backup_20250825_070018/core/filemanager/tools/read_files.py +0 -58
- janito/plugins_backup_20250825_070018/core/filemanager/tools/remove_directory.py +0 -55
- janito/plugins_backup_20250825_070018/core/filemanager/tools/remove_file.py +0 -58
- janito/plugins_backup_20250825_070018/core/filemanager/tools/replace_text_in_file.py +0 -270
- janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/__init__.py +0 -1
- janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/core.py +0 -114
- janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/css_validator.py +0 -35
- janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/html_validator.py +0 -100
- janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/jinja2_validator.py +0 -50
- janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/js_validator.py +0 -27
- janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/json_validator.py +0 -6
- janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/markdown_validator.py +0 -109
- janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/ps1_validator.py +0 -32
- janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/python_validator.py +0 -5
- janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/xml_validator.py +0 -11
- janito/plugins_backup_20250825_070018/core/filemanager/tools/validate_file_syntax/yaml_validator.py +0 -6
- janito/plugins_backup_20250825_070018/core/filemanager/tools/view_file.py +0 -172
- janito/plugins_backup_20250825_070018/core/imagedisplay/__init__.py +0 -14
- janito/plugins_backup_20250825_070018/core/imagedisplay/plugin.py +0 -51
- janito/plugins_backup_20250825_070018/core/imagedisplay/tools/__init__.py +0 -1
- janito/plugins_backup_20250825_070018/core/imagedisplay/tools/show_image.py +0 -83
- janito/plugins_backup_20250825_070018/core/imagedisplay/tools/show_image_grid.py +0 -84
- janito/plugins_backup_20250825_070018/core/system/__init__.py +0 -23
- janito/plugins_backup_20250825_070018/core/system/tools/run_bash_command.py +0 -183
- janito/plugins_backup_20250825_070018/core/system/tools/run_powershell_command.py +0 -218
- janito/plugins_backup_20250825_070018/dev/__init__.py +0 -7
- janito/plugins_backup_20250825_070018/dev/pythondev/__init__.py +0 -37
- janito/plugins_backup_20250825_070018/dev/pythondev/tools/python_code_run.py +0 -172
- janito/plugins_backup_20250825_070018/dev/pythondev/tools/python_command_run.py +0 -171
- janito/plugins_backup_20250825_070018/dev/pythondev/tools/python_file_run.py +0 -172
- janito/plugins_backup_20250825_070018/dev/visualization/__init__.py +0 -23
- janito/plugins_backup_20250825_070018/dev/visualization/tools/read_chart.py +0 -259
- janito/plugins_backup_20250825_070018/discovery.py +0 -289
- janito/plugins_backup_20250825_070018/example_plugin.py +0 -108
- janito/plugins_backup_20250825_070018/manager.py +0 -243
- janito/plugins_backup_20250825_070018/tools/__init__.py +0 -10
- janito/plugins_backup_20250825_070018/tools/copy_file.py +0 -87
- janito/plugins_backup_20250825_070018/tools/core_tools_plugin.py +0 -88
- janito/plugins_backup_20250825_070018/tools/create_directory.py +0 -70
- janito/plugins_backup_20250825_070018/tools/decorators.py +0 -19
- janito/plugins_backup_20250825_070018/tools/delete_text_in_file.py +0 -135
- janito/plugins_backup_20250825_070018/tools/find_files.py +0 -143
- janito/plugins_backup_20250825_070018/tools/get_file_outline/__init__.py +0 -7
- janito/plugins_backup_20250825_070018/tools/get_file_outline/core.py +0 -122
- janito/plugins_backup_20250825_070018/tools/get_file_outline/java_outline.py +0 -47
- janito/plugins_backup_20250825_070018/tools/get_file_outline/markdown_outline.py +0 -14
- janito/plugins_backup_20250825_070018/tools/get_file_outline/python_outline.py +0 -303
- janito/plugins_backup_20250825_070018/tools/get_file_outline/search_outline.py +0 -36
- janito/plugins_backup_20250825_070018/tools/move_file.py +0 -131
- janito/plugins_backup_20250825_070018/tools/open_html_in_browser.py +0 -51
- janito/plugins_backup_20250825_070018/tools/open_url.py +0 -37
- janito/plugins_backup_20250825_070018/tools/python_code_run.py +0 -172
- janito/plugins_backup_20250825_070018/tools/python_command_run.py +0 -171
- janito/plugins_backup_20250825_070018/tools/python_file_run.py +0 -172
- janito/plugins_backup_20250825_070018/tools/read_chart.py +0 -259
- janito/plugins_backup_20250825_070018/tools/read_files.py +0 -58
- janito/plugins_backup_20250825_070018/tools/remove_directory.py +0 -55
- janito/plugins_backup_20250825_070018/tools/remove_file.py +0 -58
- janito/plugins_backup_20250825_070018/tools/run_bash_command.py +0 -183
- janito/plugins_backup_20250825_070018/tools/run_powershell_command.py +0 -218
- janito/plugins_backup_20250825_070018/tools/search_text/__init__.py +0 -7
- janito/plugins_backup_20250825_070018/tools/search_text/core.py +0 -205
- janito/plugins_backup_20250825_070018/tools/search_text/match_lines.py +0 -67
- janito/plugins_backup_20250825_070018/tools/search_text/pattern_utils.py +0 -73
- janito/plugins_backup_20250825_070018/tools/search_text/traverse_directory.py +0 -145
- janito/plugins_backup_20250825_070018/tools/show_image_grid.py +0 -85
- janito/plugins_backup_20250825_070018/tools/validate_file_syntax/__init__.py +0 -7
- janito/plugins_backup_20250825_070018/tools/validate_file_syntax/core.py +0 -114
- janito/plugins_backup_20250825_070018/tools/validate_file_syntax/css_validator.py +0 -35
- janito/plugins_backup_20250825_070018/tools/validate_file_syntax/html_validator.py +0 -100
- janito/plugins_backup_20250825_070018/tools/validate_file_syntax/jinja2_validator.py +0 -50
- janito/plugins_backup_20250825_070018/tools/validate_file_syntax/js_validator.py +0 -27
- janito/plugins_backup_20250825_070018/tools/validate_file_syntax/json_validator.py +0 -6
- janito/plugins_backup_20250825_070018/tools/validate_file_syntax/markdown_validator.py +0 -109
- janito/plugins_backup_20250825_070018/tools/validate_file_syntax/ps1_validator.py +0 -32
- janito/plugins_backup_20250825_070018/tools/validate_file_syntax/python_validator.py +0 -5
- janito/plugins_backup_20250825_070018/tools/validate_file_syntax/xml_validator.py +0 -11
- janito/plugins_backup_20250825_070018/tools/validate_file_syntax/yaml_validator.py +0 -6
- janito/plugins_backup_20250825_070018/tools/view_file.py +0 -172
- janito/plugins_backup_20250825_070018/ui/__init__.py +0 -7
- janito/plugins_backup_20250825_070018/ui/userinterface/__init__.py +0 -16
- janito/plugins_backup_20250825_070018/ui/userinterface/tools/ask_user.py +0 -110
- janito/plugins_backup_20250825_070018/web/__init__.py +0 -7
- janito/plugins_backup_20250825_070018/web/webtools/__init__.py +0 -33
- janito/plugins_backup_20250825_070018/web/webtools/tools/fetch_url.py +0 -458
- janito/plugins_backup_20250825_070018/web/webtools/tools/open_html_in_browser.py +0 -51
- janito/plugins_backup_20250825_070018/web/webtools/tools/open_url.py +0 -37
- janito/tools/cli_initializer.py +0 -88
- janito/tools/initialize.py +0 -70
- janito-3.3.0.dist-info/RECORD +0 -400
- /janito/{plugins_backup_20250825_070018 → plugins}/auto_loader.py +0 -0
- /janito/{plugins_backup_20250825_070018 → plugins}/discovery_core.py +0 -0
- /janito/{plugins_backup_20250825_070018/core/filemanager/tools → tools/adapters/local}/copy_file.py +0 -0
- /janito/{plugins_backup_20250825_070018/core/filemanager/tools → tools/adapters/local}/create_directory.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/find_files.py +0 -0
- /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/get_file_outline/__init__.py +0 -0
- /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/get_file_outline/core.py +0 -0
- /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/get_file_outline/java_outline.py +0 -0
- /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/get_file_outline/markdown_outline.py +0 -0
- /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/get_file_outline/python_outline.py +0 -0
- /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/get_file_outline/search_outline.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/move_file.py +0 -0
- /janito/{plugins/web/webtools/tools → tools/adapters/local}/open_html_in_browser.py +0 -0
- /janito/{plugins/web/webtools/tools → tools/adapters/local}/open_url.py +0 -0
- /janito/{plugins/dev/pythondev/tools → tools/adapters/local}/python_code_run.py +0 -0
- /janito/{plugins/dev/pythondev/tools → tools/adapters/local}/python_command_run.py +0 -0
- /janito/{plugins/dev/pythondev/tools → tools/adapters/local}/python_file_run.py +0 -0
- /janito/{plugins/dev/visualization/tools → tools/adapters/local}/read_chart.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/read_files.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/remove_directory.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/remove_file.py +0 -0
- /janito/{plugins/core/system/tools → tools/adapters/local}/run_bash_command.py +0 -0
- /janito/{plugins/core/system/tools → tools/adapters/local}/run_powershell_command.py +0 -0
- /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/search_text/__init__.py +0 -0
- /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/search_text/core.py +0 -0
- /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/search_text/match_lines.py +0 -0
- /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/search_text/pattern_utils.py +0 -0
- /janito/{plugins/core/codeanalyzer/tools → tools/adapters/local}/search_text/traverse_directory.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/__init__.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/core.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/css_validator.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/html_validator.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/jinja2_validator.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/js_validator.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/json_validator.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/markdown_validator.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/ps1_validator.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/python_validator.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/xml_validator.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/validate_file_syntax/yaml_validator.py +0 -0
- /janito/{plugins/core/filemanager/tools → tools/adapters/local}/view_file.py +0 -0
- {janito-3.3.0.dist-info → janito-3.4.0.dist-info}/WHEEL +0 -0
- {janito-3.3.0.dist-info → janito-3.4.0.dist-info}/entry_points.txt +0 -0
- {janito-3.3.0.dist-info → janito-3.4.0.dist-info}/licenses/LICENSE +0 -0
- {janito-3.3.0.dist-info → janito-3.4.0.dist-info}/top_level.txt +0 -0
@@ -1,289 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Plugin discovery utilities.
|
3
|
-
|
4
|
-
Plugins can be provided in several formats:
|
5
|
-
|
6
|
-
1. Single Python file: A .py file containing a Plugin class
|
7
|
-
Example: plugins/my_plugin.py
|
8
|
-
|
9
|
-
2. Python package directory: A directory with __init__.py or plugin.py
|
10
|
-
Example: plugins/my_plugin/__init__.py
|
11
|
-
Example: plugins/my_plugin/plugin.py
|
12
|
-
|
13
|
-
3. Installed Python package: An installed package with a Plugin class
|
14
|
-
Example: pip install janito-plugin-example
|
15
|
-
|
16
|
-
4. ZIP file: A .zip file containing a Python package structure
|
17
|
-
Example: plugins/my_plugin.zip (containing package structure)
|
18
|
-
|
19
|
-
The plugin discovery system searches these locations in order:
|
20
|
-
- Current working directory/plugins/
|
21
|
-
- ~/.janito/plugins/
|
22
|
-
- Python installation share/janito/plugins/
|
23
|
-
- Any additional paths specified via configuration
|
24
|
-
"""
|
25
|
-
|
26
|
-
import os
|
27
|
-
import sys
|
28
|
-
import importlib
|
29
|
-
import importlib.util
|
30
|
-
from pathlib import Path
|
31
|
-
from typing import Optional, List
|
32
|
-
import logging
|
33
|
-
|
34
|
-
from janito.plugin_system.base import Plugin
|
35
|
-
from .builtin import load_builtin_plugin, BuiltinPluginRegistry
|
36
|
-
from janito.plugin_system.core_loader import load_core_plugin
|
37
|
-
|
38
|
-
logger = logging.getLogger(__name__)
|
39
|
-
|
40
|
-
|
41
|
-
def discover_plugins(
|
42
|
-
plugin_name: str, search_paths: List[Path] = None
|
43
|
-
) -> Optional[Plugin]:
|
44
|
-
"""
|
45
|
-
Discover and load a plugin by name.
|
46
|
-
|
47
|
-
Supports multiple plugin formats:
|
48
|
-
- Single .py files
|
49
|
-
- Python package directories
|
50
|
-
- Package-based plugins (e.g., core.filemanager)
|
51
|
-
- Installed Python packages
|
52
|
-
- ZIP files containing packages
|
53
|
-
|
54
|
-
Args:
|
55
|
-
plugin_name: Name of the plugin to discover
|
56
|
-
search_paths: List of directories to search for plugins
|
57
|
-
|
58
|
-
Returns:
|
59
|
-
Plugin instance if found, None otherwise
|
60
|
-
"""
|
61
|
-
if search_paths is None:
|
62
|
-
search_paths = []
|
63
|
-
|
64
|
-
# Add default search paths
|
65
|
-
default_paths = [
|
66
|
-
Path.cwd() / "plugins",
|
67
|
-
Path.home() / ".janito" / "plugins",
|
68
|
-
Path(sys.prefix) / "share" / "janito" / "plugins",
|
69
|
-
]
|
70
|
-
|
71
|
-
all_paths = search_paths + default_paths
|
72
|
-
|
73
|
-
# Handle package-based plugins (e.g., core.filemanager)
|
74
|
-
if "." in plugin_name:
|
75
|
-
parts = plugin_name.split(".")
|
76
|
-
if len(parts) == 2:
|
77
|
-
package_name, submodule_name = parts
|
78
|
-
|
79
|
-
# Handle core plugins with dedicated loader
|
80
|
-
if plugin_name.startswith(("core.", "dev.", "ui.", "web.")):
|
81
|
-
plugin = load_core_plugin(plugin_name)
|
82
|
-
if plugin:
|
83
|
-
return plugin
|
84
|
-
|
85
|
-
for base_path in all_paths:
|
86
|
-
package_path = base_path / package_name / submodule_name / "__init__.py"
|
87
|
-
if package_path.exists():
|
88
|
-
return _load_plugin_from_file(package_path, plugin_name=plugin_name)
|
89
|
-
|
90
|
-
plugin_path = base_path / package_name / submodule_name / "plugin.py"
|
91
|
-
if plugin_path.exists():
|
92
|
-
return _load_plugin_from_file(plugin_path, plugin_name=plugin_name)
|
93
|
-
|
94
|
-
# Try to find plugin in search paths
|
95
|
-
for base_path in all_paths:
|
96
|
-
plugin_path = base_path / plugin_name
|
97
|
-
if plugin_path.exists():
|
98
|
-
return _load_plugin_from_directory(plugin_path)
|
99
|
-
|
100
|
-
# Try as Python module
|
101
|
-
module_path = base_path / f"{plugin_name}.py"
|
102
|
-
if module_path.exists():
|
103
|
-
return _load_plugin_from_file(module_path)
|
104
|
-
|
105
|
-
# Check for builtin plugins
|
106
|
-
builtin_plugin = load_builtin_plugin(plugin_name)
|
107
|
-
if builtin_plugin:
|
108
|
-
return builtin_plugin
|
109
|
-
|
110
|
-
# Try importing as installed package
|
111
|
-
try:
|
112
|
-
return _load_plugin_from_package(plugin_name)
|
113
|
-
except ImportError:
|
114
|
-
pass
|
115
|
-
|
116
|
-
return None
|
117
|
-
|
118
|
-
|
119
|
-
def _load_plugin_from_directory(plugin_path: Path) -> Optional[Plugin]:
|
120
|
-
"""Load a plugin from a directory."""
|
121
|
-
try:
|
122
|
-
# Look for __init__.py or plugin.py
|
123
|
-
init_file = plugin_path / "__init__.py"
|
124
|
-
plugin_file = plugin_path / "plugin.py"
|
125
|
-
|
126
|
-
if init_file.exists():
|
127
|
-
return _load_plugin_from_file(init_file, plugin_name=plugin_path.name)
|
128
|
-
elif plugin_file.exists():
|
129
|
-
return _load_plugin_from_file(plugin_file, plugin_name=plugin_path.name)
|
130
|
-
|
131
|
-
except Exception as e:
|
132
|
-
logger.error(f"Failed to load plugin from directory {plugin_path}: {e}")
|
133
|
-
|
134
|
-
return None
|
135
|
-
|
136
|
-
|
137
|
-
def _load_plugin_from_file(
|
138
|
-
file_path: Path, plugin_name: str = None
|
139
|
-
) -> Optional[Plugin]:
|
140
|
-
"""Load a plugin from a Python file."""
|
141
|
-
try:
|
142
|
-
if plugin_name is None:
|
143
|
-
plugin_name = file_path.stem
|
144
|
-
|
145
|
-
spec = importlib.util.spec_from_file_location(plugin_name, file_path)
|
146
|
-
if spec is None or spec.loader is None:
|
147
|
-
return None
|
148
|
-
|
149
|
-
module = importlib.util.module_from_spec(spec)
|
150
|
-
spec.loader.exec_module(module)
|
151
|
-
|
152
|
-
# Look for Plugin class
|
153
|
-
for attr_name in dir(module):
|
154
|
-
attr = getattr(module, attr_name)
|
155
|
-
if isinstance(attr, type) and issubclass(attr, Plugin) and attr != Plugin:
|
156
|
-
return attr()
|
157
|
-
|
158
|
-
# Check for package-based plugin with __plugin_name__ metadata
|
159
|
-
if hasattr(module, "__plugin_name__"):
|
160
|
-
from janito.plugin_system.base import PluginMetadata
|
161
|
-
|
162
|
-
# Create a dynamic plugin class
|
163
|
-
class PackagePlugin(Plugin):
|
164
|
-
def __init__(self):
|
165
|
-
super().__init__()
|
166
|
-
self._module = module
|
167
|
-
|
168
|
-
def get_metadata(self) -> PluginMetadata:
|
169
|
-
return PluginMetadata(
|
170
|
-
name=getattr(module, "__plugin_name__", plugin_name),
|
171
|
-
version=getattr(module, "__plugin_version__", "1.0.0"),
|
172
|
-
description=getattr(
|
173
|
-
module,
|
174
|
-
"__plugin_description__",
|
175
|
-
f"Package plugin: {plugin_name}",
|
176
|
-
),
|
177
|
-
author=getattr(module, "__plugin_author__", "Unknown"),
|
178
|
-
license=getattr(module, "__plugin_license__", "MIT"),
|
179
|
-
)
|
180
|
-
|
181
|
-
def get_tools(self):
|
182
|
-
return getattr(module, "__plugin_tools__", [])
|
183
|
-
|
184
|
-
def initialize(self):
|
185
|
-
if hasattr(module, "initialize"):
|
186
|
-
module.initialize()
|
187
|
-
|
188
|
-
def cleanup(self):
|
189
|
-
if hasattr(module, "cleanup"):
|
190
|
-
module.cleanup()
|
191
|
-
|
192
|
-
return PackagePlugin()
|
193
|
-
|
194
|
-
except Exception as e:
|
195
|
-
logger.error(f"Failed to load plugin from file {file_path}: {e}")
|
196
|
-
|
197
|
-
return None
|
198
|
-
|
199
|
-
|
200
|
-
def _load_plugin_from_package(package_name: str) -> Optional[Plugin]:
|
201
|
-
"""Load a plugin from an installed package."""
|
202
|
-
try:
|
203
|
-
module = importlib.import_module(package_name)
|
204
|
-
|
205
|
-
# Look for Plugin class
|
206
|
-
for attr_name in dir(module):
|
207
|
-
attr = getattr(module, attr_name)
|
208
|
-
if isinstance(attr, type) and issubclass(attr, Plugin) and attr != Plugin:
|
209
|
-
return attr()
|
210
|
-
|
211
|
-
except ImportError as e:
|
212
|
-
logger.debug(f"Could not import package {package_name}: {e}")
|
213
|
-
|
214
|
-
return None
|
215
|
-
|
216
|
-
|
217
|
-
def list_available_plugins(search_paths: List[Path] = None) -> List[str]:
|
218
|
-
"""
|
219
|
-
List all available plugins in search paths.
|
220
|
-
|
221
|
-
Scans for plugins in multiple formats:
|
222
|
-
- .py files (excluding __init__.py)
|
223
|
-
- Directories with __init__.py or plugin.py
|
224
|
-
- Package directories with plugin metadata (__plugin_name__)
|
225
|
-
- Any valid plugin structure in search paths
|
226
|
-
|
227
|
-
Args:
|
228
|
-
search_paths: List of directories to search for plugins
|
229
|
-
|
230
|
-
Returns:
|
231
|
-
List of plugin names found
|
232
|
-
"""
|
233
|
-
if search_paths is None:
|
234
|
-
search_paths = []
|
235
|
-
|
236
|
-
# Add default search paths
|
237
|
-
default_paths = [
|
238
|
-
Path.cwd() / "plugins",
|
239
|
-
Path.home() / ".janito" / "plugins",
|
240
|
-
Path(sys.prefix) / "share" / "janito" / "plugins",
|
241
|
-
]
|
242
|
-
|
243
|
-
all_paths = search_paths + default_paths
|
244
|
-
plugins = []
|
245
|
-
|
246
|
-
for base_path in all_paths:
|
247
|
-
if not base_path.exists():
|
248
|
-
continue
|
249
|
-
|
250
|
-
# Look for directories with __init__.py or plugin.py
|
251
|
-
for item in base_path.iterdir():
|
252
|
-
if item.is_dir():
|
253
|
-
# Check for package-based plugins (subdirectories with __init__.py)
|
254
|
-
if (item / "__init__.py").exists():
|
255
|
-
# Check subdirectories for plugin metadata
|
256
|
-
for subitem in item.iterdir():
|
257
|
-
if subitem.is_dir() and (subitem / "__init__.py").exists():
|
258
|
-
try:
|
259
|
-
import importlib.util
|
260
|
-
|
261
|
-
spec = importlib.util.spec_from_file_location(
|
262
|
-
f"{item.name}.{subitem.name}",
|
263
|
-
subitem / "__init__.py",
|
264
|
-
)
|
265
|
-
if spec and spec.loader:
|
266
|
-
module = importlib.util.module_from_spec(spec)
|
267
|
-
spec.loader.exec_module(module)
|
268
|
-
|
269
|
-
# Check for plugin metadata
|
270
|
-
if hasattr(module, "__plugin_name__"):
|
271
|
-
plugins.append(
|
272
|
-
getattr(module, "__plugin_name__")
|
273
|
-
)
|
274
|
-
except Exception:
|
275
|
-
pass
|
276
|
-
|
277
|
-
# Also check for plugin.py files
|
278
|
-
plugin_file = item / "plugin.py"
|
279
|
-
if plugin_file.exists():
|
280
|
-
plugins.append(item.name)
|
281
|
-
|
282
|
-
elif item.suffix == ".py" and item.stem != "__init__":
|
283
|
-
plugins.append(item.stem)
|
284
|
-
|
285
|
-
# Add builtin plugins
|
286
|
-
builtin_plugins = BuiltinPluginRegistry.list_builtin_plugins()
|
287
|
-
plugins.extend(builtin_plugins)
|
288
|
-
|
289
|
-
return sorted(set(plugins))
|
@@ -1,108 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Example plugin demonstrating the plugin system.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from janito.plugin_system.base import Plugin, PluginMetadata, PluginResource
|
6
|
-
from janito.tools.tool_base import ToolBase, ToolPermissions
|
7
|
-
from typing import Dict, Any
|
8
|
-
|
9
|
-
|
10
|
-
class HelloWorldTool(ToolBase):
|
11
|
-
"""A simple tool that says hello."""
|
12
|
-
|
13
|
-
tool_name = "hello_world"
|
14
|
-
permissions = ToolPermissions(read=True, write=False, execute=True)
|
15
|
-
|
16
|
-
def run(self, name: str = "World") -> str:
|
17
|
-
"""
|
18
|
-
Say hello to someone.
|
19
|
-
|
20
|
-
Args:
|
21
|
-
name: Name of the person to greet
|
22
|
-
|
23
|
-
Returns:
|
24
|
-
Greeting message
|
25
|
-
"""
|
26
|
-
self.report_action(f"Saying hello to {name}", "greet")
|
27
|
-
return f"Hello, {name}!"
|
28
|
-
|
29
|
-
|
30
|
-
class CalculatorTool(ToolBase):
|
31
|
-
"""A simple calculator tool."""
|
32
|
-
|
33
|
-
tool_name = "calculator"
|
34
|
-
permissions = ToolPermissions(read=True, write=False, execute=True)
|
35
|
-
|
36
|
-
def run(self, operation: str, a: float, b: float) -> str:
|
37
|
-
"""
|
38
|
-
Perform basic calculations.
|
39
|
-
|
40
|
-
Args:
|
41
|
-
operation: Operation to perform (add, subtract, multiply, divide)
|
42
|
-
a: First number
|
43
|
-
b: Second number
|
44
|
-
|
45
|
-
Returns:
|
46
|
-
Result as string
|
47
|
-
"""
|
48
|
-
self.report_action(f"Calculating {a} {operation} {b}", "calculate")
|
49
|
-
|
50
|
-
if operation == "add":
|
51
|
-
result = a + b
|
52
|
-
elif operation == "subtract":
|
53
|
-
result = a - b
|
54
|
-
elif operation == "multiply":
|
55
|
-
result = a * b
|
56
|
-
elif operation == "divide":
|
57
|
-
if b == 0:
|
58
|
-
return "Error: Division by zero"
|
59
|
-
result = a / b
|
60
|
-
else:
|
61
|
-
return f"Error: Unknown operation '{operation}'"
|
62
|
-
|
63
|
-
return str(result)
|
64
|
-
|
65
|
-
|
66
|
-
class ExamplePlugin(Plugin):
|
67
|
-
"""Example plugin providing basic tools."""
|
68
|
-
|
69
|
-
def get_metadata(self) -> PluginMetadata:
|
70
|
-
return PluginMetadata(
|
71
|
-
name="example",
|
72
|
-
version="1.0.0",
|
73
|
-
description="Example plugin with basic tools",
|
74
|
-
author="Janito Team",
|
75
|
-
license="MIT",
|
76
|
-
homepage="https://github.com/janito/example-plugin",
|
77
|
-
)
|
78
|
-
|
79
|
-
def get_tools(self):
|
80
|
-
return [HelloWorldTool, CalculatorTool]
|
81
|
-
|
82
|
-
def initialize(self):
|
83
|
-
print("Example plugin initialized!")
|
84
|
-
|
85
|
-
def cleanup(self):
|
86
|
-
print("Example plugin cleaned up!")
|
87
|
-
|
88
|
-
def get_config_schema(self) -> Dict[str, Any]:
|
89
|
-
"""Return JSON schema for plugin configuration."""
|
90
|
-
return {
|
91
|
-
"type": "object",
|
92
|
-
"properties": {
|
93
|
-
"greeting_prefix": {
|
94
|
-
"type": "string",
|
95
|
-
"description": "Custom greeting prefix for hello_world tool",
|
96
|
-
"default": "Hello",
|
97
|
-
},
|
98
|
-
"max_calculation": {
|
99
|
-
"type": "number",
|
100
|
-
"description": "Maximum allowed calculation result",
|
101
|
-
"default": 1000000,
|
102
|
-
},
|
103
|
-
},
|
104
|
-
}
|
105
|
-
|
106
|
-
|
107
|
-
# This makes the plugin discoverable
|
108
|
-
PLUGIN_CLASS = ExamplePlugin
|
@@ -1,243 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Plugin manager for loading and managing plugins.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import os
|
6
|
-
import sys
|
7
|
-
import importlib
|
8
|
-
import importlib.util
|
9
|
-
from pathlib import Path
|
10
|
-
from typing import Dict, List, Optional, Any
|
11
|
-
import logging
|
12
|
-
|
13
|
-
from janito.plugin_system.base import Plugin, PluginMetadata
|
14
|
-
from .discovery import discover_plugins
|
15
|
-
from .config import load_plugins_config, get_user_plugins_dir
|
16
|
-
from .builtin import BuiltinPluginRegistry, load_builtin_plugin
|
17
|
-
from janito.tools.adapters.local import LocalToolsAdapter
|
18
|
-
|
19
|
-
logger = logging.getLogger(__name__)
|
20
|
-
|
21
|
-
|
22
|
-
class PluginManager:
|
23
|
-
"""
|
24
|
-
Manages plugin loading, registration, and lifecycle.
|
25
|
-
"""
|
26
|
-
|
27
|
-
def __init__(self, tools_adapter: Optional[LocalToolsAdapter] = None):
|
28
|
-
self.tools_adapter = tools_adapter or LocalToolsAdapter()
|
29
|
-
self.plugins: Dict[str, Plugin] = {}
|
30
|
-
self.plugin_configs: Dict[str, Dict[str, Any]] = {}
|
31
|
-
self.plugin_paths: List[Path] = []
|
32
|
-
|
33
|
-
def add_plugin_path(self, path: str) -> None:
|
34
|
-
"""Add a directory to search for plugins."""
|
35
|
-
plugin_path = Path(path)
|
36
|
-
if plugin_path.exists() and plugin_path.is_dir():
|
37
|
-
self.plugin_paths.append(plugin_path)
|
38
|
-
if str(plugin_path) not in sys.path:
|
39
|
-
sys.path.insert(0, str(plugin_path))
|
40
|
-
|
41
|
-
def load_plugin(
|
42
|
-
self, plugin_name: str, config: Optional[Dict[str, Any]] = None
|
43
|
-
) -> bool:
|
44
|
-
"""
|
45
|
-
Load a plugin by name.
|
46
|
-
|
47
|
-
Args:
|
48
|
-
plugin_name: Name of the plugin to load
|
49
|
-
config: Optional configuration for the plugin
|
50
|
-
|
51
|
-
Returns:
|
52
|
-
True if plugin loaded successfully
|
53
|
-
"""
|
54
|
-
try:
|
55
|
-
if plugin_name in self.plugins:
|
56
|
-
logger.warning(f"Plugin {plugin_name} already loaded")
|
57
|
-
return True
|
58
|
-
|
59
|
-
plugin = discover_plugins(plugin_name, self.plugin_paths)
|
60
|
-
if not plugin:
|
61
|
-
logger.error(f"Plugin {plugin_name} not found")
|
62
|
-
return False
|
63
|
-
|
64
|
-
# Store config
|
65
|
-
if config:
|
66
|
-
self.plugin_configs[plugin_name] = config
|
67
|
-
|
68
|
-
# Validate config if provided
|
69
|
-
if config and hasattr(plugin, "validate_config"):
|
70
|
-
if not plugin.validate_config(config):
|
71
|
-
logger.error(f"Invalid configuration for plugin {plugin_name}")
|
72
|
-
return False
|
73
|
-
|
74
|
-
# Initialize plugin
|
75
|
-
plugin.initialize()
|
76
|
-
|
77
|
-
# Register tools
|
78
|
-
tools = plugin.get_tools()
|
79
|
-
for tool_class in tools:
|
80
|
-
self.tools_adapter.register_tool(tool_class)
|
81
|
-
|
82
|
-
# Store plugin
|
83
|
-
self.plugins[plugin_name] = plugin
|
84
|
-
|
85
|
-
logger.info(f"Successfully loaded plugin: {plugin_name}")
|
86
|
-
return True
|
87
|
-
|
88
|
-
except Exception as e:
|
89
|
-
logger.error(f"Failed to load plugin {plugin_name}: {e}")
|
90
|
-
return False
|
91
|
-
|
92
|
-
def unload_plugin(self, plugin_name: str) -> bool:
|
93
|
-
"""
|
94
|
-
Unload a plugin.
|
95
|
-
|
96
|
-
Args:
|
97
|
-
plugin_name: Name of the plugin to unload
|
98
|
-
|
99
|
-
Returns:
|
100
|
-
True if plugin unloaded successfully
|
101
|
-
"""
|
102
|
-
try:
|
103
|
-
if plugin_name not in self.plugins:
|
104
|
-
logger.warning(f"Plugin {plugin_name} not loaded")
|
105
|
-
return False
|
106
|
-
|
107
|
-
plugin = self.plugins[plugin_name]
|
108
|
-
|
109
|
-
# Unregister tools
|
110
|
-
tools = plugin.get_tools()
|
111
|
-
for tool_class in tools:
|
112
|
-
tool_name = getattr(tool_class(), "tool_name", None)
|
113
|
-
if tool_name:
|
114
|
-
self.tools_adapter.unregister_tool(tool_name)
|
115
|
-
|
116
|
-
# Cleanup plugin
|
117
|
-
plugin.cleanup()
|
118
|
-
|
119
|
-
# Remove from registry
|
120
|
-
del self.plugins[plugin_name]
|
121
|
-
if plugin_name in self.plugin_configs:
|
122
|
-
del self.plugin_configs[plugin_name]
|
123
|
-
|
124
|
-
logger.info(f"Successfully unloaded plugin: {plugin_name}")
|
125
|
-
return True
|
126
|
-
|
127
|
-
except Exception as e:
|
128
|
-
logger.error(f"Failed to unload plugin {plugin_name}: {e}")
|
129
|
-
return False
|
130
|
-
|
131
|
-
def list_plugins(self) -> List[str]:
|
132
|
-
"""Return list of loaded plugin names."""
|
133
|
-
return list(self.plugins.keys())
|
134
|
-
|
135
|
-
def get_plugin(self, plugin_name: str) -> Optional[Plugin]:
|
136
|
-
"""Get a loaded plugin by name."""
|
137
|
-
return self.plugins.get(plugin_name)
|
138
|
-
|
139
|
-
def get_plugin_metadata(self, plugin_name: str) -> Optional[PluginMetadata]:
|
140
|
-
"""Get metadata for a loaded plugin."""
|
141
|
-
plugin = self.plugins.get(plugin_name)
|
142
|
-
return plugin.metadata if plugin else None
|
143
|
-
|
144
|
-
def load_plugins_from_config(self, config: Dict[str, Any]) -> None:
|
145
|
-
"""
|
146
|
-
Load plugins from configuration.
|
147
|
-
|
148
|
-
Args:
|
149
|
-
config: Configuration dict with plugin settings
|
150
|
-
"""
|
151
|
-
plugins_config = config.get("plugins", {})
|
152
|
-
|
153
|
-
# Add plugin paths
|
154
|
-
for path in plugins_config.get("paths", []):
|
155
|
-
self.add_plugin_path(path)
|
156
|
-
|
157
|
-
# Load plugins
|
158
|
-
for plugin_name, plugin_config in plugins_config.get("load", {}).items():
|
159
|
-
if isinstance(plugin_config, bool):
|
160
|
-
if plugin_config:
|
161
|
-
self.load_plugin(plugin_name)
|
162
|
-
else:
|
163
|
-
self.load_plugin(plugin_name, plugin_config)
|
164
|
-
|
165
|
-
def load_plugins_from_user_config(self) -> None:
|
166
|
-
"""
|
167
|
-
Load plugins from user configuration directory.
|
168
|
-
Uses ~/.janito/plugins.json instead of janito.json
|
169
|
-
"""
|
170
|
-
config = load_plugins_config()
|
171
|
-
self.load_plugins_from_config(config)
|
172
|
-
|
173
|
-
def reload_plugin(self, plugin_name: str) -> bool:
|
174
|
-
"""
|
175
|
-
Reload a plugin.
|
176
|
-
|
177
|
-
Args:
|
178
|
-
plugin_name: Name of the plugin to reload
|
179
|
-
|
180
|
-
Returns:
|
181
|
-
True if plugin reloaded successfully
|
182
|
-
"""
|
183
|
-
config = self.plugin_configs.get(plugin_name)
|
184
|
-
self.unload_plugin(plugin_name)
|
185
|
-
return self.load_plugin(plugin_name, config)
|
186
|
-
|
187
|
-
def get_loaded_plugins_info(self) -> Dict[str, Dict[str, Any]]:
|
188
|
-
"""Get information about all loaded plugins."""
|
189
|
-
info = {}
|
190
|
-
for name, plugin in self.plugins.items():
|
191
|
-
info[name] = {
|
192
|
-
"metadata": plugin.metadata,
|
193
|
-
"tools": [tool.__name__ for tool in plugin.get_tools()],
|
194
|
-
"commands": list(plugin.get_commands().keys()),
|
195
|
-
"config": self.plugin_configs.get(name, {}),
|
196
|
-
"builtin": BuiltinPluginRegistry.is_builtin(name),
|
197
|
-
"resources": [
|
198
|
-
{
|
199
|
-
"name": resource.name,
|
200
|
-
"type": resource.type,
|
201
|
-
"description": resource.description,
|
202
|
-
"schema": resource.schema,
|
203
|
-
}
|
204
|
-
for resource in plugin.get_resources()
|
205
|
-
],
|
206
|
-
}
|
207
|
-
return info
|
208
|
-
|
209
|
-
def get_plugin_resources(self, plugin_name: str) -> List[Dict[str, Any]]:
|
210
|
-
"""
|
211
|
-
Get resources provided by a specific plugin.
|
212
|
-
|
213
|
-
Args:
|
214
|
-
plugin_name: Name of the plugin
|
215
|
-
|
216
|
-
Returns:
|
217
|
-
List of resource dictionaries
|
218
|
-
"""
|
219
|
-
plugin = self.plugins.get(plugin_name)
|
220
|
-
if not plugin:
|
221
|
-
return []
|
222
|
-
|
223
|
-
return [
|
224
|
-
{
|
225
|
-
"name": resource.name,
|
226
|
-
"type": resource.type,
|
227
|
-
"description": resource.description,
|
228
|
-
"schema": resource.schema,
|
229
|
-
}
|
230
|
-
for resource in plugin.get_resources()
|
231
|
-
]
|
232
|
-
|
233
|
-
def list_all_resources(self) -> Dict[str, List[Dict[str, Any]]]:
|
234
|
-
"""
|
235
|
-
List all resources from all loaded plugins.
|
236
|
-
|
237
|
-
Returns:
|
238
|
-
Dict mapping plugin names to their resources
|
239
|
-
"""
|
240
|
-
all_resources = {}
|
241
|
-
for plugin_name in self.plugins:
|
242
|
-
all_resources[plugin_name] = self.get_plugin_resources(plugin_name)
|
243
|
-
return all_resources
|
@@ -1,10 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Core tools plugin for janito.
|
3
|
-
|
4
|
-
This plugin provides the essential tools for file operations, code execution,
|
5
|
-
and system interactions that are core to janito's functionality.
|
6
|
-
"""
|
7
|
-
|
8
|
-
from .core_tools_plugin import CoreToolsPlugin
|
9
|
-
|
10
|
-
__all__ = ["CoreToolsPlugin"]
|