janito 1.4.0__py3-none-any.whl → 1.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.
- janito/__init__.py +1 -1
- janito/agent/__init__.py +0 -1
- janito/agent/agent.py +7 -25
- janito/agent/config.py +4 -6
- janito/agent/config_defaults.py +2 -2
- janito/agent/content_handler.py +0 -0
- janito/agent/conversation.py +63 -37
- janito/agent/message_handler.py +18 -0
- janito/agent/openai_schema_generator.py +116 -0
- janito/agent/queued_message_handler.py +32 -0
- janito/agent/rich_tool_handler.py +43 -0
- janito/agent/runtime_config.py +1 -1
- janito/agent/templates/system_instructions.j2 +10 -4
- janito/agent/tool_registry.py +92 -0
- janito/agent/tools/append_text_to_file.py +41 -0
- janito/agent/tools/ask_user.py +16 -3
- janito/agent/tools/create_directory.py +31 -0
- janito/agent/tools/create_file.py +52 -0
- janito/agent/tools/fetch_url.py +23 -8
- janito/agent/tools/find_files.py +40 -21
- janito/agent/tools/get_file_outline.py +26 -8
- janito/agent/tools/get_lines.py +53 -19
- janito/agent/tools/move_file.py +50 -0
- janito/agent/tools/py_compile.py +27 -11
- janito/agent/tools/python_exec.py +43 -14
- janito/agent/tools/remove_directory.py +23 -7
- janito/agent/tools/remove_file.py +38 -0
- janito/agent/tools/replace_text_in_file.py +40 -17
- janito/agent/tools/run_bash_command.py +107 -80
- janito/agent/tools/search_files.py +38 -19
- janito/agent/tools/tool_base.py +30 -3
- janito/agent/tools/tools_utils.py +11 -0
- janito/agent/tools/utils.py +0 -1
- janito/cli/_print_config.py +1 -1
- janito/cli/arg_parser.py +2 -1
- janito/cli/config_commands.py +3 -6
- janito/cli/main.py +2 -2
- janito/cli/runner.py +18 -14
- janito/cli_chat_shell/chat_loop.py +10 -15
- janito/cli_chat_shell/commands.py +8 -3
- janito/cli_chat_shell/config_shell.py +0 -3
- janito/cli_chat_shell/session_manager.py +11 -0
- janito/cli_chat_shell/ui.py +12 -113
- janito/render_prompt.py +0 -1
- janito/rich_utils.py +30 -0
- janito/web/app.py +10 -12
- janito-1.5.0.dist-info/METADATA +176 -0
- janito-1.5.0.dist-info/RECORD +64 -0
- janito/agent/queued_tool_handler.py +0 -16
- janito/agent/tool_handler.py +0 -196
- janito/agent/tools/file_ops.py +0 -114
- janito/agent/tools/rich_utils.py +0 -31
- janito-1.4.0.dist-info/METADATA +0 -142
- janito-1.4.0.dist-info/RECORD +0 -55
- {janito-1.4.0.dist-info → janito-1.5.0.dist-info}/WHEEL +0 -0
- {janito-1.4.0.dist-info → janito-1.5.0.dist-info}/entry_points.txt +0 -0
- {janito-1.4.0.dist-info → janito-1.5.0.dist-info}/licenses/LICENSE +0 -0
- {janito-1.4.0.dist-info → janito-1.5.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
janito/__init__.py,sha256=TJdX3kZk_MYc3dWRgST-ZjHyS_SdJ3N_VqRvVAVCkc4,23
|
2
|
+
janito/__main__.py,sha256=CBScR30Tm-vuhIJM8o5HXKr0q-smICiwSVyuU68BP8U,78
|
3
|
+
janito/render_prompt.py,sha256=y2pqntkfC34bh5psNobW2Vv1YAI3se04-ZcFCaoWU1s,457
|
4
|
+
janito/rich_utils.py,sha256=g5D-McYEUhzhPFpZGML41sw4w75eT51gu0x7anMQjxA,1048
|
5
|
+
janito/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
+
janito/agent/agent.py,sha256=j0ZffOAbeRpFMfAlIllEt5EjWRNTvkVuukbcdTpY6Z0,3517
|
7
|
+
janito/agent/config.py,sha256=jmGQAvVvFKE4V2nZHUeLRLyneydQNfEnUu8TmxDLxq0,4428
|
8
|
+
janito/agent/config_defaults.py,sha256=73tmwpICsgpWEnpCasSR97g59LXKQBB5xQFut7ZepTE,438
|
9
|
+
janito/agent/config_utils.py,sha256=UmvR236wDrMc-aTy9LxVbop6YeoJaaPb1d2DBMlkSRg,254
|
10
|
+
janito/agent/content_handler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
+
janito/agent/conversation.py,sha256=qwfQeM8Rv-Tl-pBVzlTIHrFyl20vgMO82W82JLYmTjk,7550
|
12
|
+
janito/agent/message_handler.py,sha256=6g-cQg-jR-93nZIku3dNLJhLL8nZtHSbMwQqmfpyBRA,673
|
13
|
+
janito/agent/openai_schema_generator.py,sha256=dE3gUPX_ZqYzuY9rWY5Ygo9imXvy-Mn1rqPsm59Tle8,4329
|
14
|
+
janito/agent/queued_message_handler.py,sha256=raz_tQLooWpWvx1qqPrl1s4F4Xx_-wyCxQPfwcDI4II,1365
|
15
|
+
janito/agent/rich_tool_handler.py,sha256=L0YGZTnkD_iISAUdP6sLdZ8fuKKQQrRlATIlmhInPQs,1906
|
16
|
+
janito/agent/runtime_config.py,sha256=ztmU0Ajd2NS7olJxhXjHPtndqIZKuWMqFXuQm-TqCUE,891
|
17
|
+
janito/agent/tool_registry.py,sha256=4vDVdAzm_a12M2h94h_IgYeAkIVGMwDlIRohS8SydBA,3376
|
18
|
+
janito/agent/templates/system_instructions.j2,sha256=Y24edrqLydMTcbaZYSW8_xJMMEbTNVS3Iy4IHrBe0-Q,1885
|
19
|
+
janito/agent/tools/__init__.py,sha256=Vv1oWF6Ur-Tkm3p0KCz5HD7wwar9rUHtY596NGPnn2s,378
|
20
|
+
janito/agent/tools/append_text_to_file.py,sha256=sSklc9Ifo7tTKB81yRgfU7yWfeHsRBNdUQVbOYw52EE,1881
|
21
|
+
janito/agent/tools/ask_user.py,sha256=36pZLy3WPEIQyKKallbH9Bq-8ASLWb-Eza4g1VbYZ-c,2482
|
22
|
+
janito/agent/tools/create_directory.py,sha256=fFMXIqSFRx6NyRtbJvgUId-rN83mYHsAQqP-2sBjGMA,1340
|
23
|
+
janito/agent/tools/create_file.py,sha256=YQISWGBUOMFTFA_hKqanYjXNJMHK22jDSrGIxOAMWDY,2551
|
24
|
+
janito/agent/tools/fetch_url.py,sha256=RuicvHm8uQJSCPwfLv6KV9my1HCJd0ehl3yutjKyd3g,2068
|
25
|
+
janito/agent/tools/find_files.py,sha256=3jQAJTOeh8eqjnajX-jIPsTJmKablHw5c_OvPfkmqZ4,2283
|
26
|
+
janito/agent/tools/get_file_outline.py,sha256=NwyIY2XAJr9REmeyX6Lyd6SyQiLdAiSzN4dii_iltM0,1447
|
27
|
+
janito/agent/tools/get_lines.py,sha256=Y7tHnHZB0PFylcRIXtDvmFPXdoWTeXUmVrENpBgVBdM,3364
|
28
|
+
janito/agent/tools/gitignore_utils.py,sha256=z_IYilabTD_-c14aRxuVasojOzTsg-11xJPJqudWIKA,1306
|
29
|
+
janito/agent/tools/move_file.py,sha256=x-A3g6D_tdboVhsBkA-jWYm6h6K7uCYglFoY_9agbuM,2270
|
30
|
+
janito/agent/tools/py_compile.py,sha256=WzaPRoJcNtAwtyNTg5jNRSXuKGUkbqDWGYkbJuUX-vk,1470
|
31
|
+
janito/agent/tools/python_exec.py,sha256=lbOhguPDSR3xru8XrHoB5_sT_Wx8PBiS4qxWami6LpA,2932
|
32
|
+
janito/agent/tools/remove_directory.py,sha256=fcfm9nLYiLEjbaeSHC-fCH5DqvurJZS6lh4v5brlblk,1384
|
33
|
+
janito/agent/tools/remove_file.py,sha256=qVfuAJXThA4UR7iCU5DLc_UMY81iextp0_zXTgHQYg4,1506
|
34
|
+
janito/agent/tools/replace_text_in_file.py,sha256=0w5cG_MvXcxwQI-i8hX-GedW0qnEwn-eYXYaNlv4NxA,4969
|
35
|
+
janito/agent/tools/rich_live.py,sha256=cuZ3-ZxpuHxR1TvIcp0bi9F3QM1M6Ms0XiOMd8If8gU,1161
|
36
|
+
janito/agent/tools/run_bash_command.py,sha256=1LcoNNhRHH65tCmGmdEFtpA5S4L1kmODuvBQUl7LGnA,5246
|
37
|
+
janito/agent/tools/search_files.py,sha256=Po6Xnngqq95WVIkQkKLkpjugom7D4E4-RnaE50jBtc8,2222
|
38
|
+
janito/agent/tools/tool_base.py,sha256=ch08PaWMEC8hC0UmWC7fEXmRBdnsmqXn6pXhoXbGXFU,1898
|
39
|
+
janito/agent/tools/tools_utils.py,sha256=G_Ib8QamhHbBzpKDW3TeoaxGDQgjs8_Zj8TFUInl78k,354
|
40
|
+
janito/agent/tools/utils.py,sha256=cKPE9HVA1yHmKzML8Uz4YCVLNDK13MQw9ThvhC9COCI,1101
|
41
|
+
janito/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
42
|
+
janito/cli/_print_config.py,sha256=keQ0XJN2w5ZDG4SSQxMPaayE436mn8eSUSRuB57pGCI,3254
|
43
|
+
janito/cli/_utils.py,sha256=Q_OCFZmbr78qW4hSSUUhjondVc0ao7-iUHE7Ig8IP1g,289
|
44
|
+
janito/cli/arg_parser.py,sha256=CLHv2sbHxbSwnPvnDk10-cyasCvR9lPv4Yc96QoW1qA,3885
|
45
|
+
janito/cli/config_commands.py,sha256=lhlutyVM2lBbXTeZ2FXW9iWOvFG35uDr9Rjoksx3iJY,7957
|
46
|
+
janito/cli/logging_setup.py,sha256=dWQ0wFf4YuF5lxZlhpN6lis7G56LeFYUwQdh9nA5NmA,1141
|
47
|
+
janito/cli/main.py,sha256=O483LhcDMxNqwr5PWsVNOf-ms6DRTfUKawB9MVMJIfM,1418
|
48
|
+
janito/cli/runner.py,sha256=aQvbxzOaRQ44ZP6CutDdpms0K8inOeI1pKRyCPYPIkQ,5193
|
49
|
+
janito/cli_chat_shell/__init__.py,sha256=PDGl7xK_vgkROoXvUxGZqVQFfuL9U4TjdexpP8E2JKg,41
|
50
|
+
janito/cli_chat_shell/chat_loop.py,sha256=35BJeKLhAkdARrMUADK2qRP-Q2bQPB2P7JSUrQ8bUxY,5501
|
51
|
+
janito/cli_chat_shell/commands.py,sha256=gBdfvujRDchRl_M5HZO-eO55dmKvDi3twS8jo3qo-a4,7301
|
52
|
+
janito/cli_chat_shell/config_shell.py,sha256=vBKAJvDRaqC2uSjTFBZ2KgQJT0FoTqbCI8u1N6VoPF4,3208
|
53
|
+
janito/cli_chat_shell/load_prompt.py,sha256=B7C_IhMk3n1XBQcfOwFVDnjrj1278JL3kV4UtkeeZx8,604
|
54
|
+
janito/cli_chat_shell/session_manager.py,sha256=mdmt6mWOZOYqBiqKJ_8D2ff_31RdeJhFB_xp3g3P6B4,2164
|
55
|
+
janito/cli_chat_shell/ui.py,sha256=sPuDhRapcdJ8MRyi1DKkaU8Vot_O29RVLqOjDZPpFaU,2354
|
56
|
+
janito/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
57
|
+
janito/web/__main__.py,sha256=oPXNF332aCeI7aUWr7_8M57oOKugw422VrEubxFp0P4,354
|
58
|
+
janito/web/app.py,sha256=kJhrKDI7X2Ujzk_SVxctvq1loiAXHil0ckn3RQ8e3gg,6549
|
59
|
+
janito-1.5.0.dist-info/licenses/LICENSE,sha256=sHBqv0bvtrb29H7WRR-Z603YHm9pLtJIo3nHU_9cmgE,1091
|
60
|
+
janito-1.5.0.dist-info/METADATA,sha256=gyl65Ab0HqC08D1hJ0P3_ghOG6-3aqE9josu449WOFQ,7539
|
61
|
+
janito-1.5.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
62
|
+
janito-1.5.0.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
|
63
|
+
janito-1.5.0.dist-info/top_level.txt,sha256=m0NaVCq0-ivxbazE2-ND0EA9Hmuijj_OGkmCbnBcCig,7
|
64
|
+
janito-1.5.0.dist-info/RECORD,,
|
@@ -1,16 +0,0 @@
|
|
1
|
-
from janito.agent.tool_handler import ToolHandler
|
2
|
-
|
3
|
-
class QueuedToolHandler(ToolHandler):
|
4
|
-
def __init__(self, queue, *args, **kwargs):
|
5
|
-
super().__init__(*args, **kwargs)
|
6
|
-
self._queue = queue
|
7
|
-
|
8
|
-
def handle_tool_call(self, tool_call, on_progress=None):
|
9
|
-
def enqueue_progress(data):
|
10
|
-
|
11
|
-
self._queue.put(('tool_progress', data))
|
12
|
-
|
13
|
-
if on_progress is None:
|
14
|
-
on_progress = enqueue_progress
|
15
|
-
|
16
|
-
return super().handle_tool_call(tool_call, on_progress=on_progress)
|
janito/agent/tool_handler.py
DELETED
@@ -1,196 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import json
|
3
|
-
import traceback
|
4
|
-
from janito.agent.tools.tool_base import ToolBase
|
5
|
-
|
6
|
-
class ToolHandler:
|
7
|
-
_tool_registry = {}
|
8
|
-
|
9
|
-
def __init__(self, verbose=False, enable_tools=True):
|
10
|
-
self.verbose = verbose
|
11
|
-
self.tools = []
|
12
|
-
self.enable_tools = enable_tools
|
13
|
-
|
14
|
-
@classmethod
|
15
|
-
def register_tool(cls, tool=None, *, name: str = None):
|
16
|
-
"""
|
17
|
-
Register a tool class derived from ToolBase.
|
18
|
-
Args:
|
19
|
-
tool: The tool class (must inherit from ToolBase).
|
20
|
-
name: Optional override for the tool name.
|
21
|
-
Raises:
|
22
|
-
TypeError: If the tool is not a subclass of ToolBase.
|
23
|
-
"""
|
24
|
-
if tool is None:
|
25
|
-
return lambda t: cls.register_tool(t, name=name)
|
26
|
-
import inspect
|
27
|
-
import typing
|
28
|
-
from typing import get_origin, get_args
|
29
|
-
|
30
|
-
override_name = name
|
31
|
-
if not (isinstance(tool, type) and issubclass(tool, ToolBase)):
|
32
|
-
raise TypeError("Tool must be a class derived from ToolBase.")
|
33
|
-
instance = tool()
|
34
|
-
func = instance.call
|
35
|
-
default_name = tool.__name__
|
36
|
-
name = override_name or default_name
|
37
|
-
description = tool.__doc__ or func.__doc__ or ""
|
38
|
-
|
39
|
-
sig = inspect.signature(func)
|
40
|
-
params_schema = {
|
41
|
-
"type": "object",
|
42
|
-
"properties": {},
|
43
|
-
"required": []
|
44
|
-
}
|
45
|
-
|
46
|
-
for param_name, param in sig.parameters.items():
|
47
|
-
if param.annotation is param.empty:
|
48
|
-
raise TypeError(f"Parameter '{param_name}' in tool '{name}' is missing a type hint.")
|
49
|
-
param_type = param.annotation
|
50
|
-
schema = {}
|
51
|
-
|
52
|
-
# Handle typing.Optional, typing.List, typing.Literal, etc.
|
53
|
-
origin = get_origin(param_type)
|
54
|
-
args = get_args(param_type)
|
55
|
-
|
56
|
-
if origin is typing.Union and type(None) in args:
|
57
|
-
# Optional[...] type
|
58
|
-
main_type = args[0] if args[1] is type(None) else args[1]
|
59
|
-
origin = get_origin(main_type)
|
60
|
-
args = get_args(main_type)
|
61
|
-
param_type = main_type
|
62
|
-
else:
|
63
|
-
main_type = param_type
|
64
|
-
|
65
|
-
if origin is list or origin is typing.List:
|
66
|
-
item_type = args[0] if args else str
|
67
|
-
item_schema = {"type": _pytype_to_json_type(item_type)}
|
68
|
-
schema = {"type": "array", "items": item_schema}
|
69
|
-
elif origin is typing.Literal:
|
70
|
-
schema = {"type": _pytype_to_json_type(type(args[0])), "enum": list(args)}
|
71
|
-
elif main_type == int:
|
72
|
-
schema = {"type": "integer"}
|
73
|
-
elif main_type == float:
|
74
|
-
schema = {"type": "number"}
|
75
|
-
elif main_type == bool:
|
76
|
-
schema = {"type": "boolean"}
|
77
|
-
elif main_type == dict:
|
78
|
-
schema = {"type": "object"}
|
79
|
-
elif main_type == list:
|
80
|
-
schema = {"type": "array", "items": {"type": "string"}}
|
81
|
-
else:
|
82
|
-
schema = {"type": "string"}
|
83
|
-
|
84
|
-
# Add description from call method docstring if available (Google-style Args parsing)
|
85
|
-
if func.__doc__:
|
86
|
-
import re
|
87
|
-
doc = func.__doc__
|
88
|
-
args_section = re.search(r"Args:\s*(.*?)(?:\n\s*\w|Returns:|$)", doc, re.DOTALL)
|
89
|
-
param_descs = {}
|
90
|
-
if args_section:
|
91
|
-
args_text = args_section.group(1)
|
92
|
-
for match in re.finditer(r"(\w+) \([^)]+\): ([^\n]+)", args_text):
|
93
|
-
pname, pdesc = match.groups()
|
94
|
-
param_descs[pname] = pdesc.strip()
|
95
|
-
if param_name in param_descs:
|
96
|
-
schema["description"] = param_descs[param_name]
|
97
|
-
params_schema["properties"][param_name] = schema
|
98
|
-
if param.default is param.empty:
|
99
|
-
params_schema["required"].append(param_name)
|
100
|
-
|
101
|
-
# register the bound call function
|
102
|
-
cls._tool_registry[name] = {
|
103
|
-
"function": func,
|
104
|
-
"description": description,
|
105
|
-
"parameters": params_schema
|
106
|
-
}
|
107
|
-
return tool
|
108
|
-
|
109
|
-
def register(self, func):
|
110
|
-
self.tools.append(func)
|
111
|
-
return func
|
112
|
-
|
113
|
-
def get_tools(self):
|
114
|
-
return self.tools
|
115
|
-
|
116
|
-
def get_tool_schemas(self):
|
117
|
-
if not getattr(self, 'enable_tools', True):
|
118
|
-
return []
|
119
|
-
schemas = []
|
120
|
-
for name, entry in self._tool_registry.items():
|
121
|
-
schemas.append({
|
122
|
-
"type": "function",
|
123
|
-
"function": {
|
124
|
-
"name": name,
|
125
|
-
"description": entry["description"],
|
126
|
-
"parameters": entry["parameters"]
|
127
|
-
}
|
128
|
-
})
|
129
|
-
return schemas
|
130
|
-
|
131
|
-
def handle_tool_call(self, tool_call, on_progress=None):
|
132
|
-
import uuid
|
133
|
-
call_id = getattr(tool_call, 'id', None) or str(uuid.uuid4())
|
134
|
-
tool_entry = self._tool_registry.get(tool_call.function.name)
|
135
|
-
if not tool_entry:
|
136
|
-
return f"Unknown tool: {tool_call.function.name}"
|
137
|
-
func = tool_entry["function"]
|
138
|
-
args = json.loads(tool_call.function.arguments)
|
139
|
-
if self.verbose:
|
140
|
-
print(f"[Tool Call] {tool_call.function.name} called with arguments: {args}")
|
141
|
-
import inspect
|
142
|
-
sig = inspect.signature(func)
|
143
|
-
# Set progress callback on tool instance if possible
|
144
|
-
instance = None
|
145
|
-
if hasattr(func, '__self__') and isinstance(func.__self__, ToolBase):
|
146
|
-
instance = func.__self__
|
147
|
-
instance._progress_callback = on_progress
|
148
|
-
if on_progress:
|
149
|
-
on_progress({
|
150
|
-
'event': 'start',
|
151
|
-
'call_id': call_id,
|
152
|
-
'tool': tool_call.function.name,
|
153
|
-
'args': args
|
154
|
-
})
|
155
|
-
try:
|
156
|
-
result = func(**args)
|
157
|
-
except Exception as e:
|
158
|
-
import traceback
|
159
|
-
error_message = f"[Tool Error] {type(e).__name__}: {e}\n" + traceback.format_exc()
|
160
|
-
result = error_message
|
161
|
-
if self.verbose:
|
162
|
-
preview = result
|
163
|
-
if isinstance(result, str):
|
164
|
-
lines = result.splitlines()
|
165
|
-
if len(lines) > 10:
|
166
|
-
preview = "\n".join(lines[:10]) + "\n... (truncated)"
|
167
|
-
elif len(result) > 500:
|
168
|
-
preview = result[:500] + "... (truncated)"
|
169
|
-
print(f"[Tool Result] {tool_call.function.name} returned:\n{preview}")
|
170
|
-
if on_progress:
|
171
|
-
on_progress({
|
172
|
-
'event': 'finish',
|
173
|
-
'call_id': call_id,
|
174
|
-
'tool': tool_call.function.name,
|
175
|
-
'args': args,
|
176
|
-
'result': result
|
177
|
-
})
|
178
|
-
# Clean up progress callback
|
179
|
-
if instance is not None:
|
180
|
-
instance._progress_callback = None
|
181
|
-
return result
|
182
|
-
|
183
|
-
def _pytype_to_json_type(pytype):
|
184
|
-
import typing
|
185
|
-
if pytype == int:
|
186
|
-
return "integer"
|
187
|
-
elif pytype == float:
|
188
|
-
return "number"
|
189
|
-
elif pytype == bool:
|
190
|
-
return "boolean"
|
191
|
-
elif pytype == dict:
|
192
|
-
return "object"
|
193
|
-
elif pytype == list or pytype == typing.List:
|
194
|
-
return "array"
|
195
|
-
else:
|
196
|
-
return "string"
|
janito/agent/tools/file_ops.py
DELETED
@@ -1,114 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import shutil
|
3
|
-
from janito.agent.tool_handler import ToolHandler
|
4
|
-
from janito.agent.tools.rich_utils import print_info, print_success, print_error
|
5
|
-
from janito.agent.tools.utils import expand_path, display_path
|
6
|
-
from janito.agent.tools.tool_base import ToolBase
|
7
|
-
|
8
|
-
class CreateFileTool(ToolBase):
|
9
|
-
"""
|
10
|
-
Create a new file or update an existing file with the given content.
|
11
|
-
"""
|
12
|
-
def call(self, path: str, content: str, overwrite: bool = False) -> str:
|
13
|
-
original_path = path
|
14
|
-
path = expand_path(path)
|
15
|
-
updating = os.path.exists(path) and not os.path.isdir(path)
|
16
|
-
disp_path = display_path(original_path, path)
|
17
|
-
if os.path.exists(path):
|
18
|
-
if os.path.isdir(path):
|
19
|
-
print_error(f"❌ Error: is a directory")
|
20
|
-
return f"❌ Cannot create file: '{disp_path}' is an existing directory."
|
21
|
-
if not overwrite:
|
22
|
-
print_error(f"❗ Error: file '{disp_path}' exists and overwrite is False")
|
23
|
-
return f"❗ Cannot create file: '{disp_path}' already exists and overwrite is False."
|
24
|
-
if updating and overwrite:
|
25
|
-
print_info(f"📝 Updating file: '{disp_path}' ... ")
|
26
|
-
else:
|
27
|
-
print_info(f"📝 Creating file: '{disp_path}' ... ")
|
28
|
-
old_lines = None
|
29
|
-
if updating and overwrite:
|
30
|
-
with open(path, "r", encoding="utf-8") as f:
|
31
|
-
old_lines = sum(1 for _ in f)
|
32
|
-
with open(path, "w", encoding="utf-8") as f:
|
33
|
-
f.write(content)
|
34
|
-
print_success("✅ Success")
|
35
|
-
if old_lines is not None:
|
36
|
-
new_lines = content.count('\n') + 1 if content else 0
|
37
|
-
return f"✅ Successfully updated the file at '{disp_path}' ({old_lines} > {new_lines} lines)."
|
38
|
-
new_lines = content.count('\n') + 1 if content else 0
|
39
|
-
return f"✅ Successfully created the file at '{disp_path}' ({new_lines} lines)."
|
40
|
-
|
41
|
-
class CreateDirectoryTool(ToolBase):
|
42
|
-
"""
|
43
|
-
Create a new directory at the specified path.
|
44
|
-
"""
|
45
|
-
def call(self, path: str, overwrite: bool = False) -> str:
|
46
|
-
"""
|
47
|
-
Create a new directory at the specified path.
|
48
|
-
Args:
|
49
|
-
path (str): Path to the directory to create.
|
50
|
-
overwrite (bool): Whether to remove the directory if it exists.
|
51
|
-
Returns:
|
52
|
-
str: Result message.
|
53
|
-
"""
|
54
|
-
original_path = path
|
55
|
-
path = expand_path(path)
|
56
|
-
disp_path = display_path(original_path, path)
|
57
|
-
if os.path.exists(path):
|
58
|
-
if not os.path.isdir(path):
|
59
|
-
print_error(f"❌ Path '{disp_path}' exists and is not a directory.")
|
60
|
-
return f"❌ Path '{disp_path}' exists and is not a directory."
|
61
|
-
if not overwrite:
|
62
|
-
print_error(f"❗ Directory '{disp_path}' already exists and overwrite is False.")
|
63
|
-
return f"❗ Directory '{disp_path}' already exists and overwrite is False."
|
64
|
-
# Remove existing directory if overwrite is True
|
65
|
-
shutil.rmtree(path)
|
66
|
-
print_info(f"🗑️ Removed existing directory: '{disp_path}'")
|
67
|
-
os.makedirs(path, exist_ok=True)
|
68
|
-
print_success(f"✅ Created directory: '{disp_path}'")
|
69
|
-
return f"✅ Successfully created directory at '{disp_path}'."
|
70
|
-
|
71
|
-
class RemoveFileTool(ToolBase):
|
72
|
-
"""
|
73
|
-
Remove a file at the specified path.
|
74
|
-
"""
|
75
|
-
def call(self, path: str) -> str:
|
76
|
-
original_path = path
|
77
|
-
path = expand_path(path)
|
78
|
-
disp_path = display_path(original_path, path)
|
79
|
-
print_info(f"🗑️ Removing file: '{disp_path}' ... ")
|
80
|
-
os.remove(path)
|
81
|
-
print_success("✅ Success")
|
82
|
-
return f"✅ Successfully deleted the file at '{disp_path}'."
|
83
|
-
|
84
|
-
class MoveFileTool(ToolBase):
|
85
|
-
"""
|
86
|
-
Move or rename a file from source to destination.
|
87
|
-
"""
|
88
|
-
def call(self, source_path: str, destination_path: str, overwrite: bool = False) -> str:
|
89
|
-
orig_source = source_path
|
90
|
-
orig_dest = destination_path
|
91
|
-
source_path = expand_path(source_path)
|
92
|
-
destination_path = expand_path(destination_path)
|
93
|
-
disp_source = display_path(orig_source, source_path)
|
94
|
-
disp_dest = display_path(orig_dest, destination_path)
|
95
|
-
print_info(f"🚚 Moving '{disp_source}' to '{disp_dest}' ... ")
|
96
|
-
if not os.path.exists(source_path):
|
97
|
-
print_error(f"❌ Error: source does not exist")
|
98
|
-
return f"❌ Source path '{disp_source}' does not exist."
|
99
|
-
if os.path.exists(destination_path):
|
100
|
-
if not overwrite:
|
101
|
-
print_error(f"❗ Error: destination exists and overwrite is False")
|
102
|
-
return f"❗ Destination path '{disp_dest}' already exists and overwrite is False."
|
103
|
-
if os.path.isdir(destination_path):
|
104
|
-
print_error(f"❌ Error: destination is a directory")
|
105
|
-
return f"❌ Destination path '{disp_dest}' is an existing directory."
|
106
|
-
shutil.move(source_path, destination_path)
|
107
|
-
print_success("✅ Success")
|
108
|
-
return f"✅ Successfully moved '{disp_source}' to '{disp_dest}'."
|
109
|
-
|
110
|
-
# register tools
|
111
|
-
ToolHandler.register_tool(CreateFileTool, name="create_file")
|
112
|
-
ToolHandler.register_tool(CreateDirectoryTool, name="create_directory")
|
113
|
-
ToolHandler.register_tool(RemoveFileTool, name="remove_file")
|
114
|
-
ToolHandler.register_tool(MoveFileTool, name="move_file")
|
janito/agent/tools/rich_utils.py
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
from rich.console import Console
|
2
|
-
from rich.text import Text
|
3
|
-
|
4
|
-
console = Console()
|
5
|
-
|
6
|
-
def print_info(message: str, end="\n"):
|
7
|
-
console.print(message, style="cyan", end=end)
|
8
|
-
|
9
|
-
def print_success(message: str, end="\n"):
|
10
|
-
console.print(message, style="bold green", end=end)
|
11
|
-
|
12
|
-
def print_error(message: str, end="\n"):
|
13
|
-
console.print(message, style="bold red", end=end)
|
14
|
-
|
15
|
-
def print_warning(message: str):
|
16
|
-
console.print(message, style="yellow")
|
17
|
-
|
18
|
-
def print_magenta(message: str):
|
19
|
-
console.print(message, style="magenta")
|
20
|
-
|
21
|
-
def print_bash_stdout(message: str):
|
22
|
-
console.print(message, style="bold white on blue")
|
23
|
-
|
24
|
-
def print_bash_stderr(message: str):
|
25
|
-
console.print(message, style="bold white on red")
|
26
|
-
|
27
|
-
def format_path(path: str) -> Text:
|
28
|
-
return Text(path, style="cyan")
|
29
|
-
|
30
|
-
def format_number(number) -> Text:
|
31
|
-
return Text(str(number), style="magenta")
|
janito-1.4.0.dist-info/METADATA
DELETED
@@ -1,142 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: janito
|
3
|
-
Version: 1.4.0
|
4
|
-
Summary: A Natural Programming Language Agent,
|
5
|
-
Author-email: João Pinto <joao.pinto@gmail.com>
|
6
|
-
License: MIT
|
7
|
-
Project-URL: homepage, https://github.com/joaompinto/janito
|
8
|
-
Project-URL: repository, https://github.com/joaompinto/janito
|
9
|
-
Keywords: agent,framework,tools,automation
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
11
|
-
Classifier: License :: OSI Approved :: MIT License
|
12
|
-
Classifier: Operating System :: OS Independent
|
13
|
-
Requires-Python: >=3.10
|
14
|
-
Description-Content-Type: text/markdown
|
15
|
-
License-File: LICENSE
|
16
|
-
Requires-Dist: beautifulsoup4
|
17
|
-
Requires-Dist: flask
|
18
|
-
Requires-Dist: jinja2
|
19
|
-
Requires-Dist: openai
|
20
|
-
Requires-Dist: pathspec
|
21
|
-
Requires-Dist: prompt_toolkit
|
22
|
-
Requires-Dist: requests
|
23
|
-
Requires-Dist: rich
|
24
|
-
Dynamic: license-file
|
25
|
-
|
26
|
-
# 🚀 Janito: Natural Programming Language Agent
|
27
|
-
|
28
|
-
Janito is an AI-powered assistant for the command line and web that interprets natural language instructions to edit code, manage files, and analyze projects using patterns and tools designed by experienced software engineers. It prioritizes transparency, interactive clarification, and precise, reviewable changes.
|
29
|
-
|
30
|
-
---
|
31
|
-
|
32
|
-
## ⚡ Quick Start
|
33
|
-
|
34
|
-
Run a one-off prompt:
|
35
|
-
```bash
|
36
|
-
python -m janito "Refactor the data processing module to improve readability."
|
37
|
-
```
|
38
|
-
|
39
|
-
Or start the interactive chat shell:
|
40
|
-
```bash
|
41
|
-
python -m janito
|
42
|
-
```
|
43
|
-
|
44
|
-
Launch the web UI:
|
45
|
-
```bash
|
46
|
-
python -m janito.web
|
47
|
-
```
|
48
|
-
|
49
|
-
---
|
50
|
-
|
51
|
-
## ✨ Key Features
|
52
|
-
- 📝 **Code Editing via Natural Language:** Modify, create, or delete code files simply by describing the changes.
|
53
|
-
- 📁 **File & Directory Management:** Navigate, create, move, or remove files and folders.
|
54
|
-
- 🧠 **Context-Aware:** Understands your project structure for precise edits.
|
55
|
-
- 💬 **Interactive User Prompts:** Asks for clarification when needed.
|
56
|
-
- 🧩 **Extensible Tooling:** Built-in tools for file operations, shell commands, directory listing, Python file validation, text replacement, code execution, and more. Recent tools include:
|
57
|
-
- `find_files`: Search for files matching a pattern in directories.
|
58
|
-
- `get_lines`: Retrieve specific lines from files for efficient context.
|
59
|
-
- `py_compile_file`: Validate Python files for syntax correctness.
|
60
|
-
- `replace_text_in_file`: Replace exact text fragments in files.
|
61
|
-
- `search_files`: Search for text patterns across files.
|
62
|
-
- `python_exec`: Execute Python code and capture output.
|
63
|
-
- And more built-in operations for code and file management.
|
64
|
-
- 🌐 **Web Interface (In Development):** Upcoming simple web UI for streaming responses and tool progress.
|
65
|
-
|
66
|
-
---
|
67
|
-
|
68
|
-
|
69
|
-
## 📦 Installation
|
70
|
-
|
71
|
-
### Requirements
|
72
|
-
- Python 3.10+
|
73
|
-
|
74
|
-
...
|
75
|
-
|
76
|
-
### Configuration & CLI Options
|
77
|
-
|
78
|
-
Below are the supported configuration parameters and CLI flags. Some options can be set via config files, CLI flags, or both. Use `python -m janito --help` for a full list, or `python -m janito --help-config` to see all config keys and their descriptions.
|
79
|
-
|
80
|
-
| Key / Flag | Description | How to set | Default |
|
81
|
-
|---------------------------|---------------------------------------------------------------------------------------------|-----------------------------------------------------------------|--------------------------------------------|
|
82
|
-
| `api_key` | API key for a compatible language model service | `--set-api-key`, config file | _None_ (required) |
|
83
|
-
| `model` | Model name to use for this session | `--model` (session only), `--set-local-config model=...`, or `--set-global-config` | _(example: gpt-4)_ |
|
84
|
-
| `base_url` | API base URL for your language model service | `--set-local-config base_url=...` or `--set-global-config` | _(example: https://api.your-model.com)_ |
|
85
|
-
| `role` | Role description for the system prompt | `--role` or config | "software engineer" |
|
86
|
-
| `system_prompt` | Override the entire system prompt as a raw string | `--system-prompt` or config | _Default prompt_ |
|
87
|
-
| `system_file` | Use a plain text file as the system prompt (takes precedence over `system_prompt`) | `--system-file` (CLI only) | _None_ |
|
88
|
-
| `temperature` | Sampling temperature (float, e.g., 0.0 - 2.0) | `--temperature` or config | 0.2 |
|
89
|
-
| `max_tokens` | Maximum tokens for model response | `--max-tokens` or config | 200000 |
|
90
|
-
| `max_rounds` | Maximum number of agent rounds per prompt/session | `--max-rounds` or config | 50 |
|
91
|
-
| `max_tools` | Maximum number of tool calls allowed within a chat session | `--max-tools` or config | _None_ (unlimited) |
|
92
|
-
| `no_tools` | Disable tool use (no tools passed to agent) | `-n`, `--no-tools` (CLI only) | False |
|
93
|
-
| `trust` | Trust mode: suppresses run_bash_command output, only shows output file locations | `--trust` (CLI only) | False |
|
94
|
-
| `template` / `template.*` | Template context dictionary for prompt rendering (nested or flat keys) | Config only | _None_ |
|
95
|
-
|
96
|
-
Other config-related CLI flags:
|
97
|
-
|
98
|
-
- `--set-local-config key=val` Set a local config value
|
99
|
-
- `--set-global-config key=val` Set a global config value
|
100
|
-
- `--run-config key=val` Set a runtime (in-memory only) config value (can be repeated)
|
101
|
-
- `--show-config` Show effective configuration and exit
|
102
|
-
- `--config-reset-local` Remove the local config file
|
103
|
-
- `--config-reset-global` Remove the global config file
|
104
|
-
- `--set-api-key KEY` Set and save the API key globally
|
105
|
-
- `--help-config` Show all configuration options and exit
|
106
|
-
|
107
|
-
Session & shell options:
|
108
|
-
|
109
|
-
- `--continue-session` Continue from the last saved conversation
|
110
|
-
- `--web` Launch the Janito web server instead of CLI
|
111
|
-
|
112
|
-
Verbose/debugging flags:
|
113
|
-
|
114
|
-
- `--verbose-http` Enable verbose HTTP logging
|
115
|
-
- `--verbose-http-raw` Enable raw HTTP wire-level logging
|
116
|
-
- `--verbose-response` Pretty print the full response object
|
117
|
-
- `--verbose-tools` Print tool call parameters and results
|
118
|
-
- `--show-system` Show model, parameters, system prompt, and tool definitions, then exit
|
119
|
-
- `--version` Show program's version number and exit
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
---
|
124
|
-
|
125
|
-
## 🧩 System Prompt & Role
|
126
|
-
|
127
|
-
Janito operates using a system prompt template that defines its behavior, communication style, and capabilities. By default, Janito assumes the role of a "software engineer"—this means its responses and actions are tailored to the expectations and best practices of professional software engineering.
|
128
|
-
|
129
|
-
- **Role:** You can customize the agent's role (e.g., "data scientist", "DevOps engineer") using the `--role` flag or config. The default is `software engineer`.
|
130
|
-
- **System Prompt Template:** The system prompt is rendered from a Jinja2 template (see `janito/agent/templates/system_instructions.j2` (now located directly under the agent directory)). This template governs how the agent interprets instructions, interacts with files, and communicates with users.
|
131
|
-
- **Customization:** Advanced users can override the system prompt with the `--system-prompt` flag (raw string), or point to a custom file using `--system-file`.
|
132
|
-
|
133
|
-
The default template ensures the agent:
|
134
|
-
- Prioritizes safe, reviewable, and minimal changes
|
135
|
-
- Asks for clarification when instructions are ambiguous
|
136
|
-
- Provides concise plans before taking action
|
137
|
-
- Documents any changes made
|
138
|
-
|
139
|
-
For more details or to customize the prompt, see the template file at `janito/agent/templates/system_instructions.j2`.
|
140
|
-
|
141
|
-
---
|
142
|
-
|
janito-1.4.0.dist-info/RECORD
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
janito/__init__.py,sha256=-pa9pj_zJgPDZtE3ena4mjuVS3FEWQWYij1shjLYS80,23
|
2
|
-
janito/__main__.py,sha256=CBScR30Tm-vuhIJM8o5HXKr0q-smICiwSVyuU68BP8U,78
|
3
|
-
janito/render_prompt.py,sha256=xCQgYRqMyz9Pzi7096NoZfC4lFiKEHEaXiTYP6ByViY,513
|
4
|
-
janito/agent/__init__.py,sha256=CByAH5Yk-yH64zo0RU7Z3nsn_7Vmandphqk0JNlpyj8,21
|
5
|
-
janito/agent/agent.py,sha256=X5swt-SUKnIxrSQaGfhxPk61M-BXREz4n02ynE0dVVU,4245
|
6
|
-
janito/agent/config.py,sha256=Z-_IeWxJB_1ca5LVR7PtHChZgc5eAsgegyEmVAxr1NY,4472
|
7
|
-
janito/agent/config_defaults.py,sha256=vSif3tJYZ7pMHaNqH6jGb7EKctfE-Kt8ueD17sC0ESY,395
|
8
|
-
janito/agent/config_utils.py,sha256=UmvR236wDrMc-aTy9LxVbop6YeoJaaPb1d2DBMlkSRg,254
|
9
|
-
janito/agent/conversation.py,sha256=vbCL-1LlJjKRN6q3CjfSe4ENGplP-YQKsAEA1uX3RWU,6184
|
10
|
-
janito/agent/queued_tool_handler.py,sha256=THPymKXnpoXfN49EhW5b4hrwpWZZup73JKFDJ_U03tI,540
|
11
|
-
janito/agent/runtime_config.py,sha256=H6bnRVYR0zC-WhmLpBU-IXikXWKcIiBQqFnc4uGooj4,908
|
12
|
-
janito/agent/tool_handler.py,sha256=h-pxG1lhyIJohZmvwHSsknBSonrJQYGGzBL6Tobgmrg,7414
|
13
|
-
janito/agent/templates/system_instructions.j2,sha256=BtwMcibxnwZmQhGN7p_VGhhyAPzCfqksnW4B-PTWa-8,1532
|
14
|
-
janito/agent/tools/__init__.py,sha256=Vv1oWF6Ur-Tkm3p0KCz5HD7wwar9rUHtY596NGPnn2s,378
|
15
|
-
janito/agent/tools/ask_user.py,sha256=C1YC_gr0kh3-7vw2PgdIi4D8Paw-eNGpaWQy4HD3Gmo,2180
|
16
|
-
janito/agent/tools/fetch_url.py,sha256=XUHEex1An1Ql4p8H1UKWzaIxo9a6WkZC4uRPkhBQHeU,1418
|
17
|
-
janito/agent/tools/file_ops.py,sha256=5FnggSPv-Tsgq038T1YK5bpJZE5kPY_biB5fXZg48X0,5476
|
18
|
-
janito/agent/tools/find_files.py,sha256=jq55uUSfAUJ2gmJ29YQmo8XZ92cptb2C5hpc_pjbrQg,1364
|
19
|
-
janito/agent/tools/get_file_outline.py,sha256=aLNNWMalvE-3CXLEuBVe4ihDMciP4grbsol6Yw01O44,959
|
20
|
-
janito/agent/tools/get_lines.py,sha256=0Yg6JFPAOCJuR7HYcFIGwn83BCv_SnuWp0T7v4RtT9Q,1555
|
21
|
-
janito/agent/tools/gitignore_utils.py,sha256=z_IYilabTD_-c14aRxuVasojOzTsg-11xJPJqudWIKA,1306
|
22
|
-
janito/agent/tools/py_compile.py,sha256=y8f48WaHpsPFCt1Ksi-JEVbFxWvZU-lQzCHsR796pWg,1099
|
23
|
-
janito/agent/tools/python_exec.py,sha256=TPU1LvRNNJMpsyhy1kD8pe2go5V2fheD93HBjKrXrFM,2188
|
24
|
-
janito/agent/tools/remove_directory.py,sha256=xcyGyF5vC_AU7dzIVNa65aYUYuF5mBjGZ2MwnLsLafs,1076
|
25
|
-
janito/agent/tools/replace_text_in_file.py,sha256=eO7YumsT8Eq3_SOgl5DW_k9vhXO7egyMaiB6ZgtiHRU,3894
|
26
|
-
janito/agent/tools/rich_live.py,sha256=cuZ3-ZxpuHxR1TvIcp0bi9F3QM1M6Ms0XiOMd8If8gU,1161
|
27
|
-
janito/agent/tools/rich_utils.py,sha256=Lc4phM4DUG-eiiub2PFThc6pBk5aOo_6f09JPdZIdsk,894
|
28
|
-
janito/agent/tools/run_bash_command.py,sha256=rKAx_n6xxpHeBzDg_7BVkAjMgPGiXVLpjx6i2o1lMb0,3883
|
29
|
-
janito/agent/tools/search_files.py,sha256=ejHDp_I-GGQPucAKcXLgVO3LFPiOXNS77tEHME9QsvQ,1250
|
30
|
-
janito/agent/tools/tool_base.py,sha256=nS2FXSw3YY6gJiKh-l1m1udnHT7F3yKwGpGHJHfERbY,836
|
31
|
-
janito/agent/tools/utils.py,sha256=cKZ2qxK-S01mzBmCXYWwQ9zOyT994SaoRZYbD1o57Dk,1113
|
32
|
-
janito/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
33
|
-
janito/cli/_print_config.py,sha256=vMMlCY-hJPsLHUxx9TJuOY9iyYVBH8C4nVACCwY4l5U,3294
|
34
|
-
janito/cli/_utils.py,sha256=Q_OCFZmbr78qW4hSSUUhjondVc0ao7-iUHE7Ig8IP1g,289
|
35
|
-
janito/cli/arg_parser.py,sha256=4dSxHk02VD2_-utR5XCDt6Xs7tsye2HeQmTbaJiWFME,3724
|
36
|
-
janito/cli/config_commands.py,sha256=kYZ_SlHkZRlg-hLAdYKj50qnJgPCZUbW7zU4FykE7XQ,8098
|
37
|
-
janito/cli/logging_setup.py,sha256=dWQ0wFf4YuF5lxZlhpN6lis7G56LeFYUwQdh9nA5NmA,1141
|
38
|
-
janito/cli/main.py,sha256=ONmn_lIPu8_Rd57j3YfWEx46fWj8gAkONPLdctABwy0,1333
|
39
|
-
janito/cli/runner.py,sha256=64BErYxTvJjzFPKpbQvOoq6ARiEbPp03ZGFZBVogkgg,5043
|
40
|
-
janito/cli_chat_shell/__init__.py,sha256=PDGl7xK_vgkROoXvUxGZqVQFfuL9U4TjdexpP8E2JKg,41
|
41
|
-
janito/cli_chat_shell/chat_loop.py,sha256=AcryIgXb36g6214XKj75Xx4VxOYG-i8_IC_ROZyOLdk,5516
|
42
|
-
janito/cli_chat_shell/commands.py,sha256=ytt_5dym2sKOIlTjwAmfMg2jQVBlenDbPNwKJasPsDg,7245
|
43
|
-
janito/cli_chat_shell/config_shell.py,sha256=WlOxt7YOTIJluD3hURXbtOSodPHPnCwcO0LaH8_XXJE,3301
|
44
|
-
janito/cli_chat_shell/load_prompt.py,sha256=B7C_IhMk3n1XBQcfOwFVDnjrj1278JL3kV4UtkeeZx8,604
|
45
|
-
janito/cli_chat_shell/session_manager.py,sha256=PdqmFw4jZaCtQpazjgkKk_yhleZrzZOz_QqFeIf9Km4,1818
|
46
|
-
janito/cli_chat_shell/ui.py,sha256=9IngH8HFherjatfa9Eu37jb4b2gOP0lsgcUhbnQKCZA,5557
|
47
|
-
janito/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
48
|
-
janito/web/__main__.py,sha256=oPXNF332aCeI7aUWr7_8M57oOKugw422VrEubxFp0P4,354
|
49
|
-
janito/web/app.py,sha256=stogs_HaM-axsWTwoiVma9M46Y8dMu0QRjopsekRjQs,6622
|
50
|
-
janito-1.4.0.dist-info/licenses/LICENSE,sha256=sHBqv0bvtrb29H7WRR-Z603YHm9pLtJIo3nHU_9cmgE,1091
|
51
|
-
janito-1.4.0.dist-info/METADATA,sha256=_rNaRL-V53vjwrWJVJmgfz5XqRvekKr-Ju2bhi9G7FE,9114
|
52
|
-
janito-1.4.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
53
|
-
janito-1.4.0.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
|
54
|
-
janito-1.4.0.dist-info/top_level.txt,sha256=m0NaVCq0-ivxbazE2-ND0EA9Hmuijj_OGkmCbnBcCig,7
|
55
|
-
janito-1.4.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|