janito 0.5.0__py3-none-any.whl → 0.7.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 +0 -47
- janito/__main__.py +105 -17
- janito/agents/__init__.py +9 -9
- janito/agents/agent.py +10 -3
- janito/agents/claudeai.py +15 -34
- janito/agents/openai.py +5 -1
- janito/change/__init__.py +29 -16
- janito/change/__main__.py +0 -0
- janito/{analysis → change/analysis}/__init__.py +5 -15
- janito/change/analysis/__main__.py +7 -0
- janito/change/analysis/analyze.py +62 -0
- janito/change/analysis/formatting.py +78 -0
- janito/change/analysis/options.py +81 -0
- janito/{analysis → change/analysis}/prompts.py +33 -18
- janito/change/analysis/view/__init__.py +9 -0
- janito/change/analysis/view/terminal.py +181 -0
- janito/change/applier/__init__.py +5 -0
- janito/change/applier/file.py +58 -0
- janito/change/applier/main.py +156 -0
- janito/change/applier/text.py +247 -0
- janito/change/applier/workspace_dir.py +58 -0
- janito/change/core.py +124 -0
- janito/{changehistory.py → change/history.py} +12 -14
- janito/change/operations.py +7 -0
- janito/change/parser.py +287 -0
- janito/change/play.py +54 -0
- janito/change/preview.py +82 -0
- janito/change/prompts.py +121 -0
- janito/change/test.py +0 -0
- janito/change/validator.py +269 -0
- janito/{changeviewer → change/viewer}/__init__.py +3 -4
- janito/change/viewer/content.py +66 -0
- janito/{changeviewer → change/viewer}/diff.py +19 -4
- janito/change/viewer/panels.py +533 -0
- janito/change/viewer/styling.py +114 -0
- janito/{changeviewer → change/viewer}/themes.py +3 -5
- janito/clear_statement_parser/clear_statement_format.txt +328 -0
- janito/clear_statement_parser/examples.txt +326 -0
- janito/clear_statement_parser/models.py +104 -0
- janito/clear_statement_parser/parser.py +496 -0
- janito/cli/base.py +30 -0
- janito/cli/commands.py +75 -40
- janito/cli/functions.py +19 -194
- janito/cli/history.py +61 -0
- janito/common.py +65 -8
- janito/config.py +70 -5
- janito/demo/__init__.py +4 -0
- janito/demo/data.py +13 -0
- janito/demo/mock_data.py +20 -0
- janito/demo/operations.py +45 -0
- janito/demo/runner.py +59 -0
- janito/demo/scenarios.py +32 -0
- janito/prompt.py +36 -0
- janito/qa.py +6 -14
- janito/search_replace/README.md +192 -0
- janito/search_replace/__init__.py +7 -0
- janito/search_replace/__main__.py +21 -0
- janito/search_replace/core.py +120 -0
- janito/search_replace/logger.py +35 -0
- janito/search_replace/parser.py +52 -0
- janito/search_replace/play.py +61 -0
- janito/search_replace/replacer.py +36 -0
- janito/search_replace/searcher.py +411 -0
- janito/search_replace/strategy_result.py +10 -0
- janito/shell/__init__.py +38 -0
- janito/shell/bus.py +31 -0
- janito/shell/commands.py +136 -0
- janito/shell/history.py +20 -0
- janito/shell/processor.py +32 -0
- janito/shell/prompt.py +48 -0
- janito/shell/registry.py +60 -0
- janito/tui/__init__.py +21 -0
- janito/tui/base.py +22 -0
- janito/tui/flows/__init__.py +5 -0
- janito/tui/flows/changes.py +65 -0
- janito/tui/flows/content.py +128 -0
- janito/tui/flows/selection.py +117 -0
- janito/tui/screens/__init__.py +3 -0
- janito/tui/screens/app.py +1 -0
- janito/workspace/__init__.py +6 -0
- janito/workspace/analysis.py +121 -0
- janito/workspace/show.py +141 -0
- janito/workspace/stats.py +43 -0
- janito/workspace/types.py +98 -0
- janito/workspace/workset.py +108 -0
- janito/workspace/workspace.py +114 -0
- janito-0.7.0.dist-info/METADATA +167 -0
- janito-0.7.0.dist-info/RECORD +96 -0
- {janito-0.5.0.dist-info → janito-0.7.0.dist-info}/WHEEL +1 -1
- janito/_contextparser.py +0 -113
- janito/analysis/display.py +0 -149
- janito/analysis/options.py +0 -112
- janito/change/applier.py +0 -269
- janito/change/content.py +0 -62
- janito/change/indentation.py +0 -33
- janito/change/position.py +0 -169
- janito/changeviewer/panels.py +0 -268
- janito/changeviewer/styling.py +0 -59
- janito/console/__init__.py +0 -3
- janito/console/commands.py +0 -112
- janito/console/core.py +0 -62
- janito/console/display.py +0 -157
- janito/fileparser.py +0 -334
- janito/prompts.py +0 -81
- janito/scan.py +0 -176
- janito/tests/test_fileparser.py +0 -26
- janito-0.5.0.dist-info/METADATA +0 -146
- janito-0.5.0.dist-info/RECORD +0 -45
- {janito-0.5.0.dist-info → janito-0.7.0.dist-info}/entry_points.txt +0 -0
- {janito-0.5.0.dist-info → janito-0.7.0.dist-info}/licenses/LICENSE +0 -0
janito/changeviewer/panels.py
DELETED
@@ -1,268 +0,0 @@
|
|
1
|
-
from rich.console import Console
|
2
|
-
from rich.panel import Panel
|
3
|
-
from rich.columns import Columns
|
4
|
-
from rich.text import Text
|
5
|
-
from rich.syntax import Syntax
|
6
|
-
from rich.table import Table
|
7
|
-
from rich import box
|
8
|
-
from pathlib import Path
|
9
|
-
from typing import List
|
10
|
-
from datetime import datetime
|
11
|
-
from janito.fileparser import FileChange
|
12
|
-
from janito.config import config
|
13
|
-
from .styling import format_content, create_legend_items, current_theme
|
14
|
-
from .themes import ColorTheme
|
15
|
-
from .diff import find_common_sections
|
16
|
-
|
17
|
-
|
18
|
-
def create_new_file_panel(filepath: Path, content: str) -> Panel:
|
19
|
-
"""Create a panel for new file creation"""
|
20
|
-
size_bytes = len(content.encode('utf-8'))
|
21
|
-
size_str = f"{size_bytes} bytes" if size_bytes < 1024 else f"{size_bytes/1024:.1f} KB"
|
22
|
-
|
23
|
-
# Create metadata table
|
24
|
-
metadata = Table.grid(padding=(0, 1))
|
25
|
-
metadata.add_row("File Size:", size_str)
|
26
|
-
metadata.add_row("Created:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
27
|
-
|
28
|
-
# Create content preview with empty left panel
|
29
|
-
content_table = Table.grid(padding=(0, 2))
|
30
|
-
content_table.add_column("Before", justify="left")
|
31
|
-
content_table.add_column("After", justify="left")
|
32
|
-
|
33
|
-
empty_panel = Panel(
|
34
|
-
Text("(No previous content)", style="dim"),
|
35
|
-
title="Previous Content",
|
36
|
-
title_align="left",
|
37
|
-
border_style="#E06C75",
|
38
|
-
box=box.ROUNDED
|
39
|
-
)
|
40
|
-
|
41
|
-
content_display = content
|
42
|
-
if filepath.suffix in ['.py', '.js', '.ts', '.java', '.cpp', '.c']:
|
43
|
-
try:
|
44
|
-
content_display = Syntax(content, filepath.suffix.lstrip('.'), theme="monokai")
|
45
|
-
except:
|
46
|
-
pass
|
47
|
-
|
48
|
-
new_panel = Panel(
|
49
|
-
content_display,
|
50
|
-
title="New Content",
|
51
|
-
title_align="left",
|
52
|
-
border_style="#61AFEF",
|
53
|
-
box=box.ROUNDED
|
54
|
-
)
|
55
|
-
|
56
|
-
content_table.add_row(empty_panel, new_panel)
|
57
|
-
|
58
|
-
content = Table.grid(padding=(1, 0))
|
59
|
-
content.add_row(Panel(metadata, title="File Metadata", border_style="white"))
|
60
|
-
content.add_row(Panel(content_table, title="Content Preview", border_style="white"))
|
61
|
-
|
62
|
-
return Panel(
|
63
|
-
content,
|
64
|
-
title=f"[bold]✨ Creating {filepath}[/bold]",
|
65
|
-
title_align="left",
|
66
|
-
border_style="#8AE234",
|
67
|
-
box=box.ROUNDED
|
68
|
-
)
|
69
|
-
|
70
|
-
def create_change_panel(search: str, replace: str | None, description: str, index: int) -> Panel:
|
71
|
-
"""Create a panel for file changes"""
|
72
|
-
operation = 'delete' if replace is None else 'modify'
|
73
|
-
|
74
|
-
if replace is None:
|
75
|
-
return Panel(
|
76
|
-
Text(search, style="red"),
|
77
|
-
title=f"- Content to Delete{' - ' + description if description else ''}",
|
78
|
-
title_align="left",
|
79
|
-
border_style="#E06C75",
|
80
|
-
box=box.ROUNDED
|
81
|
-
)
|
82
|
-
|
83
|
-
search_lines = search.splitlines()
|
84
|
-
replace_lines = replace.splitlines()
|
85
|
-
common_top, search_middle, replace_middle, common_bottom, all_search_lines = find_common_sections(search_lines, replace_lines)
|
86
|
-
|
87
|
-
content_table = Table.grid(padding=(0, 2))
|
88
|
-
content_table.add_column("Current", justify="left", ratio=1)
|
89
|
-
content_table.add_column("New", justify="left", ratio=1)
|
90
|
-
|
91
|
-
# Add column headers
|
92
|
-
content_table.add_row(
|
93
|
-
Text("Current Content", style="bold cyan"),
|
94
|
-
Text("New Content", style="bold cyan")
|
95
|
-
)
|
96
|
-
|
97
|
-
# Add the actual content
|
98
|
-
content_table.add_row(
|
99
|
-
format_content(search_lines, search_lines, replace_lines, True, operation),
|
100
|
-
format_content(replace_lines, search_lines, replace_lines, False, operation)
|
101
|
-
)
|
102
|
-
|
103
|
-
header = f"Change {index}"
|
104
|
-
if description:
|
105
|
-
header += f": {description}"
|
106
|
-
|
107
|
-
return Panel(
|
108
|
-
content_table,
|
109
|
-
title=header,
|
110
|
-
title_align="left",
|
111
|
-
border_style="cyan",
|
112
|
-
box=box.ROUNDED
|
113
|
-
)
|
114
|
-
|
115
|
-
def create_replace_panel(filepath: Path, change: FileChange) -> Panel:
|
116
|
-
"""Create a panel for file replacement with metadata"""
|
117
|
-
old_size = len(change.original_content.encode('utf-8'))
|
118
|
-
new_size = len(change.content.encode('utf-8'))
|
119
|
-
|
120
|
-
# Create metadata table
|
121
|
-
metadata = Table.grid(padding=(0, 1))
|
122
|
-
metadata.add_row("Original Size:", f"{old_size/1024:.1f} KB")
|
123
|
-
metadata.add_row("New Size:", f"{new_size/1024:.1f} KB")
|
124
|
-
metadata.add_row("Size Change:", f"{(new_size - old_size)/1024:+.1f} KB")
|
125
|
-
metadata.add_row("Modified:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
126
|
-
|
127
|
-
# Create unified diff preview
|
128
|
-
content_table = Table.grid(padding=(0, 2))
|
129
|
-
content_table.add_column("Current", justify="left")
|
130
|
-
content_table.add_column("New", justify="left")
|
131
|
-
|
132
|
-
# Add column headers
|
133
|
-
content_table.add_row(
|
134
|
-
Text("Current Content", style="bold cyan"),
|
135
|
-
Text("New Content", style="bold cyan")
|
136
|
-
)
|
137
|
-
|
138
|
-
# Add the actual content
|
139
|
-
content_table.add_row(
|
140
|
-
format_content(change.original_content.splitlines(),
|
141
|
-
change.original_content.splitlines(),
|
142
|
-
change.content.splitlines(), True),
|
143
|
-
format_content(change.content.splitlines(),
|
144
|
-
change.original_content.splitlines(),
|
145
|
-
change.content.splitlines(), False)
|
146
|
-
)
|
147
|
-
|
148
|
-
content = Table.grid(padding=(1, 0))
|
149
|
-
content.add_row(Panel(metadata, title="File Metadata", border_style="white"))
|
150
|
-
content.add_row(Panel(content_table, title="Content Preview", border_style="white"))
|
151
|
-
|
152
|
-
return Panel(
|
153
|
-
content,
|
154
|
-
title=f"[bold]🔄 Replacing {filepath}[/bold]",
|
155
|
-
title_align="left",
|
156
|
-
border_style="#FFB86C",
|
157
|
-
box=box.ROUNDED
|
158
|
-
)
|
159
|
-
|
160
|
-
def create_remove_file_panel(filepath: Path) -> Panel:
|
161
|
-
"""Create a panel for file removal"""
|
162
|
-
return Panel(
|
163
|
-
Text(f"This file will be deleted", style="red"),
|
164
|
-
title=f"[bold]- Removing {filepath}[/bold]",
|
165
|
-
title_align="left",
|
166
|
-
border_style="#F44336",
|
167
|
-
box=box.HEAVY,
|
168
|
-
padding=(1, 2)
|
169
|
-
)
|
170
|
-
|
171
|
-
def show_change_preview(console: Console, filepath: Path, change: FileChange) -> None:
|
172
|
-
"""Display a preview of changes for a single file"""
|
173
|
-
if change.remove_file:
|
174
|
-
panel = create_remove_file_panel(filepath)
|
175
|
-
console.print(panel)
|
176
|
-
console.print()
|
177
|
-
return
|
178
|
-
|
179
|
-
if change.is_new_file:
|
180
|
-
panel = create_new_file_panel(filepath, change.content)
|
181
|
-
console.print(panel)
|
182
|
-
console.print()
|
183
|
-
return
|
184
|
-
|
185
|
-
if change.replace_file:
|
186
|
-
panel = create_replace_panel(filepath, change)
|
187
|
-
console.print(panel)
|
188
|
-
console.print()
|
189
|
-
return
|
190
|
-
|
191
|
-
main_content = []
|
192
|
-
for i, (search, replace, description) in enumerate(change.search_blocks, 1):
|
193
|
-
panel = create_change_panel(search, replace, description, i)
|
194
|
-
main_content.append(panel)
|
195
|
-
|
196
|
-
file_panel = Panel(
|
197
|
-
Columns(main_content, align="center"),
|
198
|
-
title=f"Modifying {filepath} - {change.description}",
|
199
|
-
title_align="left",
|
200
|
-
border_style="white",
|
201
|
-
box=box.ROUNDED
|
202
|
-
)
|
203
|
-
console.print(file_panel)
|
204
|
-
console.print()
|
205
|
-
|
206
|
-
def preview_all_changes(console: Console, changes: List[FileChange]) -> None:
|
207
|
-
"""Show preview for all file changes"""
|
208
|
-
if config.debug:
|
209
|
-
_print_debug_info(console, changes)
|
210
|
-
|
211
|
-
console.print("\n[bold blue]Change Preview[/bold blue]")
|
212
|
-
|
213
|
-
has_modified_files = any(not change.is_new_file for change in changes)
|
214
|
-
if has_modified_files:
|
215
|
-
_show_legend(console)
|
216
|
-
|
217
|
-
new_files = [change for change in changes if change.is_new_file]
|
218
|
-
modified_files = [change for change in changes if not change.is_new_file]
|
219
|
-
|
220
|
-
for change in new_files:
|
221
|
-
show_change_preview(console, change.path, change)
|
222
|
-
for change in modified_files:
|
223
|
-
show_change_preview(console, change.path, change)
|
224
|
-
|
225
|
-
def _print_debug_info(console: Console, changes: List[FileChange]) -> None:
|
226
|
-
"""Print debug information about file changes"""
|
227
|
-
console.print("\n[blue]Debug: File Changes to Preview:[/blue]")
|
228
|
-
for change in changes:
|
229
|
-
console.print(f"\n[cyan]File:[/cyan] {change.path}")
|
230
|
-
console.print(f" [yellow]Is New File:[/yellow] {change.is_new_file}")
|
231
|
-
console.print(f" [yellow]Description:[/yellow] {change.description}")
|
232
|
-
if change.search_blocks:
|
233
|
-
console.print(" [yellow]Search Blocks:[/yellow]")
|
234
|
-
for i, (search, replace, desc) in enumerate(change.search_blocks, 1):
|
235
|
-
console.print(f" Block {i}:")
|
236
|
-
console.print(f" Description: {desc or 'No description'}")
|
237
|
-
console.print(f" Operation: {'Replace' if replace else 'Delete'}")
|
238
|
-
console.print(f" Search Length: {len(search)} chars")
|
239
|
-
if replace:
|
240
|
-
console.print(f" Replace Length: {len(replace)} chars")
|
241
|
-
console.print("\n[blue]End Debug File Changes[/blue]\n")
|
242
|
-
|
243
|
-
def _show_legend(console: Console) -> None:
|
244
|
-
"""Show the unified legend status bar"""
|
245
|
-
legend = create_legend_items()
|
246
|
-
|
247
|
-
# Calculate panel width based on legend content
|
248
|
-
legend_width = len(str(legend)) + 10 # Add padding for borders
|
249
|
-
|
250
|
-
legend_panel = Panel(
|
251
|
-
legend,
|
252
|
-
title="Changes Legend",
|
253
|
-
title_align="center",
|
254
|
-
border_style="white",
|
255
|
-
box=box.ROUNDED,
|
256
|
-
padding=(0, 2),
|
257
|
-
width=legend_width
|
258
|
-
)
|
259
|
-
|
260
|
-
# Create a full-width container and center the legend panel
|
261
|
-
container = Columns(
|
262
|
-
[legend_panel],
|
263
|
-
align="center",
|
264
|
-
expand=True
|
265
|
-
)
|
266
|
-
|
267
|
-
console.print(container)
|
268
|
-
console.print()
|
janito/changeviewer/styling.py
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
from rich.text import Text
|
2
|
-
from rich.console import Console
|
3
|
-
from typing import List
|
4
|
-
from .themes import DEFAULT_THEME, ColorTheme, ThemeType, get_theme_by_type
|
5
|
-
|
6
|
-
current_theme = DEFAULT_THEME
|
7
|
-
|
8
|
-
def set_theme(theme: ColorTheme) -> None:
|
9
|
-
"""Set the current color theme"""
|
10
|
-
global current_theme
|
11
|
-
current_theme = theme
|
12
|
-
|
13
|
-
def format_content(lines: List[str], search_lines: List[str], replace_lines: List[str], is_search: bool, operation: str = 'modify') -> Text:
|
14
|
-
"""Format content with highlighting using consistent colors and line numbers"""
|
15
|
-
text = Text()
|
16
|
-
|
17
|
-
# Create sets of lines for comparison
|
18
|
-
search_set = set(search_lines)
|
19
|
-
replace_set = set(replace_lines)
|
20
|
-
common_lines = search_set & replace_set
|
21
|
-
new_lines = replace_set - search_set
|
22
|
-
|
23
|
-
def add_line(line: str, prefix: str = " ", line_type: str = 'unchanged'):
|
24
|
-
# Ensure line_type is one of the valid types
|
25
|
-
valid_types = {'unchanged', 'deleted', 'modified', 'added'}
|
26
|
-
if line_type not in valid_types:
|
27
|
-
line_type = 'unchanged'
|
28
|
-
|
29
|
-
bg_color = current_theme.line_backgrounds.get(line_type, current_theme.line_backgrounds['unchanged'])
|
30
|
-
style = f"{current_theme.text_color} on {bg_color}"
|
31
|
-
|
32
|
-
# Add prefix with background
|
33
|
-
text.append(prefix, style=style)
|
34
|
-
# Add line content with background and pad with spaces
|
35
|
-
text.append(" " + line, style=style)
|
36
|
-
# Add newline with same background
|
37
|
-
text.append(" " * 1000 + "\n", style=style)
|
38
|
-
|
39
|
-
for line in lines:
|
40
|
-
if line in common_lines:
|
41
|
-
add_line(line, " ", 'unchanged')
|
42
|
-
elif not is_search and line in new_lines:
|
43
|
-
add_line(line, "✚", 'added')
|
44
|
-
else:
|
45
|
-
prefix = "✕" if is_search else "✚"
|
46
|
-
line_type = 'deleted' if is_search else 'modified'
|
47
|
-
add_line(line, prefix, line_type)
|
48
|
-
|
49
|
-
return text
|
50
|
-
|
51
|
-
def create_legend_items() -> Text:
|
52
|
-
"""Create unified legend status bar"""
|
53
|
-
legend = Text()
|
54
|
-
legend.append(" Unchanged ", style=f"{current_theme.text_color} on {current_theme.line_backgrounds['unchanged']}")
|
55
|
-
legend.append(" │ ", style="dim")
|
56
|
-
legend.append(" ✕ Deleted ", style=f"{current_theme.text_color} on {current_theme.line_backgrounds['deleted']}")
|
57
|
-
legend.append(" │ ", style="dim")
|
58
|
-
legend.append(" ✚ Added ", style=f"{current_theme.text_color} on {current_theme.line_backgrounds['added']}")
|
59
|
-
return legend
|
janito/console/__init__.py
DELETED
janito/console/commands.py
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
from pathlib import Path
|
2
|
-
from typing import List
|
3
|
-
from rich.console import Console
|
4
|
-
from rich.panel import Panel
|
5
|
-
from janito.agents import AIAgent
|
6
|
-
from janito.analysis import build_request_analysis_prompt
|
7
|
-
from janito.scan import collect_files_content
|
8
|
-
from janito.common import progress_send_message
|
9
|
-
from janito.__main__ import handle_option_selection
|
10
|
-
from .display import display_help
|
11
|
-
|
12
|
-
def process_command(command: str, args: str, workdir: Path, include: List[Path], agent: AIAgent) -> None:
|
13
|
-
"""Process console commands using CLI functions for consistent behavior"""
|
14
|
-
console = Console()
|
15
|
-
|
16
|
-
# Parse command options
|
17
|
-
raw = False
|
18
|
-
verbose = False
|
19
|
-
debug = False
|
20
|
-
test_cmd = None
|
21
|
-
|
22
|
-
# Extract options from args
|
23
|
-
words = args.split()
|
24
|
-
filtered_args = []
|
25
|
-
i = 0
|
26
|
-
while i < len(words):
|
27
|
-
if words[i] == '--raw':
|
28
|
-
raw = True
|
29
|
-
elif words[i] == '--verbose':
|
30
|
-
verbose = True
|
31
|
-
elif words[i] == '--debug':
|
32
|
-
debug = True
|
33
|
-
elif words[i] == '--test' and i + 1 < len(words):
|
34
|
-
test_cmd = words[i + 1]
|
35
|
-
i += 1
|
36
|
-
else:
|
37
|
-
filtered_args.append(words[i])
|
38
|
-
i += 1
|
39
|
-
|
40
|
-
args = ' '.join(filtered_args)
|
41
|
-
|
42
|
-
# Update config with command options
|
43
|
-
from janito.config import config
|
44
|
-
config.set_debug(debug)
|
45
|
-
config.set_verbose(verbose)
|
46
|
-
config.set_test_cmd(test_cmd)
|
47
|
-
|
48
|
-
# Remove leading slash if present
|
49
|
-
command = command.lstrip('/')
|
50
|
-
|
51
|
-
# Handle command aliases
|
52
|
-
command_aliases = {
|
53
|
-
'h': 'help',
|
54
|
-
'a': 'ask',
|
55
|
-
'r': 'request',
|
56
|
-
'q': 'quit',
|
57
|
-
'exit': 'quit'
|
58
|
-
}
|
59
|
-
command = command_aliases.get(command, command)
|
60
|
-
|
61
|
-
if command == "help":
|
62
|
-
display_help()
|
63
|
-
return
|
64
|
-
|
65
|
-
if command == "quit":
|
66
|
-
raise EOFError()
|
67
|
-
|
68
|
-
if command == "ask":
|
69
|
-
if not args:
|
70
|
-
console.print(Panel(
|
71
|
-
"[red]Ask command requires a question[/red]",
|
72
|
-
title="Error",
|
73
|
-
border_style="red"
|
74
|
-
))
|
75
|
-
return
|
76
|
-
|
77
|
-
# Use CLI question processing function
|
78
|
-
from janito.__main__ import process_question
|
79
|
-
process_question(args, workdir, include, raw, claude)
|
80
|
-
return
|
81
|
-
|
82
|
-
if command == "request":
|
83
|
-
if not args:
|
84
|
-
console.print(Panel(
|
85
|
-
"[red]Request command requires a description[/red]",
|
86
|
-
title="Error",
|
87
|
-
border_style="red"
|
88
|
-
))
|
89
|
-
return
|
90
|
-
|
91
|
-
paths_to_scan = [workdir] if workdir else []
|
92
|
-
if include:
|
93
|
-
paths_to_scan.extend(include)
|
94
|
-
files_content = collect_files_content(paths_to_scan, workdir)
|
95
|
-
|
96
|
-
# Use CLI request processing functions
|
97
|
-
initial_prompt = build_request_analysis_prompt(files_content, args)
|
98
|
-
initial_response = progress_send_message(initial_prompt)
|
99
|
-
|
100
|
-
from janito.__main__ import save_to_file
|
101
|
-
save_to_file(initial_response, 'analysis', workdir)
|
102
|
-
|
103
|
-
from janito.analysis import format_analysis
|
104
|
-
format_analysis(initial_response, raw)
|
105
|
-
handle_option_selection(initial_response, args, raw, workdir, include)
|
106
|
-
return
|
107
|
-
|
108
|
-
console.print(Panel(
|
109
|
-
f"[red]Unknown command: /{command}[/red]\nType '/help' for available commands",
|
110
|
-
title="Error",
|
111
|
-
border_style="red"
|
112
|
-
))
|
janito/console/core.py
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
from pathlib import Path
|
2
|
-
from typing import List, Optional
|
3
|
-
from prompt_toolkit import PromptSession
|
4
|
-
from prompt_toolkit.history import FileHistory
|
5
|
-
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
6
|
-
from rich.console import Console
|
7
|
-
from janito.agents import AgentSingleton
|
8
|
-
from janito.prompts import SYSTEM_PROMPT
|
9
|
-
from .display import create_completer, format_prompt, display_welcome
|
10
|
-
from .commands import process_command
|
11
|
-
|
12
|
-
def start_console_session(workdir: Path, include: Optional[List[Path]] = None) -> None:
|
13
|
-
"""Start an enhanced interactive console session"""
|
14
|
-
console = Console()
|
15
|
-
agent = AgentSingleton.get_agent()
|
16
|
-
|
17
|
-
# Setup history with persistence
|
18
|
-
history_file = workdir / '.janito' / 'console_history'
|
19
|
-
history_file.parent.mkdir(parents=True, exist_ok=True)
|
20
|
-
|
21
|
-
# Create session with history and completions
|
22
|
-
session = PromptSession(
|
23
|
-
history=FileHistory(str(history_file)),
|
24
|
-
completer=create_completer(workdir),
|
25
|
-
auto_suggest=AutoSuggestFromHistory(),
|
26
|
-
complete_while_typing=True
|
27
|
-
)
|
28
|
-
|
29
|
-
display_welcome(workdir)
|
30
|
-
|
31
|
-
while True:
|
32
|
-
try:
|
33
|
-
# Get input with formatted prompt
|
34
|
-
user_input = session.prompt(
|
35
|
-
lambda: format_prompt(workdir),
|
36
|
-
complete_while_typing=True
|
37
|
-
).strip()
|
38
|
-
|
39
|
-
if not user_input:
|
40
|
-
continue
|
41
|
-
|
42
|
-
if user_input.lower() in ('exit', 'quit'):
|
43
|
-
console.print("\n[cyan]Goodbye! Have a great day![/cyan]\n")
|
44
|
-
break
|
45
|
-
|
46
|
-
# Split input into command and args
|
47
|
-
parts = user_input.split(maxsplit=1)
|
48
|
-
if parts[0].startswith('/'): # Handle /command format
|
49
|
-
command = parts[0][1:] # Remove the / prefix
|
50
|
-
else:
|
51
|
-
command = "request" # Default to request if no command specified
|
52
|
-
|
53
|
-
args = parts[1] if len(parts) > 1 else ""
|
54
|
-
|
55
|
-
# Process command with separated args
|
56
|
-
process_command(command, args, workdir, include, claude)
|
57
|
-
|
58
|
-
except KeyboardInterrupt:
|
59
|
-
continue
|
60
|
-
except EOFError:
|
61
|
-
console.print("\n[cyan]Goodbye! Have a great day![/cyan]\n")
|
62
|
-
break
|
janito/console/display.py
DELETED
@@ -1,157 +0,0 @@
|
|
1
|
-
from pathlib import Path
|
2
|
-
import shutil
|
3
|
-
from prompt_toolkit.completion import WordCompleter
|
4
|
-
from prompt_toolkit.formatted_text import HTML
|
5
|
-
from rich.console import Console
|
6
|
-
from rich.panel import Panel
|
7
|
-
from rich.table import Table
|
8
|
-
from rich.layout import Layout
|
9
|
-
from importlib.metadata import version
|
10
|
-
|
11
|
-
def create_completer(workdir: Path) -> WordCompleter:
|
12
|
-
"""Create command completer with common commands and paths"""
|
13
|
-
commands = [
|
14
|
-
'ask', 'request', 'help', 'exit', 'quit',
|
15
|
-
'--raw', '--verbose', '--debug', '--test'
|
16
|
-
]
|
17
|
-
return WordCompleter(commands, ignore_case=True)
|
18
|
-
|
19
|
-
def format_prompt(workdir: Path) -> HTML:
|
20
|
-
"""Format the prompt with current directory"""
|
21
|
-
cwd = workdir.name
|
22
|
-
return HTML(f'<ansigreen>janito</ansigreen> <ansiblue>{cwd}</ansiblue>> ')
|
23
|
-
|
24
|
-
def display_help() -> None:
|
25
|
-
"""Display available commands, options and their descriptions"""
|
26
|
-
console = Console()
|
27
|
-
|
28
|
-
layout = Layout()
|
29
|
-
layout.split_column(
|
30
|
-
Layout(name="header"),
|
31
|
-
Layout(name="commands"),
|
32
|
-
Layout(name="options"),
|
33
|
-
Layout(name="examples")
|
34
|
-
)
|
35
|
-
|
36
|
-
# Header
|
37
|
-
header_table = Table(box=None, show_header=False)
|
38
|
-
header_table.add_row("[bold cyan]Janito Console Help[/bold cyan]")
|
39
|
-
header_table.add_row("[dim]Your AI-powered software development buddy[/dim]")
|
40
|
-
|
41
|
-
# Commands table
|
42
|
-
commands_table = Table(title="Available Commands", box=None)
|
43
|
-
commands_table.add_column("Command", style="cyan", width=20)
|
44
|
-
commands_table.add_column("Description", style="white")
|
45
|
-
|
46
|
-
commands_table.add_row(
|
47
|
-
"/ask <text> (/a)",
|
48
|
-
"Ask a question about the codebase without making changes"
|
49
|
-
)
|
50
|
-
commands_table.add_row(
|
51
|
-
"<text> or /request <text> (/r)",
|
52
|
-
"Request code modifications or improvements"
|
53
|
-
)
|
54
|
-
commands_table.add_row(
|
55
|
-
"/help (/h)",
|
56
|
-
"Display this help message"
|
57
|
-
)
|
58
|
-
commands_table.add_row(
|
59
|
-
"/quit or /exit (/q)",
|
60
|
-
"Exit the console session"
|
61
|
-
)
|
62
|
-
|
63
|
-
# Options table
|
64
|
-
options_table = Table(title="Common Options", box=None)
|
65
|
-
options_table.add_column("Option", style="cyan", width=20)
|
66
|
-
options_table.add_column("Description", style="white")
|
67
|
-
|
68
|
-
options_table.add_row(
|
69
|
-
"--raw",
|
70
|
-
"Display raw response without formatting"
|
71
|
-
)
|
72
|
-
options_table.add_row(
|
73
|
-
"--verbose",
|
74
|
-
"Show additional information during execution"
|
75
|
-
)
|
76
|
-
options_table.add_row(
|
77
|
-
"--debug",
|
78
|
-
"Display detailed debug information"
|
79
|
-
)
|
80
|
-
options_table.add_row(
|
81
|
-
"--test <cmd>",
|
82
|
-
"Run specified test command before applying changes"
|
83
|
-
)
|
84
|
-
|
85
|
-
# Examples panel
|
86
|
-
examples = Panel(
|
87
|
-
"\n".join([
|
88
|
-
"[dim]Basic Commands:[/dim]",
|
89
|
-
" ask how does the error handling work?",
|
90
|
-
" request add input validation to user functions",
|
91
|
-
"",
|
92
|
-
"[dim]Using Options:[/dim]",
|
93
|
-
" request update tests --verbose",
|
94
|
-
" ask explain auth flow --raw",
|
95
|
-
" request optimize code --test 'pytest'",
|
96
|
-
"",
|
97
|
-
"[dim]Complex Examples:[/dim]",
|
98
|
-
" request refactor login function --verbose --test 'python -m unittest'",
|
99
|
-
" ask code structure --raw --debug"
|
100
|
-
]),
|
101
|
-
title="Examples",
|
102
|
-
border_style="blue"
|
103
|
-
)
|
104
|
-
|
105
|
-
# Update layout
|
106
|
-
layout["header"].update(header_table)
|
107
|
-
layout["commands"].update(commands_table)
|
108
|
-
layout["options"].update(options_table)
|
109
|
-
layout["examples"].update(examples)
|
110
|
-
|
111
|
-
console.print(layout)
|
112
|
-
|
113
|
-
def display_welcome(workdir: Path) -> None:
|
114
|
-
"""Display welcome message and console information"""
|
115
|
-
console = Console()
|
116
|
-
try:
|
117
|
-
ver = version("janito")
|
118
|
-
except:
|
119
|
-
ver = "dev"
|
120
|
-
|
121
|
-
term_width = shutil.get_terminal_size().columns
|
122
|
-
|
123
|
-
COLORS = {
|
124
|
-
'primary': '#729FCF', # Soft blue for primary elements
|
125
|
-
'secondary': '#8AE234', # Bright green for actions/success
|
126
|
-
'accent': '#AD7FA8', # Purple for accents
|
127
|
-
'muted': '#7F9F7F', # Muted green for less important text
|
128
|
-
}
|
129
|
-
|
130
|
-
welcome_text = (
|
131
|
-
f"[bold {COLORS['primary']}]Welcome to Janito v{ver}[/bold {COLORS['primary']}]\n"
|
132
|
-
f"[{COLORS['muted']}]Your AI-Powered Software Development Buddy[/{COLORS['muted']}]\n\n"
|
133
|
-
f"[{COLORS['accent']}]Keyboard Shortcuts:[/{COLORS['accent']}]\n"
|
134
|
-
"• ↑↓ : Navigate command history\n"
|
135
|
-
"• Tab : Complete commands and paths\n"
|
136
|
-
"• Ctrl+D : Exit console\n"
|
137
|
-
"• Ctrl+C : Cancel current operation\n\n"
|
138
|
-
f"[{COLORS['accent']}]Available Commands:[/{COLORS['accent']}]\n"
|
139
|
-
"• /ask (or /a) : Ask questions about code\n"
|
140
|
-
"• /request (or /r) : Request code changes\n"
|
141
|
-
"• /help (or /h) : Show detailed help\n"
|
142
|
-
"• /quit (or /q) : Exit console\n\n"
|
143
|
-
f"[{COLORS['secondary']}]Current Version:[/{COLORS['secondary']}] v{ver}\n"
|
144
|
-
f"[{COLORS['muted']}]Working Directory:[/{COLORS['muted']}] {workdir.absolute()}"
|
145
|
-
)
|
146
|
-
|
147
|
-
welcome_panel = Panel(
|
148
|
-
welcome_text,
|
149
|
-
width=min(80, term_width - 4),
|
150
|
-
border_style="blue",
|
151
|
-
title="Janito Console",
|
152
|
-
subtitle="Press Tab for completions"
|
153
|
-
)
|
154
|
-
|
155
|
-
console.print("\n")
|
156
|
-
console.print(welcome_panel)
|
157
|
-
console.print("\n[cyan]How can I help you with your code today?[/cyan]\n")
|