ai-cr 1.0.0__tar.gz → 2.0.0.dev1__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.
@@ -0,0 +1,205 @@
1
+ Metadata-Version: 2.3
2
+ Name: ai-cr
3
+ Version: 2.0.0.dev1
4
+ Summary: AI code review tool that works with any language model provider. It detects issues in GitHub pull requests or local changes—instantly, reliably, and without vendor lock-in.
5
+ License: MIT
6
+ Keywords: static code analysis,code review,code quality,ai,coding,assistant,llm,github,automation,devops,developer tools,github actions,workflows,git
7
+ Author: Nayjest
8
+ Author-email: mail@vitaliy.in
9
+ Requires-Python: >=3.11,<4.0
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development
18
+ Requires-Dist: GitPython (>=3.1.44,<4.0.0)
19
+ Requires-Dist: ai-microcore (==4.0.0)
20
+ Requires-Dist: anthropic (>=0.52.2,<0.53.0)
21
+ Requires-Dist: google-generativeai (>=0.8.5,<0.9.0)
22
+ Requires-Dist: typer (>=0.16.0,<0.17.0)
23
+ Requires-Dist: unidiff (>=0.7.5,<0.8.0)
24
+ Project-URL: Homepage, https://github.com/Nayjest/Gito
25
+ Project-URL: Repository, https://github.com/Nayjest/Gito
26
+ Description-Content-Type: text/markdown
27
+
28
+ <h1 align="center"><a href="#"><img alt="Gito: AI Code Reviewer" src="press-kit/logo/gito-ai-code-reviewer_logo-180.png" align="center" width="180"></a></h1>
29
+ <p align="center">
30
+ <a href="https://pypi.org/project/gito.bot/" target="_blank"><img src="https://img.shields.io/pypi/v/gito.bot" alt="PYPI Release"></a>
31
+ <a href="https://github.com/Nayjest/Gito/actions/workflows/code-style.yml" target="_blank"><img src="https://github.com/Nayjest/Gito/actions/workflows/code-style.yml/badge.svg" alt="PyLint"></a>
32
+ <a href="https://github.com/Nayjest/Gito/actions/workflows/tests.yml" target="_blank"><img src="https://github.com/Nayjest/Gito/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
33
+ <img src="https://github.com/Nayjest/Gito/blob/main/coverage.svg" alt="Code Coverage">
34
+ <a href="https://github.com/Nayjest/Gito/blob/main/LICENSE" target="_blank"><img src="https://img.shields.io/static/v1?label=license&message=MIT&color=d08aff" alt="License"></a>
35
+ </p>
36
+
37
+ **Gito** is an open-source **AI code reviewer** that works with any language model provider.
38
+ It detects issues in GitHub pull requests or local changes—instantly, reliably, and without vendor lock-in.
39
+
40
+ Get consistent, thorough code reviews in seconds—no waiting for human availability.
41
+
42
+ ## ✨ Why Gito?
43
+
44
+ - [⚡] **Lightning Fast:** Get detailed code reviews in seconds, not days — powered by parallelized LLM processing
45
+ - [🔧] **Vendor Agnostic:** Works with any language model provider (OpenAI, Anthropic, Google, local models, etc.)
46
+ - [🌐] **Universal:** Supports all major programming languages and frameworks
47
+ - [🔍] **Comprehensive Analysis:** Detect issues across security, performance, maintainability, best practices, and much more
48
+ - [📈] **Consistent Quality:** Never tired, never biased—consistent review quality every time
49
+ - [🚀] **Easy Integration:** Automatically reviews pull requests via GitHub Actions and posts results as PR comments
50
+ - [🎛️] **Infinitely Flexible:** Adapt to any project's standards—configure review rules, severity levels, and focus areas, build custom workflows
51
+
52
+ ## 🎯 Perfect For
53
+
54
+ - Solo developers who want expert-level code review without the wait
55
+ - Teams looking to catch issues before human review
56
+ - Open source projects maintaining high code quality at scale
57
+ - CI/CD pipelines requiring automated quality gates
58
+
59
+ ✨ See [code review in action](https://github.com/Nayjest/Gito/pull/39#issuecomment-2906968729) ✨
60
+
61
+ ## 🚀 Quickstart
62
+
63
+ ### 1. Review Pull Requests via GitHub Actions
64
+
65
+ Create a `.github/workflows/gito.yml` file:
66
+
67
+ ```yaml
68
+ name: "Gito: AI Code Review"
69
+ on: { pull_request: { types: [opened, synchronize, reopened] } }
70
+ jobs:
71
+ review:
72
+ runs-on: ubuntu-latest
73
+ permissions: { contents: read, pull-requests: write } # 'write' for leaving the summary comment
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+ with: { fetch-depth: 0 }
77
+ - name: Set up Python
78
+ uses: actions/setup-python@v5
79
+ with: { python-version: "3.13" }
80
+ - name: Install AI Code Review tool
81
+ run: pip install gito.bot~=2.0
82
+ - name: Run AI code analysis
83
+ env:
84
+ LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
85
+ LLM_API_TYPE: openai
86
+ MODEL: "gpt-4.1"
87
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
88
+ run: |
89
+ gito --verbose review
90
+ gito github-comment --token ${{ secrets.GITHUB_TOKEN }}
91
+ - uses: actions/upload-artifact@v4
92
+ with:
93
+ name: ai-code-review-results
94
+ path: |
95
+ code-review-report.md
96
+ code-review-report.json
97
+ ```
98
+
99
+ > ⚠️ Make sure to add `LLM_API_KEY` to your repository’s GitHub secrets.
100
+
101
+ 💪 Done!
102
+ PRs to your repository will now receive AI code reviews automatically. ✨
103
+ See [GitHub Setup Guide](https://github.com/Nayjest/Gito/blob/main/documentation/github_setup.md) for more details.
104
+
105
+ ### 2. Running Code Analysis Locally
106
+
107
+ #### Initial Local Setup
108
+
109
+ **Prerequisites:** [Python](https://www.python.org/downloads/) 3.11 / 3.12 / 3.13
110
+
111
+ **Step1:** Install [gito.bot](https://github.com/Nayjest/Gito) using [pip](https://en.wikipedia.org/wiki/Pip_(package_manager)).
112
+ ```bash
113
+ pip install gito.bot
114
+ ```
115
+
116
+ > **Troubleshooting:**
117
+ > pip may be also available via cli as `pip3` depending on your Python installation.
118
+
119
+ **Step2:** Perform initial setup
120
+
121
+ The following command will perform one-time setup using an interactive wizard.
122
+ You will be prompted to enter LLM configuration details (API type, API key, etc).
123
+ Configuration will be saved to `~/.gito/.env`.
124
+
125
+ ```bash
126
+ gito setup
127
+ ```
128
+
129
+ > **Troubleshooting:**
130
+ > On some systems, `gito` command may not became available immediately after installation.
131
+ > Try restarting your terminal or running `python -m gito` instead.
132
+
133
+
134
+ #### Perform your first AI code review locally
135
+
136
+ **Step1:** Navigate to your repository root directory.
137
+ **Step2:** Switch to the branch you want to review.
138
+ **Step3:** Run following command
139
+ ```bash
140
+ gito review
141
+ ```
142
+
143
+ > **Note:** This will analyze the current branch against the repository main branch by default.
144
+ > Files that are not staged for commit will be ignored.
145
+ > See `gito --help` for more options.
146
+
147
+ **Reviewing remote repository**
148
+
149
+ ```bash
150
+ gito remote git@github.com:owner/repo.git <FEATURE_BRANCH>..<MAIN_BRANCH>
151
+ ```
152
+ Use interactive help for details:
153
+ ```bash
154
+ gito remote --help
155
+ ```
156
+
157
+ ## 🔧 Configuration
158
+
159
+ Change behavior via `.gito/config.toml`:
160
+
161
+ - Prompt templates, filtering and post-processing using Python code snippets
162
+ - Tagging, severity, and confidence settings
163
+ - Custom AI awards for developer brilliance
164
+ - Output customization
165
+
166
+ You can override the default config by placing `.gito/config.toml` in your repo root.
167
+
168
+
169
+ See default configuration [here](https://github.com/Nayjest/Gito/blob/main/gito/config.toml).
170
+
171
+ More details can be found in [📖 Configuration Cookbook](https://github.com/Nayjest/Gito/blob/main/documentation/config_cookbook.md)
172
+
173
+ ## 💻 Development Setup
174
+
175
+ Install dependencies:
176
+
177
+ ```bash
178
+ make install
179
+ ```
180
+
181
+ Format code and check style:
182
+
183
+ ```bash
184
+ make black
185
+ make cs
186
+ ```
187
+
188
+ Run tests:
189
+
190
+ ```bash
191
+ pytest
192
+ ```
193
+
194
+ ## 🤝 Contributing
195
+
196
+ **Looking for a specific feature or having trouble?**
197
+ Contributions are welcome! ❤️
198
+ See [CONTRIBUTING.md](https://github.com/Nayjest/Gito/blob/main/CONTRIBUTING.md) for details.
199
+
200
+ ## 📝 License
201
+
202
+ Licensed under the [MIT License](https://github.com/Nayjest/Gito/blob/main/LICENSE).
203
+
204
+ © 2025 [Vitalii Stepanenko](mailto:mail@vitaliy.in)
205
+
@@ -0,0 +1,177 @@
1
+ <h1 align="center"><a href="#"><img alt="Gito: AI Code Reviewer" src="press-kit/logo/gito-ai-code-reviewer_logo-180.png" align="center" width="180"></a></h1>
2
+ <p align="center">
3
+ <a href="https://pypi.org/project/gito.bot/" target="_blank"><img src="https://img.shields.io/pypi/v/gito.bot" alt="PYPI Release"></a>
4
+ <a href="https://github.com/Nayjest/Gito/actions/workflows/code-style.yml" target="_blank"><img src="https://github.com/Nayjest/Gito/actions/workflows/code-style.yml/badge.svg" alt="PyLint"></a>
5
+ <a href="https://github.com/Nayjest/Gito/actions/workflows/tests.yml" target="_blank"><img src="https://github.com/Nayjest/Gito/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
6
+ <img src="https://github.com/Nayjest/Gito/blob/main/coverage.svg" alt="Code Coverage">
7
+ <a href="https://github.com/Nayjest/Gito/blob/main/LICENSE" target="_blank"><img src="https://img.shields.io/static/v1?label=license&message=MIT&color=d08aff" alt="License"></a>
8
+ </p>
9
+
10
+ **Gito** is an open-source **AI code reviewer** that works with any language model provider.
11
+ It detects issues in GitHub pull requests or local changes—instantly, reliably, and without vendor lock-in.
12
+
13
+ Get consistent, thorough code reviews in seconds—no waiting for human availability.
14
+
15
+ ## ✨ Why Gito?
16
+
17
+ - [⚡] **Lightning Fast:** Get detailed code reviews in seconds, not days — powered by parallelized LLM processing
18
+ - [🔧] **Vendor Agnostic:** Works with any language model provider (OpenAI, Anthropic, Google, local models, etc.)
19
+ - [🌐] **Universal:** Supports all major programming languages and frameworks
20
+ - [🔍] **Comprehensive Analysis:** Detect issues across security, performance, maintainability, best practices, and much more
21
+ - [📈] **Consistent Quality:** Never tired, never biased—consistent review quality every time
22
+ - [🚀] **Easy Integration:** Automatically reviews pull requests via GitHub Actions and posts results as PR comments
23
+ - [🎛️] **Infinitely Flexible:** Adapt to any project's standards—configure review rules, severity levels, and focus areas, build custom workflows
24
+
25
+ ## 🎯 Perfect For
26
+
27
+ - Solo developers who want expert-level code review without the wait
28
+ - Teams looking to catch issues before human review
29
+ - Open source projects maintaining high code quality at scale
30
+ - CI/CD pipelines requiring automated quality gates
31
+
32
+ ✨ See [code review in action](https://github.com/Nayjest/Gito/pull/39#issuecomment-2906968729) ✨
33
+
34
+ ## 🚀 Quickstart
35
+
36
+ ### 1. Review Pull Requests via GitHub Actions
37
+
38
+ Create a `.github/workflows/gito.yml` file:
39
+
40
+ ```yaml
41
+ name: "Gito: AI Code Review"
42
+ on: { pull_request: { types: [opened, synchronize, reopened] } }
43
+ jobs:
44
+ review:
45
+ runs-on: ubuntu-latest
46
+ permissions: { contents: read, pull-requests: write } # 'write' for leaving the summary comment
47
+ steps:
48
+ - uses: actions/checkout@v4
49
+ with: { fetch-depth: 0 }
50
+ - name: Set up Python
51
+ uses: actions/setup-python@v5
52
+ with: { python-version: "3.13" }
53
+ - name: Install AI Code Review tool
54
+ run: pip install gito.bot~=2.0
55
+ - name: Run AI code analysis
56
+ env:
57
+ LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
58
+ LLM_API_TYPE: openai
59
+ MODEL: "gpt-4.1"
60
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
61
+ run: |
62
+ gito --verbose review
63
+ gito github-comment --token ${{ secrets.GITHUB_TOKEN }}
64
+ - uses: actions/upload-artifact@v4
65
+ with:
66
+ name: ai-code-review-results
67
+ path: |
68
+ code-review-report.md
69
+ code-review-report.json
70
+ ```
71
+
72
+ > ⚠️ Make sure to add `LLM_API_KEY` to your repository’s GitHub secrets.
73
+
74
+ 💪 Done!
75
+ PRs to your repository will now receive AI code reviews automatically. ✨
76
+ See [GitHub Setup Guide](https://github.com/Nayjest/Gito/blob/main/documentation/github_setup.md) for more details.
77
+
78
+ ### 2. Running Code Analysis Locally
79
+
80
+ #### Initial Local Setup
81
+
82
+ **Prerequisites:** [Python](https://www.python.org/downloads/) 3.11 / 3.12 / 3.13
83
+
84
+ **Step1:** Install [gito.bot](https://github.com/Nayjest/Gito) using [pip](https://en.wikipedia.org/wiki/Pip_(package_manager)).
85
+ ```bash
86
+ pip install gito.bot
87
+ ```
88
+
89
+ > **Troubleshooting:**
90
+ > pip may be also available via cli as `pip3` depending on your Python installation.
91
+
92
+ **Step2:** Perform initial setup
93
+
94
+ The following command will perform one-time setup using an interactive wizard.
95
+ You will be prompted to enter LLM configuration details (API type, API key, etc).
96
+ Configuration will be saved to `~/.gito/.env`.
97
+
98
+ ```bash
99
+ gito setup
100
+ ```
101
+
102
+ > **Troubleshooting:**
103
+ > On some systems, `gito` command may not became available immediately after installation.
104
+ > Try restarting your terminal or running `python -m gito` instead.
105
+
106
+
107
+ #### Perform your first AI code review locally
108
+
109
+ **Step1:** Navigate to your repository root directory.
110
+ **Step2:** Switch to the branch you want to review.
111
+ **Step3:** Run following command
112
+ ```bash
113
+ gito review
114
+ ```
115
+
116
+ > **Note:** This will analyze the current branch against the repository main branch by default.
117
+ > Files that are not staged for commit will be ignored.
118
+ > See `gito --help` for more options.
119
+
120
+ **Reviewing remote repository**
121
+
122
+ ```bash
123
+ gito remote git@github.com:owner/repo.git <FEATURE_BRANCH>..<MAIN_BRANCH>
124
+ ```
125
+ Use interactive help for details:
126
+ ```bash
127
+ gito remote --help
128
+ ```
129
+
130
+ ## 🔧 Configuration
131
+
132
+ Change behavior via `.gito/config.toml`:
133
+
134
+ - Prompt templates, filtering and post-processing using Python code snippets
135
+ - Tagging, severity, and confidence settings
136
+ - Custom AI awards for developer brilliance
137
+ - Output customization
138
+
139
+ You can override the default config by placing `.gito/config.toml` in your repo root.
140
+
141
+
142
+ See default configuration [here](https://github.com/Nayjest/Gito/blob/main/gito/config.toml).
143
+
144
+ More details can be found in [📖 Configuration Cookbook](https://github.com/Nayjest/Gito/blob/main/documentation/config_cookbook.md)
145
+
146
+ ## 💻 Development Setup
147
+
148
+ Install dependencies:
149
+
150
+ ```bash
151
+ make install
152
+ ```
153
+
154
+ Format code and check style:
155
+
156
+ ```bash
157
+ make black
158
+ make cs
159
+ ```
160
+
161
+ Run tests:
162
+
163
+ ```bash
164
+ pytest
165
+ ```
166
+
167
+ ## 🤝 Contributing
168
+
169
+ **Looking for a specific feature or having trouble?**
170
+ Contributions are welcome! ❤️
171
+ See [CONTRIBUTING.md](https://github.com/Nayjest/Gito/blob/main/CONTRIBUTING.md) for details.
172
+
173
+ ## 📝 License
174
+
175
+ Licensed under the [MIT License](https://github.com/Nayjest/Gito/blob/main/LICENSE).
176
+
177
+ © 2025 [Vitalii Stepanenko](mailto:mail@vitaliy.in)
@@ -3,9 +3,10 @@ import os
3
3
  from datetime import datetime
4
4
 
5
5
  import microcore as mc
6
- from ai_code_review.utils import is_running_in_github_action
6
+ import typer
7
7
 
8
- from .constants import ENV_CONFIG_FILE
8
+ from .utils import is_running_in_github_action
9
+ from .constants import HOME_ENV_PATH, EXECUTABLE
9
10
 
10
11
 
11
12
  def setup_logging():
@@ -32,7 +33,7 @@ def bootstrap():
32
33
  logging.info("Bootstrapping...")
33
34
  try:
34
35
  mc.configure(
35
- DOT_ENV_FILE=ENV_CONFIG_FILE,
36
+ DOT_ENV_FILE=HOME_ENV_PATH,
36
37
  USE_LOGGING=True,
37
38
  EMBEDDING_DB_TYPE=mc.EmbeddingDbType.NONE,
38
39
  )
@@ -51,7 +52,7 @@ def bootstrap():
51
52
  )
52
53
  else:
53
54
  msg += (
54
- "\nPlease run 'ai-code-review setup' "
55
+ f"\nPlease run '{EXECUTABLE} setup' "
55
56
  "to configure LLM API access (API keys, model, etc)."
56
57
  )
57
58
  print(mc.ui.red(msg))
@@ -60,3 +61,6 @@ def bootstrap():
60
61
  logging.error(f"Unexpected configuration error: {e}")
61
62
  raise SystemExit(3)
62
63
  mc.logging.LoggingConfig.STRIP_REQUEST_LINES = [300, 15]
64
+
65
+
66
+ app = typer.Typer(pretty_exceptions_show_locals=False)
@@ -12,18 +12,25 @@ from git import Repo
12
12
 
13
13
  from .core import review, get_diff, filter_diff
14
14
  from .report_struct import Report
15
- from .constants import ENV_CONFIG_FILE
16
- from .bootstrap import bootstrap
15
+ from .constants import HOME_ENV_PATH
16
+ from .bootstrap import bootstrap, app
17
17
  from .project_config import ProjectConfig
18
18
  from .utils import no_subcommand, parse_refs_pair
19
19
 
20
- app = typer.Typer(pretty_exceptions_show_locals=False)
20
+ # Import fix command to register it
21
+ from .commands import fix # noqa
22
+
23
+
21
24
  app_no_subcommand = typer.Typer(pretty_exceptions_show_locals=False)
22
25
 
23
26
 
24
27
  def main():
25
28
  if sys.platform == "win32":
26
29
  asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
30
+ # Help subcommand alias: if 'help' appears as first non-option arg, replace it with '--help'
31
+ if len(sys.argv) > 1 and sys.argv[1] == "help":
32
+ sys.argv = [sys.argv[0]] + sys.argv[2:] + ["--help"]
33
+
27
34
  if no_subcommand(app):
28
35
  bootstrap()
29
36
  app_no_subcommand()
@@ -117,12 +124,21 @@ def cmd_review(
117
124
 
118
125
  @app.command(help="Configure LLM for local usage interactively")
119
126
  def setup():
120
- mc.interactive_setup(ENV_CONFIG_FILE)
121
-
122
-
123
- @app.command()
124
- def render(format: str = Report.Format.MARKDOWN):
125
- print(Report.load().render(format=format))
127
+ mc.interactive_setup(HOME_ENV_PATH)
128
+
129
+
130
+ @app.command(name="render")
131
+ @app.command(name="report", hidden=True)
132
+ def render(
133
+ format: str = typer.Argument(default=Report.Format.CLI),
134
+ source: str = typer.Option(
135
+ "",
136
+ "--src",
137
+ "--source",
138
+ help="Source file (json) to load the report from"
139
+ )
140
+ ):
141
+ Report.load(file_name=source).to_cli(report_format=format)
126
142
 
127
143
 
128
144
  @app.command(help="Review remote code")
@@ -225,7 +241,7 @@ def files(
225
241
  f"{mc.ui.yellow(_against or repo.remotes.origin.refs.HEAD.reference.name)}"
226
242
  f"{' filtered by '+mc.ui.cyan(filters) if filters else ''}"
227
243
  )
228
-
244
+ repo.close()
229
245
  for patch in patch_set:
230
246
  if patch.is_added_file:
231
247
  color = mc.ui.green
@@ -0,0 +1 @@
1
+ # Command modules register themselves with the CLI app
@@ -0,0 +1,124 @@
1
+ """
2
+ Fix issues from code review report
3
+ """
4
+ import json
5
+ import logging
6
+ from pathlib import Path
7
+ from typing import Optional
8
+
9
+ import typer
10
+ from microcore import ui
11
+
12
+ from ..bootstrap import app
13
+ from ..constants import JSON_REPORT_FILE_NAME
14
+ from ..report_struct import Report
15
+
16
+
17
+ @app.command(help="Fix an issue from the code review report")
18
+ def fix(
19
+ issue_number: int = typer.Argument(..., help="Issue number to fix"),
20
+ report_path: Optional[str] = typer.Option(
21
+ None,
22
+ "--report",
23
+ "-r",
24
+ help="Path to the code review report (default: code-review-report.json)"
25
+ ),
26
+ dry_run: bool = typer.Option(
27
+ False, "--dry-run", "-d", help="Only print changes without applying them"
28
+ ),
29
+ ):
30
+ """
31
+ Applies the proposed change for the specified issue number from the code review report.
32
+ """
33
+ # Load the report
34
+ report_path = report_path or JSON_REPORT_FILE_NAME
35
+ try:
36
+ report = Report.load(report_path)
37
+ except (FileNotFoundError, json.JSONDecodeError) as e:
38
+ logging.error(f"Failed to load report from {report_path}: {e}")
39
+ raise typer.Exit(code=1)
40
+
41
+ # Find the issue by number
42
+ issue = None
43
+ for file_issues in report.issues.values():
44
+ for i in file_issues:
45
+ if i.id == issue_number:
46
+ issue = i
47
+ break
48
+ if issue:
49
+ break
50
+
51
+ if not issue:
52
+ logging.error(f"Issue #{issue_number} not found in the report")
53
+ raise typer.Exit(code=1)
54
+
55
+ if not issue.affected_lines:
56
+ logging.error(f"Issue #{issue_number} has no affected lines specified")
57
+ raise typer.Exit(code=1)
58
+
59
+ if not any(affected_line.proposal for affected_line in issue.affected_lines):
60
+ logging.error(f"Issue #{issue_number} has no proposal for fixing")
61
+ raise typer.Exit(code=1)
62
+
63
+ # Apply the fix
64
+ logging.info(f"Fixing issue #{issue_number}: {ui.cyan(issue.title)}")
65
+
66
+ for affected_line in issue.affected_lines:
67
+ if not affected_line.proposal:
68
+ continue
69
+
70
+ file_path = Path(issue.file)
71
+ if not file_path.exists():
72
+ logging.error(f"File {file_path} not found")
73
+ continue
74
+
75
+ try:
76
+ with open(file_path, "r", encoding="utf-8") as f:
77
+ lines = f.readlines()
78
+ except Exception as e:
79
+ logging.error(f"Failed to read file {file_path}: {e}")
80
+ continue
81
+
82
+ # Check if line numbers are valid
83
+ if affected_line.start_line < 1 or affected_line.end_line > len(lines):
84
+ logging.error(
85
+ f"Invalid line range: {affected_line.start_line}-{affected_line.end_line} "
86
+ f"(file has {len(lines)} lines)"
87
+ )
88
+ continue
89
+
90
+ # Get the affected line content for display
91
+ affected_content = "".join(lines[affected_line.start_line - 1:affected_line.end_line])
92
+ print(f"\nFile: {ui.blue(issue.file)}")
93
+ print(f"Lines: {affected_line.start_line}-{affected_line.end_line}")
94
+ print(f"Current content:\n{ui.red(affected_content)}")
95
+ print(f"Proposed change:\n{ui.green(affected_line.proposal)}")
96
+
97
+ if dry_run:
98
+ print(f"{ui.yellow('Dry run')}: Changes not applied")
99
+ continue
100
+
101
+ # Apply the change
102
+ proposal_lines = affected_line.proposal.splitlines(keepends=True)
103
+ if not proposal_lines:
104
+ proposal_lines = [""]
105
+ elif not proposal_lines[-1].endswith(("\n", "\r")):
106
+ # Ensure the last line has a newline if the original does
107
+ if (
108
+ affected_line.end_line < len(lines)
109
+ and lines[affected_line.end_line - 1].endswith(("\n", "\r"))
110
+ ):
111
+ proposal_lines[-1] += "\n"
112
+
113
+ lines[affected_line.start_line - 1:affected_line.end_line] = proposal_lines
114
+
115
+ # Write changes back to the file
116
+ try:
117
+ with open(file_path, "w", encoding="utf-8") as f:
118
+ f.writelines(lines)
119
+ print(f"{ui.green('Success')}: Changes applied to {file_path}")
120
+ except Exception as e:
121
+ logging.error(f"Failed to write changes to {file_path}: {e}")
122
+ raise typer.Exit(code=1)
123
+
124
+ print(f"\n{ui.green('✓')} Issue #{issue_number} fixed successfully")
@@ -3,7 +3,7 @@ Python REPL
3
3
  """
4
4
  # flake8: noqa: F401
5
5
  import code
6
- from ema.cli import app
6
+
7
7
 
8
8
  # Imports for usage in REPL
9
9
  import os
@@ -17,6 +17,8 @@ from rich.pretty import pprint
17
17
  import microcore as mc
18
18
  from microcore import ui
19
19
 
20
+ from ..cli import app
21
+
20
22
  @app.command(help="python REPL")
21
23
  def repl():
22
24
  code.interact(local=globals())