janito 2.25.0__py3-none-any.whl → 2.27.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.
@@ -0,0 +1,40 @@
1
+ """Unrestricted mode command for chat mode."""
2
+
3
+ from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
4
+ from janito.cli.console import shared_console
5
+
6
+
7
+ class UnrestrictedShellHandler(ShellCmdHandler):
8
+ """Toggle unrestricted mode (equivalent to -u CLI flag)."""
9
+
10
+ help_text = "Toggle unrestricted mode (disable path security and URL whitelist)"
11
+
12
+ def run(self):
13
+ """Execute the unrestricted command."""
14
+ if not self.shell_state:
15
+ shared_console.print("[red]Error: Shell state not available[/red]")
16
+ return
17
+
18
+ # Toggle unrestricted mode
19
+ current_unrestricted = getattr(self.shell_state, 'unrestricted_mode', False)
20
+ new_unrestricted = not current_unrestricted
21
+
22
+ # Update shell state
23
+ self.shell_state.unrestricted_mode = new_unrestricted
24
+
25
+ # Update tools adapter
26
+ if hasattr(self.shell_state, 'tools_adapter'):
27
+ setattr(self.shell_state.tools_adapter, 'unrestricted_paths', new_unrestricted)
28
+
29
+ # Update URL whitelist manager
30
+ from janito.tools.url_whitelist import get_url_whitelist_manager
31
+ whitelist_manager = get_url_whitelist_manager()
32
+ whitelist_manager.set_unrestricted_mode(new_unrestricted)
33
+
34
+ status = "enabled" if new_unrestricted else "disabled"
35
+ warning = " (DANGEROUS - no path or URL restrictions)" if new_unrestricted else ""
36
+
37
+ shared_console.print(
38
+ f"[bold {'red' if new_unrestricted else 'green'}]"
39
+ f"Unrestricted mode {status}{warning}[/bold {'red' if new_unrestricted else 'green'}]"
40
+ )
@@ -42,6 +42,30 @@ def handle_show_config(args):
42
42
  console.print(f"[bold yellow]Current provider:[/bold yellow] {provider!r}\n")
43
43
  if model is not None:
44
44
  console.print(f"[bold yellow]Global model:[/bold yellow] {model!r}\n")
45
+
46
+ # Show all configuration values
47
+ console.print("[bold green]Configuration values:[/bold green]")
48
+ all_config = config.all()
49
+ if all_config:
50
+ for key, value in sorted(all_config.items()):
51
+ # Hide sensitive values like API keys
52
+ if 'api_key' in key.lower() and value:
53
+ masked_value = value[:8] + '***' + value[-4:] if len(value) > 12 else '***'
54
+ console.print(f" {key}: {masked_value!r}")
55
+ elif key == 'providers' and isinstance(value, dict):
56
+ # Handle nested provider configs with API keys
57
+ masked_providers = {}
58
+ for provider_name, provider_config in value.items():
59
+ masked_config = dict(provider_config)
60
+ if 'api_key' in masked_config and masked_config['api_key']:
61
+ api_key = masked_config['api_key']
62
+ masked_config['api_key'] = api_key[:8] + '***' + api_key[-4:] if len(api_key) > 12 else '***'
63
+ masked_providers[provider_name] = masked_config
64
+ console.print(f" {key}: {masked_providers!r}")
65
+ else:
66
+ console.print(f" {key}: {value!r}")
67
+ else:
68
+ console.print(" (no configuration values set)")
45
69
 
46
70
  # Show disabled tools
47
71
  from janito.tools.disabled_tools import load_disabled_tools_from_config
janito/cli/main_cli.py CHANGED
@@ -293,7 +293,8 @@ class JanitoCLI:
293
293
  self.parser = argparse.ArgumentParser(
294
294
  description="Janito CLI - A tool for running LLM-powered workflows from the command line."
295
295
  "\n\nExample usage: janito -p moonshotai -m kimi-k1-8k 'Your prompt here'\n\n"
296
- "Use -m or --model to set the model for the session."
296
+ "Use -m or --model to set the model for the session.",
297
+
297
298
  )
298
299
  self._define_args()
299
300
  self.args = self.parser.parse_args()
@@ -409,6 +410,17 @@ class JanitoCLI:
409
410
  self._maybe_print_verbose_provider_model()
410
411
  handle_getter(self.args)
411
412
  return
413
+ # Handle /rwx prefix for enabling all permissions
414
+ if self.args.user_prompt and self.args.user_prompt[0] == '/rwx':
415
+ self.args.read = True
416
+ self.args.write = True
417
+ self.args.exec = True
418
+ # Remove the /rwx prefix from the prompt
419
+ self.args.user_prompt = self.args.user_prompt[1:]
420
+ elif self.args.user_prompt and self.args.user_prompt[0].startswith('/'):
421
+ # Skip LLM processing for other commands that start with /
422
+ return
423
+
412
424
  # If running in single shot mode and --profile is not provided, default to 'developer' profile
413
425
  if get_prompt_mode(self.args) == "single_shot" and not getattr(
414
426
  self.args, "profile", None
@@ -4,6 +4,7 @@ import os
4
4
  import json
5
5
  from pathlib import Path
6
6
  from bs4 import BeautifulSoup
7
+ from typing import Dict, Any, Optional
7
8
  from janito.tools.adapters.local.adapter import register_local_tool
8
9
  from janito.tools.tool_base import ToolBase, ToolPermissions
9
10
  from janito.report_events import ReportAction
@@ -45,6 +46,9 @@ class FetchUrlTool(ToolBase):
45
46
  timeout (int, optional): Timeout in seconds for the HTTP request. Defaults to 10.
46
47
  save_to_file (str, optional): File path to save the full resource content. If provided,
47
48
  the complete response will be saved to this file instead of being processed.
49
+ headers (Dict[str, str], optional): Custom HTTP headers to send with the request.
50
+ cookies (Dict[str, str], optional): Custom cookies to send with the request.
51
+ follow_redirects (bool, optional): Whether to follow HTTP redirects. Defaults to True.
48
52
  Returns:
49
53
  str: Extracted text content from the web page, or a warning message. Example:
50
54
  - "<main text content...>"
@@ -64,6 +68,22 @@ class FetchUrlTool(ToolBase):
64
68
  {}
65
69
  ) # In-memory session cache - lifetime matches tool instance
66
70
  self._load_cache()
71
+
72
+ # Browser-like session with cookies and headers
73
+ self.session = requests.Session()
74
+ self.session.headers.update({
75
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
76
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
77
+ 'Accept-Language': 'en-US,en;q=0.5',
78
+ 'Accept-Encoding': 'gzip, deflate, br',
79
+ 'DNT': '1',
80
+ 'Connection': 'keep-alive',
81
+ 'Upgrade-Insecure-Requests': '1',
82
+ })
83
+
84
+ # Load cookies from disk if they exist
85
+ self.cookies_file = self.cache_dir / "cookies.json"
86
+ self._load_cookies()
67
87
 
68
88
  def _load_cache(self):
69
89
  """Load error cache from disk."""
@@ -84,6 +104,33 @@ class FetchUrlTool(ToolBase):
84
104
  except IOError:
85
105
  pass # Silently fail if we can't write cache
86
106
 
107
+ def _load_cookies(self):
108
+ """Load cookies from disk into session."""
109
+ if self.cookies_file.exists():
110
+ try:
111
+ with open(self.cookies_file, "r", encoding="utf-8") as f:
112
+ cookies_data = json.load(f)
113
+ for cookie in cookies_data:
114
+ self.session.cookies.set(**cookie)
115
+ except (json.JSONDecodeError, IOError):
116
+ pass # Silently fail if we can't load cookies
117
+
118
+ def _save_cookies(self):
119
+ """Save session cookies to disk."""
120
+ try:
121
+ cookies_data = []
122
+ for cookie in self.session.cookies:
123
+ cookies_data.append({
124
+ 'name': cookie.name,
125
+ 'value': cookie.value,
126
+ 'domain': cookie.domain,
127
+ 'path': cookie.path
128
+ })
129
+ with open(self.cookies_file, "w", encoding="utf-8") as f:
130
+ json.dump(cookies_data, f, indent=2)
131
+ except IOError:
132
+ pass # Silently fail if we can't write cookies
133
+
87
134
  def _get_cached_error(self, url: str) -> tuple[str, bool]:
88
135
  """
89
136
  Check if we have a cached error for this URL.
@@ -123,14 +170,15 @@ class FetchUrlTool(ToolBase):
123
170
  }
124
171
  self._save_cache()
125
172
 
126
- def _fetch_url_content(self, url: str, timeout: int = 10) -> str:
173
+ def _fetch_url_content(self, url: str, timeout: int = 10, headers: Optional[Dict[str, str]] = None,
174
+ cookies: Optional[Dict[str, str]] = None, follow_redirects: bool = True) -> str:
127
175
  """Fetch URL content and handle HTTP errors.
128
176
 
129
177
  Implements two-tier caching:
130
178
  1. Session cache: In-memory cache for successful responses (lifetime = tool instance)
131
179
  2. Error cache: Persistent disk cache for HTTP errors with different expiration times
132
180
 
133
- Also implements URL whitelist checking.
181
+ Also implements URL whitelist checking and browser-like behavior.
134
182
  """
135
183
  # Check URL whitelist
136
184
  from janito.tools.url_whitelist import get_url_whitelist_manager
@@ -172,9 +220,27 @@ class FetchUrlTool(ToolBase):
172
220
  return cached_error
173
221
 
174
222
  try:
175
- response = requests.get(url, timeout=timeout)
223
+ # Merge custom headers with default ones
224
+ request_headers = self.session.headers.copy()
225
+ if headers:
226
+ request_headers.update(headers)
227
+
228
+ # Merge custom cookies
229
+ if cookies:
230
+ self.session.cookies.update(cookies)
231
+
232
+ response = self.session.get(
233
+ url,
234
+ timeout=timeout,
235
+ headers=request_headers,
236
+ allow_redirects=follow_redirects
237
+ )
176
238
  response.raise_for_status()
177
239
  content = response.text
240
+
241
+ # Save cookies after successful request
242
+ self._save_cookies()
243
+
178
244
  # Cache successful responses in session cache
179
245
  self.session_cache[url] = content
180
246
  return content
@@ -275,6 +341,9 @@ class FetchUrlTool(ToolBase):
275
341
  context_chars: int = 400,
276
342
  timeout: int = 10,
277
343
  save_to_file: str = None,
344
+ headers: Dict[str, str] = None,
345
+ cookies: Dict[str, str] = None,
346
+ follow_redirects: bool = True,
278
347
  ) -> str:
279
348
  if not url.strip():
280
349
  self.report_warning(tr("ℹ️ Empty URL provided."), ReportAction.READ)
@@ -284,7 +353,10 @@ class FetchUrlTool(ToolBase):
284
353
 
285
354
  # Check if we should save to file
286
355
  if save_to_file:
287
- html_content = self._fetch_url_content(url, timeout=timeout)
356
+ html_content = self._fetch_url_content(
357
+ url, timeout=timeout, headers=headers, cookies=cookies,
358
+ follow_redirects=follow_redirects
359
+ )
288
360
  if html_content.startswith("Warning:"):
289
361
  return html_content
290
362
 
@@ -307,7 +379,10 @@ class FetchUrlTool(ToolBase):
307
379
  return error_msg
308
380
 
309
381
  # Normal processing path
310
- html_content = self._fetch_url_content(url, timeout=timeout)
382
+ html_content = self._fetch_url_content(
383
+ url, timeout=timeout, headers=headers, cookies=cookies,
384
+ follow_redirects=follow_redirects
385
+ )
311
386
  if html_content.startswith("Warning:"):
312
387
  return html_content
313
388
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: janito
3
- Version: 2.25.0
3
+ Version: 2.27.0
4
4
  Summary: A new Python package called janito.
5
5
  Author-email: João Pinto <janito@ikignosis.org>
6
6
  Project-URL: Homepage, https://github.com/ikignosis/janito
@@ -187,7 +187,25 @@ janito -r -w "Read and update this file: ..."
187
187
  To enable all permissions (read, write, execute):
188
188
 
189
189
  ```bash
190
+ # Using individual flags
190
191
  janito -r -w -x "Run this code: print('Hello, world!')"
192
+
193
+ # Using the convenient /rwx prefix (single-shot mode)
194
+ janito /rwx "Run this code: print('Hello, world!')"
195
+ ```
196
+
197
+ #### One-Shot Mode
198
+ For quick tasks without entering interactive mode, provide your prompt directly:
199
+
200
+ ```bash
201
+ # Basic one-shot
202
+ janito "What are the key classes in this project?"
203
+
204
+ # One-shot with all permissions enabled
205
+ janito /rwx "Create a Python script and run it"
206
+
207
+ # One-shot with specific permissions
208
+ janito -r -w "Read this file and create a summary"
191
209
  ```
192
210
 
193
211
  > **Warning:** Enabling execution tools allows running arbitrary code or shell commands. Only use `--exec` if you trust your prompt and environment.
@@ -29,7 +29,7 @@ janito/cli/__init__.py,sha256=xaPDOrWphBbCR63Xpcx_yfpXSJIlCaaICc4j2qpWqrM,194
29
29
  janito/cli/config.py,sha256=HkZ14701HzIqrvaNyDcDhGlVHfpX_uHlLp2rHmhRm_k,872
30
30
  janito/cli/console.py,sha256=gJolqzWL7jEPLxeuH-CwBDRFpXt976KdZOEAB2tdBDs,64
31
31
  janito/cli/main.py,sha256=s5odou0txf8pzTf1ADk2yV7T5m8B6cejJ81e7iu776U,312
32
- janito/cli/main_cli.py,sha256=GzuWWHYqvK_ebbvXKNvqKaSh0lObQH5qYSNN2mvsf14,16380
32
+ janito/cli/main_cli.py,sha256=VusBQQd9tpeBWPzERVobYCeR75A96W_1VnEWCX2R1Xo,16927
33
33
  janito/cli/prompt_core.py,sha256=F68J4Xl6jZMYFN4oBBYZFj15Jp-HTYoLub4bw2XpNRU,11648
34
34
  janito/cli/prompt_handler.py,sha256=SnPTlL64noeAMGlI08VBDD5IDD8jlVMIYA4-fS8zVLg,215
35
35
  janito/cli/prompt_setup.py,sha256=1SSvvgS568-3BO_4Sw9A-QF_iLWiIXsNHT0JVqaLwkU,2120
@@ -68,6 +68,7 @@ janito/cli/chat_mode/shell/commands/security_command.py,sha256=7Xgjb8Gunk9CjKxz1
68
68
  janito/cli/chat_mode/shell/commands/session.py,sha256=9wsw5U24-KJgTT70KAwnGuS8MVPyvpxCJfAt_Io76O0,1574
69
69
  janito/cli/chat_mode/shell/commands/session_control.py,sha256=tmMGJ8IvWoBwSIJu7T6GPnFYFrmXWIG2Gr9tTni4y3U,1307
70
70
  janito/cli/chat_mode/shell/commands/tools.py,sha256=8BWgqB0j5sp7mYupxoAjYvLWjb_wODOfCk-I8yNfk-U,3473
71
+ janito/cli/chat_mode/shell/commands/unrestricted.py,sha256=cVlQ0o-Zq0ll1ZMCq5TLm52fAee44TwwiRen0kN6hWU,1699
71
72
  janito/cli/chat_mode/shell/commands/utility.py,sha256=K982P-UwgPLzpEvSuSBGwiQ3zC34S_6T2ork_djweQw,847
72
73
  janito/cli/chat_mode/shell/commands/verbose.py,sha256=HDTe0NhdcjBuhh-eJSW8iLPDeeBO95K5iSDAMAljxa4,953
73
74
  janito/cli/chat_mode/shell/commands/write.py,sha256=bpvJzHY7wlpgsB-cpslzfQQl7h6n-NLqj2gFCuJfjVk,2309
@@ -88,7 +89,7 @@ janito/cli/cli_commands/model_selection.py,sha256=ANWtwC5glZkGMdaNtARDbEG3QmuBUc
88
89
  janito/cli/cli_commands/model_utils.py,sha256=PO64PW-TIlWyPY8CzYnI0y5Zp6ukV_NjaSj8CEXflV0,4889
89
90
  janito/cli/cli_commands/ping_providers.py,sha256=U3iTETPXDEGr3dqlJqNTPvpkhKo2KfXe_bN2_LGJtx0,2015
90
91
  janito/cli/cli_commands/set_api_key.py,sha256=ZItSuB0HO14UsbyXXCgTKAXS-EUCHfCkntzg3WAAtK0,1048
91
- janito/cli/cli_commands/show_config.py,sha256=eYMcuvU-d7mvvuctbQacZFERqcKHEnxaRRjasyj-_lE,2004
92
+ janito/cli/cli_commands/show_config.py,sha256=UnitVtjYqR0XR2viAFaeiODqkfUwJA5xdkqfQa7kr_0,3313
92
93
  janito/cli/cli_commands/show_system_prompt.py,sha256=YKOVHKzz6pzwvJGlqVEK2R4i98HGrUZHsrsFNvBBEd8,5898
93
94
  janito/cli/core/__init__.py,sha256=YH95fhgY9yBX8RgqX9dSrEkl4exjV0T4rbmJ6xUpG-Y,196
94
95
  janito/cli/core/event_logger.py,sha256=1X6lR0Ax7AgF8HlPWFoY5Ystuu7Bh4ooTo78vXzeGB0,2008
@@ -203,7 +204,7 @@ janito/tools/adapters/local/copy_file.py,sha256=SBJm19Ipe5dqRE1Mxl6JSrn4bNmfObVn
203
204
  janito/tools/adapters/local/create_directory.py,sha256=LxwqQEsnOrEphCIoaMRRx9P9bu0MzidP3Fc5q6letxc,2584
204
205
  janito/tools/adapters/local/create_file.py,sha256=Y3cSYg0nWt2HGPj0j4Ut25joSkecsXOcw3OUc28IZCg,3764
205
206
  janito/tools/adapters/local/delete_text_in_file.py,sha256=uEeedRxXAR7_CqUc_qhbEdM0OzRi_pgnP-iDjs2Zvjk,5087
206
- janito/tools/adapters/local/fetch_url.py,sha256=IhqAqT-htHJbCcPYs2ENDVCXpsiq63foDGC3XpgjJ9c,13010
207
+ janito/tools/adapters/local/fetch_url.py,sha256=dDcgyCBnUw5zG6gLEon0Mu4GfucUbK0tN9xtH6jBaIg,16296
207
208
  janito/tools/adapters/local/find_files.py,sha256=Zbag3aP34vc7ffJh8bOqAwXj3KiZhV--uzTVHtNb-fI,6250
208
209
  janito/tools/adapters/local/move_file.py,sha256=LMGm8bn3NNyIPJG4vrlO09smXQcgzA09EwoooZxkIA8,4695
209
210
  janito/tools/adapters/local/open_html_in_browser.py,sha256=XqICIwVx5vEE77gHkaNAC-bAeEEy0DBmDksATiL-sRY,2101
@@ -242,14 +243,14 @@ janito/tools/adapters/local/validate_file_syntax/ps1_validator.py,sha256=TeIkPt0
242
243
  janito/tools/adapters/local/validate_file_syntax/python_validator.py,sha256=BfCO_K18qy92m-2ZVvHsbEU5e11OPo1pO9Vz4G4616E,130
243
244
  janito/tools/adapters/local/validate_file_syntax/xml_validator.py,sha256=AijlsP_PgNuC8ZbGsC5vOTt3Jur76otQzkd_7qR0QFY,284
244
245
  janito/tools/adapters/local/validate_file_syntax/yaml_validator.py,sha256=TgyI0HRL6ug_gBcWEm5TGJJuA4E34ZXcIzMpAbv3oJs,155
245
- janito-2.25.0.dist-info/licenses/LICENSE,sha256=GSAKapQH5ZIGWlpQTA7v5YrfECyaxaohUb1vJX-qepw,1090
246
+ janito-2.27.0.dist-info/licenses/LICENSE,sha256=GSAKapQH5ZIGWlpQTA7v5YrfECyaxaohUb1vJX-qepw,1090
246
247
  janito-coder/pyproject.toml,sha256=HPJgGe6YJ4CV93YxD8DYw_A18F51MW-iqweCXLVFko4,12990
247
248
  janito-coder/janito_coder/__init__.py,sha256=QbCJXOHgiXXohtJeUc8frav8mee12ve-eUifpACndrY,198
248
249
  janito-coder/janito_coder/plugins/__init__.py,sha256=NdjMhAEu8FEnVxEkYAN-Cz17Cx2qbMq8dMZMOQwBc-k,844
249
250
  janito-coder/janito_coder/plugins/code_navigator.py,sha256=9f8mt713yXVjuM4RFXrR2Y1ibznOYOaLyeTqfnt2wvE,22101
250
251
  janito-coder/janito_coder/plugins/git_analyzer.py,sha256=DEF_6J8z1-_Fshl1RAesz5b-aYC2nhf7COla44FdntE,8398
251
- janito-2.25.0.dist-info/METADATA,sha256=X_UylJzTNb0sGEqnrrdksiRtfT_mmfzLN-Vru8Sq4VY,16365
252
- janito-2.25.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
253
- janito-2.25.0.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
254
- janito-2.25.0.dist-info/top_level.txt,sha256=rL2_EzEekHIjO_EteQ1nOywm0B9Ywb0ZeqSKtzZMGUc,20
255
- janito-2.25.0.dist-info/RECORD,,
252
+ janito-2.27.0.dist-info/METADATA,sha256=sFUAedoBtF62qhiKZeA36nQsGKqUp0Qjpy3kV1Us2P8,16875
253
+ janito-2.27.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
254
+ janito-2.27.0.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
255
+ janito-2.27.0.dist-info/top_level.txt,sha256=rL2_EzEekHIjO_EteQ1nOywm0B9Ywb0ZeqSKtzZMGUc,20
256
+ janito-2.27.0.dist-info/RECORD,,