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.
Files changed (112) hide show
  1. janito/__main__.py +127 -141
  2. janito/agents/__init__.py +22 -22
  3. janito/agents/agent.py +24 -27
  4. janito/agents/claudeai.py +41 -45
  5. janito/agents/deepseekai.py +47 -0
  6. janito/change/applied_blocks.py +34 -0
  7. janito/change/applier.py +167 -0
  8. janito/change/edit_blocks.py +148 -0
  9. janito/change/finder.py +72 -0
  10. janito/change/request.py +144 -0
  11. janito/change/validator.py +87 -269
  12. janito/change/view/content.py +63 -0
  13. janito/change/{viewer → view}/diff.py +44 -43
  14. janito/change/view/panels.py +201 -0
  15. janito/change/view/sections.py +69 -0
  16. janito/change/view/styling.py +140 -0
  17. janito/change/view/summary.py +37 -0
  18. janito/change/{viewer → view}/themes.py +62 -55
  19. janito/change/view/viewer.py +59 -0
  20. janito/cli/__init__.py +1 -1
  21. janito/cli/commands.py +68 -88
  22. janito/cli/functions.py +66 -111
  23. janito/common.py +132 -79
  24. janito/config.py +99 -101
  25. janito/data/change_prompt.txt +81 -0
  26. janito/data/system_prompt.txt +3 -0
  27. janito/qa.py +56 -57
  28. janito/version.py +22 -22
  29. janito/workspace/__init__.py +8 -6
  30. janito/workspace/analysis.py +120 -120
  31. janito/workspace/{types.py → models.py} +97 -98
  32. janito/workspace/show.py +115 -141
  33. janito/workspace/stats.py +42 -43
  34. janito/workspace/workset.py +135 -108
  35. janito/workspace/workspace.py +335 -114
  36. janito-0.8.0.dist-info/METADATA +106 -0
  37. janito-0.8.0.dist-info/RECORD +40 -0
  38. {janito-0.7.0.dist-info → janito-0.8.0.dist-info}/licenses/LICENSE +20 -20
  39. janito/__init__.py +0 -2
  40. janito/agents/openai.py +0 -57
  41. janito/agents/test.py +0 -34
  42. janito/change/__init__.py +0 -32
  43. janito/change/__main__.py +0 -0
  44. janito/change/analysis/__init__.py +0 -23
  45. janito/change/analysis/__main__.py +0 -7
  46. janito/change/analysis/analyze.py +0 -62
  47. janito/change/analysis/formatting.py +0 -78
  48. janito/change/analysis/options.py +0 -81
  49. janito/change/analysis/prompts.py +0 -90
  50. janito/change/analysis/view/__init__.py +0 -9
  51. janito/change/analysis/view/terminal.py +0 -181
  52. janito/change/applier/__init__.py +0 -5
  53. janito/change/applier/file.py +0 -58
  54. janito/change/applier/main.py +0 -156
  55. janito/change/applier/text.py +0 -247
  56. janito/change/applier/workspace_dir.py +0 -58
  57. janito/change/core.py +0 -124
  58. janito/change/history.py +0 -44
  59. janito/change/operations.py +0 -7
  60. janito/change/parser.py +0 -287
  61. janito/change/play.py +0 -54
  62. janito/change/preview.py +0 -82
  63. janito/change/prompts.py +0 -121
  64. janito/change/test.py +0 -0
  65. janito/change/viewer/__init__.py +0 -11
  66. janito/change/viewer/content.py +0 -66
  67. janito/change/viewer/panels.py +0 -533
  68. janito/change/viewer/styling.py +0 -114
  69. janito/clear_statement_parser/clear_statement_format.txt +0 -328
  70. janito/clear_statement_parser/examples.txt +0 -326
  71. janito/clear_statement_parser/models.py +0 -104
  72. janito/clear_statement_parser/parser.py +0 -496
  73. janito/cli/base.py +0 -30
  74. janito/cli/history.py +0 -61
  75. janito/cli/registry.py +0 -26
  76. janito/demo/__init__.py +0 -4
  77. janito/demo/data.py +0 -13
  78. janito/demo/mock_data.py +0 -20
  79. janito/demo/operations.py +0 -45
  80. janito/demo/runner.py +0 -59
  81. janito/demo/scenarios.py +0 -32
  82. janito/prompt.py +0 -36
  83. janito/review.py +0 -13
  84. janito/search_replace/README.md +0 -192
  85. janito/search_replace/__init__.py +0 -7
  86. janito/search_replace/__main__.py +0 -21
  87. janito/search_replace/core.py +0 -120
  88. janito/search_replace/logger.py +0 -35
  89. janito/search_replace/parser.py +0 -52
  90. janito/search_replace/play.py +0 -61
  91. janito/search_replace/replacer.py +0 -36
  92. janito/search_replace/searcher.py +0 -411
  93. janito/search_replace/strategy_result.py +0 -10
  94. janito/shell/__init__.py +0 -38
  95. janito/shell/bus.py +0 -31
  96. janito/shell/commands.py +0 -136
  97. janito/shell/history.py +0 -20
  98. janito/shell/processor.py +0 -32
  99. janito/shell/prompt.py +0 -48
  100. janito/shell/registry.py +0 -60
  101. janito/tui/__init__.py +0 -21
  102. janito/tui/base.py +0 -22
  103. janito/tui/flows/__init__.py +0 -5
  104. janito/tui/flows/changes.py +0 -65
  105. janito/tui/flows/content.py +0 -128
  106. janito/tui/flows/selection.py +0 -117
  107. janito/tui/screens/__init__.py +0 -3
  108. janito/tui/screens/app.py +0 -1
  109. janito-0.7.0.dist-info/METADATA +0 -167
  110. janito-0.7.0.dist-info/RECORD +0 -96
  111. {janito-0.7.0.dist-info → janito-0.8.0.dist-info}/WHEEL +0 -0
  112. {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.debug_line = None
15
- self.test_cmd = os.getenv('JANITO_TEST_CMD')
16
- self.workspace_dir = Path.cwd()
17
- self.raw = False
18
- self.auto_apply: bool = False
19
- self.tui: bool = False
20
- self.skip_work: bool = False
21
-
22
- @classmethod
23
- def get_instance(cls) -> "ConfigManager":
24
- """Return the singleton instance of ConfigManager.
25
-
26
- Returns:
27
- ConfigManager: The singleton instance
28
- """
29
- if cls._instance is None:
30
- cls._instance = cls()
31
- return cls._instance
32
-
33
- def set_debug(self, enabled: bool) -> None:
34
- """Set debug mode.
35
-
36
- Args:
37
- enabled: True to enable debug mode, False to disable
38
- """
39
- self.debug = enabled
40
-
41
- def set_verbose(self, enabled: bool) -> None:
42
- """Set verbose output mode.
43
-
44
- Args:
45
- enabled: True to enable verbose output, False to disable
46
- """
47
- self.verbose = enabled
48
-
49
- def set_debug_line(self, line: Optional[int]) -> None:
50
- """Set specific line number for debug output.
51
-
52
- Args:
53
- line: Line number to debug, or None for all lines
54
- """
55
- self.debug_line = line
56
-
57
- def should_debug_line(self, line: int) -> bool:
58
- """Return True if we should show debug for this line number"""
59
- return self.debug and (self.debug_line is None or self.debug_line == line)
60
-
61
- def set_test_cmd(self, cmd: Optional[str]) -> None:
62
- """Set the test command, overriding environment variable"""
63
- self.test_cmd = cmd if cmd is not None else os.getenv('JANITO_TEST_CMD')
64
-
65
- def set_workspace_dir(self, path: Optional[Path]) -> None:
66
- """Set the workspace directory"""
67
- self.workspace_dir = path if path is not None else Path.cwd()
68
-
69
- def set_raw(self, enabled: bool) -> None:
70
- """Set raw output mode.
71
-
72
- Args:
73
- enabled: True to enable raw output mode, False to disable
74
- """
75
- self.raw = enabled
76
-
77
- def set_auto_apply(self, enabled: bool) -> None:
78
- """Set auto apply mode for changes.
79
-
80
- Args:
81
- enabled: True to enable auto apply mode, False to disable
82
- """
83
- self.auto_apply = enabled
84
-
85
- def set_tui(self, enabled: bool) -> None:
86
- """Set Text User Interface mode.
87
-
88
- Args:
89
- enabled: True to enable TUI mode, False to disable
90
- """
91
- self.tui = enabled
92
-
93
- def set_skip_work(self, enabled: bool) -> None:
94
- """Set whether to skip scanning the workspace directory.
95
-
96
- Args:
97
- enabled: True to skip workspace directory, False to include it
98
- """
99
- self.skip_work = enabled
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.
@@ -0,0 +1,3 @@
1
+ The assistant is an intelligent programmer, powered by Claude 3.5 Sonnet.
2
+ It is happy to help answer any questions that the user has (usually about coding).
3
+
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 rich.rule import Rule
5
- from janito.common import progress_send_message
6
- from janito.workspace import workset # Updated import
7
-
8
-
9
- QA_PROMPT = """Please provide a clear and concise answer to the following question about the workset you received above.
10
-
11
- Question: {question}
12
-
13
- Focus on providing factual information and explanations. Do not suggest code changes.
14
- Format your response using markdown with appropriate headers and code blocks.
15
- """
16
-
17
- def ask_question(question: str) -> str:
18
- """Process a question about the codebase and return the answer"""
19
- # Ensure content is refreshed and analyzed
20
- workset.show()
21
-
22
- prompt = QA_PROMPT.format(
23
- question=question,
24
- )
25
- return progress_send_message(prompt)
26
-
27
-
28
- def display_answer(answer: str, raw: bool = False) -> None:
29
- """Display the answer as markdown with consistent colors"""
30
- console = Console()
31
-
32
- # Define consistent colors
33
- COLORS = {
34
- 'primary': '#729FCF', # Soft blue for primary elements
35
- 'secondary': '#8AE234', # Bright green for actions/success
36
- 'accent': '#AD7FA8', # Purple for accents
37
- 'muted': '#7F9F7F', # Muted green for less important text
38
- }
39
-
40
- if raw:
41
- console.print(answer)
42
- return
43
-
44
- # Display markdown answer in a panel with consistent styling
45
- answer_panel = Panel(
46
- Markdown(answer),
47
- title="[bold]Answer[/bold]",
48
- title_align="center",
49
- border_style=COLORS['primary'],
50
- padding=(1, 2)
51
- )
52
-
53
- console.print("\n")
54
- console.print(Rule(style=COLORS['accent']))
55
- console.print(answer_panel)
56
- console.print(Rule(style=COLORS['accent']))
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"
@@ -1,6 +1,8 @@
1
- from .workset import Workset
2
-
3
- # Create and export singleton instance
4
- workset = Workset()
5
-
6
- __all__ = ['workset']
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']