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/README.md
CHANGED
@@ -15,17 +15,17 @@ pip install janito
|
|
15
15
|
1. **Get your API key**: Sign up at [Moonshot AI](https://platform.moonshot.cn/) and get your API key
|
16
16
|
2. **Set your API key**:
|
17
17
|
```bash
|
18
|
-
janito --set-api-key YOUR_MOONSHOT_API_KEY -p
|
18
|
+
janito --set-api-key YOUR_MOONSHOT_API_KEY -p moonshot
|
19
19
|
```
|
20
20
|
|
21
21
|
### Basic Usage
|
22
22
|
|
23
|
-
**
|
23
|
+
**Moonshot (Recommended - Default Provider)**
|
24
24
|
```bash
|
25
|
-
# Using the default provider (
|
25
|
+
# Using the default provider (moonshot) and model
|
26
26
|
janito "Create a Python script that reads a CSV file"
|
27
27
|
|
28
|
-
# Using a specific
|
28
|
+
# Using a specific Moonshot model
|
29
29
|
janito -m kimi-k1-8k "Explain quantum computing"
|
30
30
|
```
|
31
31
|
|
@@ -71,13 +71,13 @@ In chat mode, you can:
|
|
71
71
|
|
72
72
|
Set default provider and model:
|
73
73
|
```bash
|
74
|
-
janito --set provider=
|
74
|
+
janito --set provider=moonshot
|
75
75
|
janito --set model=kimi-k1-8k
|
76
76
|
```
|
77
77
|
|
78
78
|
## Providers
|
79
79
|
|
80
|
-
###
|
80
|
+
### Moonshot (Recommended)
|
81
81
|
|
82
82
|
- **Models**: kimi-k1-8k, kimi-k1-32k, kimi-k1-128k, kimi-k2-turbo-preview
|
83
83
|
- **Strengths**: Excellent Chinese/English support, competitive pricing, fast responses
|
@@ -126,10 +126,10 @@ janito --role python-expert "Optimize this algorithm"
|
|
126
126
|
### Environment Variables
|
127
127
|
You can also configure via environment variables:
|
128
128
|
|
129
|
-
**
|
129
|
+
**Moonshot:**
|
130
130
|
```bash
|
131
|
-
export
|
132
|
-
export JANITO_PROVIDER=
|
131
|
+
export MOONSHOT_API_KEY=your_key_here
|
132
|
+
export JANITO_PROVIDER=moonshot
|
133
133
|
export JANITO_MODEL=kimi-k1-8k
|
134
134
|
```
|
135
135
|
|
janito/agent/setup_agent.py
CHANGED
@@ -53,38 +53,48 @@ def _load_template_content(profile, templates_dir):
|
|
53
53
|
return file.read(), user_template_path
|
54
54
|
|
55
55
|
# If nothing matched, list available profiles and raise an informative error
|
56
|
-
from janito.cli.cli_commands.list_profiles import
|
57
|
-
|
56
|
+
from janito.cli.cli_commands.list_profiles import (
|
57
|
+
_gather_default_profiles,
|
58
|
+
_gather_user_profiles,
|
59
|
+
)
|
60
|
+
|
58
61
|
default_profiles = _gather_default_profiles()
|
59
62
|
user_profiles = _gather_user_profiles()
|
60
|
-
|
63
|
+
|
61
64
|
available_profiles = []
|
62
65
|
if default_profiles:
|
63
66
|
available_profiles.extend([(p, "default") for p in default_profiles])
|
64
67
|
if user_profiles:
|
65
68
|
available_profiles.extend([(p, "user") for p in user_profiles])
|
66
|
-
|
69
|
+
|
67
70
|
# Normalize the input profile for better matching suggestions
|
68
71
|
normalized_input = re.sub(r"\s+", " ", profile.strip().lower())
|
69
|
-
|
72
|
+
|
70
73
|
if available_profiles:
|
71
|
-
profile_list = "\n".join(
|
72
|
-
|
74
|
+
profile_list = "\n".join(
|
75
|
+
[f" - {name} ({source})" for name, source in available_profiles]
|
76
|
+
)
|
77
|
+
|
73
78
|
# Find close matches
|
74
79
|
close_matches = []
|
75
80
|
for name, source in available_profiles:
|
76
81
|
normalized_name = name.lower()
|
77
|
-
if
|
82
|
+
if (
|
83
|
+
normalized_input in normalized_name
|
84
|
+
or normalized_name in normalized_input
|
85
|
+
):
|
78
86
|
close_matches.append(name)
|
79
|
-
|
87
|
+
|
80
88
|
suggestion = ""
|
81
89
|
if close_matches:
|
82
90
|
suggestion = f"\nDid you mean: {', '.join(close_matches)}?"
|
83
|
-
|
91
|
+
|
84
92
|
error_msg = f"[janito] Could not find profile '{profile}'. Available profiles:\n{profile_list}{suggestion}"
|
85
93
|
else:
|
86
|
-
error_msg =
|
87
|
-
|
94
|
+
error_msg = (
|
95
|
+
f"[janito] Could not find profile '{profile}'. No profiles available."
|
96
|
+
)
|
97
|
+
|
88
98
|
raise FileNotFoundError(error_msg)
|
89
99
|
# Replace spaces in profile name with underscores for filename resolution
|
90
100
|
sanitized_profile = re.sub(r"\\s+", "_", profile.strip()) if profile else profile
|
@@ -144,20 +154,23 @@ def _prepare_template_context(role, profile, allowed_permissions):
|
|
144
154
|
context["platform"] = pd.get_platform_name()
|
145
155
|
context["python_version"] = pd.get_python_version()
|
146
156
|
context["shell_info"] = pd.detect_shell()
|
147
|
-
|
157
|
+
|
148
158
|
# Add allowed sites for market analyst profile
|
149
159
|
if profile == "market-analyst":
|
150
160
|
from janito.tools.url_whitelist import get_url_whitelist_manager
|
161
|
+
|
151
162
|
whitelist_manager = get_url_whitelist_manager()
|
152
163
|
allowed_sites = whitelist_manager.get_allowed_sites()
|
153
164
|
context["allowed_sites"] = allowed_sites
|
154
|
-
|
165
|
+
|
155
166
|
# Add market data sources documentation
|
156
167
|
if not allowed_sites:
|
157
|
-
context["allowed_sites_info"] =
|
168
|
+
context["allowed_sites_info"] = (
|
169
|
+
"No whitelist restrictions - all sites allowed"
|
170
|
+
)
|
158
171
|
else:
|
159
172
|
context["allowed_sites_info"] = f"Restricted to: {', '.join(allowed_sites)}"
|
160
|
-
|
173
|
+
|
161
174
|
return context
|
162
175
|
|
163
176
|
|
janito/cli/chat_mode/session.py
CHANGED
@@ -116,7 +116,9 @@ class ChatSession:
|
|
116
116
|
def _select_profile_and_role(self, args, role):
|
117
117
|
profile = getattr(args, "profile", None) if args is not None else None
|
118
118
|
role_arg = getattr(args, "role", None) if args is not None else None
|
119
|
-
python_profile =
|
119
|
+
python_profile = (
|
120
|
+
getattr(args, "developer", False) if args is not None else False
|
121
|
+
)
|
120
122
|
market_profile = getattr(args, "market", False) if args is not None else False
|
121
123
|
profile_system_prompt = None
|
122
124
|
no_tools_mode = False
|
@@ -129,10 +131,15 @@ class ChatSession:
|
|
129
131
|
if market_profile and profile is None and role_arg is None:
|
130
132
|
profile = "Market Analyst"
|
131
133
|
|
132
|
-
if
|
134
|
+
if (
|
135
|
+
profile is None
|
136
|
+
and role_arg is None
|
137
|
+
and not python_profile
|
138
|
+
and not market_profile
|
139
|
+
):
|
133
140
|
# Skip interactive profile selection for list commands
|
134
141
|
from janito.cli.core.getters import GETTER_KEYS
|
135
|
-
|
142
|
+
|
136
143
|
# Check if any getter command is active - these don't need interactive mode
|
137
144
|
skip_profile_selection = False
|
138
145
|
if args is not None:
|
@@ -140,12 +147,14 @@ class ChatSession:
|
|
140
147
|
if getattr(args, key, False):
|
141
148
|
skip_profile_selection = True
|
142
149
|
break
|
143
|
-
|
150
|
+
|
144
151
|
if skip_profile_selection:
|
145
152
|
profile = "Developer with Python Tools" # Default for non-interactive commands
|
146
153
|
else:
|
147
154
|
try:
|
148
|
-
from janito.cli.chat_mode.session_profile_select import
|
155
|
+
from janito.cli.chat_mode.session_profile_select import (
|
156
|
+
select_profile,
|
157
|
+
)
|
149
158
|
|
150
159
|
result = select_profile()
|
151
160
|
if isinstance(result, dict):
|
@@ -338,6 +347,7 @@ class ChatSession:
|
|
338
347
|
if top_base:
|
339
348
|
candidates.append(top_base)
|
340
349
|
from urllib.parse import urlparse
|
350
|
+
|
341
351
|
for candidate in candidates:
|
342
352
|
try:
|
343
353
|
if not candidate:
|
@@ -367,6 +377,8 @@ class ChatSession:
|
|
367
377
|
print_token_message_summary(
|
368
378
|
self.console, self.msg_count, usage, elapsed=elapsed
|
369
379
|
)
|
380
|
+
# Send terminal bell character to trigger TUI bell after printing token summary
|
381
|
+
print("\a", end="", flush=True)
|
370
382
|
if final_event and hasattr(final_event, "metadata"):
|
371
383
|
exit_reason = (
|
372
384
|
final_event.metadata.get("exit_reason")
|
@@ -149,7 +149,10 @@ def select_profile():
|
|
149
149
|
|
150
150
|
# Get the absolute path relative to the current script location
|
151
151
|
current_dir = Path(__file__).parent
|
152
|
-
template_path =
|
152
|
+
template_path = (
|
153
|
+
current_dir
|
154
|
+
/ "../../agent/templates/profiles/system_prompt_template_developer.txt.j2"
|
155
|
+
)
|
153
156
|
with open(template_path, "r", encoding="utf-8") as f:
|
154
157
|
template_content = f.read()
|
155
158
|
|
@@ -165,7 +168,10 @@ def select_profile():
|
|
165
168
|
|
166
169
|
# Get the absolute path relative to the current script location
|
167
170
|
current_dir = Path(__file__).parent
|
168
|
-
template_path =
|
171
|
+
template_path = (
|
172
|
+
current_dir
|
173
|
+
/ "../../agent/templates/profiles/system_prompt_template_market_analyst.txt.j2"
|
174
|
+
)
|
169
175
|
with open(template_path, "r", encoding="utf-8") as f:
|
170
176
|
template_content = f.read()
|
171
177
|
|
@@ -6,8 +6,10 @@ class ExecuteShellHandler(ShellCmdHandler):
|
|
6
6
|
help_text = "/execute on|off: Enable or disable code and command execution tools. Usage: /execute on or /execute off."
|
7
7
|
|
8
8
|
def run(self):
|
9
|
-
if self.shell_state and getattr(self.shell_state,
|
10
|
-
shared_console.print(
|
9
|
+
if self.shell_state and getattr(self.shell_state, "no_tools_mode", False):
|
10
|
+
shared_console.print(
|
11
|
+
"[yellow]No tools are available in this mode (no tools, no context).[/yellow]"
|
12
|
+
)
|
11
13
|
return
|
12
14
|
if not self.shell_state:
|
13
15
|
shared_console.print("[red]Shell state unavailable.[/red]")
|
@@ -9,8 +9,10 @@ class HelpShellHandler(ShellCmdHandler):
|
|
9
9
|
def run(self):
|
10
10
|
# Ensure /provider command is registered before showing help
|
11
11
|
from janito.cli.chat_mode.shell.commands import COMMAND_HANDLERS
|
12
|
+
|
12
13
|
if "/provider" not in COMMAND_HANDLERS:
|
13
14
|
from janito.cli.chat_mode.shell.commands.provider import ProviderCmdHandler
|
15
|
+
|
14
16
|
COMMAND_HANDLERS["/provider"] = ProviderCmdHandler
|
15
17
|
|
16
18
|
from ._priv_check import user_has_any_privileges
|
@@ -1,16 +1,20 @@
|
|
1
1
|
from janito.cli.console import shared_console
|
2
2
|
from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
|
3
3
|
|
4
|
+
|
4
5
|
class PrivilegesShellHandler(ShellCmdHandler):
|
5
6
|
help_text = "Show current tool privileges or availability."
|
6
7
|
|
7
8
|
def run(self):
|
8
9
|
# Check for no_tools_mode in shell_state
|
9
|
-
if self.shell_state and getattr(self.shell_state,
|
10
|
-
shared_console.print(
|
10
|
+
if self.shell_state and getattr(self.shell_state, "no_tools_mode", False):
|
11
|
+
shared_console.print(
|
12
|
+
"[yellow]No tools are available in this mode (no tools, no context).[/yellow]"
|
13
|
+
)
|
11
14
|
return
|
12
15
|
try:
|
13
16
|
from janito.tools.permissions import get_global_allowed_permissions
|
17
|
+
|
14
18
|
perms = get_global_allowed_permissions()
|
15
19
|
lines = ["[bold]Current tool privileges:[/bold]"]
|
16
20
|
lines.append(f"Read: {'✅' if perms.read else '❌'}")
|
@@ -3,11 +3,12 @@ from janito.cli.core.setters import set_provider
|
|
3
3
|
from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
|
4
4
|
from janito.cli.console import shared_console as console
|
5
5
|
|
6
|
+
|
6
7
|
class ProviderCmdHandler(ShellCmdHandler):
|
7
8
|
"""Handler for the /provider command to view or change the current provider."""
|
8
|
-
|
9
|
+
|
9
10
|
help_text = "Manage the current LLM provider. Usage: /provider [provider_name]"
|
10
|
-
|
11
|
+
|
11
12
|
def run(self):
|
12
13
|
"""Execute the provider command."""
|
13
14
|
if not self.after_cmd_line.strip():
|
@@ -15,11 +16,13 @@ class ProviderCmdHandler(ShellCmdHandler):
|
|
15
16
|
current = get_current_provider()
|
16
17
|
console.print(f"[bold]Current provider:[/bold] {current}")
|
17
18
|
return
|
18
|
-
|
19
|
+
|
19
20
|
# Argument provided, attempt to change provider
|
20
21
|
new_provider = self.after_cmd_line.strip()
|
21
22
|
try:
|
22
23
|
set_provider(new_provider)
|
23
|
-
console.print(
|
24
|
+
console.print(
|
25
|
+
f"[bold green]Provider changed to:[/bold green] {new_provider}"
|
26
|
+
)
|
24
27
|
except ValueError as e:
|
25
28
|
console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
@@ -6,8 +6,10 @@ class ReadShellHandler(ShellCmdHandler):
|
|
6
6
|
help_text = "/read on|off: Enable or disable read permissions for tools. Usage: /read on or /read off."
|
7
7
|
|
8
8
|
def run(self):
|
9
|
-
if self.shell_state and getattr(self.shell_state,
|
10
|
-
shared_console.print(
|
9
|
+
if self.shell_state and getattr(self.shell_state, "no_tools_mode", False):
|
10
|
+
shared_console.print(
|
11
|
+
"[yellow]No tools are available in this mode (no tools, no context).[/yellow]"
|
12
|
+
)
|
11
13
|
return
|
12
14
|
if not self.shell_state:
|
13
15
|
shared_console.print("[red]Shell state unavailable.[/red]")
|
@@ -1 +1 @@
|
|
1
|
-
"""Security management commands for chat mode."""
|
1
|
+
"""Security management commands for chat mode."""
|
@@ -6,15 +6,17 @@ from janito.tools.url_whitelist import get_url_whitelist_manager
|
|
6
6
|
|
7
7
|
class SecurityAllowedSitesCommand(BaseCommand):
|
8
8
|
"""Manage allowed sites for fetch_url tool."""
|
9
|
-
|
9
|
+
|
10
10
|
def get_name(self) -> str:
|
11
11
|
return "allowed-sites"
|
12
|
-
|
12
|
+
|
13
13
|
def get_description(self) -> str:
|
14
14
|
return "Manage allowed sites for the fetch_url tool"
|
15
|
-
|
15
|
+
|
16
16
|
def get_usage(self):
|
17
|
-
return
|
17
|
+
return (
|
18
|
+
self.get_description()
|
19
|
+
+ """
|
18
20
|
Usage: /security allowed-sites [command] [site]
|
19
21
|
|
20
22
|
Commands:
|
@@ -29,6 +31,7 @@ Examples:
|
|
29
31
|
/security allowed-sites remove yahoo.com
|
30
32
|
/security allowed-sites clear
|
31
33
|
"""
|
34
|
+
)
|
32
35
|
return """
|
33
36
|
Usage: /security allowed-sites [command] [site]
|
34
37
|
|
@@ -44,18 +47,18 @@ Examples:
|
|
44
47
|
/security allowed-sites remove yahoo.com
|
45
48
|
/security allowed-sites clear
|
46
49
|
"""
|
47
|
-
|
50
|
+
|
48
51
|
def run(self):
|
49
52
|
"""Execute the allowed-sites command."""
|
50
53
|
args = self.after_cmd_line.strip().split()
|
51
|
-
|
54
|
+
|
52
55
|
if not args:
|
53
56
|
print(self.get_usage())
|
54
57
|
return
|
55
|
-
|
58
|
+
|
56
59
|
command = args[0].lower()
|
57
60
|
whitelist_manager = get_url_whitelist_manager()
|
58
|
-
|
61
|
+
|
59
62
|
if command == "list":
|
60
63
|
sites = whitelist_manager.get_allowed_sites()
|
61
64
|
if sites:
|
@@ -64,7 +67,7 @@ Examples:
|
|
64
67
|
print(f" • {site}")
|
65
68
|
else:
|
66
69
|
print("No sites are whitelisted (all sites are allowed)")
|
67
|
-
|
70
|
+
|
68
71
|
elif command == "add":
|
69
72
|
if len(args) < 2:
|
70
73
|
print("Error: Please specify a site to add")
|
@@ -74,7 +77,7 @@ Examples:
|
|
74
77
|
print(f"✅ Added '{site}' to allowed sites")
|
75
78
|
else:
|
76
79
|
print(f"ℹ️ '{site}' is already in allowed sites")
|
77
|
-
|
80
|
+
|
78
81
|
elif command == "remove":
|
79
82
|
if len(args) < 2:
|
80
83
|
print("Error: Please specify a site to remove")
|
@@ -84,11 +87,11 @@ Examples:
|
|
84
87
|
print(f"✅ Removed '{site}' from allowed sites")
|
85
88
|
else:
|
86
89
|
print(f"ℹ️ '{site}' was not in allowed sites")
|
87
|
-
|
90
|
+
|
88
91
|
elif command == "clear":
|
89
92
|
whitelist_manager.clear_whitelist()
|
90
93
|
print("✅ Cleared all allowed sites (all sites are now allowed)")
|
91
|
-
|
94
|
+
|
92
95
|
else:
|
93
96
|
print(f"Error: Unknown command '{command}'")
|
94
|
-
print(self.get_usage())
|
97
|
+
print(self.get_usage())
|
@@ -1,18 +1,20 @@
|
|
1
1
|
"""Security command group for chat mode."""
|
2
2
|
|
3
3
|
from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler as BaseCommand
|
4
|
-
from janito.cli.chat_mode.shell.commands.security.allowed_sites import
|
4
|
+
from janito.cli.chat_mode.shell.commands.security.allowed_sites import (
|
5
|
+
SecurityAllowedSitesCommand,
|
6
|
+
)
|
5
7
|
|
6
8
|
|
7
9
|
class SecurityCommand(BaseCommand):
|
8
10
|
"""Security management command group."""
|
9
|
-
|
11
|
+
|
10
12
|
def get_name(self) -> str:
|
11
13
|
return "security"
|
12
|
-
|
14
|
+
|
13
15
|
def get_description(self) -> str:
|
14
16
|
return "Security management commands"
|
15
|
-
|
17
|
+
|
16
18
|
def get_usage(self):
|
17
19
|
return """
|
18
20
|
Usage: /security <subcommand> [args...]
|
@@ -25,21 +27,23 @@ Examples:
|
|
25
27
|
/security allowed-sites add tradingview.com
|
26
28
|
/security allowed-sites remove yahoo.com
|
27
29
|
"""
|
28
|
-
|
30
|
+
|
29
31
|
def __init__(self, after_cmd_line=None, shell_state=None):
|
30
32
|
super().__init__(after_cmd_line=after_cmd_line, shell_state=shell_state)
|
31
33
|
self.subcommands = {
|
32
|
-
"allowed-sites": SecurityAllowedSitesCommand(
|
34
|
+
"allowed-sites": SecurityAllowedSitesCommand(
|
35
|
+
after_cmd_line=after_cmd_line, shell_state=shell_state
|
36
|
+
)
|
33
37
|
}
|
34
|
-
|
38
|
+
|
35
39
|
def run(self):
|
36
40
|
"""Execute the security command."""
|
37
41
|
args = self.after_cmd_line.strip().split()
|
38
|
-
|
42
|
+
|
39
43
|
if not args:
|
40
44
|
print(self.get_usage())
|
41
45
|
return
|
42
|
-
|
46
|
+
|
43
47
|
subcommand = args[0].lower()
|
44
48
|
if subcommand in self.subcommands:
|
45
49
|
# Pass the remaining args to the subcommand
|
@@ -48,4 +52,4 @@ Examples:
|
|
48
52
|
self.subcommands[subcommand].run()
|
49
53
|
else:
|
50
54
|
print(f"Error: Unknown security subcommand '{subcommand}'")
|
51
|
-
print(self.get_usage())
|
55
|
+
print(self.get_usage())
|
@@ -56,8 +56,10 @@ class ToolsShellHandler(ShellCmdHandler):
|
|
56
56
|
|
57
57
|
def run(self):
|
58
58
|
# Check for no_tools_mode in shell_state
|
59
|
-
if self.shell_state and getattr(self.shell_state,
|
60
|
-
shared_console.print(
|
59
|
+
if self.shell_state and getattr(self.shell_state, "no_tools_mode", False):
|
60
|
+
shared_console.print(
|
61
|
+
"[yellow]No tools are available in this mode (no tools, no context).[/yellow]"
|
62
|
+
)
|
61
63
|
return
|
62
64
|
try:
|
63
65
|
import janito.tools # Ensure all tools are registered
|
@@ -6,7 +6,7 @@ from janito.cli.console import shared_console
|
|
6
6
|
|
7
7
|
class UnrestrictedShellHandler(ShellCmdHandler):
|
8
8
|
"""Toggle unrestricted mode (equivalent to -u CLI flag)."""
|
9
|
-
|
9
|
+
|
10
10
|
help_text = "Toggle unrestricted mode (disable path security and URL whitelist)"
|
11
11
|
|
12
12
|
def run(self):
|
@@ -14,27 +14,32 @@ class UnrestrictedShellHandler(ShellCmdHandler):
|
|
14
14
|
if not self.shell_state:
|
15
15
|
shared_console.print("[red]Error: Shell state not available[/red]")
|
16
16
|
return
|
17
|
-
|
17
|
+
|
18
18
|
# Toggle unrestricted mode
|
19
|
-
current_unrestricted = getattr(self.shell_state,
|
19
|
+
current_unrestricted = getattr(self.shell_state, "unrestricted_mode", False)
|
20
20
|
new_unrestricted = not current_unrestricted
|
21
|
-
|
21
|
+
|
22
22
|
# Update shell state
|
23
23
|
self.shell_state.unrestricted_mode = new_unrestricted
|
24
|
-
|
24
|
+
|
25
25
|
# Update tools adapter
|
26
|
-
if hasattr(self.shell_state,
|
27
|
-
setattr(
|
28
|
-
|
26
|
+
if hasattr(self.shell_state, "tools_adapter"):
|
27
|
+
setattr(
|
28
|
+
self.shell_state.tools_adapter, "unrestricted_paths", new_unrestricted
|
29
|
+
)
|
30
|
+
|
29
31
|
# Update URL whitelist manager
|
30
32
|
from janito.tools.url_whitelist import get_url_whitelist_manager
|
33
|
+
|
31
34
|
whitelist_manager = get_url_whitelist_manager()
|
32
35
|
whitelist_manager.set_unrestricted_mode(new_unrestricted)
|
33
|
-
|
36
|
+
|
34
37
|
status = "enabled" if new_unrestricted else "disabled"
|
35
|
-
warning =
|
36
|
-
|
38
|
+
warning = (
|
39
|
+
" (DANGEROUS - no path or URL restrictions)" if new_unrestricted else ""
|
40
|
+
)
|
41
|
+
|
37
42
|
shared_console.print(
|
38
43
|
f"[bold {'red' if new_unrestricted else 'green'}]"
|
39
44
|
f"Unrestricted mode {status}{warning}[/bold {'red' if new_unrestricted else 'green'}]"
|
40
|
-
)
|
45
|
+
)
|
@@ -6,8 +6,10 @@ class WriteShellHandler(ShellCmdHandler):
|
|
6
6
|
help_text = "/write on|off: Enable or disable write permissions for tools. Usage: /write on or /write off."
|
7
7
|
|
8
8
|
def run(self):
|
9
|
-
if self.shell_state and getattr(self.shell_state,
|
10
|
-
shared_console.print(
|
9
|
+
if self.shell_state and getattr(self.shell_state, "no_tools_mode", False):
|
10
|
+
shared_console.print(
|
11
|
+
"[yellow]No tools are available in this mode (no tools, no context).[/yellow]"
|
12
|
+
)
|
11
13
|
return
|
12
14
|
if not self.shell_state:
|
13
15
|
shared_console.print("[red]Shell state unavailable.[/red]")
|
janito/cli/chat_mode/toolbar.py
CHANGED
@@ -20,17 +20,17 @@ def format_tokens(n, tag=None):
|
|
20
20
|
def assemble_first_line(provider_name, model_name, role, agent=None):
|
21
21
|
cwd = os.getcwd()
|
22
22
|
home = os.path.expanduser("~")
|
23
|
-
|
23
|
+
|
24
24
|
# Convert to relative path if under home directory
|
25
25
|
if cwd.startswith(home):
|
26
|
-
cwd_display = "~" + cwd[len(home):]
|
26
|
+
cwd_display = "~" + cwd[len(home) :]
|
27
27
|
else:
|
28
28
|
cwd_display = cwd
|
29
|
-
|
29
|
+
|
30
30
|
# Shorten long paths for display
|
31
31
|
if len(cwd_display) > 50:
|
32
32
|
cwd_display = "..." + cwd_display[-47:]
|
33
|
-
|
33
|
+
|
34
34
|
return f" Janito {VERSION} | Provider: <provider>{provider_name}</provider> | Model: <model>{model_name}</model> | Dir: <model>{cwd_display}</model>"
|
35
35
|
|
36
36
|
|