janito 2.3.1__py3-none-any.whl → 2.4.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/__init__.py +1 -1
- janito/_version.py +57 -0
- janito/agent/setup_agent.py +92 -18
- janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +44 -0
- janito/cli/chat_mode/bindings.py +21 -2
- janito/cli/chat_mode/chat_entry.py +2 -3
- janito/cli/chat_mode/prompt_style.py +5 -0
- janito/cli/chat_mode/session.py +80 -94
- janito/cli/chat_mode/session_profile_select.py +80 -0
- janito/cli/chat_mode/shell/commands/__init__.py +13 -7
- janito/cli/chat_mode/shell/commands/_priv_check.py +5 -0
- janito/cli/chat_mode/shell/commands/conversation_restart.py +30 -0
- janito/cli/chat_mode/shell/commands/execute.py +42 -0
- janito/cli/chat_mode/shell/commands/help.py +6 -3
- janito/cli/chat_mode/shell/commands/model.py +28 -0
- janito/cli/chat_mode/shell/commands/read.py +37 -0
- janito/cli/chat_mode/shell/commands/tools.py +45 -18
- janito/cli/chat_mode/shell/commands/write.py +37 -0
- janito/cli/chat_mode/shell/commands.bak.zip +0 -0
- janito/cli/chat_mode/shell/session.bak.zip +0 -0
- janito/cli/chat_mode/toolbar.py +44 -27
- janito/cli/cli_commands/list_tools.py +44 -11
- janito/cli/cli_commands/model_utils.py +95 -95
- janito/cli/cli_commands/show_system_prompt.py +57 -14
- janito/cli/config.py +5 -6
- janito/cli/core/getters.py +33 -33
- janito/cli/core/runner.py +25 -18
- janito/cli/core/setters.py +10 -1
- janito/cli/main_cli.py +28 -5
- janito/cli/prompt_core.py +18 -2
- janito/cli/prompt_setup.py +56 -0
- janito/cli/single_shot_mode/handler.py +14 -73
- janito/cli/verbose_output.py +1 -1
- janito/config_manager.py +125 -112
- janito/drivers/dashscope.bak.zip +0 -0
- janito/drivers/openai/README.md +20 -0
- janito/drivers/openai_responses.bak.zip +0 -0
- janito/event_bus/event.py +2 -2
- janito/i18n/pt.py +0 -1
- janito/llm/README.md +23 -0
- janito/llm/agent.py +80 -16
- janito/llm/auth.py +63 -63
- janito/llm/driver.py +8 -0
- janito/provider_registry.py +178 -176
- janito/providers/azure_openai/model_info.py +16 -16
- janito/providers/dashscope.bak.zip +0 -0
- janito/providers/registry.py +26 -26
- janito/shell.bak.zip +0 -0
- janito/tools/DOCSTRING_STANDARD.txt +33 -0
- janito/tools/README.md +3 -0
- janito/tools/__init__.py +20 -6
- janito/tools/adapters/local/__init__.py +65 -62
- janito/tools/adapters/local/adapter.py +18 -35
- janito/tools/adapters/local/ask_user.py +3 -4
- janito/tools/adapters/local/copy_file.py +2 -2
- janito/tools/adapters/local/create_directory.py +2 -2
- janito/tools/adapters/local/create_file.py +2 -2
- janito/tools/adapters/local/delete_text_in_file.py +2 -2
- janito/tools/adapters/local/fetch_url.py +2 -2
- janito/tools/adapters/local/find_files.py +2 -1
- janito/tools/adapters/local/get_file_outline/core.py +2 -2
- janito/tools/adapters/local/get_file_outline/search_outline.py +2 -2
- janito/tools/adapters/local/move_file.py +2 -2
- janito/tools/adapters/local/open_html_in_browser.py +2 -1
- janito/tools/adapters/local/open_url.py +2 -2
- janito/tools/adapters/local/python_code_run.py +3 -3
- janito/tools/adapters/local/python_command_run.py +3 -3
- janito/tools/adapters/local/python_file_run.py +3 -3
- janito/tools/adapters/local/remove_directory.py +2 -2
- janito/tools/adapters/local/remove_file.py +2 -2
- janito/tools/adapters/local/replace_text_in_file.py +2 -2
- janito/tools/adapters/local/run_bash_command.py +3 -3
- janito/tools/adapters/local/run_powershell_command.py +3 -3
- janito/tools/adapters/local/search_text/core.py +2 -2
- janito/tools/adapters/local/validate_file_syntax/core.py +2 -2
- janito/tools/adapters/local/view_file.py +2 -1
- janito/tools/outline_file.bak.zip +0 -0
- janito/tools/permissions.py +45 -0
- janito/tools/permissions_parse.py +12 -0
- janito/tools/tool_base.py +14 -1
- janito/tools/tool_utils.py +4 -6
- janito/tools/tools_adapter.py +25 -20
- {janito-2.3.1.dist-info → janito-2.4.0.dist-info}/METADATA +51 -16
- {janito-2.3.1.dist-info → janito-2.4.0.dist-info}/RECORD +88 -74
- janito/agent/templates/profiles/system_prompt_template_base_pt.txt.j2 +0 -13
- janito/agent/templates/profiles/system_prompt_template_main.txt.j2 +0 -37
- janito/cli/chat_mode/shell/commands/edit.py +0 -25
- janito/cli/chat_mode/shell/commands/exec.py +0 -27
- janito/cli/chat_mode/shell/commands/termweb_log.py +0 -92
- janito/cli/termweb_starter.py +0 -122
- janito/termweb/app.py +0 -95
- janito/version.py +0 -4
- {janito-2.3.1.dist-info → janito-2.4.0.dist-info}/WHEEL +0 -0
- {janito-2.3.1.dist-info → janito-2.4.0.dist-info}/entry_points.txt +0 -0
- {janito-2.3.1.dist-info → janito-2.4.0.dist-info}/licenses/LICENSE +0 -0
- {janito-2.3.1.dist-info → janito-2.4.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
import os
|
2
2
|
from janito.i18n import tr
|
3
|
-
from janito.tools.tool_base import ToolBase
|
3
|
+
from janito.tools.tool_base import ToolBase, ToolPermissions
|
4
4
|
from janito.report_events import ReportAction
|
5
5
|
from janito.tools.adapters.local.adapter import register_local_tool
|
6
6
|
from janito.tools.tool_utils import display_path
|
@@ -82,7 +82,7 @@ class ValidateFileSyntaxTool(ToolBase):
|
|
82
82
|
- "⚠️ Warning: Syntax error: <error message>"
|
83
83
|
- "⚠️ Warning: Unsupported file extension: <ext>"
|
84
84
|
"""
|
85
|
-
|
85
|
+
permissions = ToolPermissions(read=True)
|
86
86
|
tool_name = "validate_file_syntax"
|
87
87
|
|
88
88
|
def run(self, file_path: str) -> str:
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from janito.tools.tool_base import ToolBase
|
1
|
+
from janito.tools.tool_base import ToolBase, ToolPermissions
|
2
2
|
from janito.report_events import ReportAction
|
3
3
|
from janito.tools.adapters.local.adapter import register_local_tool
|
4
4
|
from janito.tools.tool_utils import pluralize
|
@@ -25,6 +25,7 @@ class ViewFileTool(ToolBase):
|
|
25
25
|
- "❗ not found"
|
26
26
|
"""
|
27
27
|
|
28
|
+
permissions = ToolPermissions(read=True)
|
28
29
|
tool_name = "view_file"
|
29
30
|
|
30
31
|
def run(self, file_path: str, from_line: int = None, to_line: int = None) -> str:
|
Binary file
|
@@ -0,0 +1,45 @@
|
|
1
|
+
from janito.tools.tool_base import ToolPermissions
|
2
|
+
|
3
|
+
class AllowedPermissionsState:
|
4
|
+
_instance = None
|
5
|
+
_permissions = ToolPermissions(read=False, write=False, execute=False)
|
6
|
+
_default_permissions = None
|
7
|
+
|
8
|
+
def __new__(cls):
|
9
|
+
if cls._instance is None:
|
10
|
+
cls._instance = super().__new__(cls)
|
11
|
+
return cls._instance
|
12
|
+
|
13
|
+
@classmethod
|
14
|
+
def get_permissions(cls):
|
15
|
+
return cls._permissions
|
16
|
+
|
17
|
+
@classmethod
|
18
|
+
def set_permissions(cls, permissions):
|
19
|
+
if not isinstance(permissions, ToolPermissions):
|
20
|
+
raise ValueError("permissions must be a ToolPermissions instance")
|
21
|
+
cls._permissions = permissions
|
22
|
+
|
23
|
+
@classmethod
|
24
|
+
def set_default_permissions(cls, permissions):
|
25
|
+
if not isinstance(permissions, ToolPermissions):
|
26
|
+
raise ValueError("permissions must be a ToolPermissions instance")
|
27
|
+
cls._default_permissions = permissions
|
28
|
+
|
29
|
+
@classmethod
|
30
|
+
def get_default_permissions(cls):
|
31
|
+
return cls._default_permissions
|
32
|
+
|
33
|
+
# Convenience functions
|
34
|
+
|
35
|
+
def get_global_allowed_permissions():
|
36
|
+
return AllowedPermissionsState.get_permissions()
|
37
|
+
|
38
|
+
def set_global_allowed_permissions(permissions):
|
39
|
+
AllowedPermissionsState.set_permissions(permissions)
|
40
|
+
|
41
|
+
def set_default_allowed_permissions(permissions):
|
42
|
+
AllowedPermissionsState.set_default_permissions(permissions)
|
43
|
+
|
44
|
+
def get_default_allowed_permissions():
|
45
|
+
return AllowedPermissionsState.get_default_permissions()
|
@@ -0,0 +1,12 @@
|
|
1
|
+
from janito.tools.tool_base import ToolPermissions
|
2
|
+
|
3
|
+
def parse_permissions_string(perm_str: str) -> ToolPermissions:
|
4
|
+
"""
|
5
|
+
Parse a string like 'rwx', 'rw', 'r', etc. into a ToolPermissions object.
|
6
|
+
"""
|
7
|
+
perm_str = perm_str.lower()
|
8
|
+
return ToolPermissions(
|
9
|
+
read='r' in perm_str,
|
10
|
+
write='w' in perm_str,
|
11
|
+
execute='x' in perm_str,
|
12
|
+
)
|
janito/tools/tool_base.py
CHANGED
@@ -2,14 +2,27 @@ from janito.report_events import ReportEvent, ReportSubtype, ReportAction
|
|
2
2
|
from janito.event_bus.bus import event_bus as default_event_bus
|
3
3
|
|
4
4
|
|
5
|
+
from collections import namedtuple
|
6
|
+
|
7
|
+
class ToolPermissions(namedtuple('ToolPermissions', ['read', 'write', 'execute'])):
|
8
|
+
__slots__ = ()
|
9
|
+
def __new__(cls, read=False, write=False, execute=False):
|
10
|
+
return super().__new__(cls, read, write, execute)
|
11
|
+
|
12
|
+
def __repr__(self):
|
13
|
+
return f"ToolPermissions(read={self.read}, write={self.write}, execute={self.execute})"
|
14
|
+
|
15
|
+
|
5
16
|
class ToolBase:
|
6
17
|
"""
|
7
18
|
Base class for all tools in the janito project.
|
8
19
|
Extend this class to implement specific tool functionality.
|
9
20
|
"""
|
10
|
-
|
21
|
+
permissions: 'ToolPermissions' = None # Required: must be set by subclasses
|
11
22
|
|
12
23
|
def __init__(self, name=None, event_bus=None):
|
24
|
+
if self.permissions is None or not isinstance(self.permissions, ToolPermissions):
|
25
|
+
raise ValueError(f"Tool '{self.__class__.__name__}' must define a 'permissions' attribute of type ToolPermissions.")
|
13
26
|
self.name = name or self.__class__.__name__
|
14
27
|
self._event_bus = event_bus or default_event_bus
|
15
28
|
|
janito/tools/tool_utils.py
CHANGED
@@ -20,9 +20,8 @@ def display_path(path):
|
|
20
20
|
Returns:
|
21
21
|
str: Display path, as an ANSI hyperlink.
|
22
22
|
"""
|
23
|
-
|
24
|
-
|
25
|
-
port = get_termweb_port()
|
23
|
+
|
24
|
+
port = 8088
|
26
25
|
if os.path.isabs(path):
|
27
26
|
cwd = os.path.abspath(os.getcwd())
|
28
27
|
abs_path = os.path.abspath(path)
|
@@ -33,9 +32,8 @@ def display_path(path):
|
|
33
32
|
disp = path
|
34
33
|
else:
|
35
34
|
disp = os.path.relpath(path)
|
36
|
-
|
37
|
-
|
38
|
-
return f"[link={url}]{disp}[/link]"
|
35
|
+
# URL injection removed; just return display path
|
36
|
+
return disp
|
39
37
|
|
40
38
|
|
41
39
|
def pluralize(word: str, count: int) -> str:
|
janito/tools/tools_adapter.py
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
from janito.tools.tool_base import ToolBase
|
2
2
|
from janito.tools.tool_events import ToolCallStarted, ToolCallFinished, ToolCallError
|
3
3
|
from janito.exceptions import ToolCallException
|
4
|
-
from
|
5
|
-
|
4
|
+
from janito.tools.tool_base import ToolPermissions
|
6
5
|
|
7
6
|
class ToolsAdapterBase:
|
8
7
|
"""
|
@@ -13,11 +12,10 @@ class ToolsAdapterBase:
|
|
13
12
|
"""
|
14
13
|
|
15
14
|
def __init__(
|
16
|
-
self, tools=None, event_bus=None
|
15
|
+
self, tools=None, event_bus=None
|
17
16
|
):
|
18
17
|
self._tools = tools or []
|
19
18
|
self._event_bus = event_bus # event bus can be set on all adapters
|
20
|
-
self._enabled_tools = set(enabled_tools) if enabled_tools is not None else None
|
21
19
|
self.verbose_tools = False
|
22
20
|
|
23
21
|
def set_verbose_tools(self, value: bool):
|
@@ -31,11 +29,28 @@ class ToolsAdapterBase:
|
|
31
29
|
def event_bus(self, bus):
|
32
30
|
self._event_bus = bus
|
33
31
|
|
32
|
+
def is_tool_allowed(self, tool):
|
33
|
+
"""Check if a tool is allowed based on current global AllowedPermissionsState."""
|
34
|
+
from janito.tools.permissions import get_global_allowed_permissions
|
35
|
+
allowed_permissions = get_global_allowed_permissions()
|
36
|
+
perms = tool.permissions # permissions are mandatory and type-checked
|
37
|
+
# If all permissions are False, block all tools
|
38
|
+
if not (allowed_permissions.read or allowed_permissions.write or allowed_permissions.execute):
|
39
|
+
return False
|
40
|
+
for perm in ['read', 'write', 'execute']:
|
41
|
+
if getattr(perms, perm) and not getattr(allowed_permissions, perm):
|
42
|
+
return False
|
43
|
+
return True
|
44
|
+
|
34
45
|
def get_tools(self):
|
35
|
-
"""Return the list of enabled tools managed by this provider."""
|
36
|
-
|
37
|
-
|
38
|
-
|
46
|
+
"""Return the list of enabled tools managed by this provider, filtered by allowed permissions."""
|
47
|
+
tools = [tool for tool in self._tools if self.is_tool_allowed(tool)]
|
48
|
+
return tools
|
49
|
+
|
50
|
+
def set_allowed_permissions(self, allowed_permissions):
|
51
|
+
"""Set the allowed permissions at runtime. This now updates the global AllowedPermissionsState only."""
|
52
|
+
from janito.tools.permissions import set_global_allowed_permissions
|
53
|
+
set_global_allowed_permissions(allowed_permissions)
|
39
54
|
|
40
55
|
def add_tool(self, tool):
|
41
56
|
self._tools.append(tool)
|
@@ -231,18 +246,8 @@ class ToolsAdapterBase:
|
|
231
246
|
)
|
232
247
|
|
233
248
|
def _check_tool_permissions(self, tool_name, request_id, arguments):
|
234
|
-
|
235
|
-
|
236
|
-
if self._event_bus:
|
237
|
-
self._event_bus.publish(
|
238
|
-
ToolCallError(
|
239
|
-
tool_name=tool_name,
|
240
|
-
request_id=request_id,
|
241
|
-
error=error_msg,
|
242
|
-
arguments=arguments,
|
243
|
-
)
|
244
|
-
)
|
245
|
-
raise ToolCallException(tool_name, error_msg, arguments=arguments)
|
249
|
+
# No enabled_tools check anymore; permission checks are handled by is_tool_allowed
|
250
|
+
pass
|
246
251
|
|
247
252
|
def _ensure_tool_exists(self, tool, tool_name, request_id, arguments):
|
248
253
|
if tool is None:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: janito
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.4.0
|
4
4
|
Summary: A new Python package called janito.
|
5
5
|
Author-email: João Pinto <lamego.pinto@gmail.com>
|
6
6
|
Project-URL: Homepage, https://github.com/janito-dev/janito
|
@@ -17,7 +17,7 @@ Requires-Dist: prompt_toolkit>=3.0.51
|
|
17
17
|
Requires-Dist: lxml>=5.4.0
|
18
18
|
Requires-Dist: requests>=2.32.4
|
19
19
|
Requires-Dist: bs4>=0.0.2
|
20
|
-
Requires-Dist:
|
20
|
+
Requires-Dist: questionary>=2.0.1
|
21
21
|
Provides-Extra: dev
|
22
22
|
Requires-Dist: pytest; extra == "dev"
|
23
23
|
Requires-Dist: pre-commit; extra == "dev"
|
@@ -25,7 +25,8 @@ Requires-Dist: ruff==0.11.9; extra == "dev"
|
|
25
25
|
Requires-Dist: detect-secrets==1.4.0; extra == "dev"
|
26
26
|
Requires-Dist: codespell==2.4.1; extra == "dev"
|
27
27
|
Requires-Dist: black; extra == "dev"
|
28
|
-
Requires-Dist:
|
28
|
+
Requires-Dist: questionary>=2.0.1; extra == "dev"
|
29
|
+
Requires-Dist: setuptools_scm>=8.0; extra == "dev"
|
29
30
|
Dynamic: license-file
|
30
31
|
|
31
32
|
# Janito
|
@@ -106,6 +107,21 @@ janito -set provider=PROVIDER
|
|
106
107
|
|
107
108
|
After installation, use the `janito` command in your terminal.
|
108
109
|
|
110
|
+
Janito supports both general-purpose and specialized assistance through the use of **profiles**. Profiles allow you to select a specific system prompt template and behavior for the agent, enabling workflows tailored to different roles or tasks (e.g., developer, writer, data analyst), or to use Janito as a generic AI assistant.
|
111
|
+
|
112
|
+
### Profiles: General-Purpose and Specialized Assistance
|
113
|
+
|
114
|
+
- By default, Janito acts as a general-purpose assistant.
|
115
|
+
- You can select a specialized profile using the `--profile` option:
|
116
|
+
```bash
|
117
|
+
janito --profile developer "Refactor this code for better readability."
|
118
|
+
janito --profile writer "Draft a blog post about AI in healthcare."
|
119
|
+
```
|
120
|
+
- Profiles change the system prompt and agent behavior to suit the selected role or workflow.
|
121
|
+
- To see available profiles or customize them, refer to the documentation or the `agent/templates/profiles/` directory.
|
122
|
+
|
123
|
+
> **Tip:** Use `--profile` for targeted workflows, or omit it for a general-purpose assistant.
|
124
|
+
|
109
125
|
Janito has configuration options, like `--set api-key API_KEY` and `--set provider=PROVIDER`, that create durable configurations and single shoot options, like `-p PROVIDER` and `-m MODEL`, that are active for the single run of the command or session.
|
110
126
|
|
111
127
|
### Basic Commands
|
@@ -153,25 +169,38 @@ Janito has configuration options, like `--set api-key API_KEY` and `--set provid
|
|
153
169
|
|
154
170
|
- **Enable Inline Web File Viewer for Clickable Links**
|
155
171
|
|
156
|
-
By default, Janito can open referenced files in a browser-based viewer when you click on file links in supported terminals. To enable this feature for your session, use the
|
172
|
+
By default, Janito can open referenced files in a browser-based viewer when you click on file links in supported terminals. To enable this feature for your session, use the `--web` flag:
|
157
173
|
|
158
174
|
```bash
|
159
|
-
janito
|
175
|
+
janito --web
|
160
176
|
```
|
161
177
|
|
162
|
-
This starts the lightweight web file viewer (
|
178
|
+
This starts the lightweight web file viewer () in the background, allowing you to inspect files referenced in responses directly in your browser. Combine with interactive mode or prompts as needed.
|
163
179
|
|
164
180
|
> **Tip:** Use with the interactive shell for the best experience with clickable file links.
|
165
181
|
|
166
182
|
|
167
183
|
- **Enable Execution Tools (Code/Shell Execution)**
|
168
184
|
|
169
|
-
By default,
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
185
|
+
By default, **all tool privileges (read, write, execute)** are disabled for safety. This means Janito starts with no permissions to run tools that read, write, or execute code/shell commands unless you explicitly enable them.
|
186
|
+
|
187
|
+
- To enable **read** tools (e.g., file reading, searching): add `-r` or `--read`
|
188
|
+
- To enable **write** tools (e.g., file editing): add `-w` or `--write`
|
189
|
+
- To enable **execution** tools (code/shell execution): add `-x` or `--exec`
|
190
|
+
|
191
|
+
You can combine these flags as needed. For example, to enable both read and write tools:
|
192
|
+
|
193
|
+
```bash
|
194
|
+
janito -r -w "Read and update this file: ..."
|
195
|
+
```
|
196
|
+
|
197
|
+
To enable all permissions (read, write, execute):
|
198
|
+
|
199
|
+
```bash
|
200
|
+
janito -r -w -x "Run this code: print('Hello, world!')"
|
201
|
+
```
|
202
|
+
|
203
|
+
> **Warning:** Enabling execution tools allows running arbitrary code or shell commands. Only use `--exec` if you trust your prompt and environment.
|
175
204
|
|
176
205
|
- **Set a System Prompt**
|
177
206
|
```bash
|
@@ -203,7 +232,7 @@ Janito has configuration options, like `--set api-key API_KEY` and `--set provid
|
|
203
232
|
### Core CLI Options
|
204
233
|
| Option | Description |
|
205
234
|
|------------------------|-----------------------------------------------------------------------------|
|
206
|
-
|
|
235
|
+
| `--web` | Enable the builtin lightweight web file viewer for clickable file links (). |
|
207
236
|
| `--version` | Show program version |
|
208
237
|
| `--list-tools` | List all registered tools |
|
209
238
|
| `--list-providers` | List all supported LLM providers |
|
@@ -212,7 +241,7 @@ Janito has configuration options, like `--set api-key API_KEY` and `--set provid
|
|
212
241
|
| `--set provider=name` | Set the current LLM provider (e.g., `janito --set provider=openai`) |
|
213
242
|
| `--set PROVIDER.model=MODEL` or `--set model=MODEL` | Set the default model for the current/selected provider, or globally. (e.g., `janito --set openai.model=gpt-3.5-turbo`) |
|
214
243
|
| `-s`, `--system` | Set a system prompt (e.g., `janito -s path/to/system_prompt.txt "Your prompt here"`) |
|
215
|
-
|
244
|
+
|
216
245
|
| `-p`, `--provider` | Select LLM provider (overrides config) (e.g., `janito -p openai "Your prompt here"`) |
|
217
246
|
| `-m`, `--model` | Select model for the provider (e.g., `janito -m gpt-3.5-turbo "Your prompt here"`) |
|
218
247
|
| `-v`, `--verbose` | Print extra information before answering |
|
@@ -246,8 +275,8 @@ Once inside the interactive chat mode, you can use these slash commands:
|
|
246
275
|
| Command | Description |
|
247
276
|
|----------------------|----------------------------------------------|
|
248
277
|
| `/tools` | List available tools |
|
249
|
-
|
|
250
|
-
|
|
278
|
+
| `/-status` | Show status of server |
|
279
|
+
| `/-logs` | Show last lines of logs |
|
251
280
|
| `/livelogs` | Show live updates from server log file |
|
252
281
|
| `/edit <filename>` | Open file in browser-based editor |
|
253
282
|
|
@@ -274,6 +303,12 @@ See [docs/supported-providers-models.md](docs/supported-providers-models.md) for
|
|
274
303
|
|
275
304
|
Contributions are welcome! Please see the `CONTRIBUTING.md` (if available) or open an issue to get started.
|
276
305
|
|
306
|
+
---
|
307
|
+
|
308
|
+
## Developer Documentation
|
309
|
+
|
310
|
+
For developer-specific setup, versioning, and contribution guidelines, see [README-dev.md](./README-dev.md).
|
311
|
+
|
277
312
|
## License
|
278
313
|
|
279
314
|
This project is licensed under the terms of the MIT license.
|