janito 0.7.0__py3-none-any.whl → 0.8.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/__main__.py +127 -141
- janito/agents/__init__.py +22 -22
- janito/agents/agent.py +24 -27
- janito/agents/claudeai.py +41 -45
- janito/agents/deepseekai.py +47 -0
- janito/change/applied_blocks.py +34 -0
- janito/change/applier.py +167 -0
- janito/change/edit_blocks.py +148 -0
- janito/change/finder.py +72 -0
- janito/change/request.py +144 -0
- janito/change/validator.py +87 -269
- janito/change/view/content.py +63 -0
- janito/change/{viewer → view}/diff.py +44 -43
- janito/change/view/panels.py +201 -0
- janito/change/view/sections.py +69 -0
- janito/change/view/styling.py +140 -0
- janito/change/view/summary.py +37 -0
- janito/change/{viewer → view}/themes.py +62 -55
- janito/change/view/viewer.py +59 -0
- janito/cli/__init__.py +1 -1
- janito/cli/commands.py +68 -88
- janito/cli/functions.py +66 -111
- janito/common.py +132 -79
- janito/config.py +99 -101
- janito/data/change_prompt.txt +81 -0
- janito/data/system_prompt.txt +3 -0
- janito/qa.py +56 -57
- janito/version.py +22 -22
- janito/workspace/__init__.py +8 -6
- janito/workspace/analysis.py +120 -120
- janito/workspace/{types.py → models.py} +97 -98
- janito/workspace/show.py +115 -141
- janito/workspace/stats.py +42 -43
- janito/workspace/workset.py +135 -108
- janito/workspace/workspace.py +335 -114
- janito-0.8.0.dist-info/METADATA +106 -0
- janito-0.8.0.dist-info/RECORD +40 -0
- {janito-0.7.0.dist-info → janito-0.8.0.dist-info}/licenses/LICENSE +20 -20
- janito/__init__.py +0 -2
- janito/agents/openai.py +0 -57
- janito/agents/test.py +0 -34
- janito/change/__init__.py +0 -32
- janito/change/__main__.py +0 -0
- janito/change/analysis/__init__.py +0 -23
- janito/change/analysis/__main__.py +0 -7
- janito/change/analysis/analyze.py +0 -62
- janito/change/analysis/formatting.py +0 -78
- janito/change/analysis/options.py +0 -81
- janito/change/analysis/prompts.py +0 -90
- janito/change/analysis/view/__init__.py +0 -9
- janito/change/analysis/view/terminal.py +0 -181
- janito/change/applier/__init__.py +0 -5
- janito/change/applier/file.py +0 -58
- janito/change/applier/main.py +0 -156
- janito/change/applier/text.py +0 -247
- janito/change/applier/workspace_dir.py +0 -58
- janito/change/core.py +0 -124
- janito/change/history.py +0 -44
- janito/change/operations.py +0 -7
- janito/change/parser.py +0 -287
- janito/change/play.py +0 -54
- janito/change/preview.py +0 -82
- janito/change/prompts.py +0 -121
- janito/change/test.py +0 -0
- janito/change/viewer/__init__.py +0 -11
- janito/change/viewer/content.py +0 -66
- janito/change/viewer/panels.py +0 -533
- janito/change/viewer/styling.py +0 -114
- janito/clear_statement_parser/clear_statement_format.txt +0 -328
- janito/clear_statement_parser/examples.txt +0 -326
- janito/clear_statement_parser/models.py +0 -104
- janito/clear_statement_parser/parser.py +0 -496
- janito/cli/base.py +0 -30
- janito/cli/history.py +0 -61
- janito/cli/registry.py +0 -26
- janito/demo/__init__.py +0 -4
- janito/demo/data.py +0 -13
- janito/demo/mock_data.py +0 -20
- janito/demo/operations.py +0 -45
- janito/demo/runner.py +0 -59
- janito/demo/scenarios.py +0 -32
- janito/prompt.py +0 -36
- janito/review.py +0 -13
- janito/search_replace/README.md +0 -192
- janito/search_replace/__init__.py +0 -7
- janito/search_replace/__main__.py +0 -21
- janito/search_replace/core.py +0 -120
- janito/search_replace/logger.py +0 -35
- janito/search_replace/parser.py +0 -52
- janito/search_replace/play.py +0 -61
- janito/search_replace/replacer.py +0 -36
- janito/search_replace/searcher.py +0 -411
- janito/search_replace/strategy_result.py +0 -10
- janito/shell/__init__.py +0 -38
- janito/shell/bus.py +0 -31
- janito/shell/commands.py +0 -136
- janito/shell/history.py +0 -20
- janito/shell/processor.py +0 -32
- janito/shell/prompt.py +0 -48
- janito/shell/registry.py +0 -60
- janito/tui/__init__.py +0 -21
- janito/tui/base.py +0 -22
- janito/tui/flows/__init__.py +0 -5
- janito/tui/flows/changes.py +0 -65
- janito/tui/flows/content.py +0 -128
- janito/tui/flows/selection.py +0 -117
- janito/tui/screens/__init__.py +0 -3
- janito/tui/screens/app.py +0 -1
- janito-0.7.0.dist-info/METADATA +0 -167
- janito-0.7.0.dist-info/RECORD +0 -96
- {janito-0.7.0.dist-info → janito-0.8.0.dist-info}/WHEEL +0 -0
- {janito-0.7.0.dist-info → janito-0.8.0.dist-info}/entry_points.txt +0 -0
janito/config.py
CHANGED
@@ -1,102 +1,100 @@
|
|
1
|
-
from typing import Optional
|
2
|
-
import os
|
3
|
-
from pathlib import Path
|
4
|
-
|
5
|
-
class ConfigManager:
|
6
|
-
"""Singleton configuration manager for the application."""
|
7
|
-
|
8
|
-
_instance = None
|
9
|
-
|
10
|
-
def __init__(self):
|
11
|
-
"""Initialize configuration with default values."""
|
12
|
-
self.debug = False
|
13
|
-
self.verbose = False
|
14
|
-
self.
|
15
|
-
self.
|
16
|
-
self.
|
17
|
-
self.
|
18
|
-
self.
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
# Create a singleton instance
|
1
|
+
from typing import Optional
|
2
|
+
import os
|
3
|
+
from pathlib import Path
|
4
|
+
|
5
|
+
class ConfigManager:
|
6
|
+
"""Singleton configuration manager for the application."""
|
7
|
+
|
8
|
+
_instance = None
|
9
|
+
|
10
|
+
def __init__(self):
|
11
|
+
"""Initialize configuration with default values."""
|
12
|
+
self.debug = False
|
13
|
+
self.verbose = False
|
14
|
+
self.test_cmd = os.getenv('JANITO_TEST_CMD')
|
15
|
+
self.workspace_dir = Path.cwd()
|
16
|
+
self.raw = False
|
17
|
+
self.auto_apply: bool = False
|
18
|
+
self.skip_work: bool = False
|
19
|
+
|
20
|
+
@classmethod
|
21
|
+
def get_instance(cls) -> "ConfigManager":
|
22
|
+
"""Return the singleton instance of ConfigManager.
|
23
|
+
|
24
|
+
Returns:
|
25
|
+
ConfigManager: The singleton instance
|
26
|
+
"""
|
27
|
+
if cls._instance is None:
|
28
|
+
cls._instance = cls()
|
29
|
+
return cls._instance
|
30
|
+
|
31
|
+
def set_debug(self, enabled: bool) -> None:
|
32
|
+
"""Set debug mode.
|
33
|
+
|
34
|
+
Args:
|
35
|
+
enabled: True to enable debug mode, False to disable
|
36
|
+
"""
|
37
|
+
self.debug = enabled
|
38
|
+
|
39
|
+
def set_verbose(self, enabled: bool) -> None:
|
40
|
+
"""Set verbose output mode.
|
41
|
+
|
42
|
+
Args:
|
43
|
+
enabled: True to enable verbose output, False to disable
|
44
|
+
"""
|
45
|
+
self.verbose = enabled
|
46
|
+
|
47
|
+
def set_debug_line(self, line: Optional[int]) -> None:
|
48
|
+
"""Set specific line number for debug output.
|
49
|
+
|
50
|
+
Args:
|
51
|
+
line: Line number to debug, or None for all lines
|
52
|
+
"""
|
53
|
+
self.debug_line = line
|
54
|
+
|
55
|
+
def should_debug_line(self, line: int) -> bool:
|
56
|
+
"""Return True if we should show debug for this line number"""
|
57
|
+
return self.debug and (self.debug_line is None or self.debug_line == line)
|
58
|
+
|
59
|
+
def set_test_cmd(self, cmd: Optional[str]) -> None:
|
60
|
+
"""Set the test command, overriding environment variable"""
|
61
|
+
self.test_cmd = cmd if cmd is not None else os.getenv('JANITO_TEST_CMD')
|
62
|
+
|
63
|
+
def set_workspace_dir(self, path: Optional[Path]) -> None:
|
64
|
+
"""Set the workspace directory"""
|
65
|
+
self.workspace_dir = path if path is not None else Path.cwd()
|
66
|
+
|
67
|
+
def set_raw(self, enabled: bool) -> None:
|
68
|
+
"""Set raw output mode.
|
69
|
+
|
70
|
+
Args:
|
71
|
+
enabled: True to enable raw output mode, False to disable
|
72
|
+
"""
|
73
|
+
self.raw = enabled
|
74
|
+
|
75
|
+
def set_auto_apply(self, enabled: bool) -> None:
|
76
|
+
"""Set auto apply mode for changes.
|
77
|
+
|
78
|
+
Args:
|
79
|
+
enabled: True to enable auto apply mode, False to disable
|
80
|
+
"""
|
81
|
+
self.auto_apply = enabled
|
82
|
+
|
83
|
+
def set_tui(self, enabled: bool) -> None:
|
84
|
+
"""Set Text User Interface mode.
|
85
|
+
|
86
|
+
Args:
|
87
|
+
enabled: True to enable TUI mode, False to disable
|
88
|
+
"""
|
89
|
+
self.tui = enabled
|
90
|
+
|
91
|
+
def set_skip_work(self, enabled: bool) -> None:
|
92
|
+
"""Set whether to skip scanning the workspace directory.
|
93
|
+
|
94
|
+
Args:
|
95
|
+
enabled: True to skip workspace directory, False to include it
|
96
|
+
"""
|
97
|
+
self.skip_work = enabled
|
98
|
+
|
99
|
+
# Create a singleton instance
|
102
100
|
config = ConfigManager.get_instance()
|
@@ -0,0 +1,81 @@
|
|
1
|
+
Provide the instructions for the change request:
|
2
|
+
{request}
|
3
|
+
|
4
|
+
This is the workset:
|
5
|
+
|
6
|
+
{workset}
|
7
|
+
|
8
|
+
Before providing the actual changes, please provide an action plan in markdown format. The action plan should include the following sections:
|
9
|
+
|
10
|
+
Execution Planning:
|
11
|
+
1. Brief introduction refering the files and sections that will be affected.
|
12
|
+
|
13
|
+
Implementation:
|
14
|
+
- Both the original code and the modified code should be provided in plain text format with:
|
15
|
+
- original indentation as found in the original file
|
16
|
+
- original or modified indentation as might be required for the changes (eg, adding a try block will shift the indentation of the code inside the block)
|
17
|
+
- When the user asks for edits to their code, the assistant will provide one or edit blocks, a block can contain multiple changes to the same file.
|
18
|
+
- When new imports are required, they should be placed at the top of the existing files, even if that requires an extra edit block.
|
19
|
+
- Merge edit blocks that would affect the same function/method into a single edit block
|
20
|
+
|
21
|
+
Edit <path/to/file> "<reason for the change>"
|
22
|
+
<<<< original
|
23
|
+
{{ Assistant writes original lines found in the workset }}
|
24
|
+
>>>> modified
|
25
|
+
{{ Assistant writes the lines to replace the original }}
|
26
|
+
==== # marks end of file edit block
|
27
|
+
|
28
|
+
# For removing large pieces of code, use the "clean" operation
|
29
|
+
Clean <path/to/file> "{{ Assistant writes reason }}"
|
30
|
+
<<<< starting
|
31
|
+
{{ Assistant writes the first lines to match where cleaning starts }}
|
32
|
+
>>>> ending
|
33
|
+
{{ Assistant writes the last lines to match where cleaning ends }}
|
34
|
+
# The cleaning operation removes all content between and including the starting and ending markers
|
35
|
+
# Be careful to provide minimal but sufficient lines to identify the correct content
|
36
|
+
====
|
37
|
+
|
38
|
+
Create <path/to/file> "{{ Assistant writes reason }}"
|
39
|
+
>>>> modified
|
40
|
+
{{ Assistant writes the full content of the file }}
|
41
|
+
====
|
42
|
+
|
43
|
+
Delete <path/to/file> "{{ Assistant writes reason }}"
|
44
|
+
==== # for deletes there is no need for markers, just the end marker
|
45
|
+
|
46
|
+
Avoid common pitfalls:
|
47
|
+
|
48
|
+
- Adding a try block without the entire affected content
|
49
|
+
Edit file
|
50
|
+
<<<< original
|
51
|
+
def _apply_and_collect_change(self, edit: CodeChange) -> AppliedBlock:
|
52
|
+
"""Apply a single edit and collect its change information."""
|
53
|
+
do_thing()
|
54
|
+
|
55
|
+
>>>> modified
|
56
|
+
def _apply_and_collect_change(self, edit: CodeChange) -> AppliedBlock:
|
57
|
+
"""Apply a single edit and collect its change information."""
|
58
|
+
try:
|
59
|
+
do_thing()
|
60
|
+
====
|
61
|
+
This would cause a syntax error, because do_thing is very likely followed by other code which would be kept outside the try block. The correct way to add a try block is to include all the code that should be inside the try block.
|
62
|
+
|
63
|
+
Correct would be:
|
64
|
+
Edit file
|
65
|
+
<<<< original
|
66
|
+
def _apply_and_collect_change(self, edit: CodeChange) -> AppliedBlock:
|
67
|
+
"""Apply a single edit and collect its change information."""
|
68
|
+
do_thing()
|
69
|
+
do_other_thing()
|
70
|
+
>>>> modified
|
71
|
+
def _apply_and_collect_change(self, edit: CodeChange) -> AppliedBlock:
|
72
|
+
"""Apply a single edit and collect its change information."""
|
73
|
+
try:
|
74
|
+
do_thing()
|
75
|
+
do_other_thing()
|
76
|
+
except Exception as e:
|
77
|
+
handle_exception(e)
|
78
|
+
=====
|
79
|
+
|
80
|
+
Final Summary:
|
81
|
+
Provide a one line summary of the expected result of the changes.
|
janito/qa.py
CHANGED
@@ -1,57 +1,56 @@
|
|
1
|
-
from rich.console import Console
|
2
|
-
from rich.markdown import Markdown
|
3
|
-
from rich.panel import Panel
|
4
|
-
from
|
5
|
-
from janito.
|
6
|
-
from
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
question
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
console.print(
|
57
|
-
console.print("\n")
|
1
|
+
from rich.console import Console
|
2
|
+
from rich.markdown import Markdown
|
3
|
+
from rich.panel import Panel
|
4
|
+
from janito.common import progress_send_message
|
5
|
+
from janito.workspace import workset
|
6
|
+
from pathlib import Path
|
7
|
+
|
8
|
+
QA_PROMPT = """Please provide a clear and concise answer to the following question about the workset provided later.
|
9
|
+
|
10
|
+
Question: {question}
|
11
|
+
|
12
|
+
Focus on providing factual information and explanations. Do not suggest code changes.
|
13
|
+
Format your response using markdown with appropriate headers and code blocks.
|
14
|
+
|
15
|
+
workset content:
|
16
|
+
{workset}
|
17
|
+
"""
|
18
|
+
|
19
|
+
def ask_question(question: str, file_filter: list[Path] = None) -> str:
|
20
|
+
"""Process a question about the codebase and return the answer
|
21
|
+
|
22
|
+
Args:
|
23
|
+
question: The question to ask about the codebase
|
24
|
+
file_filter: list of paths to files to include in the workset
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
str: The answer from the AI agent, or an error message if interrupted
|
28
|
+
"""
|
29
|
+
workset.refresh()
|
30
|
+
|
31
|
+
prompt = QA_PROMPT.format(
|
32
|
+
question=question,
|
33
|
+
workset=workset.content
|
34
|
+
)
|
35
|
+
answer = progress_send_message(prompt)
|
36
|
+
|
37
|
+
if answer is None:
|
38
|
+
return "Sorry, the response was interrupted. Please try asking your question again."
|
39
|
+
|
40
|
+
return answer
|
41
|
+
|
42
|
+
|
43
|
+
def display_answer(answer: str, raw: bool = False) -> None:
|
44
|
+
"""Display the answer as markdown"""
|
45
|
+
if answer is None:
|
46
|
+
Console().print("\n[red]Error: No answer received - the response was interrupted[/red]\n")
|
47
|
+
return
|
48
|
+
|
49
|
+
console = Console()
|
50
|
+
|
51
|
+
if raw:
|
52
|
+
console.print(answer)
|
53
|
+
return
|
54
|
+
|
55
|
+
# Display markdown answer directly
|
56
|
+
console.print(Markdown(answer))
|
janito/version.py
CHANGED
@@ -1,23 +1,23 @@
|
|
1
|
-
"""Version management module for Janito."""
|
2
|
-
from pathlib import Path
|
3
|
-
from typing import Optional
|
4
|
-
import tomli
|
5
|
-
from importlib.metadata import version as pkg_version
|
6
|
-
|
7
|
-
def get_version() -> str:
|
8
|
-
"""
|
9
|
-
Get Janito version from package metadata or pyproject.toml.
|
10
|
-
|
11
|
-
Returns:
|
12
|
-
str: The version string
|
13
|
-
"""
|
14
|
-
try:
|
15
|
-
return pkg_version("janito")
|
16
|
-
except Exception:
|
17
|
-
# Fallback to pyproject.toml
|
18
|
-
pyproject_path = Path(__file__).parent.parent / "pyproject.toml"
|
19
|
-
if pyproject_path.exists():
|
20
|
-
with open(pyproject_path, "rb") as f:
|
21
|
-
pyproject_data = tomli.load(f)
|
22
|
-
return pyproject_data.get("project", {}).get("version", "unknown")
|
1
|
+
"""Version management module for Janito."""
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import Optional
|
4
|
+
import tomli
|
5
|
+
from importlib.metadata import version as pkg_version
|
6
|
+
|
7
|
+
def get_version() -> str:
|
8
|
+
"""
|
9
|
+
Get Janito version from package metadata or pyproject.toml.
|
10
|
+
|
11
|
+
Returns:
|
12
|
+
str: The version string
|
13
|
+
"""
|
14
|
+
try:
|
15
|
+
return pkg_version("janito")
|
16
|
+
except Exception:
|
17
|
+
# Fallback to pyproject.toml
|
18
|
+
pyproject_path = Path(__file__).parent.parent / "pyproject.toml"
|
19
|
+
if pyproject_path.exists():
|
20
|
+
with open(pyproject_path, "rb") as f:
|
21
|
+
pyproject_data = tomli.load(f)
|
22
|
+
return pyproject_data.get("project", {}).get("version", "unknown")
|
23
23
|
return "unknown"
|
janito/workspace/__init__.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
from .workset import Workset
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
from .workset import Workset
|
2
|
+
from .workspace import Workspace
|
3
|
+
|
4
|
+
# Create and export singleton instance
|
5
|
+
workset = Workset()
|
6
|
+
workspace = Workspace()
|
7
|
+
|
8
|
+
__all__ = ['workset', 'workspace']
|