janito 2.27.1__py3-none-any.whl → 2.28.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/README.md +9 -9
- janito/agent/setup_agent.py +29 -16
- janito/cli/chat_mode/script_runner.py +1 -1
- janito/cli/chat_mode/session.py +17 -5
- janito/cli/chat_mode/session_profile_select.py +8 -2
- janito/cli/chat_mode/shell/commands/execute.py +4 -2
- janito/cli/chat_mode/shell/commands/help.py +2 -0
- janito/cli/chat_mode/shell/commands/privileges.py +6 -2
- janito/cli/chat_mode/shell/commands/provider.py +7 -4
- janito/cli/chat_mode/shell/commands/read.py +4 -2
- janito/cli/chat_mode/shell/commands/security/__init__.py +1 -1
- janito/cli/chat_mode/shell/commands/security/allowed_sites.py +16 -13
- janito/cli/chat_mode/shell/commands/security_command.py +14 -10
- janito/cli/chat_mode/shell/commands/tools.py +4 -2
- janito/cli/chat_mode/shell/commands/unrestricted.py +17 -12
- janito/cli/chat_mode/shell/commands/write.py +4 -2
- janito/cli/chat_mode/toolbar.py +4 -4
- janito/cli/cli_commands/enable_disable_plugin.py +48 -25
- janito/cli/cli_commands/list_models.py +2 -2
- janito/cli/cli_commands/list_plugins.py +18 -18
- janito/cli/cli_commands/list_profiles.py +6 -6
- janito/cli/cli_commands/list_providers.py +1 -1
- janito/cli/cli_commands/model_utils.py +45 -20
- janito/cli/cli_commands/ping_providers.py +10 -10
- janito/cli/cli_commands/set_api_key.py +5 -3
- janito/cli/cli_commands/show_config.py +13 -7
- janito/cli/cli_commands/show_system_prompt.py +13 -6
- janito/cli/core/getters.py +1 -0
- janito/cli/core/model_guesser.py +18 -15
- janito/cli/core/runner.py +15 -7
- janito/cli/core/setters.py +9 -6
- janito/cli/main_cli.py +15 -12
- janito/cli/prompt_core.py +2 -0
- janito/cli/prompt_setup.py +4 -4
- janito/cli/single_shot_mode/handler.py +2 -0
- janito/config_manager.py +2 -0
- janito/docs/GETTING_STARTED.md +9 -9
- janito/drivers/cerebras/__init__.py +1 -1
- janito/exceptions.py +6 -4
- janito/plugins/__init__.py +2 -2
- janito/plugins/base.py +48 -40
- janito/plugins/builtin.py +13 -9
- janito/plugins/config.py +16 -19
- janito/plugins/discovery.py +73 -66
- janito/plugins/manager.py +62 -60
- janito/provider_registry.py +10 -10
- janito/providers/__init__.py +1 -1
- janito/providers/alibaba/model_info.py +3 -5
- janito/providers/alibaba/provider.py +3 -1
- janito/providers/cerebras/__init__.py +1 -1
- janito/providers/cerebras/model_info.py +12 -27
- janito/providers/cerebras/provider.py +11 -9
- janito/providers/mistral/__init__.py +1 -1
- janito/providers/mistral/model_info.py +1 -1
- janito/providers/mistral/provider.py +1 -1
- janito/providers/moonshot/__init__.py +1 -0
- janito/providers/{moonshotai → moonshot}/model_info.py +3 -3
- janito/providers/{moonshotai → moonshot}/provider.py +8 -8
- janito/providers/openai/provider.py +3 -1
- janito/report_events.py +0 -1
- janito/tools/adapters/local/create_file.py +1 -1
- janito/tools/adapters/local/fetch_url.py +45 -29
- janito/tools/adapters/local/python_command_run.py +2 -1
- janito/tools/adapters/local/python_file_run.py +1 -0
- janito/tools/adapters/local/run_powershell_command.py +1 -1
- janito/tools/adapters/local/search_text/core.py +1 -1
- janito/tools/adapters/local/validate_file_syntax/jinja2_validator.py +14 -11
- janito/tools/base.py +4 -3
- janito/tools/loop_protection.py +24 -22
- janito/tools/path_utils.py +7 -7
- janito/tools/tool_base.py +0 -2
- janito/tools/tools_adapter.py +15 -5
- janito/tools/url_whitelist.py +27 -26
- {janito-2.27.1.dist-info → janito-2.28.0.dist-info}/METADATA +1 -1
- {janito-2.27.1.dist-info → janito-2.28.0.dist-info}/RECORD +79 -79
- janito/providers/moonshotai/__init__.py +0 -1
- {janito-2.27.1.dist-info → janito-2.28.0.dist-info}/WHEEL +0 -0
- {janito-2.27.1.dist-info → janito-2.28.0.dist-info}/entry_points.txt +0 -0
- {janito-2.27.1.dist-info → janito-2.28.0.dist-info}/licenses/LICENSE +0 -0
- {janito-2.27.1.dist-info → janito-2.28.0.dist-info}/top_level.txt +0 -0
janito/cli/core/runner.py
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
from janito.llm.driver_config import LLMDriverConfig
|
4
4
|
from janito.provider_config import get_config_provider
|
5
|
-
from janito.cli.core.model_guesser import
|
5
|
+
from janito.cli.core.model_guesser import (
|
6
|
+
guess_provider_from_model as _guess_provider_from_model,
|
7
|
+
)
|
6
8
|
from janito.cli.verbose_output import print_verbose_info
|
7
9
|
|
8
10
|
|
@@ -22,10 +24,13 @@ def _choose_provider(args):
|
|
22
24
|
if guessed_provider:
|
23
25
|
if getattr(args, "verbose", False):
|
24
26
|
print_verbose_info(
|
25
|
-
"Guessed provider",
|
27
|
+
"Guessed provider",
|
28
|
+
guessed_provider,
|
29
|
+
style="magenta",
|
30
|
+
align_content=True,
|
26
31
|
)
|
27
32
|
return guessed_provider
|
28
|
-
|
33
|
+
|
29
34
|
print(
|
30
35
|
"Error: No provider selected and no provider found in config. Please set a provider using '-p PROVIDER', '--set provider=name', or configure a provider."
|
31
36
|
)
|
@@ -151,9 +156,10 @@ def handle_runner(
|
|
151
156
|
if unrestricted:
|
152
157
|
# Patch: disable path security enforcement for this adapter instance
|
153
158
|
setattr(adapter, "unrestricted_paths", True)
|
154
|
-
|
159
|
+
|
155
160
|
# Also disable URL whitelist restrictions in unrestricted mode
|
156
161
|
from janito.tools.url_whitelist import get_url_whitelist_manager
|
162
|
+
|
157
163
|
whitelist_manager = get_url_whitelist_manager()
|
158
164
|
whitelist_manager.set_unrestricted_mode(True)
|
159
165
|
|
@@ -174,19 +180,21 @@ def handle_runner(
|
|
174
180
|
"Active LLMDriverConfig (after provider)", llm_driver_config, style="green"
|
175
181
|
)
|
176
182
|
print_verbose_info("Agent role", agent_role, style="green")
|
177
|
-
|
183
|
+
|
178
184
|
# Skip chat mode for list commands - handle them directly
|
179
185
|
from janito.cli.core.getters import GETTER_KEYS
|
186
|
+
|
180
187
|
skip_chat_mode = False
|
181
188
|
if args is not None:
|
182
189
|
for key in GETTER_KEYS:
|
183
190
|
if getattr(args, key, False):
|
184
191
|
skip_chat_mode = True
|
185
192
|
break
|
186
|
-
|
193
|
+
|
187
194
|
if skip_chat_mode:
|
188
195
|
# Handle list commands directly without prompt
|
189
196
|
from janito.cli.core.getters import handle_getter
|
197
|
+
|
190
198
|
handle_getter(args)
|
191
199
|
elif mode == "single_shot":
|
192
200
|
from janito.cli.single_shot_mode.handler import (
|
@@ -222,4 +230,4 @@ def handle_runner(
|
|
222
230
|
|
223
231
|
|
224
232
|
def get_prompt_mode(args):
|
225
|
-
return "single_shot" if getattr(args, "user_prompt", None) else "chat_mode"
|
233
|
+
return "single_shot" if getattr(args, "user_prompt", None) else "chat_mode"
|
janito/cli/core/setters.py
CHANGED
@@ -71,8 +71,8 @@ def _dispatch_set_key(key, value):
|
|
71
71
|
return True
|
72
72
|
if key == "allowed_sites":
|
73
73
|
from janito.tools.url_whitelist import get_url_whitelist_manager
|
74
|
-
|
75
|
-
sites = [site.strip() for site in value.split(
|
74
|
+
|
75
|
+
sites = [site.strip() for site in value.split(",") if site.strip()]
|
76
76
|
whitelist_manager = get_url_whitelist_manager()
|
77
77
|
whitelist_manager.set_allowed_sites(sites)
|
78
78
|
global_config.file_set("allowed_sites", value)
|
@@ -103,20 +103,23 @@ def _handle_set_base_url(value):
|
|
103
103
|
|
104
104
|
def set_provider(value):
|
105
105
|
"""Set the current provider.
|
106
|
-
|
106
|
+
|
107
107
|
Args:
|
108
108
|
value (str): The provider name to set
|
109
|
-
|
109
|
+
|
110
110
|
Raises:
|
111
111
|
ValueError: If the provider is not supported
|
112
112
|
"""
|
113
113
|
try:
|
114
114
|
supported = ProviderRegistry().get_provider(value)
|
115
115
|
except Exception:
|
116
|
-
raise ValueError(
|
116
|
+
raise ValueError(
|
117
|
+
f"Provider '{value}' is not supported. Run '--list-providers' to see the supported list."
|
118
|
+
)
|
117
119
|
from janito.provider_config import set_config_provider
|
120
|
+
|
118
121
|
set_config_provider(value)
|
119
|
-
|
122
|
+
|
120
123
|
|
121
124
|
def _handle_set_config_provider(value):
|
122
125
|
try:
|
janito/cli/main_cli.py
CHANGED
@@ -134,7 +134,10 @@ definition = [
|
|
134
134
|
),
|
135
135
|
(
|
136
136
|
["--ping"],
|
137
|
-
{
|
137
|
+
{
|
138
|
+
"action": "store_true",
|
139
|
+
"help": "Ping/test connectivity for all providers (use with --list-providers)",
|
140
|
+
},
|
138
141
|
),
|
139
142
|
(
|
140
143
|
["--list-drivers"],
|
@@ -157,7 +160,6 @@ definition = [
|
|
157
160
|
"help": "List all providers with their regional API information",
|
158
161
|
},
|
159
162
|
),
|
160
|
-
|
161
163
|
(
|
162
164
|
["-l", "--list-models"],
|
163
165
|
{"action": "store_true", "help": "List all supported models"},
|
@@ -232,7 +234,10 @@ definition = [
|
|
232
234
|
),
|
233
235
|
(
|
234
236
|
["--list-resources"],
|
235
|
-
{
|
237
|
+
{
|
238
|
+
"action": "store_true",
|
239
|
+
"help": "List all resources (tools, commands, config) from loaded plugins",
|
240
|
+
},
|
236
241
|
),
|
237
242
|
]
|
238
243
|
|
@@ -292,9 +297,8 @@ class JanitoCLI:
|
|
292
297
|
|
293
298
|
self.parser = argparse.ArgumentParser(
|
294
299
|
description="Janito CLI - A tool for running LLM-powered workflows from the command line."
|
295
|
-
"\n\nExample usage: janito -p
|
300
|
+
"\n\nExample usage: janito -p moonshot -m kimi-k1-8k 'Your prompt here'\n\n"
|
296
301
|
"Use -m or --model to set the model for the session.",
|
297
|
-
|
298
302
|
)
|
299
303
|
self._define_args()
|
300
304
|
self.args = self.parser.parse_args()
|
@@ -346,8 +350,6 @@ class JanitoCLI:
|
|
346
350
|
|
347
351
|
argkwargs["version"] = f"Janito {janito_version}"
|
348
352
|
self.parser.add_argument(*argnames, **argkwargs)
|
349
|
-
|
350
|
-
|
351
353
|
|
352
354
|
def _set_all_arg_defaults(self):
|
353
355
|
# Gather all possible keys from definition, MODIFIER_KEYS, SETTER_KEYS, GETTER_KEYS
|
@@ -412,20 +414,21 @@ class JanitoCLI:
|
|
412
414
|
handle_getter(self.args)
|
413
415
|
return
|
414
416
|
# Handle /rwx prefix for enabling all permissions
|
415
|
-
if self.args.user_prompt and self.args.user_prompt[0] ==
|
417
|
+
if self.args.user_prompt and self.args.user_prompt[0] == "/rwx":
|
416
418
|
self.args.read = True
|
417
419
|
self.args.write = True
|
418
420
|
self.args.exec = True
|
419
421
|
# Remove the /rwx prefix from the prompt
|
420
422
|
self.args.user_prompt = self.args.user_prompt[1:]
|
421
|
-
elif self.args.user_prompt and self.args.user_prompt[0].startswith(
|
423
|
+
elif self.args.user_prompt and self.args.user_prompt[0].startswith("/"):
|
422
424
|
# Skip LLM processing for other commands that start with /
|
423
425
|
return
|
424
|
-
|
426
|
+
|
425
427
|
# If running in single shot mode and --profile is not provided, default to 'developer' profile
|
426
428
|
# Skip profile selection for list commands that don't need it
|
427
|
-
if
|
428
|
-
|
429
|
+
if get_prompt_mode(self.args) == "single_shot" and not getattr(
|
430
|
+
self.args, "profile", None
|
431
|
+
):
|
429
432
|
self.args.profile = "developer"
|
430
433
|
provider = self._get_provider_or_default()
|
431
434
|
if provider is None:
|
janito/cli/prompt_core.py
CHANGED
@@ -216,6 +216,8 @@ class PromptHandler:
|
|
216
216
|
if on_event and final_event is not None:
|
217
217
|
on_event(final_event)
|
218
218
|
global_event_bus.publish(final_event)
|
219
|
+
# Terminal bell moved to token summary printing in session.py and handler.py
|
220
|
+
pass # print('\a', end='', flush=True)
|
219
221
|
except KeyboardInterrupt:
|
220
222
|
# Capture user interrupt / cancellation
|
221
223
|
self.console.print("[red]Interrupted by the user.[/red]")
|
janito/cli/prompt_setup.py
CHANGED
@@ -35,10 +35,10 @@ def setup_agent_and_prompt_handler(
|
|
35
35
|
prompt handler that points to that agent.
|
36
36
|
"""
|
37
37
|
no_tools_mode = False
|
38
|
-
if hasattr(args,
|
39
|
-
no_tools_mode = getattr(args,
|
40
|
-
|
41
|
-
zero_mode = getattr(args,
|
38
|
+
if hasattr(args, "no_tools_mode"):
|
39
|
+
no_tools_mode = getattr(args, "no_tools_mode", False)
|
40
|
+
|
41
|
+
zero_mode = getattr(args, "zero", False)
|
42
42
|
agent = create_configured_agent(
|
43
43
|
provider_instance=provider_instance,
|
44
44
|
llm_driver_config=llm_driver_config,
|
@@ -125,6 +125,8 @@ class PromptHandler:
|
|
125
125
|
print_token_message_summary(
|
126
126
|
shared_console, msg_count=1, usage=usage, elapsed=elapsed
|
127
127
|
)
|
128
|
+
# Send terminal bell character to trigger TUI bell after printing token summary
|
129
|
+
print("\a", end="", flush=True)
|
128
130
|
self._cleanup_driver_and_console()
|
129
131
|
|
130
132
|
def _cleanup_driver_and_console(self):
|
janito/config_manager.py
CHANGED
@@ -60,6 +60,7 @@ class ConfigManager:
|
|
60
60
|
if plugins_config:
|
61
61
|
try:
|
62
62
|
from janito.plugins.manager import PluginManager
|
63
|
+
|
63
64
|
plugin_manager = PluginManager()
|
64
65
|
plugin_manager.load_plugins_from_config({"plugins": plugins_config})
|
65
66
|
except Exception as e:
|
@@ -68,6 +69,7 @@ class ConfigManager:
|
|
68
69
|
# Try loading from user config directory
|
69
70
|
try:
|
70
71
|
from janito.plugins.manager import PluginManager
|
72
|
+
|
71
73
|
plugin_manager = PluginManager()
|
72
74
|
plugin_manager.load_plugins_from_user_config()
|
73
75
|
except Exception as e:
|
janito/docs/GETTING_STARTED.md
CHANGED
@@ -13,7 +13,7 @@ pip install janito
|
|
13
13
|
|
14
14
|
Janito supports multiple AI providers. Choose one to get started:
|
15
15
|
|
16
|
-
**
|
16
|
+
**Moonshot (Recommended for Chinese users)**
|
17
17
|
1. Go to [Moonshot AI Platform](https://platform.moonshot.cn/)
|
18
18
|
2. Sign up for an account
|
19
19
|
3. Navigate to API Keys section
|
@@ -31,10 +31,10 @@ Janito supports multiple AI providers. Choose one to get started:
|
|
31
31
|
|
32
32
|
### 3. Configure Janito
|
33
33
|
|
34
|
-
**
|
34
|
+
**Moonshot Setup:**
|
35
35
|
```bash
|
36
|
-
# Set
|
37
|
-
janito --set-api-key YOUR_API_KEY -p
|
36
|
+
# Set Moonshot as your default provider
|
37
|
+
janito --set-api-key YOUR_API_KEY -p moonshot
|
38
38
|
|
39
39
|
# Verify it's working
|
40
40
|
janito "Hello, can you introduce yourself?"
|
@@ -87,17 +87,17 @@ janito -W ./my_project "Create a REST API with FastAPI"
|
|
87
87
|
### Set as Default Provider
|
88
88
|
```bash
|
89
89
|
# Make your chosen provider the permanent default
|
90
|
-
janito --set provider=
|
90
|
+
janito --set provider=moonshot # or openai, ibm, etc.
|
91
91
|
janito --set model=kimi-k1-8k # or gpt-5, ibm/granite-3-8b-instruct, etc.
|
92
92
|
```
|
93
93
|
|
94
94
|
### Environment Variables
|
95
95
|
You can also use environment variables:
|
96
96
|
|
97
|
-
**
|
97
|
+
**Moonshot:**
|
98
98
|
```bash
|
99
|
-
export
|
100
|
-
export JANITO_PROVIDER=
|
99
|
+
export MOONSHOT_API_KEY=your_key_here
|
100
|
+
export JANITO_PROVIDER=moonshot
|
101
101
|
export JANITO_MODEL=kimi-k1-8k
|
102
102
|
```
|
103
103
|
|
@@ -119,7 +119,7 @@ export JANITO_MODEL=ibm/granite-3-3-8b-instruct
|
|
119
119
|
|
120
120
|
## Available Models by Provider
|
121
121
|
|
122
|
-
###
|
122
|
+
### Moonshot Models
|
123
123
|
- **kimi-k1-8k**: Fast responses, good for general tasks
|
124
124
|
- **kimi-k1-32k**: Better for longer contexts
|
125
125
|
- **kimi-k1-128k**: Best for very long documents
|
@@ -1 +1 @@
|
|
1
|
-
# Cerebras driver package
|
1
|
+
# Cerebras driver package
|
janito/exceptions.py
CHANGED
@@ -9,11 +9,11 @@ class ToolCallException(Exception):
|
|
9
9
|
self.error = error
|
10
10
|
self.arguments = arguments
|
11
11
|
self.original_exception = exception
|
12
|
-
|
12
|
+
|
13
13
|
# Build detailed error message
|
14
14
|
details = []
|
15
15
|
details.append(f"ToolCallException: {tool_name}: {error}")
|
16
|
-
|
16
|
+
|
17
17
|
if arguments is not None:
|
18
18
|
details.append(f"Arguments received: {arguments}")
|
19
19
|
if isinstance(arguments, dict):
|
@@ -25,8 +25,10 @@ class ToolCallException(Exception):
|
|
25
25
|
for i, value in enumerate(arguments):
|
26
26
|
details.append(f" [{i}]: {repr(value)} ({type(value).__name__})")
|
27
27
|
else:
|
28
|
-
details.append(
|
29
|
-
|
28
|
+
details.append(
|
29
|
+
f"Single argument: {repr(arguments)} ({type(arguments).__name__})"
|
30
|
+
)
|
31
|
+
|
30
32
|
super().__init__("\n".join(details))
|
31
33
|
|
32
34
|
|
janito/plugins/__init__.py
CHANGED
janito/plugins/base.py
CHANGED
@@ -11,6 +11,7 @@ from janito.tools.tool_base import ToolBase
|
|
11
11
|
@dataclass
|
12
12
|
class PluginMetadata:
|
13
13
|
"""Metadata describing a plugin."""
|
14
|
+
|
14
15
|
name: str
|
15
16
|
version: str
|
16
17
|
description: str
|
@@ -18,7 +19,7 @@ class PluginMetadata:
|
|
18
19
|
license: str = "MIT"
|
19
20
|
homepage: Optional[str] = None
|
20
21
|
dependencies: List[str] = None
|
21
|
-
|
22
|
+
|
22
23
|
def __post_init__(self):
|
23
24
|
if self.dependencies is None:
|
24
25
|
self.dependencies = []
|
@@ -27,6 +28,7 @@ class PluginMetadata:
|
|
27
28
|
@dataclass
|
28
29
|
class PluginResource:
|
29
30
|
"""Represents a resource provided by a plugin."""
|
31
|
+
|
30
32
|
name: str
|
31
33
|
type: str # "tool", "command", "config"
|
32
34
|
description: str
|
@@ -36,66 +38,66 @@ class PluginResource:
|
|
36
38
|
class Plugin(ABC):
|
37
39
|
"""
|
38
40
|
Base class for all janito plugins.
|
39
|
-
|
41
|
+
|
40
42
|
Plugins can provide tools, commands, or other functionality.
|
41
43
|
"""
|
42
|
-
|
44
|
+
|
43
45
|
def __init__(self):
|
44
46
|
self.metadata: PluginMetadata = self.get_metadata()
|
45
|
-
|
47
|
+
|
46
48
|
@abstractmethod
|
47
49
|
def get_metadata(self) -> PluginMetadata:
|
48
50
|
"""Return metadata describing this plugin."""
|
49
51
|
pass
|
50
|
-
|
52
|
+
|
51
53
|
def get_tools(self) -> List[Type[ToolBase]]:
|
52
54
|
"""
|
53
55
|
Return a list of tool classes provided by this plugin.
|
54
|
-
|
56
|
+
|
55
57
|
Returns:
|
56
58
|
List of ToolBase subclasses that should be registered
|
57
59
|
"""
|
58
60
|
return []
|
59
|
-
|
61
|
+
|
60
62
|
def get_commands(self) -> Dict[str, Any]:
|
61
63
|
"""
|
62
64
|
Return a dictionary of CLI commands provided by this plugin.
|
63
|
-
|
65
|
+
|
64
66
|
Returns:
|
65
67
|
Dict mapping command names to command handlers
|
66
68
|
"""
|
67
69
|
return {}
|
68
|
-
|
70
|
+
|
69
71
|
def initialize(self) -> None:
|
70
72
|
"""
|
71
73
|
Called when the plugin is loaded.
|
72
74
|
Override to perform any initialization needed.
|
73
75
|
"""
|
74
76
|
pass
|
75
|
-
|
77
|
+
|
76
78
|
def cleanup(self) -> None:
|
77
79
|
"""
|
78
80
|
Called when the plugin is unloaded.
|
79
81
|
Override to perform any cleanup needed.
|
80
82
|
"""
|
81
83
|
pass
|
82
|
-
|
84
|
+
|
83
85
|
def get_config_schema(self) -> Dict[str, Any]:
|
84
86
|
"""
|
85
87
|
Return JSON schema for plugin configuration.
|
86
|
-
|
88
|
+
|
87
89
|
Returns:
|
88
90
|
JSON schema dict describing configuration options
|
89
91
|
"""
|
90
92
|
return {}
|
91
|
-
|
93
|
+
|
92
94
|
def validate_config(self, config: Dict[str, Any]) -> bool:
|
93
95
|
"""
|
94
96
|
Validate plugin configuration.
|
95
|
-
|
97
|
+
|
96
98
|
Args:
|
97
99
|
config: Configuration dict to validate
|
98
|
-
|
100
|
+
|
99
101
|
Returns:
|
100
102
|
True if configuration is valid
|
101
103
|
"""
|
@@ -104,41 +106,47 @@ class Plugin(ABC):
|
|
104
106
|
def get_resources(self) -> List[PluginResource]:
|
105
107
|
"""
|
106
108
|
Return a list of resources provided by this plugin.
|
107
|
-
|
109
|
+
|
108
110
|
Returns:
|
109
111
|
List of PluginResource objects describing the resources
|
110
112
|
"""
|
111
113
|
resources = []
|
112
|
-
|
114
|
+
|
113
115
|
# Add tools as resources
|
114
116
|
for tool_class in self.get_tools():
|
115
117
|
tool_instance = tool_class()
|
116
|
-
tool_name = getattr(tool_instance,
|
117
|
-
tool_desc = getattr(tool_class,
|
118
|
-
resources.append(
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
118
|
+
tool_name = getattr(tool_instance, "tool_name", tool_class.__name__)
|
119
|
+
tool_desc = getattr(tool_class, "__doc__", f"Tool: {tool_name}")
|
120
|
+
resources.append(
|
121
|
+
PluginResource(
|
122
|
+
name=tool_name,
|
123
|
+
type="tool",
|
124
|
+
description=tool_desc or f"Tool provided by {self.metadata.name}",
|
125
|
+
)
|
126
|
+
)
|
127
|
+
|
124
128
|
# Add commands as resources
|
125
129
|
commands = self.get_commands()
|
126
130
|
for cmd_name, cmd_handler in commands.items():
|
127
|
-
cmd_desc = getattr(cmd_handler,
|
128
|
-
resources.append(
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
131
|
+
cmd_desc = getattr(cmd_handler, "__doc__", f"Command: {cmd_name}")
|
132
|
+
resources.append(
|
133
|
+
PluginResource(
|
134
|
+
name=cmd_name,
|
135
|
+
type="command",
|
136
|
+
description=cmd_desc or f"Command provided by {self.metadata.name}",
|
137
|
+
)
|
138
|
+
)
|
139
|
+
|
134
140
|
# Add config schema as resource
|
135
141
|
config_schema = self.get_config_schema()
|
136
142
|
if config_schema:
|
137
|
-
resources.append(
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
143
|
+
resources.append(
|
144
|
+
PluginResource(
|
145
|
+
name=f"{self.metadata.name}_config",
|
146
|
+
type="config",
|
147
|
+
description=f"Configuration schema for {self.metadata.name} plugin",
|
148
|
+
schema=config_schema,
|
149
|
+
)
|
150
|
+
)
|
151
|
+
|
152
|
+
return resources
|
janito/plugins/builtin.py
CHANGED
@@ -12,24 +12,24 @@ from janito.plugins.base import Plugin
|
|
12
12
|
|
13
13
|
class BuiltinPluginRegistry:
|
14
14
|
"""Registry for builtin plugins that come packaged with janito."""
|
15
|
-
|
15
|
+
|
16
16
|
_plugins: Dict[str, Type[Plugin]] = {}
|
17
|
-
|
17
|
+
|
18
18
|
@classmethod
|
19
19
|
def register(cls, name: str, plugin_class: Type[Plugin]) -> None:
|
20
20
|
"""Register a builtin plugin."""
|
21
21
|
cls._plugins[name] = plugin_class
|
22
|
-
|
22
|
+
|
23
23
|
@classmethod
|
24
24
|
def get_plugin_class(cls, name: str) -> Optional[Type[Plugin]]:
|
25
25
|
"""Get the plugin class for a builtin plugin."""
|
26
26
|
return cls._plugins.get(name)
|
27
|
-
|
27
|
+
|
28
28
|
@classmethod
|
29
29
|
def list_builtin_plugins(cls) -> List[str]:
|
30
30
|
"""List all registered builtin plugins."""
|
31
31
|
return list(cls._plugins.keys())
|
32
|
-
|
32
|
+
|
33
33
|
@classmethod
|
34
34
|
def is_builtin(cls, name: str) -> bool:
|
35
35
|
"""Check if a plugin is builtin."""
|
@@ -38,9 +38,11 @@ class BuiltinPluginRegistry:
|
|
38
38
|
|
39
39
|
def register_builtin_plugin(name: str):
|
40
40
|
"""Decorator to register a plugin as builtin."""
|
41
|
+
|
41
42
|
def decorator(plugin_class: Type[Plugin]) -> Type[Plugin]:
|
42
43
|
BuiltinPluginRegistry.register(name, plugin_class)
|
43
44
|
return plugin_class
|
45
|
+
|
44
46
|
return decorator
|
45
47
|
|
46
48
|
|
@@ -66,7 +68,7 @@ try:
|
|
66
68
|
SecurityScannerPlugin,
|
67
69
|
DocumentationGeneratorPlugin,
|
68
70
|
)
|
69
|
-
|
71
|
+
|
70
72
|
# Register all janito-coder plugins as builtin
|
71
73
|
BuiltinPluginRegistry.register("git_analyzer", GitAnalyzerPlugin)
|
72
74
|
BuiltinPluginRegistry.register("code_navigator", CodeNavigatorPlugin)
|
@@ -77,8 +79,10 @@ try:
|
|
77
79
|
BuiltinPluginRegistry.register("debugger", DebuggerPlugin)
|
78
80
|
BuiltinPluginRegistry.register("performance_profiler", PerformanceProfilerPlugin)
|
79
81
|
BuiltinPluginRegistry.register("security_scanner", SecurityScannerPlugin)
|
80
|
-
BuiltinPluginRegistry.register(
|
81
|
-
|
82
|
+
BuiltinPluginRegistry.register(
|
83
|
+
"documentation_generator", DocumentationGeneratorPlugin
|
84
|
+
)
|
85
|
+
|
82
86
|
except ImportError:
|
83
87
|
# janito-coder not available, skip registration
|
84
|
-
pass
|
88
|
+
pass
|
janito/plugins/config.py
CHANGED
@@ -21,35 +21,32 @@ def get_plugins_config_path() -> Path:
|
|
21
21
|
def load_plugins_config() -> Dict[str, Any]:
|
22
22
|
"""
|
23
23
|
Load plugins configuration from user directory.
|
24
|
-
|
24
|
+
|
25
25
|
Returns:
|
26
26
|
Dict containing plugins configuration
|
27
27
|
"""
|
28
28
|
config_path = get_plugins_config_path()
|
29
|
-
|
29
|
+
|
30
30
|
if not config_path.exists():
|
31
31
|
# Create default config if it doesn't exist
|
32
32
|
default_config = {
|
33
33
|
"plugins": {
|
34
|
-
"paths": [
|
35
|
-
|
36
|
-
"./plugins"
|
37
|
-
],
|
38
|
-
"load": {}
|
34
|
+
"paths": [str(Path.home() / ".janito" / "plugins"), "./plugins"],
|
35
|
+
"load": {},
|
39
36
|
}
|
40
37
|
}
|
41
|
-
|
38
|
+
|
42
39
|
# Ensure directory exists
|
43
40
|
config_path.parent.mkdir(parents=True, exist_ok=True)
|
44
|
-
|
41
|
+
|
45
42
|
# Save default config
|
46
|
-
with open(config_path,
|
43
|
+
with open(config_path, "w") as f:
|
47
44
|
json.dump(default_config, f, indent=2)
|
48
|
-
|
45
|
+
|
49
46
|
return default_config
|
50
|
-
|
47
|
+
|
51
48
|
try:
|
52
|
-
with open(config_path,
|
49
|
+
with open(config_path, "r") as f:
|
53
50
|
return json.load(f)
|
54
51
|
except (json.JSONDecodeError, IOError) as e:
|
55
52
|
print(f"Warning: Failed to load plugins config from {config_path}: {e}")
|
@@ -59,20 +56,20 @@ def load_plugins_config() -> Dict[str, Any]:
|
|
59
56
|
def save_plugins_config(config: Dict[str, Any]) -> bool:
|
60
57
|
"""
|
61
58
|
Save plugins configuration to user directory.
|
62
|
-
|
59
|
+
|
63
60
|
Args:
|
64
61
|
config: Configuration dict to save
|
65
|
-
|
62
|
+
|
66
63
|
Returns:
|
67
64
|
True if saved successfully
|
68
65
|
"""
|
69
66
|
config_path = get_plugins_config_path()
|
70
|
-
|
67
|
+
|
71
68
|
try:
|
72
69
|
# Ensure directory exists
|
73
70
|
config_path.parent.mkdir(parents=True, exist_ok=True)
|
74
|
-
|
75
|
-
with open(config_path,
|
71
|
+
|
72
|
+
with open(config_path, "w") as f:
|
76
73
|
json.dump(config, f, indent=2)
|
77
74
|
return True
|
78
75
|
except IOError as e:
|
@@ -84,4 +81,4 @@ def get_user_plugins_dir() -> Path:
|
|
84
81
|
"""Get the user plugins directory."""
|
85
82
|
plugins_dir = get_user_config_dir() / "plugins"
|
86
83
|
plugins_dir.mkdir(parents=True, exist_ok=True)
|
87
|
-
return plugins_dir
|
84
|
+
return plugins_dir
|