janito 1.10.0__py3-none-any.whl → 1.11.1__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/__init__.py +1 -1
- janito/agent/conversation_api.py +178 -90
- janito/agent/conversation_ui.py +1 -1
- janito/agent/llm_conversation_history.py +12 -0
- janito/agent/templates/profiles/system_prompt_template_base.txt.j2 +19 -4
- janito/agent/tools/__init__.py +2 -0
- janito/agent/tools/create_directory.py +1 -1
- janito/agent/tools/create_file.py +1 -1
- janito/agent/tools/fetch_url.py +1 -1
- janito/agent/tools/find_files.py +26 -13
- janito/agent/tools/get_file_outline/core.py +1 -1
- janito/agent/tools/get_file_outline/python_outline.py +139 -95
- janito/agent/tools/get_lines.py +92 -63
- janito/agent/tools/move_file.py +58 -32
- janito/agent/tools/open_url.py +31 -0
- janito/agent/tools/python_command_runner.py +85 -86
- janito/agent/tools/python_file_runner.py +85 -86
- janito/agent/tools/python_stdin_runner.py +87 -88
- janito/agent/tools/remove_directory.py +1 -1
- janito/agent/tools/remove_file.py +1 -1
- janito/agent/tools/replace_file.py +2 -2
- janito/agent/tools/replace_text_in_file.py +193 -149
- janito/agent/tools/run_bash_command.py +1 -1
- janito/agent/tools/run_powershell_command.py +4 -0
- janito/agent/tools/search_text/__init__.py +1 -0
- janito/agent/tools/search_text/core.py +176 -0
- janito/agent/tools/search_text/match_lines.py +58 -0
- janito/agent/tools/search_text/pattern_utils.py +65 -0
- janito/agent/tools/search_text/traverse_directory.py +132 -0
- janito/agent/tools/validate_file_syntax/core.py +41 -30
- janito/agent/tools/validate_file_syntax/html_validator.py +21 -5
- janito/agent/tools/validate_file_syntax/markdown_validator.py +77 -34
- janito/agent/tools_utils/gitignore_utils.py +25 -2
- janito/agent/tools_utils/utils.py +7 -1
- janito/cli/config_commands.py +112 -109
- janito/shell/main.py +51 -8
- janito/shell/session/config.py +83 -75
- janito/shell/ui/interactive.py +97 -73
- janito/termweb/static/editor.css +32 -29
- janito/termweb/static/editor.css.bak +140 -22
- janito/termweb/static/editor.html +12 -7
- janito/termweb/static/editor.html.bak +16 -11
- janito/termweb/static/editor.js +94 -40
- janito/termweb/static/editor.js.bak +97 -65
- janito/termweb/static/index.html +1 -2
- janito/termweb/static/index.html.bak +1 -1
- janito/termweb/static/termweb.css +1 -22
- janito/termweb/static/termweb.css.bak +6 -4
- janito/termweb/static/termweb.js +0 -6
- janito/termweb/static/termweb.js.bak +1 -2
- {janito-1.10.0.dist-info → janito-1.11.1.dist-info}/METADATA +1 -1
- {janito-1.10.0.dist-info → janito-1.11.1.dist-info}/RECORD +56 -51
- {janito-1.10.0.dist-info → janito-1.11.1.dist-info}/WHEEL +1 -1
- janito/agent/tools/search_text.py +0 -254
- {janito-1.10.0.dist-info → janito-1.11.1.dist-info}/entry_points.txt +0 -0
- {janito-1.10.0.dist-info → janito-1.11.1.dist-info}/licenses/LICENSE +0 -0
- {janito-1.10.0.dist-info → janito-1.11.1.dist-info}/top_level.txt +0 -0
janito/cli/config_commands.py
CHANGED
@@ -4,12 +4,11 @@ from janito.agent.runtime_config import unified_config, runtime_config
|
|
4
4
|
from janito.agent.config_defaults import CONFIG_DEFAULTS
|
5
5
|
from rich import print
|
6
6
|
from ._utils import home_shorten
|
7
|
+
import os
|
8
|
+
from pathlib import Path
|
7
9
|
|
8
10
|
|
9
|
-
def
|
10
|
-
"""Handle --set-local-config, --set-global-config, --show-config. Exit if any are used."""
|
11
|
-
did_something = False
|
12
|
-
|
11
|
+
def handle_run_config(args):
|
13
12
|
if args.run_config:
|
14
13
|
for run_item in args.run_config:
|
15
14
|
try:
|
@@ -24,6 +23,11 @@ def handle_config_commands(args):
|
|
24
23
|
)
|
25
24
|
sys.exit(1)
|
26
25
|
runtime_config.set(key, val.strip())
|
26
|
+
return True
|
27
|
+
return False
|
28
|
+
|
29
|
+
|
30
|
+
def handle_set_local_config(args):
|
27
31
|
if args.set_local_config:
|
28
32
|
try:
|
29
33
|
key, val = args.set_local_config.split("=", 1)
|
@@ -40,8 +44,11 @@ def handle_config_commands(args):
|
|
40
44
|
local_config.save()
|
41
45
|
runtime_config.set(key, val.strip())
|
42
46
|
print(f"Local config updated: {key} = {val.strip()}")
|
43
|
-
|
47
|
+
return True
|
48
|
+
return False
|
49
|
+
|
44
50
|
|
51
|
+
def handle_set_global_config(args):
|
45
52
|
if args.set_global_config:
|
46
53
|
try:
|
47
54
|
key, val = args.set_global_config.split("=", 1)
|
@@ -65,129 +72,111 @@ def handle_config_commands(args):
|
|
65
72
|
del global_config._data[key]
|
66
73
|
runtime_config.set("template", template_dict)
|
67
74
|
print(f"Global config updated: template.{subkey} = {val.strip()}")
|
68
|
-
|
75
|
+
return True
|
69
76
|
else:
|
70
77
|
global_config.set(key, val.strip())
|
71
78
|
global_config.save()
|
72
79
|
runtime_config.set(key, val.strip())
|
73
80
|
print(f"Global config updated: {key} = {val.strip()}")
|
74
|
-
|
81
|
+
return True
|
82
|
+
return False
|
75
83
|
|
84
|
+
|
85
|
+
def handle_set_api_key(args):
|
76
86
|
if args.set_api_key:
|
77
|
-
# Merge: load full config, update api_key, save all
|
78
87
|
existing = dict(global_config.all())
|
79
88
|
existing["api_key"] = args.set_api_key.strip()
|
80
89
|
global_config._data = existing
|
81
90
|
global_config.save()
|
82
91
|
runtime_config.set("api_key", args.set_api_key.strip())
|
83
92
|
print("Global API key saved.")
|
84
|
-
|
93
|
+
return True
|
94
|
+
return False
|
95
|
+
|
85
96
|
|
97
|
+
def handle_show_config(args):
|
86
98
|
if args.show_config:
|
87
|
-
local_items =
|
88
|
-
global_items =
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
# Handle template as nested dict
|
98
|
-
for key in sorted(local_keys):
|
99
|
-
if key == "template":
|
100
|
-
template_dict = local_config.get("template", {})
|
101
|
-
if template_dict:
|
102
|
-
local_items["template"] = f"({len(template_dict)} keys set)"
|
103
|
-
for tkey, tval in template_dict.items():
|
104
|
-
local_items[f" template.{tkey}"] = tval
|
105
|
-
continue
|
106
|
-
if key.startswith("template."):
|
107
|
-
# Skip legacy flat keys
|
108
|
-
continue
|
109
|
-
if key == "api_key":
|
110
|
-
value = local_config.get("api_key")
|
111
|
-
value = (
|
112
|
-
value[:4] + "..." + value[-4:]
|
113
|
-
if value and len(value) > 8
|
114
|
-
else ("***" if value else None)
|
115
|
-
)
|
116
|
-
else:
|
117
|
-
value = unified_config.get(key)
|
118
|
-
local_items[key] = value
|
119
|
-
for key in sorted(global_keys - local_keys):
|
120
|
-
if key == "template":
|
121
|
-
template_dict = global_config.get("template", {})
|
122
|
-
if template_dict:
|
123
|
-
global_items["template"] = f"({len(template_dict)} keys set)"
|
124
|
-
for tkey, tval in template_dict.items():
|
125
|
-
global_items[f" template.{tkey}"] = tval
|
126
|
-
continue
|
127
|
-
if key.startswith("template."):
|
128
|
-
continue
|
129
|
-
if key == "api_key":
|
130
|
-
value = global_config.get("api_key")
|
131
|
-
value = (
|
132
|
-
value[:4] + "..." + value[-4:]
|
133
|
-
if value and len(value) > 8
|
134
|
-
else ("***" if value else None)
|
135
|
-
)
|
136
|
-
else:
|
137
|
-
value = unified_config.get(key)
|
138
|
-
global_items[key] = value
|
139
|
-
|
140
|
-
# Mask API key
|
141
|
-
for cfg in (local_items, global_items):
|
142
|
-
if "api_key" in cfg and cfg["api_key"]:
|
143
|
-
val = cfg["api_key"]
|
144
|
-
cfg["api_key"] = (
|
145
|
-
val[:4] + "..." + val[-4:] if len(val) > 8 else "***"
|
146
|
-
)
|
147
|
-
|
148
|
-
# Print local config
|
149
|
-
from ._print_config import print_config_items
|
150
|
-
|
151
|
-
print_config_items(
|
152
|
-
local_items, color_label="[cyan]🏠 Local Configuration[/cyan]"
|
153
|
-
)
|
99
|
+
local_items = _collect_config_items(local_config, unified_config, True)
|
100
|
+
global_items = _collect_config_items(
|
101
|
+
global_config, unified_config, False, set(local_items.keys())
|
102
|
+
)
|
103
|
+
_mask_api_keys(local_items)
|
104
|
+
_mask_api_keys(global_items)
|
105
|
+
_print_config_items(local_items, global_items)
|
106
|
+
_print_default_items(local_items, global_items)
|
107
|
+
return True
|
108
|
+
return False
|
154
109
|
|
155
|
-
|
156
|
-
|
157
|
-
|
110
|
+
|
111
|
+
def _collect_config_items(config, unified_config, is_local, exclude_keys=None):
|
112
|
+
items = {}
|
113
|
+
keys = set(config.all().keys())
|
114
|
+
if exclude_keys:
|
115
|
+
keys = keys - set(exclude_keys)
|
116
|
+
for key in sorted(keys):
|
117
|
+
if key == "template":
|
118
|
+
template_dict = config.get("template", {})
|
119
|
+
if template_dict:
|
120
|
+
items["template"] = f"({len(template_dict)} keys set)"
|
121
|
+
for tkey, tval in template_dict.items():
|
122
|
+
items[f" template.{tkey}"] = tval
|
123
|
+
continue
|
124
|
+
if key.startswith("template."):
|
125
|
+
continue
|
126
|
+
if key == "api_key":
|
127
|
+
value = config.get("api_key")
|
128
|
+
value = (
|
129
|
+
value[:4] + "..." + value[-4:]
|
130
|
+
if value and len(value) > 8
|
131
|
+
else ("***" if value else None)
|
158
132
|
)
|
133
|
+
else:
|
134
|
+
value = unified_config.get(key)
|
135
|
+
items[key] = value
|
136
|
+
return items
|
137
|
+
|
138
|
+
|
139
|
+
def _mask_api_keys(cfg):
|
140
|
+
if "api_key" in cfg and cfg["api_key"]:
|
141
|
+
val = cfg["api_key"]
|
142
|
+
cfg["api_key"] = val[:4] + "..." + val[-4:] if len(val) > 8 else "***"
|
159
143
|
|
160
|
-
# Show defaults for unset keys
|
161
|
-
shown_keys = set(local_items.keys()) | set(global_items.keys())
|
162
|
-
default_items = {
|
163
|
-
k: v
|
164
|
-
for k, v in CONFIG_DEFAULTS.items()
|
165
|
-
if k not in shown_keys and k != "api_key"
|
166
|
-
}
|
167
|
-
if default_items:
|
168
|
-
print("[green]🟢 Defaults (not set in config files)[/green]")
|
169
|
-
for key, value in default_items.items():
|
170
|
-
# Special case for system_prompt: show template file if None
|
171
|
-
if key == "system_prompt" and value is None:
|
172
|
-
from pathlib import Path
|
173
|
-
|
174
|
-
template_path = (
|
175
|
-
Path(__file__).parent
|
176
|
-
/ "agent"
|
177
|
-
/ "templates"
|
178
|
-
/ "system_prompt_template_default.j2"
|
179
|
-
)
|
180
|
-
print(
|
181
|
-
f"{key} = (default template path: {home_shorten(str(template_path))})"
|
182
|
-
)
|
183
|
-
else:
|
184
|
-
print(f"{key} = {value}")
|
185
|
-
print()
|
186
|
-
did_something = True
|
187
|
-
|
188
|
-
import os
|
189
|
-
from pathlib import Path
|
190
144
|
|
145
|
+
def _print_config_items(local_items, global_items):
|
146
|
+
from ._print_config import print_config_items
|
147
|
+
|
148
|
+
print_config_items(local_items, color_label="[cyan]🏠 Local Configuration[/cyan]")
|
149
|
+
print_config_items(
|
150
|
+
global_items, color_label="[yellow]🌐 Global Configuration[/yellow]"
|
151
|
+
)
|
152
|
+
|
153
|
+
|
154
|
+
def _print_default_items(local_items, global_items):
|
155
|
+
shown_keys = set(local_items.keys()) | set(global_items.keys())
|
156
|
+
default_items = {
|
157
|
+
k: v
|
158
|
+
for k, v in CONFIG_DEFAULTS.items()
|
159
|
+
if k not in shown_keys and k != "api_key"
|
160
|
+
}
|
161
|
+
if default_items:
|
162
|
+
print("[green]🟢 Defaults (not set in config files)[/green]")
|
163
|
+
for key, value in default_items.items():
|
164
|
+
if key == "system_prompt" and value is None:
|
165
|
+
template_path = (
|
166
|
+
Path(__file__).parent
|
167
|
+
/ "agent"
|
168
|
+
/ "templates"
|
169
|
+
/ "system_prompt_template_default.j2"
|
170
|
+
)
|
171
|
+
print(
|
172
|
+
f"{key} = (default template path: {home_shorten(str(template_path))})"
|
173
|
+
)
|
174
|
+
else:
|
175
|
+
print(f"{key} = {value}")
|
176
|
+
print()
|
177
|
+
|
178
|
+
|
179
|
+
def handle_config_reset_local(args):
|
191
180
|
if getattr(args, "config_reset_local", False):
|
192
181
|
local_path = Path(".janito/config.json")
|
193
182
|
if local_path.exists():
|
@@ -196,6 +185,9 @@ def handle_config_commands(args):
|
|
196
185
|
else:
|
197
186
|
print(f"Local config file does not exist: {local_path}")
|
198
187
|
sys.exit(0)
|
188
|
+
|
189
|
+
|
190
|
+
def handle_config_reset_global(args):
|
199
191
|
if getattr(args, "config_reset_global", False):
|
200
192
|
global_path = Path.home() / ".janito/config.json"
|
201
193
|
if global_path.exists():
|
@@ -204,5 +196,16 @@ def handle_config_commands(args):
|
|
204
196
|
else:
|
205
197
|
print(f"Global config file does not exist: {global_path}")
|
206
198
|
sys.exit(0)
|
199
|
+
|
200
|
+
|
201
|
+
def handle_config_commands(args):
|
202
|
+
did_something = False
|
203
|
+
did_something |= handle_run_config(args)
|
204
|
+
did_something |= handle_set_local_config(args)
|
205
|
+
did_something |= handle_set_global_config(args)
|
206
|
+
did_something |= handle_set_api_key(args)
|
207
|
+
did_something |= handle_show_config(args)
|
208
|
+
handle_config_reset_local(args)
|
209
|
+
handle_config_reset_global(args)
|
207
210
|
if did_something:
|
208
211
|
sys.exit(0)
|
janito/shell/main.py
CHANGED
@@ -158,6 +158,50 @@ def handle_prompt_loop(
|
|
158
158
|
save_conversation_history(conversation_history, session_id)
|
159
159
|
|
160
160
|
|
161
|
+
def handle_keyboard_interrupt(conversation_history, message_handler):
|
162
|
+
removed_count = 0
|
163
|
+
while (
|
164
|
+
conversation_history.last_message()
|
165
|
+
and conversation_history.last_message().get("role") != "assistant"
|
166
|
+
):
|
167
|
+
conversation_history.remove_last_message()
|
168
|
+
removed_count += 1
|
169
|
+
# Remove the assistant message itself, if present
|
170
|
+
if (
|
171
|
+
conversation_history.last_message()
|
172
|
+
and conversation_history.last_message().get("role") == "assistant"
|
173
|
+
):
|
174
|
+
conversation_history.remove_last_message()
|
175
|
+
removed_count += 1
|
176
|
+
message_handler.handle_message(
|
177
|
+
{
|
178
|
+
"type": "info",
|
179
|
+
"message": f"\nLast turn cleared due to interruption. Returning to prompt. (removed {removed_count} last msgs)\n",
|
180
|
+
}
|
181
|
+
)
|
182
|
+
|
183
|
+
|
184
|
+
def handle_chat_error(message_handler, error_type, error):
|
185
|
+
if error_type == "ProviderError":
|
186
|
+
message_handler.handle_message(
|
187
|
+
{"type": "error", "message": f"Provider error: {error}"}
|
188
|
+
)
|
189
|
+
elif error_type == "EmptyResponseError":
|
190
|
+
message_handler.handle_message({"type": "error", "message": f"Error: {error}"})
|
191
|
+
elif error_type == "ApiError":
|
192
|
+
message_handler.handle_message({"type": "error", "message": str(error)})
|
193
|
+
elif error_type == "Exception":
|
194
|
+
import traceback
|
195
|
+
|
196
|
+
tb = traceback.format_exc()
|
197
|
+
message_handler.handle_message(
|
198
|
+
{
|
199
|
+
"type": "error",
|
200
|
+
"message": f"Unexpected error: {error}\n{tb}\nReturning to prompt.",
|
201
|
+
}
|
202
|
+
)
|
203
|
+
|
204
|
+
|
161
205
|
def handle_chat(shell_state, profile_manager, agent, max_rounds, session_id):
|
162
206
|
conversation_history = shell_state.conversation_history
|
163
207
|
message_handler = RichMessageHandler()
|
@@ -171,20 +215,19 @@ def handle_chat(shell_state, profile_manager, agent, max_rounds, session_id):
|
|
171
215
|
spinner=True,
|
172
216
|
)
|
173
217
|
except KeyboardInterrupt:
|
174
|
-
message_handler
|
175
|
-
{"type": "info", "message": "Request interrupted. Returning to prompt."}
|
176
|
-
)
|
218
|
+
handle_keyboard_interrupt(conversation_history, message_handler)
|
177
219
|
return
|
178
220
|
except ProviderError as e:
|
179
|
-
message_handler
|
180
|
-
{"type": "error", "message": f"Provider error: {e}"}
|
181
|
-
)
|
221
|
+
handle_chat_error(message_handler, "ProviderError", e)
|
182
222
|
return
|
183
223
|
except EmptyResponseError as e:
|
184
|
-
message_handler
|
224
|
+
handle_chat_error(message_handler, "EmptyResponseError", e)
|
185
225
|
return
|
186
226
|
except ApiError as e:
|
187
|
-
message_handler
|
227
|
+
handle_chat_error(message_handler, "ApiError", e)
|
228
|
+
return
|
229
|
+
except Exception as e:
|
230
|
+
handle_chat_error(message_handler, "Exception", e)
|
188
231
|
return
|
189
232
|
shell_state.last_elapsed = time.time() - start_time
|
190
233
|
usage = response.get("usage")
|
janito/shell/session/config.py
CHANGED
@@ -12,90 +12,98 @@ def handle_config_shell(console, *args, **kwargs):
|
|
12
12
|
/config reset global
|
13
13
|
"""
|
14
14
|
if not args or args[0] not in ("show", "set", "reset"):
|
15
|
-
console
|
16
|
-
"[bold red]Usage:[/bold red] /config show | /config set local|global key=value | /config reset local|global"
|
17
|
-
)
|
15
|
+
_print_usage(console)
|
18
16
|
return
|
19
|
-
|
20
17
|
if args[0] == "show":
|
21
|
-
|
22
|
-
from janito.cli._print_config import print_full_config
|
23
|
-
|
24
|
-
print_full_config(
|
25
|
-
local_config,
|
26
|
-
global_config,
|
27
|
-
unified_config,
|
28
|
-
CONFIG_DEFAULTS,
|
29
|
-
console=console,
|
30
|
-
)
|
18
|
+
_show_config(console)
|
31
19
|
return
|
32
|
-
|
33
20
|
if args[0] == "reset":
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
21
|
+
_reset_config(console, args)
|
22
|
+
return
|
23
|
+
if args[0] == "set":
|
24
|
+
_set_config(console, args)
|
25
|
+
return
|
39
26
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
console.print(
|
62
|
-
"[bold yellow]Please use /restart for changes to take full effect.[/bold yellow]"
|
63
|
-
)
|
27
|
+
|
28
|
+
def _print_usage(console):
|
29
|
+
console.print(
|
30
|
+
"[bold red]Usage:[/bold red] /config show | /config set local|global key=value | /config reset local|global"
|
31
|
+
)
|
32
|
+
|
33
|
+
|
34
|
+
def _show_config(console):
|
35
|
+
from janito.cli._print_config import print_full_config
|
36
|
+
|
37
|
+
print_full_config(
|
38
|
+
local_config,
|
39
|
+
global_config,
|
40
|
+
unified_config,
|
41
|
+
CONFIG_DEFAULTS,
|
42
|
+
console=console,
|
43
|
+
)
|
44
|
+
|
45
|
+
|
46
|
+
def _reset_config(console, args):
|
47
|
+
if len(args) < 2 or args[1] not in ("local", "global"):
|
48
|
+
console.print("[bold red]Usage:[/bold red] /config reset local|global")
|
64
49
|
return
|
50
|
+
import os
|
51
|
+
from pathlib import Path
|
65
52
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
)
|
71
|
-
|
72
|
-
|
73
|
-
try:
|
74
|
-
key, val = args[2].split("=", 1)
|
75
|
-
except ValueError:
|
76
|
-
console.print("[bold red]Invalid format, expected key=val[/bold red]")
|
77
|
-
return
|
78
|
-
key = key.strip()
|
79
|
-
if key not in CONFIG_OPTIONS and not key.startswith("template."):
|
80
|
-
console.print(
|
81
|
-
f"[bold red]Invalid config key: '{key}'. Supported keys are: {', '.join(CONFIG_OPTIONS.keys())}"
|
82
|
-
)
|
83
|
-
return
|
84
|
-
val = val.strip()
|
85
|
-
if scope == "local":
|
86
|
-
local_config.set(key, val)
|
87
|
-
local_config.save()
|
88
|
-
runtime_config.set(key, val)
|
89
|
-
console.print(f"[green]Local config updated:[/green] {key} = {val}")
|
53
|
+
scope = args[1]
|
54
|
+
if scope == "local":
|
55
|
+
local_path = Path(".janito/config.json")
|
56
|
+
if local_path.exists():
|
57
|
+
os.remove(local_path)
|
58
|
+
console.print(f"[green]Removed local config file:[/green] {local_path}")
|
59
|
+
else:
|
90
60
|
console.print(
|
91
|
-
"[
|
61
|
+
f"[yellow]Local config file does not exist:[/yellow] {local_path}"
|
92
62
|
)
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
console.print(f"[green]
|
63
|
+
elif scope == "global":
|
64
|
+
global_path = Path.home() / ".janito/config.json"
|
65
|
+
if global_path.exists():
|
66
|
+
os.remove(global_path)
|
67
|
+
console.print(f"[green]Removed global config file:[/green] {global_path}")
|
68
|
+
else:
|
98
69
|
console.print(
|
99
|
-
"[
|
70
|
+
f"[yellow]Global config file does not exist:[/yellow] {global_path}"
|
100
71
|
)
|
72
|
+
console.print(
|
73
|
+
"[bold yellow]Please use /restart for changes to take full effect.[/bold yellow]"
|
74
|
+
)
|
75
|
+
|
76
|
+
|
77
|
+
def _set_config(console, args):
|
78
|
+
if len(args) < 3 or args[1] not in ("local", "global"):
|
79
|
+
console.print("[bold red]Usage:[/bold red] /config set local|global key=value")
|
101
80
|
return
|
81
|
+
scope = args[1]
|
82
|
+
try:
|
83
|
+
key, val = args[2].split("=", 1)
|
84
|
+
except ValueError:
|
85
|
+
console.print("[bold red]Invalid format, expected key=val[/bold red]")
|
86
|
+
return
|
87
|
+
key = key.strip()
|
88
|
+
if key not in CONFIG_OPTIONS and not key.startswith("template."):
|
89
|
+
console.print(
|
90
|
+
f"[bold red]Invalid config key: '{key}'. Supported keys are: {', '.join(CONFIG_OPTIONS.keys())}"
|
91
|
+
)
|
92
|
+
return
|
93
|
+
val = val.strip()
|
94
|
+
if scope == "local":
|
95
|
+
local_config.set(key, val)
|
96
|
+
local_config.save()
|
97
|
+
runtime_config.set(key, val)
|
98
|
+
console.print(f"[green]Local config updated:[/green] {key} = {val}")
|
99
|
+
console.print(
|
100
|
+
"[bold yellow]Please use /restart for changes to take full effect.[/bold yellow]"
|
101
|
+
)
|
102
|
+
elif scope == "global":
|
103
|
+
global_config.set(key, val)
|
104
|
+
global_config.save()
|
105
|
+
runtime_config.set(key, val)
|
106
|
+
console.print(f"[green]Global config updated:[/green] {key} = {val}")
|
107
|
+
console.print(
|
108
|
+
"[bold yellow]Please use /restart for changes to take full effect.[/bold yellow]"
|
109
|
+
)
|