janito 0.3.0__tar.gz
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-0.3.0/.gitignore +88 -0
- janito-0.3.0/CHANGELOG.md +26 -0
- janito-0.3.0/LICENSE +21 -0
- janito-0.3.0/PKG-INFO +138 -0
- janito-0.3.0/README.md +115 -0
- janito-0.3.0/janito/__init__.py +2 -0
- janito-0.3.0/janito/__main__.py +260 -0
- janito-0.3.0/janito/changeviewer.py +64 -0
- janito-0.3.0/janito/claude.py +74 -0
- janito-0.3.0/janito/config.py +32 -0
- janito-0.3.0/janito/console.py +60 -0
- janito-0.3.0/janito/contentchange.py +165 -0
- janito-0.3.0/janito/prompts.py +97 -0
- janito-0.3.0/janito/qa.py +32 -0
- janito-0.3.0/janito/scan.py +122 -0
- janito-0.3.0/pyproject.toml +40 -0
- janito-0.3.0/setup.py +4 -0
- janito-0.3.0/tests/__init__.py +2 -0
- janito-0.3.0/tests/test_main.py +51 -0
- janito-0.3.0/tools/release.sh +28 -0
janito-0.3.0/.gitignore
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# Python
|
2
|
+
|
3
|
+
__pycache__/
|
4
|
+
*.py[cod]
|
5
|
+
*$py.class
|
6
|
+
*.so
|
7
|
+
.Python
|
8
|
+
build/
|
9
|
+
develop-eggs/
|
10
|
+
dist/
|
11
|
+
downloads/
|
12
|
+
eggs/
|
13
|
+
.eggs/
|
14
|
+
lib/
|
15
|
+
lib64/
|
16
|
+
parts/
|
17
|
+
sdist/
|
18
|
+
var/
|
19
|
+
wheels/
|
20
|
+
*.egg-info/
|
21
|
+
.installed.cfg
|
22
|
+
*.egg
|
23
|
+
|
24
|
+
# Virtual Environment
|
25
|
+
venv/
|
26
|
+
env/
|
27
|
+
ENV/
|
28
|
+
|
29
|
+
# IDE
|
30
|
+
.idea/
|
31
|
+
.vscode/
|
32
|
+
*.swp
|
33
|
+
*.swo
|
34
|
+
|
35
|
+
# Testing
|
36
|
+
.coverage
|
37
|
+
.pytest_cache/
|
38
|
+
htmlcov/
|
39
|
+
|
40
|
+
# Documentation
|
41
|
+
docs/_build/
|
42
|
+
site/
|
43
|
+
|
44
|
+
# Misc
|
45
|
+
.DS_Store
|
46
|
+
# Janito
|
47
|
+
.janito/history/
|
48
|
+
|
49
|
+
# Poetry
|
50
|
+
poetry.lock
|
51
|
+
.poetry/
|
52
|
+
|
53
|
+
# Pipenv
|
54
|
+
Pipfile.lock
|
55
|
+
.venv
|
56
|
+
|
57
|
+
# Tox
|
58
|
+
.tox/
|
59
|
+
.coverage.*
|
60
|
+
nosetests.xml
|
61
|
+
coverage.xml
|
62
|
+
*.cover
|
63
|
+
|
64
|
+
# Additional IDE
|
65
|
+
*.sublime-workspace
|
66
|
+
*.sublime-project
|
67
|
+
.settings/
|
68
|
+
.project
|
69
|
+
.pydevproject
|
70
|
+
.spyproject/
|
71
|
+
.ropeproject/
|
72
|
+
|
73
|
+
# Jupyter
|
74
|
+
.ipynb_checkpoints
|
75
|
+
*.ipynb
|
76
|
+
|
77
|
+
# mypy
|
78
|
+
.mypy_cache/
|
79
|
+
.dmypy.json
|
80
|
+
dmypy.json
|
81
|
+
|
82
|
+
# Environments
|
83
|
+
.env
|
84
|
+
.venv
|
85
|
+
env.bak/
|
86
|
+
venv.bak/
|
87
|
+
|
88
|
+
.janito/
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
## [0.3.0] - 2024-01-24
|
6
|
+
|
7
|
+
### Added
|
8
|
+
- Initial changelog
|
9
|
+
- Version tracking
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
- Updated version from 0.1.0 to 0.3.0
|
13
|
+
|
14
|
+
## [0.1.0] - Initial Release
|
15
|
+
|
16
|
+
### Added
|
17
|
+
- Initial release of Janito CLI
|
18
|
+
- AI-powered code analysis and modifications
|
19
|
+
- Interactive console mode
|
20
|
+
- Support for multiple file types
|
21
|
+
- Syntax validation for Python files
|
22
|
+
- Interactive change preview and confirmation
|
23
|
+
- History tracking of changes
|
24
|
+
- Debug and verbose output modes
|
25
|
+
- Question-answering about codebase
|
26
|
+
- File scanning preview
|
janito-0.3.0/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 João Pinto
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
janito-0.3.0/PKG-INFO
ADDED
@@ -0,0 +1,138 @@
|
|
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/README.md
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
# 🤖 Janito CLI
|
2
|
+
|
3
|
+
A CLI tool for software development tasks powered by AI.
|
4
|
+
|
5
|
+
Janito is an AI-powered assistant that helps automate common software development tasks like refactoring, documentation updates, and code optimization.
|
6
|
+
|
7
|
+
## 📥 Installation
|
8
|
+
|
9
|
+
```bash
|
10
|
+
# Install from PyPI
|
11
|
+
pip install janito
|
12
|
+
|
13
|
+
# Install from source
|
14
|
+
git clone https://github.com/joaompinto/janito.git
|
15
|
+
cd janito
|
16
|
+
pip install -e .
|
17
|
+
```
|
18
|
+
|
19
|
+
## ⚡ Requirements
|
20
|
+
|
21
|
+
- Python 3.8+
|
22
|
+
- Anthropic API key
|
23
|
+
- Required packages (automatically installed):
|
24
|
+
- typer
|
25
|
+
- pathspec
|
26
|
+
- rich
|
27
|
+
|
28
|
+
## ⚙️ Configuration
|
29
|
+
|
30
|
+
### 🔑 API Key Setup
|
31
|
+
Janito requires an Anthropic API key to function. Set it as an environment variable:
|
32
|
+
|
33
|
+
```bash
|
34
|
+
export ANTHROPIC_API_KEY='your-api-key-here'
|
35
|
+
```
|
36
|
+
|
37
|
+
You can also add this to your shell profile (~/.bashrc, ~/.zshrc, etc.) for persistence.
|
38
|
+
|
39
|
+
## 📖 Usage
|
40
|
+
|
41
|
+
Janito can be used in two modes: Command Line or Interactive Console.
|
42
|
+
|
43
|
+
### 💻 Command Line Mode
|
44
|
+
|
45
|
+
```bash
|
46
|
+
janito REQUEST [OPTIONS]
|
47
|
+
```
|
48
|
+
|
49
|
+
#### Arguments
|
50
|
+
- `REQUEST`: The modification request
|
51
|
+
|
52
|
+
#### Options
|
53
|
+
- `-w, --workdir PATH`: Working directory (defaults to current directory)
|
54
|
+
- `--raw`: Print raw response instead of markdown format
|
55
|
+
- `--play PATH`: Replay a saved prompt file
|
56
|
+
- `-i, --include PATH`: Additional paths to include in analysis
|
57
|
+
- `--debug`: Show debug information
|
58
|
+
- `-v, --verbose`: Show verbose output
|
59
|
+
- `--ask`: Ask a question about the codebase
|
60
|
+
- `--scan`: Preview files that would be analyzed
|
61
|
+
|
62
|
+
### 🖥️ Interactive Console Mode
|
63
|
+
|
64
|
+
Start the interactive console by running `janito` without arguments:
|
65
|
+
|
66
|
+
```bash
|
67
|
+
janito
|
68
|
+
```
|
69
|
+
|
70
|
+
In console mode, you can:
|
71
|
+
- Enter requests directly
|
72
|
+
- Navigate history with up/down arrows
|
73
|
+
- Use special commands starting with /
|
74
|
+
|
75
|
+
### 📝 Examples
|
76
|
+
|
77
|
+
```bash
|
78
|
+
# Command Line Mode Examples
|
79
|
+
janito "create docstrings for all functions"
|
80
|
+
janito "add error handling" -w ./myproject
|
81
|
+
janito "update tests" -i ./tests -i ./lib
|
82
|
+
janito --ask "explain the authentication flow"
|
83
|
+
janito --scan # Preview files to be analyzed
|
84
|
+
|
85
|
+
# Console Mode
|
86
|
+
janito # Starts interactive session
|
87
|
+
```
|
88
|
+
|
89
|
+
## ✨ Features
|
90
|
+
|
91
|
+
- 🤖 AI-powered code analysis and modifications
|
92
|
+
- 💻 Interactive console mode for continuous interaction
|
93
|
+
- 📁 Support for multiple file types
|
94
|
+
- ✅ Syntax validation for Python files
|
95
|
+
- 👀 Interactive change preview and confirmation
|
96
|
+
- 📜 History tracking of all changes
|
97
|
+
- 🐛 Debug and verbose output modes
|
98
|
+
- ❓ Question-answering about codebase
|
99
|
+
- 🔍 File scanning preview
|
100
|
+
|
101
|
+
## 📚 History and Debugging
|
102
|
+
|
103
|
+
Changes are automatically saved in `.janito/history/` with timestamps:
|
104
|
+
- `*_analysis.txt`: Initial analysis
|
105
|
+
- `*_selected.txt`: Selected implementation
|
106
|
+
- `*_changes.txt`: Actual changes
|
107
|
+
|
108
|
+
Enable debug mode for detailed logging:
|
109
|
+
```bash
|
110
|
+
janito "request" --debug
|
111
|
+
```
|
112
|
+
|
113
|
+
## 📄 License
|
114
|
+
|
115
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
@@ -0,0 +1,260 @@
|
|
1
|
+
import typer
|
2
|
+
from typing import Optional, Dict, Any, List
|
3
|
+
from pathlib import Path
|
4
|
+
from janito.claude import ClaudeAPIAgent
|
5
|
+
import shutil
|
6
|
+
from janito.prompts import (
|
7
|
+
build_request_analisys_prompt,
|
8
|
+
build_selected_option_prompt,
|
9
|
+
SYSTEM_PROMPT,
|
10
|
+
parse_options
|
11
|
+
)
|
12
|
+
from rich.console import Console
|
13
|
+
from rich.markdown import Markdown
|
14
|
+
import re
|
15
|
+
import tempfile
|
16
|
+
import json
|
17
|
+
from rich.syntax import Syntax
|
18
|
+
from janito.contentchange import (
|
19
|
+
handle_changes_file,
|
20
|
+
get_file_type,
|
21
|
+
parse_block_changes,
|
22
|
+
preview_and_apply_changes,
|
23
|
+
format_parsed_changes,
|
24
|
+
)
|
25
|
+
from rich.table import Table
|
26
|
+
from rich.columns import Columns
|
27
|
+
from rich.panel import Panel
|
28
|
+
from rich.text import Text
|
29
|
+
from rich.rule import Rule
|
30
|
+
from rich import box
|
31
|
+
from datetime import datetime, timezone
|
32
|
+
from itertools import chain
|
33
|
+
from janito.scan import collect_files_content, is_dir_empty, preview_scan
|
34
|
+
from janito.qa import ask_question, display_answer
|
35
|
+
from rich.prompt import Prompt, Confirm
|
36
|
+
from janito.config import config
|
37
|
+
from importlib.metadata import version
|
38
|
+
|
39
|
+
def get_version() -> str:
|
40
|
+
try:
|
41
|
+
return version("janito")
|
42
|
+
except:
|
43
|
+
return "dev"
|
44
|
+
|
45
|
+
def format_analysis(analysis: str, raw: bool = False, claude: Optional[ClaudeAPIAgent] = None) -> None:
|
46
|
+
"""Format and display the analysis output"""
|
47
|
+
console = Console()
|
48
|
+
if raw and claude:
|
49
|
+
console.print("\n=== Message History ===")
|
50
|
+
for role, content in claude.messages_history:
|
51
|
+
console.print(f"\n[bold cyan]{role.upper()}:[/bold cyan]")
|
52
|
+
console.print(content)
|
53
|
+
console.print("\n=== End Message History ===\n")
|
54
|
+
else:
|
55
|
+
md = Markdown(analysis)
|
56
|
+
console.print(md)
|
57
|
+
|
58
|
+
def prompt_user(message: str, choices: List[str] = None) -> str:
|
59
|
+
"""Display a prominent user prompt with optional choices"""
|
60
|
+
console = Console()
|
61
|
+
console.print()
|
62
|
+
console.print(Rule(" User Input Required ", style="bold cyan"))
|
63
|
+
|
64
|
+
if choices:
|
65
|
+
choice_text = f"[cyan]Options: {', '.join(choices)}[/cyan]"
|
66
|
+
console.print(Panel(choice_text, box=box.ROUNDED))
|
67
|
+
|
68
|
+
return Prompt.ask(f"[bold cyan]> {message}[/bold cyan]")
|
69
|
+
|
70
|
+
def get_option_selection() -> int:
|
71
|
+
"""Get user input for option selection"""
|
72
|
+
while True:
|
73
|
+
try:
|
74
|
+
option = int(prompt_user("Select option number"))
|
75
|
+
return option
|
76
|
+
except ValueError:
|
77
|
+
console = Console()
|
78
|
+
console.print("[red]Please enter a valid number[/red]")
|
79
|
+
|
80
|
+
def get_history_path(workdir: Path) -> Path:
|
81
|
+
"""Create and return the history directory path"""
|
82
|
+
history_dir = workdir / '.janito' / 'history'
|
83
|
+
history_dir.mkdir(parents=True, exist_ok=True)
|
84
|
+
return history_dir
|
85
|
+
|
86
|
+
def get_timestamp() -> str:
|
87
|
+
"""Get current UTC timestamp in YMD_HMS format with leading zeros"""
|
88
|
+
return datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')
|
89
|
+
|
90
|
+
def save_prompt_to_file(prompt: str) -> Path:
|
91
|
+
"""Save prompt to a named temporary file that won't be deleted"""
|
92
|
+
temp_file = tempfile.NamedTemporaryFile(prefix='selected_', suffix='.txt', delete=False)
|
93
|
+
temp_path = Path(temp_file.name)
|
94
|
+
temp_path.write_text(prompt)
|
95
|
+
return temp_path
|
96
|
+
|
97
|
+
def save_to_file(content: str, prefix: str, workdir: Path) -> Path:
|
98
|
+
"""Save content to a timestamped file in history directory"""
|
99
|
+
history_dir = get_history_path(workdir)
|
100
|
+
timestamp = get_timestamp()
|
101
|
+
filename = f"{timestamp}_{prefix}.txt"
|
102
|
+
file_path = history_dir / filename
|
103
|
+
file_path.write_text(content)
|
104
|
+
return file_path
|
105
|
+
|
106
|
+
def handle_option_selection(claude: ClaudeAPIAgent, initial_response: str, request: str, raw: bool = False, workdir: Optional[Path] = None, include: Optional[List[Path]] = None) -> None:
|
107
|
+
"""Handle option selection and implementation details"""
|
108
|
+
option = get_option_selection()
|
109
|
+
paths_to_scan = [workdir] if workdir else []
|
110
|
+
if include:
|
111
|
+
paths_to_scan.extend(include)
|
112
|
+
files_content = collect_files_content(paths_to_scan, workdir) if paths_to_scan else ""
|
113
|
+
|
114
|
+
selected_prompt = build_selected_option_prompt(option, request, initial_response, files_content)
|
115
|
+
prompt_file = save_to_file(selected_prompt, 'selected', workdir)
|
116
|
+
if config.verbose:
|
117
|
+
print(f"\nSelected prompt saved to: {prompt_file}")
|
118
|
+
|
119
|
+
selected_response = claude.send_message(selected_prompt)
|
120
|
+
changes_file = save_to_file(selected_response, 'changes', workdir)
|
121
|
+
if config.verbose:
|
122
|
+
print(f"\nChanges saved to: {changes_file}")
|
123
|
+
|
124
|
+
changes = parse_block_changes(selected_response)
|
125
|
+
preview_and_apply_changes(changes, workdir)
|
126
|
+
|
127
|
+
def replay_saved_file(filepath: Path, claude: ClaudeAPIAgent, workdir: Path, raw: bool = False) -> None:
|
128
|
+
"""Process a saved prompt file and display the response"""
|
129
|
+
if not filepath.exists():
|
130
|
+
raise FileNotFoundError(f"File {filepath} not found")
|
131
|
+
|
132
|
+
file_type = get_file_type(filepath)
|
133
|
+
content = filepath.read_text()
|
134
|
+
|
135
|
+
if file_type == 'changes':
|
136
|
+
changes = parse_block_changes(content)
|
137
|
+
preview_and_apply_changes(changes, workdir)
|
138
|
+
elif file_type == 'analysis':
|
139
|
+
format_analysis(content, raw, claude)
|
140
|
+
handle_option_selection(claude, content, content, raw, workdir)
|
141
|
+
elif file_type == 'selected':
|
142
|
+
if raw:
|
143
|
+
console = Console()
|
144
|
+
console.print("\n=== Prompt Content ===")
|
145
|
+
console.print(content)
|
146
|
+
console.print("=== End Prompt Content ===\n")
|
147
|
+
response = claude.send_message(content)
|
148
|
+
changes_file = save_to_file(response, 'changes_', workdir)
|
149
|
+
print(f"\nChanges saved to: {changes_file}")
|
150
|
+
|
151
|
+
changes = parse_block_changes(response)
|
152
|
+
preview_and_apply_changes(preview_changes, workdir)
|
153
|
+
else:
|
154
|
+
response = claude.send_message(content)
|
155
|
+
format_analysis(response, raw)
|
156
|
+
|
157
|
+
def process_question(question: str, workdir: Path, include: List[Path], raw: bool, claude: ClaudeAPIAgent) -> None:
|
158
|
+
"""Process a question about the codebase"""
|
159
|
+
paths_to_scan = [workdir] if workdir else []
|
160
|
+
if include:
|
161
|
+
paths_to_scan.extend(include)
|
162
|
+
files_content = collect_files_content(paths_to_scan, workdir)
|
163
|
+
|
164
|
+
answer = ask_question(question, files_content, claude)
|
165
|
+
display_answer(answer, raw)
|
166
|
+
|
167
|
+
def ensure_workdir(workdir: Path) -> Path:
|
168
|
+
"""Ensure working directory exists, prompt for creation if it doesn't"""
|
169
|
+
if workdir.exists():
|
170
|
+
return workdir
|
171
|
+
|
172
|
+
console = Console()
|
173
|
+
console.print(f"\n[yellow]Directory does not exist:[/yellow] {workdir}")
|
174
|
+
if Confirm.ask("Create directory?"):
|
175
|
+
workdir.mkdir(parents=True)
|
176
|
+
console.print(f"[green]Created directory:[/green] {workdir}")
|
177
|
+
return workdir
|
178
|
+
raise typer.Exit(1)
|
179
|
+
|
180
|
+
def typer_main(
|
181
|
+
request: Optional[str] = typer.Argument(None, help="The modification request"),
|
182
|
+
ask: Optional[str] = typer.Option(None, "--ask", help="Ask a question about the codebase"),
|
183
|
+
workdir: Optional[Path] = typer.Option(None, "-w", "--workdir",
|
184
|
+
help="Working directory (defaults to current directory)",
|
185
|
+
file_okay=False, dir_okay=True),
|
186
|
+
raw: bool = typer.Option(False, "--raw", help="Print raw response instead of markdown format"),
|
187
|
+
play: Optional[Path] = typer.Option(None, "--play", help="Replay a saved prompt file"),
|
188
|
+
include: Optional[List[Path]] = typer.Option(None, "-i", "--include", help="Additional paths to include in analysis", exists=True),
|
189
|
+
debug: bool = typer.Option(False, "--debug", help="Show debug information"),
|
190
|
+
debug_line: Optional[int] = typer.Option(None, "--debug-line", help="Show debug information only for specific line number"),
|
191
|
+
verbose: bool = typer.Option(False, "-v", "--verbose", help="Show verbose output"),
|
192
|
+
scan: bool = typer.Option(False, "--scan", help="Preview files that would be analyzed"),
|
193
|
+
version: bool = typer.Option(False, "--version", help="Show version and exit"),
|
194
|
+
) -> None:
|
195
|
+
"""
|
196
|
+
Analyze files and provide modification instructions.
|
197
|
+
"""
|
198
|
+
if version:
|
199
|
+
console = Console()
|
200
|
+
console.print(f"Janito v{get_version()}")
|
201
|
+
raise typer.Exit()
|
202
|
+
|
203
|
+
config.set_debug(debug)
|
204
|
+
config.set_verbose(verbose)
|
205
|
+
config.set_debug_line(debug_line)
|
206
|
+
|
207
|
+
claude = ClaudeAPIAgent(system_prompt=SYSTEM_PROMPT)
|
208
|
+
|
209
|
+
if not any([request, ask, play, scan]):
|
210
|
+
workdir = workdir or Path.cwd()
|
211
|
+
workdir = ensure_workdir(workdir)
|
212
|
+
from janito.console import start_console_session
|
213
|
+
start_console_session(workdir, include)
|
214
|
+
return
|
215
|
+
|
216
|
+
workdir = workdir or Path.cwd()
|
217
|
+
workdir = ensure_workdir(workdir)
|
218
|
+
|
219
|
+
if include:
|
220
|
+
include = [
|
221
|
+
path if path.is_absolute() else (workdir / path).resolve()
|
222
|
+
for path in include
|
223
|
+
]
|
224
|
+
|
225
|
+
if ask:
|
226
|
+
process_question(ask, workdir, include, raw, claude)
|
227
|
+
return
|
228
|
+
|
229
|
+
if scan:
|
230
|
+
paths_to_scan = include if include else [workdir]
|
231
|
+
preview_scan(paths_to_scan, workdir)
|
232
|
+
return
|
233
|
+
|
234
|
+
if play:
|
235
|
+
replay_saved_file(play, claude, workdir, raw)
|
236
|
+
return
|
237
|
+
|
238
|
+
paths_to_scan = include if include else [workdir]
|
239
|
+
|
240
|
+
is_empty = is_dir_empty(workdir)
|
241
|
+
if is_empty and not include:
|
242
|
+
console = Console()
|
243
|
+
console.print("\n[bold blue]Empty directory - will create new files as needed[/bold blue]")
|
244
|
+
files_content = ""
|
245
|
+
else:
|
246
|
+
files_content = collect_files_content(paths_to_scan, workdir)
|
247
|
+
|
248
|
+
initial_prompt = build_request_analisys_prompt(files_content, request)
|
249
|
+
initial_response = claude.send_message(initial_prompt)
|
250
|
+
analysis_file = save_to_file(initial_response, 'analysis', workdir)
|
251
|
+
|
252
|
+
format_analysis(initial_response, raw, claude)
|
253
|
+
|
254
|
+
handle_option_selection(claude, initial_response, request, raw, workdir, include)
|
255
|
+
|
256
|
+
def main():
|
257
|
+
typer.run(typer_main)
|
258
|
+
|
259
|
+
if __name__ == "__main__":
|
260
|
+
main()
|