janito 0.3.0__py3-none-any.whl → 0.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 +48 -1
- janito/__main__.py +29 -235
- janito/_contextparser.py +113 -0
- janito/agents/__init__.py +22 -0
- janito/agents/agent.py +21 -0
- janito/agents/claudeai.py +64 -0
- janito/agents/openai.py +53 -0
- janito/agents/test.py +34 -0
- janito/analysis/__init__.py +33 -0
- janito/analysis/display.py +149 -0
- janito/analysis/options.py +112 -0
- janito/analysis/prompts.py +75 -0
- janito/change/__init__.py +19 -0
- janito/change/applier.py +269 -0
- janito/change/content.py +62 -0
- janito/change/indentation.py +33 -0
- janito/change/position.py +169 -0
- janito/changehistory.py +46 -0
- janito/changeviewer/__init__.py +12 -0
- janito/changeviewer/diff.py +28 -0
- janito/changeviewer/panels.py +268 -0
- janito/changeviewer/styling.py +59 -0
- janito/changeviewer/themes.py +57 -0
- janito/cli/__init__.py +2 -0
- janito/cli/commands.py +53 -0
- janito/cli/functions.py +286 -0
- janito/cli/registry.py +26 -0
- janito/common.py +23 -0
- janito/config.py +8 -3
- janito/console/__init__.py +3 -0
- janito/console/commands.py +112 -0
- janito/console/core.py +62 -0
- janito/console/display.py +157 -0
- janito/fileparser.py +334 -0
- janito/prompts.py +58 -74
- janito/qa.py +40 -7
- janito/review.py +13 -0
- janito/scan.py +68 -14
- janito/tests/test_fileparser.py +26 -0
- janito/version.py +23 -0
- janito-0.5.0.dist-info/METADATA +146 -0
- janito-0.5.0.dist-info/RECORD +45 -0
- janito/changeviewer.py +0 -64
- janito/claude.py +0 -74
- janito/console.py +0 -60
- janito/contentchange.py +0 -165
- janito-0.3.0.dist-info/METADATA +0 -138
- janito-0.3.0.dist-info/RECORD +0 -15
- {janito-0.3.0.dist-info → janito-0.5.0.dist-info}/WHEEL +0 -0
- {janito-0.3.0.dist-info → janito-0.5.0.dist-info}/entry_points.txt +0 -0
- {janito-0.3.0.dist-info → janito-0.5.0.dist-info}/licenses/LICENSE +0 -0
janito/contentchange.py
DELETED
@@ -1,165 +0,0 @@
|
|
1
|
-
import re
|
2
|
-
from pathlib import Path
|
3
|
-
from typing import Dict, Tuple, TypedDict, List
|
4
|
-
from rich.console import Console
|
5
|
-
from rich.prompt import Confirm
|
6
|
-
import tempfile
|
7
|
-
from janito.changeviewer import show_file_changes, FileChange, show_diff_changes
|
8
|
-
import ast
|
9
|
-
from datetime import datetime
|
10
|
-
import shutil
|
11
|
-
|
12
|
-
def get_file_type(filepath: Path) -> str:
|
13
|
-
"""Determine the type of saved file based on its name"""
|
14
|
-
name = filepath.name.lower()
|
15
|
-
if 'changes' in name:
|
16
|
-
return 'changes'
|
17
|
-
elif 'selected' in name:
|
18
|
-
return 'selected'
|
19
|
-
elif 'analysis' in name:
|
20
|
-
return 'analysis'
|
21
|
-
elif 'response' in name:
|
22
|
-
return 'response'
|
23
|
-
return 'unknown'
|
24
|
-
|
25
|
-
def parse_block_changes(content: str) -> Dict[Path, FileChange]:
|
26
|
-
"""Parse file changes from code blocks in the content.
|
27
|
-
Returns dict mapping filepath -> FileChange"""
|
28
|
-
changes = {}
|
29
|
-
pattern = r'##\s*([\da-f-]+)\s+([^\n]+)\s+begin\s*"([^"]*)"[^\n]*##\n(.*?)##\s*\1\s+\2\s+end\s*##'
|
30
|
-
matches = re.finditer(pattern, content, re.DOTALL)
|
31
|
-
|
32
|
-
for match in matches:
|
33
|
-
filepath = Path(match.group(2))
|
34
|
-
description = match.group(3)
|
35
|
-
file_content = match.group(4).strip()
|
36
|
-
changes[filepath] = FileChange(
|
37
|
-
description=description,
|
38
|
-
new_content=file_content
|
39
|
-
)
|
40
|
-
|
41
|
-
return changes
|
42
|
-
|
43
|
-
def save_changes_to_history(content: str, request: str, workdir: Path) -> Path:
|
44
|
-
"""Save change content to history folder with timestamp and request info"""
|
45
|
-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") # Already in the correct format
|
46
|
-
history_dir = workdir / '.janito' / 'history'
|
47
|
-
history_dir.mkdir(parents=True, exist_ok=True)
|
48
|
-
|
49
|
-
# Create history entry with request and changes
|
50
|
-
history_file = history_dir / f"changes_{timestamp}.txt"
|
51
|
-
|
52
|
-
history_content = f"""Request: {request}
|
53
|
-
Timestamp: {timestamp}
|
54
|
-
|
55
|
-
Changes:
|
56
|
-
{content}
|
57
|
-
"""
|
58
|
-
history_file.write_text(history_content)
|
59
|
-
return history_file
|
60
|
-
|
61
|
-
def process_and_save_changes(content: str, request: str, workdir: Path) -> Tuple[Dict[Path, Tuple[str, str]], Path]:
|
62
|
-
"""Parse changes and save to history, returns (changes_dict, history_file)"""
|
63
|
-
changes = parse_block_changes(content)
|
64
|
-
history_file = save_changes_to_history(content, request, workdir)
|
65
|
-
return changes, history_file
|
66
|
-
|
67
|
-
def validate_python_syntax(content: str, filepath: Path) -> Tuple[bool, str]:
|
68
|
-
"""Validate Python syntax and return (is_valid, error_message)"""
|
69
|
-
try:
|
70
|
-
ast.parse(content)
|
71
|
-
return True, ""
|
72
|
-
except SyntaxError as e:
|
73
|
-
return False, f"Line {e.lineno}: {e.msg}"
|
74
|
-
except Exception as e:
|
75
|
-
return False, str(e)
|
76
|
-
|
77
|
-
def format_parsed_changes(changes: Dict[Path, Tuple[str, str]]) -> str:
|
78
|
-
"""Format parsed changes to show only file change descriptions"""
|
79
|
-
result = []
|
80
|
-
for filepath, (_, description) in changes.items(): # Updated tuple unpacking
|
81
|
-
result.append(f"=== {filepath} ===\n{description}\n")
|
82
|
-
return "\n".join(result)
|
83
|
-
|
84
|
-
def validate_changes(changes: Dict[Path, FileChange]) -> Tuple[bool, List[Tuple[Path, str]]]:
|
85
|
-
"""Validate all changes, returns (is_valid, list of errors)"""
|
86
|
-
errors = []
|
87
|
-
for filepath, change in changes.items():
|
88
|
-
if filepath.suffix == '.py':
|
89
|
-
is_valid, error = validate_python_syntax(change['new_content'], filepath)
|
90
|
-
if not is_valid:
|
91
|
-
errors.append((filepath, error))
|
92
|
-
return len(errors) == 0, errors
|
93
|
-
|
94
|
-
def preview_and_apply_changes(changes: Dict[Path, FileChange], workdir: Path) -> bool:
|
95
|
-
"""Preview changes in temporary directory and apply if confirmed."""
|
96
|
-
console = Console()
|
97
|
-
|
98
|
-
if not changes:
|
99
|
-
console.print("\n[yellow]No changes were found to apply[/yellow]")
|
100
|
-
return False
|
101
|
-
|
102
|
-
with tempfile.TemporaryDirectory() as temp_dir:
|
103
|
-
preview_dir = Path(temp_dir)
|
104
|
-
if workdir.exists():
|
105
|
-
shutil.copytree(workdir, preview_dir, dirs_exist_ok=True)
|
106
|
-
|
107
|
-
for filepath, change in changes.items():
|
108
|
-
# Get original content
|
109
|
-
orig_path = workdir / filepath
|
110
|
-
original = orig_path.read_text() if orig_path.exists() else ""
|
111
|
-
|
112
|
-
# Prepare preview
|
113
|
-
preview_path = preview_dir / filepath
|
114
|
-
preview_path.parent.mkdir(parents=True, exist_ok=True)
|
115
|
-
preview_path.write_text(change['new_content'])
|
116
|
-
|
117
|
-
# Show changes
|
118
|
-
show_diff_changes(console, filepath, original, change['new_content'], change['description'])
|
119
|
-
|
120
|
-
# Apply changes if confirmed
|
121
|
-
if Confirm.ask("\nApply these changes?"):
|
122
|
-
for filepath, _ in changes.items():
|
123
|
-
preview_path = preview_dir / filepath
|
124
|
-
target_path = workdir / filepath
|
125
|
-
target_path.parent.mkdir(parents=True, exist_ok=True)
|
126
|
-
shutil.copy2(preview_path, target_path)
|
127
|
-
console.print(f"[green]✓[/green] Applied changes to {filepath}")
|
128
|
-
return True
|
129
|
-
|
130
|
-
return False
|
131
|
-
|
132
|
-
def apply_content_changes(content: str, request: str, workdir: Path) -> Tuple[bool, Path]:
|
133
|
-
"""Regular flow: Parse content, save to history, and apply changes."""
|
134
|
-
console = Console()
|
135
|
-
changes = parse_block_changes(content)
|
136
|
-
|
137
|
-
if not changes:
|
138
|
-
console.print("\n[yellow]No file changes were found in the response[/yellow]")
|
139
|
-
return False, None
|
140
|
-
|
141
|
-
# Validate changes before proceeding
|
142
|
-
is_valid, errors = validate_changes(changes)
|
143
|
-
if not is_valid:
|
144
|
-
console = Console()
|
145
|
-
console.print("\n[red bold]⚠️ Cannot apply changes: Python syntax errors detected![/red bold]")
|
146
|
-
for filepath, error in errors:
|
147
|
-
console.print(f"\n[red]⚠️ {filepath}: {error}[/red]")
|
148
|
-
return False, None
|
149
|
-
|
150
|
-
history_file = save_changes_to_history(content, request, workdir)
|
151
|
-
success = preview_and_apply_changes(changes, workdir)
|
152
|
-
return success, history_file
|
153
|
-
|
154
|
-
def handle_changes_file(filepath: Path, workdir: Path) -> Tuple[bool, Path]:
|
155
|
-
"""Replay flow: Load changes from file and apply them."""
|
156
|
-
content = filepath.read_text()
|
157
|
-
changes = parse_block_changes(content)
|
158
|
-
|
159
|
-
if not changes:
|
160
|
-
console = Console()
|
161
|
-
console.print("\n[yellow]No file changes were found in the file[/yellow]")
|
162
|
-
return False, None
|
163
|
-
|
164
|
-
success = preview_and_apply_changes(changes, workdir)
|
165
|
-
return success, filepath
|
janito-0.3.0.dist-info/METADATA
DELETED
@@ -1,138 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.3
|
2
|
-
Name: janito
|
3
|
-
Version: 0.3.0
|
4
|
-
Summary: A CLI tool for software development tasks powered by AI
|
5
|
-
Project-URL: Homepage, https://github.com/joaompinto/janito
|
6
|
-
Project-URL: Repository, https://github.com/joaompinto/janito.git
|
7
|
-
Author-email: João Pinto <lamego.pinto@gmail.com>
|
8
|
-
License: MIT
|
9
|
-
Classifier: Development Status :: 4 - Beta
|
10
|
-
Classifier: Environment :: Console
|
11
|
-
Classifier: Intended Audience :: Developers
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
13
|
-
Classifier: Programming Language :: Python :: 3.8
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
15
|
-
Classifier: Programming Language :: Python :: 3.10
|
16
|
-
Classifier: Topic :: Software Development
|
17
|
-
Requires-Python: >=3.8
|
18
|
-
Requires-Dist: anthropic
|
19
|
-
Requires-Dist: pathspec
|
20
|
-
Requires-Dist: rich
|
21
|
-
Requires-Dist: typer
|
22
|
-
Description-Content-Type: text/markdown
|
23
|
-
|
24
|
-
# 🤖 Janito CLI
|
25
|
-
|
26
|
-
A CLI tool for software development tasks powered by AI.
|
27
|
-
|
28
|
-
Janito is an AI-powered assistant that helps automate common software development tasks like refactoring, documentation updates, and code optimization.
|
29
|
-
|
30
|
-
## 📥 Installation
|
31
|
-
|
32
|
-
```bash
|
33
|
-
# Install from PyPI
|
34
|
-
pip install janito
|
35
|
-
|
36
|
-
# Install from source
|
37
|
-
git clone https://github.com/joaompinto/janito.git
|
38
|
-
cd janito
|
39
|
-
pip install -e .
|
40
|
-
```
|
41
|
-
|
42
|
-
## ⚡ Requirements
|
43
|
-
|
44
|
-
- Python 3.8+
|
45
|
-
- Anthropic API key
|
46
|
-
- Required packages (automatically installed):
|
47
|
-
- typer
|
48
|
-
- pathspec
|
49
|
-
- rich
|
50
|
-
|
51
|
-
## ⚙️ Configuration
|
52
|
-
|
53
|
-
### 🔑 API Key Setup
|
54
|
-
Janito requires an Anthropic API key to function. Set it as an environment variable:
|
55
|
-
|
56
|
-
```bash
|
57
|
-
export ANTHROPIC_API_KEY='your-api-key-here'
|
58
|
-
```
|
59
|
-
|
60
|
-
You can also add this to your shell profile (~/.bashrc, ~/.zshrc, etc.) for persistence.
|
61
|
-
|
62
|
-
## 📖 Usage
|
63
|
-
|
64
|
-
Janito can be used in two modes: Command Line or Interactive Console.
|
65
|
-
|
66
|
-
### 💻 Command Line Mode
|
67
|
-
|
68
|
-
```bash
|
69
|
-
janito REQUEST [OPTIONS]
|
70
|
-
```
|
71
|
-
|
72
|
-
#### Arguments
|
73
|
-
- `REQUEST`: The modification request
|
74
|
-
|
75
|
-
#### Options
|
76
|
-
- `-w, --workdir PATH`: Working directory (defaults to current directory)
|
77
|
-
- `--raw`: Print raw response instead of markdown format
|
78
|
-
- `--play PATH`: Replay a saved prompt file
|
79
|
-
- `-i, --include PATH`: Additional paths to include in analysis
|
80
|
-
- `--debug`: Show debug information
|
81
|
-
- `-v, --verbose`: Show verbose output
|
82
|
-
- `--ask`: Ask a question about the codebase
|
83
|
-
- `--scan`: Preview files that would be analyzed
|
84
|
-
|
85
|
-
### 🖥️ Interactive Console Mode
|
86
|
-
|
87
|
-
Start the interactive console by running `janito` without arguments:
|
88
|
-
|
89
|
-
```bash
|
90
|
-
janito
|
91
|
-
```
|
92
|
-
|
93
|
-
In console mode, you can:
|
94
|
-
- Enter requests directly
|
95
|
-
- Navigate history with up/down arrows
|
96
|
-
- Use special commands starting with /
|
97
|
-
|
98
|
-
### 📝 Examples
|
99
|
-
|
100
|
-
```bash
|
101
|
-
# Command Line Mode Examples
|
102
|
-
janito "create docstrings for all functions"
|
103
|
-
janito "add error handling" -w ./myproject
|
104
|
-
janito "update tests" -i ./tests -i ./lib
|
105
|
-
janito --ask "explain the authentication flow"
|
106
|
-
janito --scan # Preview files to be analyzed
|
107
|
-
|
108
|
-
# Console Mode
|
109
|
-
janito # Starts interactive session
|
110
|
-
```
|
111
|
-
|
112
|
-
## ✨ Features
|
113
|
-
|
114
|
-
- 🤖 AI-powered code analysis and modifications
|
115
|
-
- 💻 Interactive console mode for continuous interaction
|
116
|
-
- 📁 Support for multiple file types
|
117
|
-
- ✅ Syntax validation for Python files
|
118
|
-
- 👀 Interactive change preview and confirmation
|
119
|
-
- 📜 History tracking of all changes
|
120
|
-
- 🐛 Debug and verbose output modes
|
121
|
-
- ❓ Question-answering about codebase
|
122
|
-
- 🔍 File scanning preview
|
123
|
-
|
124
|
-
## 📚 History and Debugging
|
125
|
-
|
126
|
-
Changes are automatically saved in `.janito/history/` with timestamps:
|
127
|
-
- `*_analysis.txt`: Initial analysis
|
128
|
-
- `*_selected.txt`: Selected implementation
|
129
|
-
- `*_changes.txt`: Actual changes
|
130
|
-
|
131
|
-
Enable debug mode for detailed logging:
|
132
|
-
```bash
|
133
|
-
janito "request" --debug
|
134
|
-
```
|
135
|
-
|
136
|
-
## 📄 License
|
137
|
-
|
138
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
janito-0.3.0.dist-info/RECORD
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
janito/__init__.py,sha256=CLeVFqpY9Ki3R3MgLAiTjNsJjsj1BD3_9CzP2kgCj-k,52
|
2
|
-
janito/__main__.py,sha256=bGp3nWUZC5omneyE3hn78D_J5PkBfk19qKfMV1kIThI,9892
|
3
|
-
janito/changeviewer.py,sha256=C_CRdeD6dE4AIpOM_kryTn_HyD5XC-glaZO8n8zrQPE,2487
|
4
|
-
janito/claude.py,sha256=tj0lNNVE0CW0bBkbhVDFgBl0AFoMHicWaHnYuYOk3_E,2911
|
5
|
-
janito/config.py,sha256=YsS0bNVkjl7cIboP9nSDy0NXsJaVHYAIpPkc6bbErpo,967
|
6
|
-
janito/console.py,sha256=ieKZ7IRbvJO_KW8A3CU4FCoO4YFEjJQT8BN98YotAnM,2770
|
7
|
-
janito/contentchange.py,sha256=BxFmW8JtRjzX5lnfGfzo0JPRnGRw1RQEtqZCK1wVArw,6404
|
8
|
-
janito/prompts.py,sha256=XonVVbfIg3YY1Dpbkx9m0ZSRE4bgDP3MYHO3D-5FcIE,3080
|
9
|
-
janito/qa.py,sha256=F9bd18CBaZDpbJwwvwFL18gXPBA0cq8kRY0nA3_AKPY,916
|
10
|
-
janito/scan.py,sha256=5JV0crOepVUqCZ3LAUqCJL2yerLFvjZ6RYdOwIGHvX0,5450
|
11
|
-
janito-0.3.0.dist-info/METADATA,sha256=fq7zvCHx_PV8RND5SVfOMnM082BEptZQ2G2qWPOVisQ,3681
|
12
|
-
janito-0.3.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
13
|
-
janito-0.3.0.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
|
14
|
-
janito-0.3.0.dist-info/licenses/LICENSE,sha256=xLIUXRPjtsgQml2zD1Pn4LpgiyZ49raw6jZDlO_gZdo,1062
|
15
|
-
janito-0.3.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|