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.
Files changed (115) hide show
  1. janito-0.7.0/PKG-INFO +167 -0
  2. janito-0.7.0/README.md +142 -0
  3. {janito-0.6.0 → janito-0.7.0}/janito/__main__.py +37 -30
  4. {janito-0.6.0 → janito-0.7.0}/janito/agents/__init__.py +8 -2
  5. {janito-0.6.0 → janito-0.7.0}/janito/agents/agent.py +10 -3
  6. {janito-0.6.0 → janito-0.7.0}/janito/agents/claudeai.py +13 -23
  7. {janito-0.6.0 → janito-0.7.0}/janito/agents/openai.py +5 -1
  8. {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/analyze.py +8 -7
  9. {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/prompts.py +4 -12
  10. {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/view/terminal.py +21 -11
  11. {janito-0.6.0 → janito-0.7.0}/janito/change/applier/text.py +7 -5
  12. {janito-0.6.0 → janito-0.7.0}/janito/change/core.py +22 -29
  13. {janito-0.6.0 → janito-0.7.0}/janito/change/parser.py +0 -2
  14. {janito-0.6.0 → janito-0.7.0}/janito/change/prompts.py +16 -21
  15. {janito-0.6.0 → janito-0.7.0}/janito/change/validator.py +27 -9
  16. {janito-0.6.0 → janito-0.7.0}/janito/change/viewer/content.py +1 -1
  17. {janito-0.6.0 → janito-0.7.0}/janito/change/viewer/panels.py +93 -115
  18. {janito-0.6.0 → janito-0.7.0}/janito/change/viewer/styling.py +15 -4
  19. janito-0.7.0/janito/cli/commands.py +88 -0
  20. janito-0.7.0/janito/common.py +80 -0
  21. {janito-0.6.0 → janito-0.7.0}/janito/config.py +44 -44
  22. janito-0.7.0/janito/prompt.py +36 -0
  23. {janito-0.6.0 → janito-0.7.0}/janito/qa.py +5 -14
  24. {janito-0.6.0 → janito-0.7.0}/janito/search_replace/README.md +63 -17
  25. {janito-0.6.0 → janito-0.7.0}/janito/search_replace/__init__.py +2 -1
  26. {janito-0.6.0 → janito-0.7.0}/janito/search_replace/core.py +15 -14
  27. janito-0.7.0/janito/search_replace/logger.py +35 -0
  28. {janito-0.6.0 → janito-0.7.0}/janito/search_replace/searcher.py +160 -48
  29. janito-0.7.0/janito/search_replace/strategy_result.py +10 -0
  30. janito-0.7.0/janito/shell/__init__.py +38 -0
  31. janito-0.6.0/janito/shell/handlers.py → janito-0.7.0/janito/shell/commands.py +46 -32
  32. janito-0.7.0/janito/shell/processor.py +32 -0
  33. janito-0.7.0/janito/shell/prompt.py +48 -0
  34. janito-0.7.0/janito/shell/registry.py +60 -0
  35. janito-0.7.0/janito/workspace/__init__.py +6 -0
  36. {janito-0.6.0 → janito-0.7.0}/janito/workspace/analysis.py +2 -2
  37. janito-0.7.0/janito/workspace/show.py +141 -0
  38. janito-0.7.0/janito/workspace/stats.py +43 -0
  39. janito-0.7.0/janito/workspace/types.py +98 -0
  40. janito-0.7.0/janito/workspace/workset.py +108 -0
  41. janito-0.7.0/janito/workspace/workspace.py +114 -0
  42. {janito-0.6.0 → janito-0.7.0}/pyproject.toml +1 -1
  43. janito-0.6.0/PKG-INFO +0 -185
  44. janito-0.6.0/README.md +0 -160
  45. janito-0.6.0/janito/change/viewer/pager.py +0 -56
  46. janito-0.6.0/janito/cli/commands.py +0 -45
  47. janito-0.6.0/janito/cli/handlers/ask.py +0 -22
  48. janito-0.6.0/janito/cli/handlers/demo.py +0 -22
  49. janito-0.6.0/janito/cli/handlers/request.py +0 -24
  50. janito-0.6.0/janito/cli/handlers/scan.py +0 -9
  51. janito-0.6.0/janito/common.py +0 -54
  52. janito-0.6.0/janito/prompts.py +0 -2
  53. janito-0.6.0/janito/shell/__init__.py +0 -39
  54. janito-0.6.0/janito/shell/commands.py +0 -195
  55. janito-0.6.0/janito/shell/processor.py +0 -52
  56. janito-0.6.0/janito/workspace/__init__.py +0 -7
  57. janito-0.6.0/janito/workspace/manager.py +0 -48
  58. janito-0.6.0/janito/workspace/scan.py +0 -232
  59. {janito-0.6.0 → janito-0.7.0}/.gitignore +0 -0
  60. {janito-0.6.0 → janito-0.7.0}/LICENSE +0 -0
  61. {janito-0.6.0 → janito-0.7.0}/janito/__init__.py +0 -0
  62. {janito-0.6.0 → janito-0.7.0}/janito/agents/test.py +0 -0
  63. {janito-0.6.0 → janito-0.7.0}/janito/change/__init__.py +0 -0
  64. {janito-0.6.0 → janito-0.7.0}/janito/change/__main__.py +0 -0
  65. {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/__init__.py +0 -0
  66. {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/__main__.py +0 -0
  67. {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/formatting.py +0 -0
  68. {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/options.py +0 -0
  69. {janito-0.6.0 → janito-0.7.0}/janito/change/analysis/view/__init__.py +0 -0
  70. {janito-0.6.0 → janito-0.7.0}/janito/change/applier/__init__.py +0 -0
  71. {janito-0.6.0 → janito-0.7.0}/janito/change/applier/file.py +0 -0
  72. {janito-0.6.0 → janito-0.7.0}/janito/change/applier/main.py +0 -0
  73. {janito-0.6.0 → janito-0.7.0}/janito/change/applier/workspace_dir.py +0 -0
  74. {janito-0.6.0 → janito-0.7.0}/janito/change/history.py +0 -0
  75. {janito-0.6.0 → janito-0.7.0}/janito/change/operations.py +0 -0
  76. {janito-0.6.0 → janito-0.7.0}/janito/change/play.py +0 -0
  77. {janito-0.6.0 → janito-0.7.0}/janito/change/preview.py +0 -0
  78. {janito-0.6.0 → janito-0.7.0}/janito/change/test.py +0 -0
  79. {janito-0.6.0 → janito-0.7.0}/janito/change/viewer/__init__.py +0 -0
  80. {janito-0.6.0 → janito-0.7.0}/janito/change/viewer/diff.py +0 -0
  81. {janito-0.6.0 → janito-0.7.0}/janito/change/viewer/themes.py +0 -0
  82. {janito-0.6.0 → janito-0.7.0}/janito/clear_statement_parser/clear_statement_format.txt +0 -0
  83. {janito-0.6.0 → janito-0.7.0}/janito/clear_statement_parser/examples.txt +0 -0
  84. {janito-0.6.0 → janito-0.7.0}/janito/clear_statement_parser/models.py +0 -0
  85. {janito-0.6.0 → janito-0.7.0}/janito/clear_statement_parser/parser.py +0 -0
  86. {janito-0.6.0 → janito-0.7.0}/janito/cli/__init__.py +0 -0
  87. {janito-0.6.0 → janito-0.7.0}/janito/cli/base.py +0 -0
  88. {janito-0.6.0 → janito-0.7.0}/janito/cli/functions.py +0 -0
  89. {janito-0.6.0 → janito-0.7.0}/janito/cli/history.py +0 -0
  90. {janito-0.6.0 → janito-0.7.0}/janito/cli/registry.py +0 -0
  91. {janito-0.6.0 → janito-0.7.0}/janito/demo/__init__.py +0 -0
  92. {janito-0.6.0 → janito-0.7.0}/janito/demo/data.py +0 -0
  93. {janito-0.6.0 → janito-0.7.0}/janito/demo/mock_data.py +0 -0
  94. {janito-0.6.0 → janito-0.7.0}/janito/demo/operations.py +0 -0
  95. {janito-0.6.0 → janito-0.7.0}/janito/demo/runner.py +0 -0
  96. {janito-0.6.0 → janito-0.7.0}/janito/demo/scenarios.py +0 -0
  97. {janito-0.6.0 → janito-0.7.0}/janito/review.py +0 -0
  98. {janito-0.6.0 → janito-0.7.0}/janito/search_replace/__main__.py +0 -0
  99. {janito-0.6.0 → janito-0.7.0}/janito/search_replace/parser.py +0 -0
  100. {janito-0.6.0 → janito-0.7.0}/janito/search_replace/play.py +0 -0
  101. {janito-0.6.0 → janito-0.7.0}/janito/search_replace/replacer.py +0 -0
  102. {janito-0.6.0 → janito-0.7.0}/janito/shell/bus.py +0 -0
  103. {janito-0.6.0 → janito-0.7.0}/janito/shell/history.py +0 -0
  104. {janito-0.6.0 → janito-0.7.0}/janito/tui/__init__.py +0 -0
  105. {janito-0.6.0 → janito-0.7.0}/janito/tui/base.py +0 -0
  106. {janito-0.6.0 → janito-0.7.0}/janito/tui/flows/__init__.py +0 -0
  107. {janito-0.6.0 → janito-0.7.0}/janito/tui/flows/changes.py +0 -0
  108. {janito-0.6.0 → janito-0.7.0}/janito/tui/flows/content.py +0 -0
  109. {janito-0.6.0 → janito-0.7.0}/janito/tui/flows/selection.py +0 -0
  110. {janito-0.6.0 → janito-0.7.0}/janito/tui/screens/__init__.py +0 -0
  111. {janito-0.6.0 → janito-0.7.0}/janito/tui/screens/app.py +0 -0
  112. {janito-0.6.0 → janito-0.7.0}/janito/version.py +0 -0
  113. {janito-0.6.0 → janito-0.7.0}/setup.py +0 -0
  114. {janito-0.6.0 → janito-0.7.0}/tests/test_python_adjustments.py +0 -0
  115. {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
+ [![PyPI version](https://badge.fury.io/py/janito.svg)](https://badge.fury.io/py/janito)
29
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
+ [![PyPI version](https://badge.fury.io/py/janito.svg)](https://badge.fury.io/py/janito)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
- from .cli.commands import handle_request, handle_ask, handle_play, handle_scan
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
- skipwork: bool = typer.Option(False, "--skipwork", help="Skip scanning workspace_dir when using include paths"),
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
- from janito.cli.handlers.demo import DemoHandler
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
- resolved_paths = []
89
+ if config.debug:
90
+ Console(stderr=True).print("[cyan]Debug: Processing include paths...[/cyan]")
95
91
  for path in include:
96
- path = config.workspace_dir / path
97
- resolved_paths.append(path.resolve())
98
- config.set_include(resolved_paths)
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
- resolved_paths = []
100
+ if config.debug:
101
+ Console(stderr=True).print("[cyan]Debug: Processing recursive paths...[/cyan]")
103
102
  for path in recursive:
104
- final_path = config.workspace_dir / path
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
- resolved_paths.append(final_path.resolve())
110
- config.set_recursive(resolved_paths)
111
- include = include or []
112
- include.extend(resolved_paths)
113
- config.set_include(include)
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
- paths_to_scan = include or [config.workspace_dir]
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, stop_event: Event = None) -> str:
20
- """Send message to AI service and return response"""
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, stop_event: Event = None) -> 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
- try:
34
- # Check if already cancelled
35
- if stop_event and stop_event.is_set():
36
- return ""
37
-
38
- response = self.client.messages.create(
39
- model=self.model, # Use discovered model
40
- system=self.system_message,
41
- max_tokens=8192,
42
- messages=[
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
- # Always return the response, let caller handle cancellation
50
- return response
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, Dict
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
- # Build and send prompt
33
- prompt = build_request_analysis_prompt(request, files_content_xml)
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
- Considering the above current files content, provide 3 sections, each identified by a keyword and representing an option.
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, files_content_xml: str) -> 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
- padding = (term_width - len(message)) // 2
38
- padded_message = " " * padding + message
39
- return Prompt.ask(f"[bold cyan]{padded_message}[/bold cyan]")
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
- error_padding = (term_width - len(error_msg)) // 2
57
- padded_error = " " * error_padding + error_msg
58
- console.print(f"[red]{padded_error}[/red]")
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
- padding = " " * (len(parent_dir) - 1)
108
- content.append(padding)
109
- content.append("↑ ", style=STRUCTURAL_COLORS['repeat'])
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
- rendered_columns = [
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
- rendered_columns,
146
+ rendered_items,
137
147
  equal=True,
138
148
  expand=True,
139
149
  width=column_width,