janito 2.3.1__py3-none-any.whl → 2.5.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.
Files changed (107) hide show
  1. janito/__init__.py +1 -1
  2. janito/_version.py +57 -0
  3. janito/agent/setup_agent.py +95 -21
  4. janito/agent/templates/profiles/system_prompt_template_assistant.txt.j2 +1 -0
  5. janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +44 -0
  6. janito/cli/chat_mode/bindings.py +21 -2
  7. janito/cli/chat_mode/chat_entry.py +2 -3
  8. janito/cli/chat_mode/prompt_style.py +5 -0
  9. janito/cli/chat_mode/script_runner.py +153 -0
  10. janito/cli/chat_mode/session.py +128 -122
  11. janito/cli/chat_mode/session_profile_select.py +80 -0
  12. janito/cli/chat_mode/shell/commands/__init__.py +19 -9
  13. janito/cli/chat_mode/shell/commands/_priv_check.py +5 -0
  14. janito/cli/chat_mode/shell/commands/bang.py +36 -0
  15. janito/cli/chat_mode/shell/commands/conversation_restart.py +31 -24
  16. janito/cli/chat_mode/shell/commands/execute.py +42 -0
  17. janito/cli/chat_mode/shell/commands/help.py +7 -4
  18. janito/cli/chat_mode/shell/commands/model.py +28 -0
  19. janito/cli/chat_mode/shell/commands/prompt.py +0 -8
  20. janito/cli/chat_mode/shell/commands/read.py +37 -0
  21. janito/cli/chat_mode/shell/commands/tools.py +45 -18
  22. janito/cli/chat_mode/shell/commands/write.py +37 -0
  23. janito/cli/chat_mode/shell/commands.bak.zip +0 -0
  24. janito/cli/chat_mode/shell/input_history.py +1 -1
  25. janito/cli/chat_mode/shell/session/manager.py +0 -68
  26. janito/cli/chat_mode/shell/session.bak.zip +0 -0
  27. janito/cli/chat_mode/toolbar.py +44 -27
  28. janito/cli/cli_commands/list_tools.py +44 -11
  29. janito/cli/cli_commands/model_utils.py +95 -95
  30. janito/cli/cli_commands/show_system_prompt.py +57 -14
  31. janito/cli/config.py +5 -6
  32. janito/cli/core/getters.py +33 -33
  33. janito/cli/core/runner.py +27 -20
  34. janito/cli/core/setters.py +10 -1
  35. janito/cli/main_cli.py +40 -10
  36. janito/cli/prompt_core.py +18 -2
  37. janito/cli/prompt_setup.py +56 -0
  38. janito/cli/rich_terminal_reporter.py +21 -6
  39. janito/cli/single_shot_mode/handler.py +24 -77
  40. janito/cli/verbose_output.py +1 -1
  41. janito/config_manager.py +125 -112
  42. janito/drivers/dashscope.bak.zip +0 -0
  43. janito/drivers/driver_registry.py +0 -2
  44. janito/drivers/openai/README.md +20 -0
  45. janito/drivers/openai_responses.bak.zip +0 -0
  46. janito/event_bus/event.py +2 -2
  47. janito/formatting_token.py +7 -6
  48. janito/i18n/pt.py +0 -1
  49. janito/llm/README.md +23 -0
  50. janito/llm/agent.py +80 -16
  51. janito/llm/auth.py +63 -63
  52. janito/llm/driver.py +8 -0
  53. janito/provider_registry.py +178 -176
  54. janito/providers/__init__.py +0 -2
  55. janito/providers/azure_openai/model_info.py +16 -16
  56. janito/providers/dashscope.bak.zip +0 -0
  57. janito/providers/provider_static_info.py +0 -3
  58. janito/providers/registry.py +26 -26
  59. janito/shell.bak.zip +0 -0
  60. janito/tools/DOCSTRING_STANDARD.txt +33 -0
  61. janito/tools/README.md +3 -0
  62. janito/tools/__init__.py +20 -6
  63. janito/tools/adapters/local/__init__.py +65 -62
  64. janito/tools/adapters/local/adapter.py +18 -35
  65. janito/tools/adapters/local/ask_user.py +3 -4
  66. janito/tools/adapters/local/copy_file.py +2 -2
  67. janito/tools/adapters/local/create_directory.py +2 -2
  68. janito/tools/adapters/local/create_file.py +2 -2
  69. janito/tools/adapters/local/delete_text_in_file.py +2 -2
  70. janito/tools/adapters/local/fetch_url.py +2 -2
  71. janito/tools/adapters/local/find_files.py +2 -1
  72. janito/tools/adapters/local/get_file_outline/core.py +2 -2
  73. janito/tools/adapters/local/get_file_outline/search_outline.py +2 -2
  74. janito/tools/adapters/local/move_file.py +2 -2
  75. janito/tools/adapters/local/open_html_in_browser.py +2 -1
  76. janito/tools/adapters/local/open_url.py +2 -2
  77. janito/tools/adapters/local/python_code_run.py +3 -3
  78. janito/tools/adapters/local/python_command_run.py +3 -3
  79. janito/tools/adapters/local/python_file_run.py +3 -3
  80. janito/tools/adapters/local/remove_directory.py +2 -2
  81. janito/tools/adapters/local/remove_file.py +2 -2
  82. janito/tools/adapters/local/replace_text_in_file.py +2 -2
  83. janito/tools/adapters/local/run_bash_command.py +3 -3
  84. janito/tools/adapters/local/run_powershell_command.py +3 -3
  85. janito/tools/adapters/local/search_text/core.py +2 -2
  86. janito/tools/adapters/local/validate_file_syntax/core.py +3 -3
  87. janito/tools/adapters/local/view_file.py +2 -1
  88. janito/tools/outline_file.bak.zip +0 -0
  89. janito/tools/permissions.py +45 -0
  90. janito/tools/permissions_parse.py +12 -0
  91. janito/tools/tool_base.py +14 -11
  92. janito/tools/tool_utils.py +4 -6
  93. janito/tools/tools_adapter.py +25 -20
  94. {janito-2.3.1.dist-info → janito-2.5.0.dist-info}/METADATA +46 -24
  95. {janito-2.3.1.dist-info → janito-2.5.0.dist-info}/RECORD +99 -82
  96. janito/agent/templates/profiles/system_prompt_template_base_pt.txt.j2 +0 -13
  97. janito/agent/templates/profiles/system_prompt_template_main.txt.j2 +0 -37
  98. janito/cli/chat_mode/shell/commands/edit.py +0 -25
  99. janito/cli/chat_mode/shell/commands/exec.py +0 -27
  100. janito/cli/chat_mode/shell/commands/termweb_log.py +0 -92
  101. janito/cli/termweb_starter.py +0 -122
  102. janito/termweb/app.py +0 -95
  103. janito/version.py +0 -4
  104. {janito-2.3.1.dist-info → janito-2.5.0.dist-info}/WHEEL +0 -0
  105. {janito-2.3.1.dist-info → janito-2.5.0.dist-info}/entry_points.txt +0 -0
  106. {janito-2.3.1.dist-info → janito-2.5.0.dist-info}/licenses/LICENSE +0 -0
  107. {janito-2.3.1.dist-info → janito-2.5.0.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,8 @@ Session management for Janito Chat CLI.
3
3
  Defines ChatSession and ChatShellState classes.
4
4
  """
5
5
 
6
+ from __future__ import annotations
7
+
6
8
  import types
7
9
  from rich.console import Console
8
10
  from rich.rule import Rule
@@ -17,23 +19,22 @@ from janito.cli.chat_mode.bindings import KeyBindingsFactory
17
19
  from janito.cli.chat_mode.shell.commands import handle_command
18
20
  from janito.cli.chat_mode.shell.autocomplete import ShellCommandCompleter
19
21
 
22
+ # Shared prompt/agent factory
23
+ from janito.cli.prompt_setup import setup_agent_and_prompt_handler
24
+
20
25
 
21
26
  class ChatShellState:
22
27
  def __init__(self, mem_history, conversation_history):
23
- self.allow_execution = False # Controls whether execution tools are enabled
24
28
  self.mem_history = mem_history
25
29
  self.conversation_history = conversation_history
26
30
  self.paste_mode = False
27
- self.termweb_port = None
28
- self.termweb_pid = None
29
- self.termweb_stdout_path = None
30
- self.termweb_stderr_path = None
31
+ self._port = None
32
+ self._pid = None
33
+ self._stdout_path = None
34
+ self._stderr_path = None
31
35
  self.livereload_stderr_path = None
32
- self.termweb_status = "starting" # Tracks the current termweb status (updated by background thread/UI)
33
- self.termweb_live_status = (
34
- None # 'online', 'offline', updated by background checker
35
- )
36
- self.termweb_live_checked_time = None # datetime.datetime of last status check
36
+ self._status = "starting" # Tracks the current status (updated by background thread/UI)
37
+
37
38
  self.last_usage_info = {}
38
39
  self.last_elapsed = None
39
40
  self.main_agent = {}
@@ -53,25 +54,10 @@ class ChatSession:
53
54
  args=None,
54
55
  verbose_tools=False,
55
56
  verbose_agent=False,
56
- exec_enabled=False
57
+
58
+ allowed_permissions=None,
57
59
  ):
58
- # Set allow_execution from exec_enabled or args
59
- if args is not None and hasattr(args, "exec"):
60
- allow_execution = bool(getattr(args, "exec", False))
61
- else:
62
- allow_execution = exec_enabled
63
- from janito.cli.prompt_core import PromptHandler as GenericPromptHandler
64
-
65
- self._prompt_handler = GenericPromptHandler(
66
- args=None,
67
- conversation_history=(
68
- None
69
- if not hasattr(self, "shell_state")
70
- else self.shell_state.conversation_history
71
- ),
72
- provider_instance=provider_instance,
73
- )
74
- self._prompt_handler.agent = None # Will be set below if agent exists
60
+
75
61
  self.console = console
76
62
  self.user_input_history = UserInputHistory()
77
63
  self.input_dicts = self.user_input_history.load()
@@ -81,27 +67,54 @@ class ChatSession:
81
67
  self.mem_history.append_string(item["input"])
82
68
  self.provider_instance = provider_instance
83
69
  self.llm_driver_config = llm_driver_config
84
- from janito.agent.setup_agent import create_configured_agent
85
70
 
86
- agent = create_configured_agent(
71
+ # --- Profile selection (interactive) ---------------------------------
72
+ profile = getattr(args, "profile", None) if args is not None else None
73
+ profile_system_prompt = None
74
+ if profile is None:
75
+ try:
76
+ from janito.cli.chat_mode.session_profile_select import select_profile
77
+
78
+ result = select_profile()
79
+ if isinstance(result, dict):
80
+ profile = result.get("profile")
81
+ profile_system_prompt = result.get("profile_system_prompt")
82
+ elif isinstance(result, str) and result.startswith("role:"):
83
+ role = result[len("role:") :].strip()
84
+ profile = "developer"
85
+ else:
86
+ profile = (
87
+ "developer" if result == "software developer" else result
88
+ )
89
+ except ImportError:
90
+ profile = "helpful assistant"
91
+
92
+ # ---------------------------------------------------------------------
93
+ from janito.conversation_history import LLMConversationHistory
94
+
95
+ conversation_history = LLMConversationHistory()
96
+
97
+ # Build agent and core prompt handler via the shared helper
98
+ self.agent, self._prompt_handler = setup_agent_and_prompt_handler(
99
+ args=args,
87
100
  provider_instance=provider_instance,
88
101
  llm_driver_config=llm_driver_config,
89
102
  role=role,
90
103
  verbose_tools=verbose_tools,
91
104
  verbose_agent=verbose_agent,
92
- exec_enabled=allow_execution
105
+
106
+ allowed_permissions=allowed_permissions,
107
+ profile=profile,
108
+ profile_system_prompt=profile_system_prompt,
109
+ conversation_history=conversation_history,
93
110
  )
94
- from janito.conversation_history import LLMConversationHistory
95
111
 
96
- self.shell_state = ChatShellState(self.mem_history, LLMConversationHistory())
97
- self.shell_state.agent = agent
98
- self.shell_state.allow_execution = allow_execution
99
- self.agent = agent
112
+ self.shell_state = ChatShellState(self.mem_history, conversation_history)
113
+ self.shell_state.agent = self.agent
100
114
  # Filter execution tools at startup
101
115
  try:
102
- registry = getattr(__import__('janito.tools', fromlist=['get_local_tools_adapter']), 'get_local_tools_adapter')()
103
- if hasattr(registry, 'set_execution_tools_enabled'):
104
- registry.set_execution_tools_enabled(allow_execution)
116
+ # Permissions are now managed globally; registry filtering is automatic
117
+ getattr(__import__('janito.tools', fromlist=['get_local_tools_adapter']), 'get_local_tools_adapter')()
105
118
  except Exception as e:
106
119
  self.console.print(f"[yellow]Warning: Could not filter execution tools at startup: {e}[/yellow]")
107
120
  from janito.perf_singleton import performance_collector
@@ -114,76 +127,54 @@ class ChatSession:
114
127
  self.shell_state.conversation_history
115
128
  )
116
129
 
117
- # TERMWEB logic migrated from runner
118
- self.termweb_support = False
130
+ self._support = False
119
131
  if args and getattr(args, "web", False):
120
- self.termweb_support = True
121
- self.shell_state.termweb_support = self.termweb_support
122
- from janito.cli.termweb_starter import termweb_start_and_watch
123
- from janito.cli.config import get_termweb_port
132
+ self._support = True
133
+ self.shell_state._support = self._support
134
+ from janito.cli._starter import _start_and_watch
135
+ from janito.cli.config import get__port
124
136
  import threading
125
137
  from rich.console import Console
126
138
 
127
- Console().print("[yellow]Starting termweb in background...[/yellow]")
128
- self.termweb_lock = threading.Lock()
129
- termweb_thread = termweb_start_and_watch(
130
- self.shell_state, self.termweb_lock, get_termweb_port()
139
+ Console().print("[yellow]Starting in background...[/yellow]")
140
+ self._lock = threading.Lock()
141
+ _thread = _start_and_watch(
142
+ self.shell_state, self._lock, get__port()
131
143
  )
132
144
  # Initial status is set to 'starting' by constructor; the watcher will update
133
- self.termweb_thread = termweb_thread
145
+ self._thread = _thread
134
146
 
135
- # Start a background timer to update live termweb status (for UI responsiveness)
147
+ # Start a background timer to update live status (for UI responsiveness)
136
148
  import threading, datetime
137
149
 
138
- def update_termweb_liveness():
139
- while True:
140
- with self.termweb_lock:
141
- port = getattr(self.shell_state, "termweb_port", None)
142
- if port:
143
- try:
144
- # is_termweb_running is removed; inline health check here:
145
- try:
146
- import http.client
147
-
148
- conn = http.client.HTTPConnection(
149
- "localhost", port, timeout=0.5
150
- )
151
- conn.request("GET", "/")
152
- resp = conn.getresponse()
153
- running = resp.status == 200
154
- except Exception:
155
- running = False
156
- self.shell_state.termweb_live_status = (
157
- "online" if running else "offline"
158
- )
159
- except Exception:
160
- self.shell_state.termweb_live_status = "offline"
161
- self.shell_state.termweb_live_checked_time = (
162
- datetime.datetime.now()
163
- )
164
- else:
165
- self.shell_state.termweb_live_status = None
166
- self.shell_state.termweb_live_checked_time = (
167
- datetime.datetime.now()
168
- )
169
- # sleep outside lock
170
- threading.Event().wait(1.0)
171
-
172
- self._termweb_liveness_thread = threading.Thread(
173
- target=update_termweb_liveness, daemon=True
174
- )
175
- self._termweb_liveness_thread.start()
176
- # No queue or blocking checks; UI (and timer) will observe self.shell_state fields
150
+ # Health check and liveness thread removed as per refactor to eliminate localhost references.
177
151
 
178
152
  else:
179
- self.shell_state.termweb_support = False
180
- self.shell_state.termweb_status = "offline"
153
+ self.shell_state._support = False
154
+ self.shell_state._status = "offline"
181
155
 
182
156
  def run(self):
183
- session = self._create_prompt_session()
157
+ self.console.clear()
158
+ from janito import __version__
184
159
  self.console.print(
185
- "[bold green]Type /help for commands. Type /exit or press Ctrl+C to quit.[/bold green]"
160
+ f"[bold green]Janito Chat Mode v{__version__}[/bold green]"
186
161
  )
162
+ self.console.print("[green]/help for commands /exit or Ctrl+C to quit[/green]")
163
+ import os
164
+ cwd = os.getcwd()
165
+ home = os.path.expanduser('~')
166
+ if cwd.startswith(home):
167
+ cwd_display = '~' + cwd[len(home):]
168
+ else:
169
+ cwd_display = cwd
170
+ self.console.print(f"[green]Working Dir:[/green] {cwd_display}")
171
+
172
+ # Inform user if no privileges are enabled
173
+ from janito.cli.chat_mode.shell.commands._priv_check import user_has_any_privileges
174
+ if not user_has_any_privileges():
175
+ self.console.print("[yellow]Note: You currently have no privileges enabled. If you need to interact with files or the system, enable permissions using /read on, /write on, or /execute on.[/yellow]")
176
+
177
+ session = self._create_prompt_session()
187
178
  self._chat_loop(session)
188
179
 
189
180
  def _chat_loop(self, session):
@@ -199,40 +190,55 @@ class ChatSession:
199
190
  continue
200
191
  if self._handle_exit_conditions(cmd_input):
201
192
  break
202
- if cmd_input.startswith("/"):
203
- handle_command(cmd_input, shell_state=self.shell_state)
193
+ if self._handle_command_input(cmd_input):
204
194
  continue
205
195
  self.user_input_history.append(cmd_input)
206
- try:
207
- final_event = (
208
- self._prompt_handler.agent.last_event
209
- if hasattr(self._prompt_handler.agent, "last_event")
196
+ self._process_prompt(cmd_input)
197
+
198
+ def _handle_command_input(self, cmd_input):
199
+ if cmd_input.startswith("/"):
200
+ handle_command(cmd_input, shell_state=self.shell_state)
201
+ return True
202
+ if cmd_input.startswith("!"):
203
+ # Pass everything after ! to the bang handler
204
+ handle_command(f"! {cmd_input[1:]}", shell_state=self.shell_state)
205
+ return True
206
+ return False
207
+
208
+ def _process_prompt(self, cmd_input):
209
+ try:
210
+ import time
211
+ final_event = (
212
+ self._prompt_handler.agent.last_event
213
+ if hasattr(self._prompt_handler.agent, "last_event")
214
+ else None
215
+ )
216
+ start_time = time.time()
217
+ self._prompt_handler.run_prompt(cmd_input)
218
+ end_time = time.time()
219
+ elapsed = end_time - start_time
220
+ self.msg_count += 1
221
+ # After prompt, print the stat line using the shared core function
222
+ from janito.formatting_token import print_token_message_summary
223
+
224
+ usage = self.performance_collector.get_last_request_usage()
225
+ print_token_message_summary(self.console, self.msg_count, usage, elapsed=elapsed)
226
+ # Print exit reason if present in the final event
227
+ if final_event and hasattr(final_event, "metadata"):
228
+ exit_reason = (
229
+ final_event.metadata.get("exit_reason")
230
+ if hasattr(final_event, "metadata")
210
231
  else None
211
232
  )
212
- self._prompt_handler.run_prompt(cmd_input)
213
- self.msg_count += 1
214
- # After prompt, print the stat line using the shared core function
215
- from janito.formatting_token import print_token_message_summary
216
-
217
- usage = self.performance_collector.get_last_request_usage()
218
- print_token_message_summary(self.console, self.msg_count, usage)
219
- # Print exit reason if present in the final event
220
- if final_event and hasattr(final_event, "metadata"):
221
- exit_reason = (
222
- final_event.metadata.get("exit_reason")
223
- if hasattr(final_event, "metadata")
224
- else None
233
+ if exit_reason:
234
+ self.console.print(
235
+ f"[bold yellow]Exit reason: {exit_reason}[/bold yellow]"
225
236
  )
226
- if exit_reason:
227
- self.console.print(
228
- f"[bold yellow]Exit reason: {exit_reason}[/bold yellow]"
229
- )
230
-
231
- except Exception as exc:
232
- self.console.print(f"[red]Exception in agent: {exc}[/red]")
233
- import traceback
234
237
 
235
- self.console.print(traceback.format_exc())
238
+ except Exception as exc:
239
+ self.console.print(f"[red]Exception in agent: {exc}[/red]")
240
+ import traceback
241
+ self.console.print(traceback.format_exc())
236
242
 
237
243
  def _create_prompt_session(self):
238
244
  return PromptSession(
@@ -0,0 +1,80 @@
1
+ """
2
+ Profile selection logic for Janito Chat CLI using questionary.
3
+ """
4
+ import questionary
5
+ from questionary import Style
6
+
7
+ def select_profile():
8
+ choices = [
9
+ "helpful assistant",
10
+ "developer",
11
+ "using role...",
12
+ "full custom system prompt..."
13
+ ]
14
+ custom_style = Style([
15
+ ("highlighted", "bg:#00aaff #ffffff"), # background for item under cursor
16
+ ("question", "fg:#00aaff bold"),
17
+ ])
18
+ answer = questionary.select(
19
+ "Select a profile to use:",
20
+ choices=choices,
21
+ default=None,
22
+ style=custom_style
23
+ ).ask()
24
+ if answer == "helpful assistant":
25
+ return {"profile": "assistant", "profile_system_prompt": None}
26
+ if answer == "using role...":
27
+ role_name = questionary.text("Enter the role name:").ask()
28
+ return f"role:{role_name}"
29
+ elif answer == "full custom system prompt...":
30
+ from prompt_toolkit import PromptSession
31
+ from prompt_toolkit.key_binding import KeyBindings
32
+ from prompt_toolkit.enums import EditingMode
33
+ from prompt_toolkit.formatted_text import HTML
34
+ from .prompt_style import chat_shell_style
35
+
36
+ mode = {"multiline": False}
37
+ bindings = KeyBindings()
38
+
39
+ @bindings.add("c-r")
40
+ def _(event):
41
+ pass
42
+
43
+ @bindings.add("f12")
44
+ def _(event):
45
+ buf = event.app.current_buffer
46
+ buf.text = "Do It"
47
+ buf.validate_and_handle()
48
+
49
+ def get_toolbar():
50
+ if mode["multiline"]:
51
+ return HTML("<b>Multiline mode (Esc+Enter to submit). Type /single to switch.</b>")
52
+ else:
53
+ return HTML("<b>Single-line mode (Enter to submit). Type /multi for multiline.</b>")
54
+
55
+ session = PromptSession(
56
+ multiline=False,
57
+ key_bindings=bindings,
58
+ editing_mode=EditingMode.EMACS,
59
+ bottom_toolbar=get_toolbar,
60
+ style=chat_shell_style,
61
+ )
62
+ prompt_icon = HTML("<inputline>📝 </inputline>")
63
+ while True:
64
+ response = session.prompt(prompt_icon)
65
+ if not mode["multiline"] and response.strip() == "/multi":
66
+ mode["multiline"] = True
67
+ session.multiline = True
68
+ continue
69
+ elif mode["multiline"] and response.strip() == "/single":
70
+ mode["multiline"] = False
71
+ session.multiline = False
72
+ continue
73
+ else:
74
+ sanitized = response.strip()
75
+ try:
76
+ sanitized.encode("utf-8")
77
+ except UnicodeEncodeError:
78
+ sanitized = sanitized.encode("utf-8", errors="replace").decode("utf-8")
79
+ return {"profile": None, "profile_system_prompt": sanitized}
80
+ return answer
@@ -1,21 +1,30 @@
1
1
  from .base import ShellCmdHandler
2
- from .edit import EditShellHandler
3
2
  from .history_view import ViewShellHandler
4
3
  from .lang import LangShellHandler
5
4
  from .livelogs import LivelogsShellHandler
6
- from .prompt import PromptShellHandler, RoleShellHandler, ProfileShellHandler
5
+ from .prompt import PromptShellHandler, RoleShellHandler
7
6
  from .multi import MultiShellHandler
7
+ from .model import ModelShellHandler
8
8
  from .role import RoleCommandShellHandler
9
9
  from .session import HistoryShellHandler
10
- from .termweb_log import TermwebLogTailShellHandler
11
10
  from .tools import ToolsShellHandler
12
11
  from .help import HelpShellHandler
13
12
  from janito.cli.console import shared_console
14
13
 
15
14
  COMMAND_HANDLERS = {
16
- "/exec": __import__(
17
- "janito.cli.chat_mode.shell.commands.exec", fromlist=["ExecShellHandler"]
18
- ).ExecShellHandler,
15
+ # Bang handler for shell commands
16
+ "!": __import__(
17
+ "janito.cli.chat_mode.shell.commands.bang", fromlist=["BangShellHandler"]
18
+ ).BangShellHandler,
19
+ "/execute": __import__(
20
+ "janito.cli.chat_mode.shell.commands.execute", fromlist=["ExecuteShellHandler"]
21
+ ).ExecuteShellHandler,
22
+ "/read": __import__(
23
+ "janito.cli.chat_mode.shell.commands.read", fromlist=["ReadShellHandler"]
24
+ ).ReadShellHandler,
25
+ "/write": __import__(
26
+ "janito.cli.chat_mode.shell.commands.write", fromlist=["WriteShellHandler"]
27
+ ).WriteShellHandler,
19
28
  "/clear": __import__(
20
29
  "janito.cli.chat_mode.shell.commands.clear", fromlist=["ClearShellHandler"]
21
30
  ).ClearShellHandler,
@@ -23,16 +32,17 @@ COMMAND_HANDLERS = {
23
32
  "janito.cli.chat_mode.shell.commands.conversation_restart",
24
33
  fromlist=["RestartShellHandler"],
25
34
  ).RestartShellHandler,
26
- "/edit": EditShellHandler,
35
+
27
36
  "/view": ViewShellHandler,
28
37
  "/lang": LangShellHandler,
29
38
  "/livelogs": LivelogsShellHandler,
30
39
  "/prompt": PromptShellHandler,
31
40
  "/role": RoleShellHandler,
32
- "/profile": ProfileShellHandler,
41
+
33
42
  "/history": HistoryShellHandler,
34
- "/termweb-logs": TermwebLogTailShellHandler,
43
+
35
44
  "/tools": ToolsShellHandler,
45
+ "/model": ModelShellHandler,
36
46
  "/multi": MultiShellHandler,
37
47
  "/help": HelpShellHandler,
38
48
  }
@@ -0,0 +1,5 @@
1
+ from janito.tools.permissions import get_global_allowed_permissions
2
+
3
+ def user_has_any_privileges():
4
+ perms = get_global_allowed_permissions()
5
+ return perms.read or perms.write or perms.execute
@@ -0,0 +1,36 @@
1
+ from janito.cli.console import shared_console
2
+ from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
3
+ from janito.platform_discovery import PlatformDiscovery
4
+ import subprocess
5
+ import sys
6
+
7
+ class BangShellHandler(ShellCmdHandler):
8
+ help_text = "!<cmd>: Run a shell command in the underlying shell (PowerShell or Bash). Usage: !ls -al or !Get-Process. Use ! with no command to launch an interactive shell."
9
+
10
+ def run(self):
11
+ if not self.shell_state:
12
+ shared_console.print("[red]Shell state unavailable.[/red]")
13
+ return
14
+ cmd = (self.after_cmd_line or "").strip()
15
+ if not cmd:
16
+ pd = PlatformDiscovery()
17
+ if pd.is_windows():
18
+ shared_console.print("[yellow]Launching interactive PowerShell. Type 'exit' to return.[/yellow]")
19
+ subprocess.run(["powershell.exe"], check=False)
20
+ else:
21
+ shared_console.print("[yellow]Launching interactive Bash shell. Type 'exit' to return.[/yellow]")
22
+ subprocess.run(["bash"], check=False)
23
+ return
24
+ pd = PlatformDiscovery()
25
+ if pd.is_windows():
26
+ shared_console.print(f"[cyan]Running in PowerShell:[/cyan] {cmd}")
27
+ completed = subprocess.run(["powershell.exe", "-Command", cmd], capture_output=True, text=True)
28
+ else:
29
+ shared_console.print(f"[cyan]Running in Bash:[/cyan] {cmd}")
30
+ completed = subprocess.run(cmd, shell=True, capture_output=True, text=True)
31
+ output = completed.stdout
32
+ error = completed.stderr
33
+ if output:
34
+ shared_console.print(output)
35
+ if error:
36
+ shared_console.print(f"[red]{error}[/red]")
@@ -5,31 +5,8 @@ from janito.cli.console import shared_console
5
5
 
6
6
 
7
7
  def handle_restart(shell_state=None):
8
- from janito.cli.chat_mode.shell.session.manager import (
9
- load_last_conversation,
10
- save_conversation,
11
- )
12
-
13
8
  reset_session_id()
14
- save_path = os.path.join(".janito", "last_conversation.json")
15
-
16
- # --- Append end-of-conversation message to old history if it exists and is non-trivial ---
17
- if os.path.exists(save_path):
18
- try:
19
- messages, prompts, usage = load_last_conversation(save_path)
20
- if messages and (
21
- len(messages) > 1
22
- or (len(messages) == 1 and messages[0].get("role") != "system")
23
- ):
24
- messages.append(
25
- {"role": "system", "content": "[Session ended by user]"}
26
- )
27
- # Save to permanent chat history (let save_conversation pick session file)
28
- save_conversation(messages, prompts, usage)
29
- except Exception as e:
30
- shared_console.print(
31
- f"[bold red]Failed to update previous conversation history:[/bold red] {e}"
32
- )
9
+ # Conversation history is no longer saved or loaded.
33
10
 
34
11
  # Clear the terminal screen
35
12
  shared_console.clear()
@@ -37,6 +14,12 @@ def handle_restart(shell_state=None):
37
14
  # Reset conversation history using the agent's method
38
15
  if hasattr(shell_state, "agent") and shell_state.agent:
39
16
  shell_state.agent.reset_conversation_history()
17
+ # Reset system prompt to original template context if available
18
+ if hasattr(shell_state.agent, "_original_template_vars"):
19
+ shell_state.agent._template_vars = shell_state.agent._original_template_vars.copy()
20
+ if hasattr(shell_state.agent, "_refresh_system_prompt_from_template"):
21
+ shell_state.agent._refresh_system_prompt_from_template()
22
+ # No need to print the system prompt after restart
40
23
 
41
24
  # Reset tool use tracker
42
25
  try:
@@ -63,6 +46,30 @@ def handle_restart(shell_state=None):
63
46
  f"[bold yellow]Warning: Failed to reset PerformanceCollector token info:[/bold yellow] {e}"
64
47
  )
65
48
 
49
+ # Restore tool permissions to the CLI default on restart
50
+ try:
51
+ from janito.tools.permissions import set_global_allowed_permissions, get_default_allowed_permissions
52
+ import janito.tools
53
+ default_perms = get_default_allowed_permissions()
54
+ if default_perms is not None:
55
+ set_global_allowed_permissions(default_perms)
56
+ janito.tools.local_tools_adapter.set_allowed_permissions(default_perms)
57
+ msg = None
58
+
59
+ else:
60
+ from janito.tools.tool_base import ToolPermissions
61
+ set_global_allowed_permissions(ToolPermissions(read=False, write=False, execute=False))
62
+ janito.tools.local_tools_adapter.set_allowed_permissions(ToolPermissions(read=False, write=False, execute=False))
63
+ msg = "[green]All tool permissions have been set to OFF (read, write, execute = False).[/green]"
64
+ # Refresh system prompt to reflect new permissions
65
+ if hasattr(shell_state, "agent") and shell_state.agent and hasattr(shell_state.agent, "_refresh_system_prompt_from_template"):
66
+ shell_state.agent._refresh_system_prompt_from_template()
67
+ if msg:
68
+ shared_console.print(msg)
69
+
70
+ except Exception as e:
71
+ shared_console.print(f"[yellow]Warning: Failed to restore tool permissions: {e}[/yellow]")
72
+
66
73
  shared_console.print(
67
74
  "[bold green]Conversation history has been started (context reset).[/bold green]"
68
75
  )
@@ -0,0 +1,42 @@
1
+ from janito.cli.console import shared_console
2
+ from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
3
+
4
+ class ExecuteShellHandler(ShellCmdHandler):
5
+ help_text = "/execute on|off: Enable or disable code and command execution tools. Usage: /execute on or /execute off."
6
+
7
+ def run(self):
8
+ if not self.shell_state:
9
+ shared_console.print("[red]Shell state unavailable.[/red]")
10
+ return
11
+ arg = (self.after_cmd_line or "").strip().lower()
12
+ if arg not in ("on", "off"):
13
+ shared_console.print("[yellow]Usage: /execute on|off[/yellow]")
14
+ return
15
+ enable = arg == "on"
16
+ # Dynamically enable/disable execution tools in the registry
17
+ try:
18
+ from janito.tools.permissions import set_global_allowed_permissions, get_global_allowed_permissions
19
+ from janito.tools.tool_base import ToolPermissions
20
+ current_perms = get_global_allowed_permissions()
21
+ new_perms = ToolPermissions(
22
+ read=getattr(current_perms, 'read', False),
23
+ write=getattr(current_perms, 'write', False),
24
+ execute=enable
25
+ )
26
+ set_global_allowed_permissions(new_perms)
27
+ # Also update the singleton tools registry permissions
28
+ import janito.tools
29
+ janito.tools.local_tools_adapter.set_allowed_permissions(new_perms)
30
+
31
+ except Exception as e:
32
+ shared_console.print(f"[yellow]Warning: Could not update execution tools dynamically: {e}[/yellow]")
33
+ # Refresh system prompt if agent is available
34
+ agent = getattr(self.shell_state, "agent", None)
35
+ if agent:
36
+ if hasattr(agent, "_refresh_system_prompt_from_template"):
37
+ agent._refresh_system_prompt_from_template()
38
+ # No need to print the system prompt after permission change
39
+ if enable:
40
+ shared_console.print("[green]Execution tools ENABLED. Tools can now execute code and commands.[/green]")
41
+ else:
42
+ shared_console.print("[yellow]Execution tools DISABLED. Tools cannot run code or commands.[/yellow]")
@@ -1,16 +1,19 @@
1
1
  from janito.cli.chat_mode.shell.commands.base import ShellCmdHandler
2
2
  from janito.cli.console import shared_console
3
-
3
+ import os
4
4
 
5
5
  class HelpShellHandler(ShellCmdHandler):
6
6
  help_text = "Show this help message"
7
7
 
8
8
  def run(self):
9
- from . import (
10
- COMMAND_HANDLERS,
11
- ) # Import moved inside method to avoid circular import
9
+ from . import COMMAND_HANDLERS
10
+ from ._priv_check import user_has_any_privileges
12
11
 
13
12
  shared_console.print("[bold magenta]Available commands:[/bold magenta]")
14
13
  for cmd, handler_cls in sorted(COMMAND_HANDLERS.items()):
15
14
  help_text = getattr(handler_cls, "help_text", "")
16
15
  shared_console.print(f"[cyan]{cmd}[/cyan]: {help_text}")
16
+
17
+ # After help, print privilege info if user has no privileges
18
+ if not user_has_any_privileges():
19
+ shared_console.print("[yellow]Note: You currently have no privileges enabled. If you need to interact with files or the system, enable permissions using /read on, /write on, or /execute on.[/yellow]")