janito 0.6.0__tar.gz → 0.7.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.7.0/PKG-INFO +167 -0
- janito-0.7.0/README.md +142 -0
- {janito-0.6.0 → janito-0.7.0}/janito/__main__.py +37 -30
- {janito-0.6.0 → janito-0.7.0}/janito/agents/__init__.py +8 -2
- {janito-0.6.0 → janito-0.7.0}/janito/agents/agent.py +10 -3
- {janito-0.6.0 → janito-0.7.0}/janito/agents/claudeai.py +13 -23
- {janito-0.6.0 → janito-0.7.0}/janito/agents/openai.py +5 -1
- {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/analyze.py +8 -7
- {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/prompts.py +4 -12
- {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/view/terminal.py +21 -11
- {janito-0.6.0 → janito-0.7.0}/janito/change/applier/text.py +7 -5
- {janito-0.6.0 → janito-0.7.0}/janito/change/core.py +22 -29
- {janito-0.6.0 → janito-0.7.0}/janito/change/parser.py +0 -2
- {janito-0.6.0 → janito-0.7.0}/janito/change/prompts.py +16 -21
- {janito-0.6.0 → janito-0.7.0}/janito/change/validator.py +27 -9
- {janito-0.6.0 → janito-0.7.0}/janito/change/viewer/content.py +1 -1
- {janito-0.6.0 → janito-0.7.0}/janito/change/viewer/panels.py +93 -115
- {janito-0.6.0 → janito-0.7.0}/janito/change/viewer/styling.py +15 -4
- janito-0.7.0/janito/cli/commands.py +88 -0
- janito-0.7.0/janito/common.py +80 -0
- {janito-0.6.0 → janito-0.7.0}/janito/config.py +44 -44
- janito-0.7.0/janito/prompt.py +36 -0
- {janito-0.6.0 → janito-0.7.0}/janito/qa.py +5 -14
- {janito-0.6.0 → janito-0.7.0}/janito/search_replace/README.md +63 -17
- {janito-0.6.0 → janito-0.7.0}/janito/search_replace/__init__.py +2 -1
- {janito-0.6.0 → janito-0.7.0}/janito/search_replace/core.py +15 -14
- janito-0.7.0/janito/search_replace/logger.py +35 -0
- {janito-0.6.0 → janito-0.7.0}/janito/search_replace/searcher.py +160 -48
- janito-0.7.0/janito/search_replace/strategy_result.py +10 -0
- janito-0.7.0/janito/shell/__init__.py +38 -0
- janito-0.6.0/janito/shell/handlers.py → janito-0.7.0/janito/shell/commands.py +46 -32
- janito-0.7.0/janito/shell/processor.py +32 -0
- janito-0.7.0/janito/shell/prompt.py +48 -0
- janito-0.7.0/janito/shell/registry.py +60 -0
- janito-0.7.0/janito/workspace/__init__.py +6 -0
- {janito-0.6.0 → janito-0.7.0}/janito/workspace/analysis.py +2 -2
- janito-0.7.0/janito/workspace/show.py +141 -0
- janito-0.7.0/janito/workspace/stats.py +43 -0
- janito-0.7.0/janito/workspace/types.py +98 -0
- janito-0.7.0/janito/workspace/workset.py +108 -0
- janito-0.7.0/janito/workspace/workspace.py +114 -0
- {janito-0.6.0 → janito-0.7.0}/pyproject.toml +1 -1
- janito-0.6.0/PKG-INFO +0 -185
- janito-0.6.0/README.md +0 -160
- janito-0.6.0/janito/change/viewer/pager.py +0 -56
- janito-0.6.0/janito/cli/commands.py +0 -45
- janito-0.6.0/janito/cli/handlers/ask.py +0 -22
- janito-0.6.0/janito/cli/handlers/demo.py +0 -22
- janito-0.6.0/janito/cli/handlers/request.py +0 -24
- janito-0.6.0/janito/cli/handlers/scan.py +0 -9
- janito-0.6.0/janito/common.py +0 -54
- janito-0.6.0/janito/prompts.py +0 -2
- janito-0.6.0/janito/shell/__init__.py +0 -39
- janito-0.6.0/janito/shell/commands.py +0 -195
- janito-0.6.0/janito/shell/processor.py +0 -52
- janito-0.6.0/janito/workspace/__init__.py +0 -7
- janito-0.6.0/janito/workspace/manager.py +0 -48
- janito-0.6.0/janito/workspace/scan.py +0 -232
- {janito-0.6.0 → janito-0.7.0}/.gitignore +0 -0
- {janito-0.6.0 → janito-0.7.0}/LICENSE +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/__init__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/agents/test.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/__init__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/__main__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/__init__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/__main__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/formatting.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/options.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/view/__init__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/applier/__init__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/applier/file.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/applier/main.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/applier/workspace_dir.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/history.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/operations.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/play.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/preview.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/test.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/viewer/__init__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/viewer/diff.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/change/viewer/themes.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/clear_statement_parser/clear_statement_format.txt +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/clear_statement_parser/examples.txt +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/clear_statement_parser/models.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/clear_statement_parser/parser.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/cli/__init__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/cli/base.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/cli/functions.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/cli/history.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/cli/registry.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/demo/__init__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/demo/data.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/demo/mock_data.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/demo/operations.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/demo/runner.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/demo/scenarios.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/review.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/search_replace/__main__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/search_replace/parser.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/search_replace/play.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/search_replace/replacer.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/shell/bus.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/shell/history.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/tui/__init__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/tui/base.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/tui/flows/__init__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/tui/flows/changes.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/tui/flows/content.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/tui/flows/selection.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/tui/screens/__init__.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/tui/screens/app.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/janito/version.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/setup.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/tests/test_python_adjustments.py +0 -0
- {janito-0.6.0 → janito-0.7.0}/tools/release.sh +0 -0
janito-0.7.0/PKG-INFO
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: janito
|
3
|
+
Version: 0.7.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
|
+
License-File: LICENSE
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
11
|
+
Classifier: Environment :: Console
|
12
|
+
Classifier: Intended Audience :: Developers
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
17
|
+
Classifier: Topic :: Software Development
|
18
|
+
Requires-Python: >=3.8
|
19
|
+
Requires-Dist: anthropic
|
20
|
+
Requires-Dist: pathspec
|
21
|
+
Requires-Dist: rich
|
22
|
+
Requires-Dist: tomli
|
23
|
+
Requires-Dist: typer
|
24
|
+
Description-Content-Type: text/markdown
|
25
|
+
|
26
|
+
# Janito
|
27
|
+
|
28
|
+
[](https://badge.fury.io/py/janito)
|
29
|
+
[](https://opensource.org/licenses/MIT)
|
30
|
+
|
31
|
+
AI-powered CLI tool for code modifications and analysis. Janito helps you modify, analyze, and understand your codebase using natural language commands.
|
32
|
+
|
33
|
+
## Table of Contents
|
34
|
+
|
35
|
+
- [Features](#features)
|
36
|
+
- [Installation](#installation)
|
37
|
+
- [Usage](#usage)
|
38
|
+
- [Basic Commands](#basic-commands)
|
39
|
+
- [Examples](#examples)
|
40
|
+
- [Configuration](#configuration)
|
41
|
+
- [Development](#development)
|
42
|
+
- [License](#license)
|
43
|
+
|
44
|
+
## Features
|
45
|
+
|
46
|
+
- 🤖 AI-powered code analysis and modifications
|
47
|
+
- 🔄 Incremental code changes with search/replace operations
|
48
|
+
- 🎯 Precise text modifications with context matching
|
49
|
+
- 💬 Natural language interface for code operations
|
50
|
+
- 🔍 Interactive code exploration
|
51
|
+
- 📝 Automatic documentation generation
|
52
|
+
- ⚡ Fast and efficient codebase navigation
|
53
|
+
- 💾 Smart Claude AI prompt caching for faster responses
|
54
|
+
|
55
|
+
## Installation
|
56
|
+
|
57
|
+
### Prerequisites
|
58
|
+
|
59
|
+
- Python 3.8 or higher
|
60
|
+
- Anthropic API key (with smart caching to reduce API costs)
|
61
|
+
|
62
|
+
### Install via pip
|
63
|
+
|
64
|
+
```bash
|
65
|
+
pip install janito
|
66
|
+
```
|
67
|
+
|
68
|
+
### Set up API key
|
69
|
+
|
70
|
+
```bash
|
71
|
+
export ANTHROPIC_API_KEY=your_api_key_here
|
72
|
+
```
|
73
|
+
|
74
|
+
## Usage
|
75
|
+
|
76
|
+
### Basic Commands
|
77
|
+
|
78
|
+
Janito supports incremental code changes through precise text operations:
|
79
|
+
- Search and replace with context matching
|
80
|
+
- Delete specific code blocks
|
81
|
+
- File operations (create, replace, rename, move, remove)
|
82
|
+
|
83
|
+
```bash
|
84
|
+
# Start interactive shell
|
85
|
+
janito
|
86
|
+
|
87
|
+
# Modify code with natural language
|
88
|
+
janito "add docstrings to this file"
|
89
|
+
|
90
|
+
# Ask questions about the codebase
|
91
|
+
janito --ask "explain the main function in this file"
|
92
|
+
|
93
|
+
# Preview files that would be analyzed
|
94
|
+
janito --scan
|
95
|
+
```
|
96
|
+
|
97
|
+
### Examples
|
98
|
+
|
99
|
+
1. Add documentation to a file:
|
100
|
+
```bash
|
101
|
+
janito "add docstrings to all functions in src/main.py"
|
102
|
+
```
|
103
|
+
|
104
|
+
2. Analyze code structure:
|
105
|
+
```bash
|
106
|
+
janito --ask "what are the main classes in this project?"
|
107
|
+
```
|
108
|
+
|
109
|
+
3. Refactor code:
|
110
|
+
```bash
|
111
|
+
janito "convert this function to use async/await"
|
112
|
+
```
|
113
|
+
|
114
|
+
4. Generate tests:
|
115
|
+
```bash
|
116
|
+
janito "create unit tests for the User class"
|
117
|
+
```
|
118
|
+
|
119
|
+
## Configuration
|
120
|
+
|
121
|
+
### Environment Variables
|
122
|
+
|
123
|
+
- `ANTHROPIC_API_KEY`: Anthropic API key for Claude AI
|
124
|
+
- `JANITO_TEST_CMD`: Default test command to run after changes
|
125
|
+
|
126
|
+
### Command Line Options
|
127
|
+
|
128
|
+
- `-w, --workspace_dir`: Set working directory
|
129
|
+
- `-i, --include`: Additional paths to include
|
130
|
+
- `--debug`: Show debug information
|
131
|
+
- `--verbose`: Show verbose output
|
132
|
+
- `--auto-apply`: Apply changes without confirmation
|
133
|
+
|
134
|
+
## Development
|
135
|
+
|
136
|
+
### Setting up Development Environment
|
137
|
+
|
138
|
+
```bash
|
139
|
+
# Clone the repository
|
140
|
+
git clone https://github.com/joaompinto/janito.git
|
141
|
+
cd janito
|
142
|
+
|
143
|
+
# Create and activate virtual environment
|
144
|
+
python -m venv venv
|
145
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
146
|
+
|
147
|
+
# Install development dependencies
|
148
|
+
pip install -e ".[dev]"
|
149
|
+
```
|
150
|
+
|
151
|
+
### Running Tests
|
152
|
+
|
153
|
+
```bash
|
154
|
+
pytest
|
155
|
+
```
|
156
|
+
|
157
|
+
### Contributing
|
158
|
+
|
159
|
+
1. Fork the repository
|
160
|
+
2. Create a feature branch
|
161
|
+
3. Commit your changes
|
162
|
+
4. Push to the branch
|
163
|
+
5. Create a Pull Request
|
164
|
+
|
165
|
+
## License
|
166
|
+
|
167
|
+
MIT License - see [LICENSE](LICENSE)
|
janito-0.7.0/README.md
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
# Janito
|
2
|
+
|
3
|
+
[](https://badge.fury.io/py/janito)
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
5
|
+
|
6
|
+
AI-powered CLI tool for code modifications and analysis. Janito helps you modify, analyze, and understand your codebase using natural language commands.
|
7
|
+
|
8
|
+
## Table of Contents
|
9
|
+
|
10
|
+
- [Features](#features)
|
11
|
+
- [Installation](#installation)
|
12
|
+
- [Usage](#usage)
|
13
|
+
- [Basic Commands](#basic-commands)
|
14
|
+
- [Examples](#examples)
|
15
|
+
- [Configuration](#configuration)
|
16
|
+
- [Development](#development)
|
17
|
+
- [License](#license)
|
18
|
+
|
19
|
+
## Features
|
20
|
+
|
21
|
+
- 🤖 AI-powered code analysis and modifications
|
22
|
+
- 🔄 Incremental code changes with search/replace operations
|
23
|
+
- 🎯 Precise text modifications with context matching
|
24
|
+
- 💬 Natural language interface for code operations
|
25
|
+
- 🔍 Interactive code exploration
|
26
|
+
- 📝 Automatic documentation generation
|
27
|
+
- ⚡ Fast and efficient codebase navigation
|
28
|
+
- 💾 Smart Claude AI prompt caching for faster responses
|
29
|
+
|
30
|
+
## Installation
|
31
|
+
|
32
|
+
### Prerequisites
|
33
|
+
|
34
|
+
- Python 3.8 or higher
|
35
|
+
- Anthropic API key (with smart caching to reduce API costs)
|
36
|
+
|
37
|
+
### Install via pip
|
38
|
+
|
39
|
+
```bash
|
40
|
+
pip install janito
|
41
|
+
```
|
42
|
+
|
43
|
+
### Set up API key
|
44
|
+
|
45
|
+
```bash
|
46
|
+
export ANTHROPIC_API_KEY=your_api_key_here
|
47
|
+
```
|
48
|
+
|
49
|
+
## Usage
|
50
|
+
|
51
|
+
### Basic Commands
|
52
|
+
|
53
|
+
Janito supports incremental code changes through precise text operations:
|
54
|
+
- Search and replace with context matching
|
55
|
+
- Delete specific code blocks
|
56
|
+
- File operations (create, replace, rename, move, remove)
|
57
|
+
|
58
|
+
```bash
|
59
|
+
# Start interactive shell
|
60
|
+
janito
|
61
|
+
|
62
|
+
# Modify code with natural language
|
63
|
+
janito "add docstrings to this file"
|
64
|
+
|
65
|
+
# Ask questions about the codebase
|
66
|
+
janito --ask "explain the main function in this file"
|
67
|
+
|
68
|
+
# Preview files that would be analyzed
|
69
|
+
janito --scan
|
70
|
+
```
|
71
|
+
|
72
|
+
### Examples
|
73
|
+
|
74
|
+
1. Add documentation to a file:
|
75
|
+
```bash
|
76
|
+
janito "add docstrings to all functions in src/main.py"
|
77
|
+
```
|
78
|
+
|
79
|
+
2. Analyze code structure:
|
80
|
+
```bash
|
81
|
+
janito --ask "what are the main classes in this project?"
|
82
|
+
```
|
83
|
+
|
84
|
+
3. Refactor code:
|
85
|
+
```bash
|
86
|
+
janito "convert this function to use async/await"
|
87
|
+
```
|
88
|
+
|
89
|
+
4. Generate tests:
|
90
|
+
```bash
|
91
|
+
janito "create unit tests for the User class"
|
92
|
+
```
|
93
|
+
|
94
|
+
## Configuration
|
95
|
+
|
96
|
+
### Environment Variables
|
97
|
+
|
98
|
+
- `ANTHROPIC_API_KEY`: Anthropic API key for Claude AI
|
99
|
+
- `JANITO_TEST_CMD`: Default test command to run after changes
|
100
|
+
|
101
|
+
### Command Line Options
|
102
|
+
|
103
|
+
- `-w, --workspace_dir`: Set working directory
|
104
|
+
- `-i, --include`: Additional paths to include
|
105
|
+
- `--debug`: Show debug information
|
106
|
+
- `--verbose`: Show verbose output
|
107
|
+
- `--auto-apply`: Apply changes without confirmation
|
108
|
+
|
109
|
+
## Development
|
110
|
+
|
111
|
+
### Setting up Development Environment
|
112
|
+
|
113
|
+
```bash
|
114
|
+
# Clone the repository
|
115
|
+
git clone https://github.com/joaompinto/janito.git
|
116
|
+
cd janito
|
117
|
+
|
118
|
+
# Create and activate virtual environment
|
119
|
+
python -m venv venv
|
120
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
121
|
+
|
122
|
+
# Install development dependencies
|
123
|
+
pip install -e ".[dev]"
|
124
|
+
```
|
125
|
+
|
126
|
+
### Running Tests
|
127
|
+
|
128
|
+
```bash
|
129
|
+
pytest
|
130
|
+
```
|
131
|
+
|
132
|
+
### Contributing
|
133
|
+
|
134
|
+
1. Fork the repository
|
135
|
+
2. Create a feature branch
|
136
|
+
3. Commit your changes
|
137
|
+
4. Push to the branch
|
138
|
+
5. Create a Pull Request
|
139
|
+
|
140
|
+
## License
|
141
|
+
|
142
|
+
MIT License - see [LICENSE](LICENSE)
|
@@ -7,12 +7,15 @@ from rich.console import Console
|
|
7
7
|
from rich.text import Text
|
8
8
|
from .version import get_version
|
9
9
|
|
10
|
-
from janito.agents import agent
|
11
10
|
from janito.config import config
|
11
|
+
from janito.workspace import workset
|
12
|
+
from janito.workspace.types import ScanType # Add this import
|
13
|
+
from .cli.commands import (
|
14
|
+
handle_request, handle_ask, handle_play,
|
15
|
+
handle_scan, handle_demo
|
16
|
+
)
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
app = typer.Typer(add_completion=False)
|
18
|
+
app = typer.Typer(pretty_exceptions_enable=False)
|
16
19
|
|
17
20
|
def validate_paths(paths: Optional[List[Path]]) -> Optional[List[Path]]:
|
18
21
|
"""Validate include paths for duplicates.
|
@@ -57,7 +60,7 @@ def typer_main(
|
|
57
60
|
history: bool = typer.Option(False, "--history", help="Display history of requests"),
|
58
61
|
recursive: Optional[List[Path]] = typer.Option(None, "-r", "--recursive", help="Paths to scan recursively (directories only)"),
|
59
62
|
demo: bool = typer.Option(False, "--demo", help="Run demo scenarios"),
|
60
|
-
|
63
|
+
skip_work: bool = typer.Option(False, "--skip-work", help="Skip scanning workspace_dir when using include paths"),
|
61
64
|
):
|
62
65
|
"""Janito - AI-powered code modification assistant"""
|
63
66
|
if version:
|
@@ -66,9 +69,7 @@ def typer_main(
|
|
66
69
|
return
|
67
70
|
|
68
71
|
if demo:
|
69
|
-
|
70
|
-
handler = DemoHandler()
|
71
|
-
handler.handle()
|
72
|
+
handle_demo()
|
72
73
|
return
|
73
74
|
|
74
75
|
if history:
|
@@ -76,52 +77,58 @@ def typer_main(
|
|
76
77
|
display_history()
|
77
78
|
return
|
78
79
|
|
80
|
+
# Configure workspace
|
79
81
|
config.set_workspace_dir(workspace_dir)
|
80
82
|
config.set_debug(debug)
|
81
83
|
config.set_verbose(verbose)
|
82
84
|
config.set_auto_apply(auto_apply)
|
83
|
-
config.set_include(include)
|
84
85
|
config.set_tui(tui)
|
85
|
-
config.set_skipwork(skipwork)
|
86
|
-
|
87
|
-
# Validate skipwork usage
|
88
|
-
if skipwork and not include and not recursive:
|
89
|
-
error_text = Text("\nError: --skipwork requires at least one include path (-i or -r)", style="red")
|
90
|
-
rich_print(error_text)
|
91
|
-
raise typer.Exit(1)
|
92
86
|
|
87
|
+
# Configure workset with scan paths
|
93
88
|
if include:
|
94
|
-
|
89
|
+
if config.debug:
|
90
|
+
Console(stderr=True).print("[cyan]Debug: Processing include paths...[/cyan]")
|
95
91
|
for path in include:
|
96
|
-
|
97
|
-
|
98
|
-
|
92
|
+
full_path = config.workspace_dir / path
|
93
|
+
if not full_path.resolve().is_relative_to(config.workspace_dir):
|
94
|
+
error_text = Text(f"\nError: Path must be within workspace: {path}", style="red")
|
95
|
+
rich_print(error_text)
|
96
|
+
raise typer.Exit(1)
|
97
|
+
workset.add_scan_path(path, ScanType.PLAIN)
|
99
98
|
|
100
|
-
# Validate recursive paths
|
101
99
|
if recursive:
|
102
|
-
|
100
|
+
if config.debug:
|
101
|
+
Console(stderr=True).print("[cyan]Debug: Processing recursive paths...[/cyan]")
|
103
102
|
for path in recursive:
|
104
|
-
|
103
|
+
full_path = config.workspace_dir / path
|
105
104
|
if not path.is_dir():
|
106
105
|
error_text = Text(f"\nError: Recursive path must be a directory: {path} ", style="red")
|
107
106
|
rich_print(error_text)
|
108
107
|
raise typer.Exit(1)
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
108
|
+
if not full_path.resolve().is_relative_to(config.workspace_dir):
|
109
|
+
error_text = Text(f"\nError: Path must be within workspace: {path}", style="red")
|
110
|
+
rich_print(error_text)
|
111
|
+
raise typer.Exit(1)
|
112
|
+
workset.add_scan_path(path, ScanType.RECURSIVE)
|
113
|
+
|
114
|
+
# Validate skip_work usage
|
115
|
+
if skip_work and not workset.paths:
|
116
|
+
error_text = Text("\nError: --skip-work requires at least one include path (-i or -r)", style="red")
|
117
|
+
rich_print(error_text)
|
118
|
+
raise typer.Exit(1)
|
114
119
|
|
115
120
|
if test_cmd:
|
116
121
|
config.set_test_cmd(test_cmd)
|
117
122
|
|
123
|
+
# Refresh workset content before handling commands
|
124
|
+
workset.refresh()
|
125
|
+
|
118
126
|
if ask:
|
119
127
|
handle_ask(ask)
|
120
128
|
elif play:
|
121
129
|
handle_play(play)
|
122
130
|
elif scan:
|
123
|
-
|
124
|
-
handle_scan(paths_to_scan)
|
131
|
+
handle_scan()
|
125
132
|
elif change_request:
|
126
133
|
handle_request(change_request)
|
127
134
|
else:
|
@@ -5,6 +5,13 @@ SYSTEM_PROMPT = """I am Janito, your friendly software development buddy. I help
|
|
5
5
|
ai_backend = os.getenv('AI_BACKEND', 'claudeai').lower()
|
6
6
|
|
7
7
|
if ai_backend == 'openai':
|
8
|
+
import warnings
|
9
|
+
warnings.warn(
|
10
|
+
"Using deprecated OpenAI backend. Please switch to Claude AI backend by removing AI_BACKEND=openai "
|
11
|
+
"from your environment variables.",
|
12
|
+
DeprecationWarning,
|
13
|
+
stacklevel=2
|
14
|
+
)
|
8
15
|
from .openai import OpenAIAgent as AIAgent
|
9
16
|
elif ai_backend == 'claudeai':
|
10
17
|
from .claudeai import ClaudeAIAgent as AIAgent
|
@@ -12,5 +19,4 @@ else:
|
|
12
19
|
raise ValueError(f"Unsupported AI_BACKEND: {ai_backend}")
|
13
20
|
|
14
21
|
# Create a singleton instance
|
15
|
-
agent = AIAgent(SYSTEM_PROMPT)
|
16
|
-
|
22
|
+
agent = AIAgent(SYSTEM_PROMPT)
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
from abc import ABC, abstractmethod
|
3
2
|
from threading import Event
|
4
3
|
from typing import Optional, List, Tuple
|
@@ -16,6 +15,14 @@ class Agent(ABC):
|
|
16
15
|
self.messages_history.append(("system", system_prompt))
|
17
16
|
|
18
17
|
@abstractmethod
|
19
|
-
def send_message(self, message: str,
|
20
|
-
"""Send message to AI
|
18
|
+
def send_message(self, message: str, system: str) -> str:
|
19
|
+
"""Send message to the AI agent
|
20
|
+
|
21
|
+
Args:
|
22
|
+
message: The message to send
|
23
|
+
stop_event: Optional event to signal cancellation
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
The response from the AI agent
|
27
|
+
"""
|
21
28
|
pass
|
@@ -24,32 +24,22 @@ class ClaudeAIAgent(Agent):
|
|
24
24
|
self.last_response = None
|
25
25
|
|
26
26
|
|
27
|
-
def send_message(self, message: str,
|
27
|
+
def send_message(self, message: str, system_message: str = None) -> str:
|
28
28
|
"""Send message to Claude API and return response"""
|
29
29
|
self.messages_history.append(("user", message))
|
30
30
|
# Store the full message
|
31
31
|
self.last_full_message = message
|
32
32
|
|
33
|
-
|
34
|
-
#
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
{"role": "user", "content": message}
|
44
|
-
],
|
45
|
-
temperature=0,
|
46
|
-
)
|
47
|
-
|
33
|
+
response = self.client.messages.create(
|
34
|
+
model=self.model, # Use discovered model
|
35
|
+
system=system_message or self.system_message,
|
36
|
+
max_tokens=8192,
|
37
|
+
messages=[
|
38
|
+
{"role": "user", "content": message}
|
39
|
+
],
|
40
|
+
temperature=0,
|
41
|
+
)
|
42
|
+
|
48
43
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
except KeyboardInterrupt:
|
53
|
-
if stop_event:
|
54
|
-
stop_event.set()
|
55
|
-
return ""
|
44
|
+
# Always return the response, let caller handle cancellation
|
45
|
+
return response
|
@@ -5,7 +5,11 @@ from threading import Event
|
|
5
5
|
from .agent import Agent
|
6
6
|
|
7
7
|
class OpenAIAgent(Agent):
|
8
|
-
"""Handles interaction with OpenAI API, including message handling
|
8
|
+
"""[DEPRECATED] Handles interaction with OpenAI API, including message handling.
|
9
|
+
|
10
|
+
This backend is no longer actively maintained. Please use the Claude AI backend instead.
|
11
|
+
The code is kept for backward compatibility but may be removed in future versions.
|
12
|
+
"""
|
9
13
|
DEFAULT_MODEL = "o1-mini-2024-09-12"
|
10
14
|
|
11
15
|
def __init__(self, api_key: Optional[str] = None, system_prompt: str = None):
|
@@ -1,10 +1,10 @@
|
|
1
1
|
"""Core analysis functionality."""
|
2
2
|
|
3
|
-
from typing import Optional
|
4
|
-
|
3
|
+
from typing import Optional
|
5
4
|
from janito.agents import agent
|
6
5
|
from janito.common import progress_send_message
|
7
6
|
from janito.config import config
|
7
|
+
from janito.workspace.workset import Workset
|
8
8
|
from .view import format_analysis
|
9
9
|
from .options import AnalysisOption, parse_analysis_options
|
10
10
|
from .prompts import (
|
@@ -15,25 +15,26 @@ from .prompts import (
|
|
15
15
|
|
16
16
|
def analyze_request(
|
17
17
|
request: str,
|
18
|
-
files_content_xml: str,
|
19
18
|
pre_select: str = ""
|
20
19
|
) -> Optional[AnalysisOption]:
|
21
20
|
"""
|
22
21
|
Analyze changes and get user selection.
|
23
22
|
|
24
23
|
Args:
|
25
|
-
files_content: Content of files to analyze
|
26
24
|
request: User's change request
|
25
|
+
files_content_xml: Optional content of files to analyze
|
27
26
|
pre_select: Optional pre-selected option letter
|
28
27
|
|
29
28
|
Returns:
|
30
29
|
Selected AnalysisOption or None if modified
|
31
30
|
"""
|
32
|
-
#
|
33
|
-
|
31
|
+
workset = Workset() # Create workset instance
|
32
|
+
|
33
|
+
# Build and send prompt using workset content directly
|
34
|
+
prompt = build_request_analysis_prompt(request)
|
34
35
|
response = progress_send_message(prompt)
|
35
36
|
|
36
|
-
# Parse options
|
37
|
+
# Parse and handle options
|
37
38
|
options = parse_analysis_options(response)
|
38
39
|
if not options:
|
39
40
|
return None
|
@@ -12,12 +12,9 @@ from .options import AnalysisOption
|
|
12
12
|
|
13
13
|
# Keep only prompt-related functionality
|
14
14
|
CHANGE_ANALYSIS_PROMPT = """
|
15
|
-
Current files:
|
16
|
-
<files>
|
17
|
-
{files_content}
|
18
|
-
</files>
|
19
15
|
|
20
|
-
|
16
|
+
|
17
|
+
Considering the above workset content, provide 3 sections, each identified by a keyword and representing an option.
|
21
18
|
Each option should include a concise description and a list of affected files.
|
22
19
|
1st option should be basic style change, 2nd organized style, 3rd exntensible style.
|
23
20
|
Do not use style as keyword, instead focus on the changes summary.
|
@@ -86,13 +83,8 @@ def get_option_selection() -> str:
|
|
86
83
|
padded_error = " " * error_padding + error_msg
|
87
84
|
console.print(f"[red]{padded_error}[/red]")
|
88
85
|
|
89
|
-
def build_request_analysis_prompt(request: str
|
86
|
+
def build_request_analysis_prompt(request: str) -> str:
|
90
87
|
"""Build prompt for information requests"""
|
91
88
|
return CHANGE_ANALYSIS_PROMPT.format(
|
92
|
-
files_content=files_content_xml,
|
93
89
|
request=request
|
94
|
-
)
|
95
|
-
|
96
|
-
def build_request_analysis_prompt(request: str, files_content_xml: str) -> str:
|
97
|
-
"""Build analysis prompt with minimal formatting."""
|
98
|
-
return f"Current files:\n{files_content_xml}\n\nRequest:\n{request}"
|
90
|
+
)
|
@@ -9,6 +9,9 @@ from rich.rule import Rule
|
|
9
9
|
from rich.padding import Padding
|
10
10
|
from rich.prompt import Prompt
|
11
11
|
from rich import box
|
12
|
+
from rich.style import Style
|
13
|
+
from rich.segment import Segment
|
14
|
+
from rich.containers import Renderables
|
12
15
|
from pathlib import Path
|
13
16
|
|
14
17
|
from ..options import AnalysisOption
|
@@ -34,9 +37,10 @@ def prompt_user(message: str, choices: List[str] = None) -> str:
|
|
34
37
|
choice_text = f"[cyan]Options: {', '.join(choices)}[/cyan]"
|
35
38
|
console.print(Panel(choice_text, box=box.ROUNDED, justify="center"))
|
36
39
|
|
37
|
-
|
38
|
-
padded_message =
|
39
|
-
|
40
|
+
message_text = Text(message, style="bold cyan")
|
41
|
+
padded_message = Padding(message_text, pad=(0, "center"))
|
42
|
+
console.print(padded_message)
|
43
|
+
return Prompt.ask("")
|
40
44
|
|
41
45
|
def get_option_selection() -> str:
|
42
46
|
"""Get user input for option selection with modify option"""
|
@@ -53,9 +57,9 @@ def get_option_selection() -> str:
|
|
53
57
|
return letter
|
54
58
|
|
55
59
|
error_msg = "Please enter a valid letter or 'M'"
|
56
|
-
|
57
|
-
padded_error =
|
58
|
-
console.print(
|
60
|
+
error_text = Text(error_msg, style="red")
|
61
|
+
padded_error = Padding(error_text, pad=(0, "center"))
|
62
|
+
console.print(padded_error)
|
59
63
|
|
60
64
|
def _create_option_content(option: AnalysisOption) -> Text:
|
61
65
|
"""Create rich formatted content for a single option."""
|
@@ -104,9 +108,14 @@ def _create_option_content(option: AnalysisOption) -> Text:
|
|
104
108
|
content.append("/", style=STRUCTURAL_COLORS['separator'])
|
105
109
|
seen_dirs[parent_dir] = True
|
106
110
|
else:
|
107
|
-
|
108
|
-
|
109
|
-
|
111
|
+
dir_width = len(parent_dir)
|
112
|
+
# Calculate padding to match full directory width
|
113
|
+
arrow = "↑"
|
114
|
+
total_padding = dir_width - len(arrow)
|
115
|
+
left_padding = total_padding // 2
|
116
|
+
right_padding = total_padding - left_padding
|
117
|
+
content.append(" " * left_padding + arrow + " " * right_padding,
|
118
|
+
style=STRUCTURAL_COLORS['repeat'])
|
110
119
|
content.append("/", style=STRUCTURAL_COLORS['separator'])
|
111
120
|
content.append(current_parts[-1], style=STATUS_COLORS[status.lower()])
|
112
121
|
else:
|
@@ -127,13 +136,14 @@ def create_columns_layout(options_content: List[Text], term_width: int) -> Colum
|
|
127
136
|
usable_width = term_width - spacing - safety_margin
|
128
137
|
column_width = max((usable_width // num_columns), MIN_PANEL_WIDTH)
|
129
138
|
|
130
|
-
|
139
|
+
# Create padded content items
|
140
|
+
rendered_items: List[Renderables] = [
|
131
141
|
Padding(content, (0, COLUMN_SPACING // 2))
|
132
142
|
for content in options_content
|
133
143
|
]
|
134
144
|
|
135
145
|
return Columns(
|
136
|
-
|
146
|
+
rendered_items,
|
137
147
|
equal=True,
|
138
148
|
expand=True,
|
139
149
|
width=column_width,
|