janito 0.7.0__tar.gz → 0.8.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.
Files changed (123) hide show
  1. janito-0.8.0/.gitignore +42 -0
  2. {janito-0.7.0 → janito-0.8.0}/LICENSE +20 -20
  3. janito-0.8.0/PKG-INFO +106 -0
  4. janito-0.8.0/README.md +82 -0
  5. {janito-0.7.0 → janito-0.8.0}/janito/__main__.py +127 -141
  6. janito-0.8.0/janito/agents/__init__.py +22 -0
  7. {janito-0.7.0 → janito-0.8.0}/janito/agents/agent.py +24 -27
  8. {janito-0.7.0 → janito-0.8.0}/janito/agents/claudeai.py +41 -45
  9. janito-0.8.0/janito/agents/deepseekai.py +47 -0
  10. janito-0.8.0/janito/change/applied_blocks.py +34 -0
  11. janito-0.8.0/janito/change/applier.py +167 -0
  12. janito-0.8.0/janito/change/edit_blocks.py +148 -0
  13. janito-0.8.0/janito/change/finder.py +72 -0
  14. janito-0.8.0/janito/change/request.py +144 -0
  15. janito-0.8.0/janito/change/validator.py +87 -0
  16. janito-0.8.0/janito/change/view/content.py +63 -0
  17. {janito-0.7.0/janito/change/viewer → janito-0.8.0/janito/change/view}/diff.py +44 -43
  18. janito-0.8.0/janito/change/view/panels.py +201 -0
  19. janito-0.8.0/janito/change/view/sections.py +69 -0
  20. janito-0.8.0/janito/change/view/styling.py +140 -0
  21. janito-0.8.0/janito/change/view/summary.py +37 -0
  22. {janito-0.7.0/janito/change/viewer → janito-0.8.0/janito/change/view}/themes.py +62 -55
  23. janito-0.8.0/janito/change/view/viewer.py +59 -0
  24. {janito-0.7.0 → janito-0.8.0}/janito/cli/__init__.py +1 -1
  25. janito-0.8.0/janito/cli/commands.py +68 -0
  26. {janito-0.7.0 → janito-0.8.0}/janito/cli/functions.py +66 -111
  27. janito-0.8.0/janito/common.py +133 -0
  28. {janito-0.7.0 → janito-0.8.0}/janito/config.py +99 -101
  29. janito-0.8.0/janito/data/change_prompt.txt +81 -0
  30. janito-0.8.0/janito/data/system_prompt.txt +3 -0
  31. janito-0.8.0/janito/qa.py +56 -0
  32. {janito-0.7.0 → janito-0.8.0}/janito/version.py +22 -22
  33. janito-0.8.0/janito/workspace/__init__.py +8 -0
  34. {janito-0.7.0 → janito-0.8.0}/janito/workspace/analysis.py +120 -120
  35. janito-0.7.0/janito/workspace/types.py → janito-0.8.0/janito/workspace/models.py +97 -98
  36. {janito-0.7.0 → janito-0.8.0}/janito/workspace/show.py +115 -141
  37. {janito-0.7.0 → janito-0.8.0}/janito/workspace/stats.py +42 -43
  38. {janito-0.7.0 → janito-0.8.0}/janito/workspace/workset.py +135 -108
  39. janito-0.8.0/janito/workspace/workspace.py +335 -0
  40. {janito-0.7.0 → janito-0.8.0}/pyproject.toml +48 -41
  41. {janito-0.7.0 → janito-0.8.0}/tools/release.sh +86 -86
  42. janito-0.7.0/.gitignore +0 -88
  43. janito-0.7.0/PKG-INFO +0 -167
  44. janito-0.7.0/README.md +0 -142
  45. janito-0.7.0/janito/__init__.py +0 -2
  46. janito-0.7.0/janito/agents/__init__.py +0 -22
  47. janito-0.7.0/janito/agents/openai.py +0 -57
  48. janito-0.7.0/janito/agents/test.py +0 -34
  49. janito-0.7.0/janito/change/__init__.py +0 -32
  50. janito-0.7.0/janito/change/__main__.py +0 -0
  51. janito-0.7.0/janito/change/analysis/__init__.py +0 -23
  52. janito-0.7.0/janito/change/analysis/__main__.py +0 -7
  53. janito-0.7.0/janito/change/analysis/analyze.py +0 -62
  54. janito-0.7.0/janito/change/analysis/formatting.py +0 -78
  55. janito-0.7.0/janito/change/analysis/options.py +0 -81
  56. janito-0.7.0/janito/change/analysis/prompts.py +0 -90
  57. janito-0.7.0/janito/change/analysis/view/__init__.py +0 -9
  58. janito-0.7.0/janito/change/analysis/view/terminal.py +0 -181
  59. janito-0.7.0/janito/change/applier/__init__.py +0 -5
  60. janito-0.7.0/janito/change/applier/file.py +0 -58
  61. janito-0.7.0/janito/change/applier/main.py +0 -156
  62. janito-0.7.0/janito/change/applier/text.py +0 -247
  63. janito-0.7.0/janito/change/applier/workspace_dir.py +0 -58
  64. janito-0.7.0/janito/change/core.py +0 -124
  65. janito-0.7.0/janito/change/history.py +0 -44
  66. janito-0.7.0/janito/change/operations.py +0 -7
  67. janito-0.7.0/janito/change/parser.py +0 -287
  68. janito-0.7.0/janito/change/play.py +0 -54
  69. janito-0.7.0/janito/change/preview.py +0 -82
  70. janito-0.7.0/janito/change/prompts.py +0 -121
  71. janito-0.7.0/janito/change/test.py +0 -0
  72. janito-0.7.0/janito/change/validator.py +0 -269
  73. janito-0.7.0/janito/change/viewer/__init__.py +0 -11
  74. janito-0.7.0/janito/change/viewer/content.py +0 -66
  75. janito-0.7.0/janito/change/viewer/panels.py +0 -533
  76. janito-0.7.0/janito/change/viewer/styling.py +0 -114
  77. janito-0.7.0/janito/clear_statement_parser/clear_statement_format.txt +0 -328
  78. janito-0.7.0/janito/clear_statement_parser/examples.txt +0 -326
  79. janito-0.7.0/janito/clear_statement_parser/models.py +0 -104
  80. janito-0.7.0/janito/clear_statement_parser/parser.py +0 -496
  81. janito-0.7.0/janito/cli/base.py +0 -30
  82. janito-0.7.0/janito/cli/commands.py +0 -88
  83. janito-0.7.0/janito/cli/history.py +0 -61
  84. janito-0.7.0/janito/cli/registry.py +0 -26
  85. janito-0.7.0/janito/common.py +0 -80
  86. janito-0.7.0/janito/demo/__init__.py +0 -4
  87. janito-0.7.0/janito/demo/data.py +0 -13
  88. janito-0.7.0/janito/demo/mock_data.py +0 -20
  89. janito-0.7.0/janito/demo/operations.py +0 -45
  90. janito-0.7.0/janito/demo/runner.py +0 -59
  91. janito-0.7.0/janito/demo/scenarios.py +0 -32
  92. janito-0.7.0/janito/prompt.py +0 -36
  93. janito-0.7.0/janito/qa.py +0 -57
  94. janito-0.7.0/janito/review.py +0 -13
  95. janito-0.7.0/janito/search_replace/README.md +0 -192
  96. janito-0.7.0/janito/search_replace/__init__.py +0 -7
  97. janito-0.7.0/janito/search_replace/__main__.py +0 -21
  98. janito-0.7.0/janito/search_replace/core.py +0 -120
  99. janito-0.7.0/janito/search_replace/logger.py +0 -35
  100. janito-0.7.0/janito/search_replace/parser.py +0 -52
  101. janito-0.7.0/janito/search_replace/play.py +0 -61
  102. janito-0.7.0/janito/search_replace/replacer.py +0 -36
  103. janito-0.7.0/janito/search_replace/searcher.py +0 -411
  104. janito-0.7.0/janito/search_replace/strategy_result.py +0 -10
  105. janito-0.7.0/janito/shell/__init__.py +0 -38
  106. janito-0.7.0/janito/shell/bus.py +0 -31
  107. janito-0.7.0/janito/shell/commands.py +0 -136
  108. janito-0.7.0/janito/shell/history.py +0 -20
  109. janito-0.7.0/janito/shell/processor.py +0 -32
  110. janito-0.7.0/janito/shell/prompt.py +0 -48
  111. janito-0.7.0/janito/shell/registry.py +0 -60
  112. janito-0.7.0/janito/tui/__init__.py +0 -21
  113. janito-0.7.0/janito/tui/base.py +0 -22
  114. janito-0.7.0/janito/tui/flows/__init__.py +0 -5
  115. janito-0.7.0/janito/tui/flows/changes.py +0 -65
  116. janito-0.7.0/janito/tui/flows/content.py +0 -128
  117. janito-0.7.0/janito/tui/flows/selection.py +0 -117
  118. janito-0.7.0/janito/tui/screens/__init__.py +0 -3
  119. janito-0.7.0/janito/tui/screens/app.py +0 -1
  120. janito-0.7.0/janito/workspace/__init__.py +0 -6
  121. janito-0.7.0/janito/workspace/workspace.py +0 -114
  122. janito-0.7.0/setup.py +0 -4
  123. janito-0.7.0/tests/test_python_adjustments.py +0 -271
@@ -0,0 +1,42 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual Environment
24
+ venv/
25
+ env/
26
+ ENV/
27
+ .env
28
+ .venv
29
+
30
+ # IDE
31
+ .idea/
32
+ .vscode/
33
+ *.swp
34
+ *.swo
35
+ .DS_Store
36
+
37
+ # Testing
38
+ .coverage
39
+ htmlcov/
40
+ .tox/
41
+ .pytest_cache/
42
+ .janito_last_response.txt
@@ -1,21 +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
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
21
  SOFTWARE.
janito-0.8.0/PKG-INFO ADDED
@@ -0,0 +1,106 @@
1
+ Metadata-Version: 2.4
2
+ Name: janito
3
+ Version: 0.8.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: tomli
22
+ Requires-Dist: typer
23
+ Description-Content-Type: text/markdown
24
+
25
+ # 🤖 Janito
26
+
27
+ [![PyPI version](https://badge.fury.io/py/janito.svg)](https://badge.fury.io/py/janito)
28
+ [![Python Versions](https://img.shields.io/pypi/pyversions/janito.svg)](https://pypi.org/project/janito/)
29
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
30
+
31
+ Janito is an AI-powered CLI tool designed to help developers manage and modify their codebase with ease. It leverages advanced AI models to understand and transform your code intelligently.
32
+
33
+ ## ✨ Features
34
+
35
+ ### 🔄 Code Modifications
36
+ - **Smart Code Changes**: Automated code modifications with AI understanding
37
+ - **Context-Aware**: Considers your entire codebase for accurate changes
38
+ - **Preview & Validate**: Review changes before applying them
39
+
40
+ ### 💡 Code Analysis
41
+ - **Intelligent Queries**: Ask questions about your codebase
42
+ - **Deep Understanding**: Get detailed explanations about code functionality
43
+ - **Context-Rich Responses**: Answers based on your actual code
44
+
45
+ ### ⚙️ Easy Configuration
46
+ - **Multiple AI Backends**: Support for Claude and DeepSeek AI
47
+ - **Flexible Setup**: Simple environment variable configuration
48
+ - **Workspace Control**: Fine-grained control over scanned files
49
+
50
+ ## 🚀 Installation
51
+
52
+ ### Prerequisites
53
+ - Python 3.8 or higher
54
+ - pip package manager
55
+
56
+ ### Install from PyPI
57
+ ```bash
58
+ pip install janito
59
+ ```
60
+
61
+ ## 🔧 Configuration
62
+
63
+ Set up your preferred AI backend using environment variables:
64
+
65
+ ### For Claude AI
66
+ ```bash
67
+ export ANTHROPIC_API_KEY=your_api_key
68
+ export AI_BACKEND=claudeai # Optional, detected from API key
69
+ ```
70
+
71
+ ### For DeepSeek AI
72
+ ```bash
73
+ export DEEPSEEK_API_KEY=your_api_key
74
+ export AI_BACKEND=deepseekai # Optional, detected from API key
75
+ ```
76
+
77
+ ## 📖 Usage
78
+
79
+ ### Basic Commands
80
+
81
+ 1. **Ask Questions**
82
+ ```bash
83
+ janito --ask "How does the error handling work in this codebase?"
84
+ ```
85
+
86
+ 2. **Request Changes**
87
+ ```bash
88
+ janito "Add error handling to the process_data function"
89
+ ```
90
+
91
+ 3. **Preview Files**
92
+ ```bash
93
+ janito --scan
94
+ ```
95
+
96
+ ### Advanced Options
97
+
98
+ - **Workspace Directory**: `-w, --workspace_dir PATH`
99
+ - **Include Paths**: `-i, --include PATH`
100
+ - **Recursive Scan**: `-r, --recursive PATH`
101
+ - **Debug Mode**: `--debug`
102
+ - **Verbose Output**: `--verbose`
103
+
104
+ ## 📝 License
105
+
106
+ This project is licensed under the MIT License - see the LICENSE file for details.
janito-0.8.0/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # 🤖 Janito
2
+
3
+ [![PyPI version](https://badge.fury.io/py/janito.svg)](https://badge.fury.io/py/janito)
4
+ [![Python Versions](https://img.shields.io/pypi/pyversions/janito.svg)](https://pypi.org/project/janito/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ Janito is an AI-powered CLI tool designed to help developers manage and modify their codebase with ease. It leverages advanced AI models to understand and transform your code intelligently.
8
+
9
+ ## ✨ Features
10
+
11
+ ### 🔄 Code Modifications
12
+ - **Smart Code Changes**: Automated code modifications with AI understanding
13
+ - **Context-Aware**: Considers your entire codebase for accurate changes
14
+ - **Preview & Validate**: Review changes before applying them
15
+
16
+ ### 💡 Code Analysis
17
+ - **Intelligent Queries**: Ask questions about your codebase
18
+ - **Deep Understanding**: Get detailed explanations about code functionality
19
+ - **Context-Rich Responses**: Answers based on your actual code
20
+
21
+ ### ⚙️ Easy Configuration
22
+ - **Multiple AI Backends**: Support for Claude and DeepSeek AI
23
+ - **Flexible Setup**: Simple environment variable configuration
24
+ - **Workspace Control**: Fine-grained control over scanned files
25
+
26
+ ## 🚀 Installation
27
+
28
+ ### Prerequisites
29
+ - Python 3.8 or higher
30
+ - pip package manager
31
+
32
+ ### Install from PyPI
33
+ ```bash
34
+ pip install janito
35
+ ```
36
+
37
+ ## 🔧 Configuration
38
+
39
+ Set up your preferred AI backend using environment variables:
40
+
41
+ ### For Claude AI
42
+ ```bash
43
+ export ANTHROPIC_API_KEY=your_api_key
44
+ export AI_BACKEND=claudeai # Optional, detected from API key
45
+ ```
46
+
47
+ ### For DeepSeek AI
48
+ ```bash
49
+ export DEEPSEEK_API_KEY=your_api_key
50
+ export AI_BACKEND=deepseekai # Optional, detected from API key
51
+ ```
52
+
53
+ ## 📖 Usage
54
+
55
+ ### Basic Commands
56
+
57
+ 1. **Ask Questions**
58
+ ```bash
59
+ janito --ask "How does the error handling work in this codebase?"
60
+ ```
61
+
62
+ 2. **Request Changes**
63
+ ```bash
64
+ janito "Add error handling to the process_data function"
65
+ ```
66
+
67
+ 3. **Preview Files**
68
+ ```bash
69
+ janito --scan
70
+ ```
71
+
72
+ ### Advanced Options
73
+
74
+ - **Workspace Directory**: `-w, --workspace_dir PATH`
75
+ - **Include Paths**: `-i, --include PATH`
76
+ - **Recursive Scan**: `-r, --recursive PATH`
77
+ - **Debug Mode**: `--debug`
78
+ - **Verbose Output**: `--verbose`
79
+
80
+ ## 📝 License
81
+
82
+ This project is licensed under the MIT License - see the LICENSE file for details.
@@ -1,142 +1,128 @@
1
- import typer
2
- from typing import Optional, List, Set
3
- from pathlib import Path
4
- from rich.text import Text
5
- from rich import print as rich_print
6
- from rich.console import Console
7
- from rich.text import Text
8
- from .version import get_version
9
-
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
- )
17
-
18
- app = typer.Typer(pretty_exceptions_enable=False)
19
-
20
- def validate_paths(paths: Optional[List[Path]]) -> Optional[List[Path]]:
21
- """Validate include paths for duplicates.
22
-
23
- Args:
24
- paths: List of paths to validate, or None if no paths provided
25
-
26
- Returns:
27
- Validated list of paths or None if no paths provided
28
- """
29
- if not paths: # This handles both None and empty list cases
30
- return None
31
-
32
- # Convert paths to absolute and resolve symlinks
33
- resolved_paths: Set[Path] = set()
34
- unique_paths: List[Path] = []
35
-
36
- for path in paths:
37
- resolved = path.absolute().resolve()
38
- if resolved in resolved_paths:
39
- error_text = Text(f"\nError: Duplicate path provided: {path} ", style="red")
40
- rich_print(error_text)
41
- raise typer.Exit(1)
42
- resolved_paths.add(resolved)
43
- unique_paths.append(path)
44
-
45
- return unique_paths if unique_paths else None
46
-
47
- def typer_main(
48
- change_request: str = typer.Argument(None, help="Change request or command"),
49
- workspace_dir: Optional[Path] = typer.Option(None, "-w", "--workspace_dir", help="Working directory", file_okay=False, dir_okay=True),
50
- debug: bool = typer.Option(False, "--debug", help="Show debug information"),
51
- verbose: bool = typer.Option(False, "--verbose", help="Show verbose output"),
52
- include: Optional[List[Path]] = typer.Option(None, "-i", "--include", help="Additional paths to include"),
53
- ask: Optional[str] = typer.Option(None, "--ask", help="Ask a question about the codebase"),
54
- play: Optional[Path] = typer.Option(None, "--play", help="Replay a saved prompt file"),
55
- scan: bool = typer.Option(False, "--scan", help="Preview files that would be analyzed"),
56
- version: bool = typer.Option(False, "--version", help="Show version information"),
57
- test_cmd: Optional[str] = typer.Option(None, "--test", help="Command to run tests after changes"),
58
- auto_apply: bool = typer.Option(False, "--auto-apply", help="Apply changes without confirmation"),
59
- tui: bool = typer.Option(False, "--tui", help="Use terminal user interface"),
60
- history: bool = typer.Option(False, "--history", help="Display history of requests"),
61
- recursive: Optional[List[Path]] = typer.Option(None, "-r", "--recursive", help="Paths to scan recursively (directories only)"),
62
- demo: bool = typer.Option(False, "--demo", help="Run demo scenarios"),
63
- skip_work: bool = typer.Option(False, "--skip-work", help="Skip scanning workspace_dir when using include paths"),
64
- ):
65
- """Janito - AI-powered code modification assistant"""
66
- if version:
67
- console = Console()
68
- console.print(f"Janito version {get_version()}")
69
- return
70
-
71
- if demo:
72
- handle_demo()
73
- return
74
-
75
- if history:
76
- from janito.cli.history import display_history
77
- display_history()
78
- return
79
-
80
- # Configure workspace
81
- config.set_workspace_dir(workspace_dir)
82
- config.set_debug(debug)
83
- config.set_verbose(verbose)
84
- config.set_auto_apply(auto_apply)
85
- config.set_tui(tui)
86
-
87
- # Configure workset with scan paths
88
- if include:
89
- if config.debug:
90
- Console(stderr=True).print("[cyan]Debug: Processing include paths...[/cyan]")
91
- for path in include:
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)
98
-
99
- if recursive:
100
- if config.debug:
101
- Console(stderr=True).print("[cyan]Debug: Processing recursive paths...[/cyan]")
102
- for path in recursive:
103
- full_path = config.workspace_dir / path
104
- if not path.is_dir():
105
- error_text = Text(f"\nError: Recursive path must be a directory: {path} ", style="red")
106
- rich_print(error_text)
107
- raise typer.Exit(1)
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)
119
-
120
- if test_cmd:
121
- config.set_test_cmd(test_cmd)
122
-
123
- # Refresh workset content before handling commands
124
- workset.refresh()
125
-
126
- if ask:
127
- handle_ask(ask)
128
- elif play:
129
- handle_play(play)
130
- elif scan:
131
- handle_scan()
132
- elif change_request:
133
- handle_request(change_request)
134
- else:
135
- from janito.shell import start_shell
136
- start_shell()
137
-
138
- def main():
139
- typer.run(typer_main)
140
-
141
- if __name__ == "__main__":
1
+ import typer
2
+ from typing import Optional, List, Set
3
+ from pathlib import Path
4
+ from rich.text import Text
5
+ from rich import print as rich_print
6
+ from rich.console import Console
7
+ from .version import get_version
8
+
9
+ from janito.config import config
10
+ from janito.workspace import workset
11
+ from janito.workspace.models import ScanType # Add this import
12
+ from .cli.commands import (
13
+ handle_request, handle_ask,
14
+ handle_scan
15
+ )
16
+
17
+
18
+ app = typer.Typer(pretty_exceptions_enable=False)
19
+
20
+ # Initialize console for CLI output
21
+ console = Console()
22
+
23
+
24
+
25
+ def typer_main(
26
+ user_request: Optional[str] = typer.Argument(None, help="User request"),
27
+ workspace_dir: Optional[Path] = typer.Option(None, "-w", "--workspace_dir", help="Working directory", file_okay=False, dir_okay=True),
28
+ debug: bool = typer.Option(False, "--debug", help="Show debug information"),
29
+ verbose: bool = typer.Option(False, "--verbose", help="Show verbose output"),
30
+ include: Optional[List[Path]] = typer.Option(None, "-i", "--include", help="Additional paths to include"),
31
+ ask: bool = typer.Option(False, "--ask", help="Treat the request as a question about the codebase"),
32
+ play: Optional[Path] = typer.Option(None, "--play", help="Replay a saved prompt file"),
33
+ replay: bool = typer.Option(False, "--replay", help="Trigger the replay response flow"),
34
+ scan: bool = typer.Option(False, "--scan", help="Preview files that would be analyzed"),
35
+ version: bool = typer.Option(False, "--version", help="Show version information"),
36
+ test_cmd: Optional[str] = typer.Option(None, "--test", help="Command to run tests after changes"),
37
+ auto_apply: bool = typer.Option(False, "--auto-apply", help="Apply changes without confirmation"),
38
+ recursive: Optional[List[Path]] = typer.Option(None, "-r", "--recursive", help="Paths to scan recursively (directories only)"),
39
+ skip_work: bool = typer.Option(False, "-s", "--skip-work", help="Skip scanning workspace_dir when using include paths"),
40
+ ):
41
+ """Janito - AI-powered code modification assistant"""
42
+ if version:
43
+ console.print(f"Janito version {get_version()}")
44
+ return
45
+
46
+ # Check if workspace directory exists and handle creation
47
+ if workspace_dir and not workspace_dir.exists():
48
+ create = typer.confirm(f"\nWorkspace directory '{workspace_dir}' does not exist. Create it?")
49
+ if create:
50
+ try:
51
+ workspace_dir.mkdir(parents=True)
52
+ console.print(f"[green]Created workspace directory: {workspace_dir}[/green]")
53
+ except Exception as e:
54
+ error_text = Text(f"\nError: Failed to create workspace directory: {e}", style="red")
55
+ rich_print(error_text)
56
+ raise typer.Exit(1)
57
+ else:
58
+ error_text = Text("\nError: Workspace directory does not exist and was not created", style="red")
59
+ rich_print(error_text)
60
+ raise typer.Exit(1)
61
+
62
+ # Configure workspace
63
+ config.set_workspace_dir(workspace_dir)
64
+ config.set_debug(debug)
65
+ config.set_verbose(verbose)
66
+ config.set_auto_apply(auto_apply)
67
+
68
+ # Configure workset with scan paths
69
+ if include:
70
+ if config.debug:
71
+ Console(stderr=True).print("[cyan]Debug: Processing include paths...[/cyan]")
72
+ for path in include:
73
+ full_path = config.workspace_dir / path
74
+ if not full_path.resolve().is_relative_to(config.workspace_dir):
75
+ error_text = Text(f"\nError: Path must be within workspace: {path}", style="red")
76
+ rich_print(error_text)
77
+ raise typer.Exit(1)
78
+ workset.add_scan_path(path, ScanType.PLAIN)
79
+
80
+ if recursive:
81
+ if config.debug:
82
+ Console(stderr=True).print("[cyan]Debug: Processing recursive paths...[/cyan]")
83
+ for path in recursive:
84
+ full_path = config.workspace_dir / path
85
+ if not path.is_dir():
86
+ error_text = Text(f"\nError: Recursive path must be a directory: {path} ", style="red")
87
+ rich_print(error_text)
88
+ raise typer.Exit(1)
89
+ if not full_path.resolve().is_relative_to(config.workspace_dir):
90
+ error_text = Text(f"\nError: Path must be within workspace: {path}", style="red")
91
+ rich_print(error_text)
92
+ raise typer.Exit(1)
93
+ workset.add_scan_path(path, ScanType.RECURSIVE)
94
+
95
+ # Validate skip_work usage
96
+ if skip_work:
97
+ # Check if any include or recursive paths are provided
98
+ if not include and not recursive:
99
+ error_text = Text("\nError: --skip-work requires at least one include path (-i or -r)", style="red")
100
+ rich_print(error_text)
101
+ raise typer.Exit(1)
102
+ # Remove root path from workset when skip_work is enabled
103
+ workset._scan_paths = [p for p in workset._scan_paths if p.path != Path(".")]
104
+
105
+ if test_cmd:
106
+ config.set_test_cmd(test_cmd)
107
+
108
+ # Refresh workset content before handling commands
109
+ workset.refresh()
110
+
111
+ if ask:
112
+ if not user_request:
113
+ error_text = Text("\nError: No question provided. Please provide a question as the main argument when using --ask", style="red")
114
+ rich_print(error_text)
115
+ raise typer.Exit(1)
116
+ handle_ask(user_request)
117
+ elif play:
118
+ handle_play(play)
119
+ elif scan:
120
+ handle_scan()
121
+ else:
122
+ handle_request(user_request, replay=replay)
123
+
124
+ def main():
125
+ typer.run(typer_main)
126
+
127
+ if __name__ == "__main__":
142
128
  main()
@@ -0,0 +1,22 @@
1
+ import os
2
+
3
+ # Try to determine backend from available API keys if not explicitly set
4
+ ai_backend = os.getenv('AI_BACKEND', '').lower()
5
+
6
+ if not ai_backend:
7
+ if os.getenv('ANTHROPIC_API_KEY'):
8
+ ai_backend = 'claudeai'
9
+ elif os.getenv('DEEPSEEK_API_KEY'):
10
+ ai_backend = 'deepseekai'
11
+ else:
12
+ raise ValueError("No AI backend API keys found. Please set either ANTHROPIC_API_KEY or DEEPSEEK_API_KEY")
13
+
14
+ if ai_backend == "deepseekai":
15
+ from .deepseekai import DeepSeekAIAgent as AIAgent
16
+ elif ai_backend == 'claudeai':
17
+ from .claudeai import ClaudeAIAgent as AIAgent
18
+ else:
19
+ raise ValueError(f"Unsupported AI_BACKEND: {ai_backend}")
20
+
21
+ # Create a singleton instance
22
+ agent = AIAgent()
@@ -1,28 +1,25 @@
1
- from abc import ABC, abstractmethod
2
- from threading import Event
3
- from typing import Optional, List, Tuple
4
-
5
- class Agent(ABC):
6
- """Abstract base class for AI agents"""
7
- def __init__(self, api_key: Optional[str] = None, system_prompt: str = None):
8
- self.api_key = api_key
9
- self.system_message = system_prompt
10
- self.last_prompt = None
11
- self.last_full_message = None
12
- self.last_response = None
13
- self.messages_history: List[Tuple[str, str]] = []
14
- if system_prompt:
15
- self.messages_history.append(("system", system_prompt))
16
-
17
- @abstractmethod
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
- """
1
+ from abc import ABC, abstractmethod
2
+ from typing import Optional
3
+
4
+ class Agent(ABC):
5
+ """Abstract base class for AI agents"""
6
+ friendly_name = "Unknown"
7
+
8
+ def __init__(self, api_key: Optional[str] = None):
9
+ self.api_key = api_key
10
+ self.last_prompt = None
11
+ self.last_full_message = None
12
+ self.last_response = None
13
+
14
+ @abstractmethod
15
+ def send_message(self, message: str, system: str) -> str:
16
+ """Send message to the AI agent
17
+
18
+ Args:
19
+ message: The message to send
20
+ stop_event: Optional event to signal cancellation
21
+
22
+ Returns:
23
+ The response from the AI agent
24
+ """
28
25
  pass