execdiff-git-ai 1.0.0__py3-none-any.whl
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.
- execdiff_git_ai/__init__.py +13 -0
- execdiff_git_ai/agent.py +328 -0
- execdiff_git_ai/cli.py +39 -0
- execdiff_git_ai-1.0.0.dist-info/METADATA +287 -0
- execdiff_git_ai-1.0.0.dist-info/RECORD +9 -0
- execdiff_git_ai-1.0.0.dist-info/WHEEL +5 -0
- execdiff_git_ai-1.0.0.dist-info/entry_points.txt +2 -0
- execdiff_git_ai-1.0.0.dist-info/licenses/LICENSE +17 -0
- execdiff_git_ai-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ExecDiff Git AI - Local-first tool for analyzing AI-driven code changes.
|
|
3
|
+
|
|
4
|
+
This package provides tools to analyze Git diffs and assess the impact
|
|
5
|
+
of changes made by AI coding assistants.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "1.0.0"
|
|
9
|
+
__author__ = "Anup Moncy"
|
|
10
|
+
|
|
11
|
+
from execdiff_git_ai.agent import run_agent, run_agent_with_ai
|
|
12
|
+
|
|
13
|
+
__all__ = ["run_agent", "run_agent_with_ai"]
|
execdiff_git_ai/agent.py
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import os
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
def get_git_diff():
|
|
6
|
+
"""Get the current git diff for unstaged changes."""
|
|
7
|
+
try:
|
|
8
|
+
result = subprocess.run(
|
|
9
|
+
["git", "diff"],
|
|
10
|
+
capture_output=True,
|
|
11
|
+
text=True,
|
|
12
|
+
check=True
|
|
13
|
+
)
|
|
14
|
+
return result.stdout
|
|
15
|
+
except subprocess.CalledProcessError:
|
|
16
|
+
return "No git repository found or no changes detected."
|
|
17
|
+
|
|
18
|
+
def parse_diff_stats(diff_text):
|
|
19
|
+
"""Parse diff to get file-level statistics."""
|
|
20
|
+
files = {}
|
|
21
|
+
current_file = None
|
|
22
|
+
|
|
23
|
+
for line in diff_text.split('\n'):
|
|
24
|
+
if line.startswith('diff --git'):
|
|
25
|
+
parts = line.split()
|
|
26
|
+
if len(parts) >= 4:
|
|
27
|
+
current_file = parts[3].replace('b/', '')
|
|
28
|
+
files[current_file] = {'added': 0, 'deleted': 0}
|
|
29
|
+
elif current_file and line.startswith('+') and not line.startswith('+++'):
|
|
30
|
+
files[current_file]['added'] += 1
|
|
31
|
+
elif current_file and line.startswith('-') and not line.startswith('---'):
|
|
32
|
+
files[current_file]['deleted'] += 1
|
|
33
|
+
|
|
34
|
+
return files
|
|
35
|
+
|
|
36
|
+
def detect_changed_symbols(diff_text):
|
|
37
|
+
"""
|
|
38
|
+
Parse the diff and extract changed symbols (functions, classes, methods).
|
|
39
|
+
Returns a list of dictionaries with symbol info.
|
|
40
|
+
"""
|
|
41
|
+
symbols = []
|
|
42
|
+
lines = diff_text.split('\n')
|
|
43
|
+
modified_functions = set()
|
|
44
|
+
|
|
45
|
+
for i, line in enumerate(lines):
|
|
46
|
+
# Detect added/modified functions
|
|
47
|
+
if line.startswith('+') and ('def ' in line or 'class ' in line):
|
|
48
|
+
if 'def ' in line:
|
|
49
|
+
try:
|
|
50
|
+
name = line.split('def ')[1].split('(')[0].strip()
|
|
51
|
+
symbols.append({
|
|
52
|
+
'name': name,
|
|
53
|
+
'type': 'function',
|
|
54
|
+
'change': 'added',
|
|
55
|
+
'risk': 'LOW'
|
|
56
|
+
})
|
|
57
|
+
except:
|
|
58
|
+
pass
|
|
59
|
+
elif 'class ' in line:
|
|
60
|
+
try:
|
|
61
|
+
name = line.split('class ')[1].split(':')[0].split('(')[0].strip()
|
|
62
|
+
symbols.append({
|
|
63
|
+
'name': name,
|
|
64
|
+
'type': 'class',
|
|
65
|
+
'change': 'added',
|
|
66
|
+
'risk': 'LOW'
|
|
67
|
+
})
|
|
68
|
+
except:
|
|
69
|
+
pass
|
|
70
|
+
# Detect modified functions (lines that have @@ context)
|
|
71
|
+
elif line.startswith('@@'):
|
|
72
|
+
for j in range(i+1, min(i+15, len(lines))):
|
|
73
|
+
if lines[j].startswith('-') and 'def ' in lines[j]:
|
|
74
|
+
try:
|
|
75
|
+
name = lines[j].split('def ')[1].split('(')[0].strip()
|
|
76
|
+
if name not in [s['name'] for s in symbols]:
|
|
77
|
+
modified_functions.add(name)
|
|
78
|
+
except:
|
|
79
|
+
pass
|
|
80
|
+
# Detect variables
|
|
81
|
+
elif line.startswith('+') and '=' in line and 'def ' not in line and 'class ' not in line:
|
|
82
|
+
try:
|
|
83
|
+
var_name = line.split('=')[0].strip().replace('+', '').strip()
|
|
84
|
+
if var_name and not var_name.startswith('#') and var_name.isidentifier():
|
|
85
|
+
symbols.append({
|
|
86
|
+
'name': var_name,
|
|
87
|
+
'type': 'variable',
|
|
88
|
+
'change': 'added',
|
|
89
|
+
'risk': 'LOW'
|
|
90
|
+
})
|
|
91
|
+
except:
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
# Add modified functions to symbols
|
|
95
|
+
for func in modified_functions:
|
|
96
|
+
symbols.append({
|
|
97
|
+
'name': func,
|
|
98
|
+
'type': 'function',
|
|
99
|
+
'change': 'modified',
|
|
100
|
+
'risk': 'LOW'
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
return symbols
|
|
104
|
+
|
|
105
|
+
def format_table_row(col1, col2, col3):
|
|
106
|
+
"""Format a table row with proper alignment."""
|
|
107
|
+
return f"{col1:<32} {col2:<20} {col3:>8}"
|
|
108
|
+
|
|
109
|
+
def run_agent():
|
|
110
|
+
"""Run the ExecDiff Git AI assessment (non-AI mode)."""
|
|
111
|
+
print("\n" + "="*30)
|
|
112
|
+
print("📊 File Change Assessment")
|
|
113
|
+
print("="*30)
|
|
114
|
+
|
|
115
|
+
diff = get_git_diff()
|
|
116
|
+
|
|
117
|
+
if not diff or diff == "No git repository found or no changes detected.":
|
|
118
|
+
print("(No changes detected)")
|
|
119
|
+
print("\n✅ Assessment complete!\n")
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
file_stats = parse_diff_stats(diff)
|
|
123
|
+
|
|
124
|
+
print(format_table_row("File", "+Lines", "-Lines"))
|
|
125
|
+
print("-" * 48)
|
|
126
|
+
for filename, stats in file_stats.items():
|
|
127
|
+
print(format_table_row(filename, str(stats['added']), str(stats['deleted'])))
|
|
128
|
+
|
|
129
|
+
print("\n" + "-" * 32)
|
|
130
|
+
print()
|
|
131
|
+
|
|
132
|
+
symbols = detect_changed_symbols(diff)
|
|
133
|
+
|
|
134
|
+
print("="*80)
|
|
135
|
+
print("📋 Impact Summary")
|
|
136
|
+
print("="*80)
|
|
137
|
+
print(format_table_row("Symbol", "Change Type", "Risk"))
|
|
138
|
+
print("-" * 56)
|
|
139
|
+
|
|
140
|
+
if symbols:
|
|
141
|
+
for symbol in symbols:
|
|
142
|
+
change_desc = f"{symbol['type']} {symbol['change']}"
|
|
143
|
+
print(format_table_row(symbol['name'], change_desc, symbol['risk']))
|
|
144
|
+
|
|
145
|
+
print()
|
|
146
|
+
print("✅ Assessment complete!\n")
|
|
147
|
+
|
|
148
|
+
def analyze_with_ollama(diff_text, symbols):
|
|
149
|
+
"""
|
|
150
|
+
Use Ollama to analyze the git diff and provide AI-powered impact assessment.
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
prompt = f"""Analyze these code changes and provide an impact assessment for each modified symbol.
|
|
154
|
+
|
|
155
|
+
For each symbol, provide:
|
|
156
|
+
- File: <filename>
|
|
157
|
+
- Symbol: <name>
|
|
158
|
+
- Impact: <LOW/MEDIUM/HIGH>
|
|
159
|
+
- Summary: <one-line explanation of the change and its impact>
|
|
160
|
+
|
|
161
|
+
Changed symbols to analyze: {', '.join([s['name'] for s in symbols])}
|
|
162
|
+
|
|
163
|
+
Git Diff (first 2000 chars):
|
|
164
|
+
{diff_text[:2000]}
|
|
165
|
+
|
|
166
|
+
Format your response as:
|
|
167
|
+
File: <filename> - Symbol: <name>
|
|
168
|
+
Impact: <LOW/MEDIUM/HIGH>
|
|
169
|
+
Summary: <explanation>
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
result = subprocess.run(
|
|
173
|
+
["ollama", "run", "llama2", prompt],
|
|
174
|
+
capture_output=True,
|
|
175
|
+
text=True,
|
|
176
|
+
timeout=60
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
if result.returncode == 0:
|
|
180
|
+
return result.stdout
|
|
181
|
+
else:
|
|
182
|
+
return "AI analysis failed. Make sure Ollama is installed and running."
|
|
183
|
+
except FileNotFoundError:
|
|
184
|
+
return "Ollama not found. Install from https://ollama.ai/"
|
|
185
|
+
except subprocess.TimeoutExpired:
|
|
186
|
+
return "AI analysis timed out."
|
|
187
|
+
except Exception as e:
|
|
188
|
+
return f"AI analysis error: {str(e)}"
|
|
189
|
+
|
|
190
|
+
def extract_impact_summary(ai_analysis):
|
|
191
|
+
"""Extract a summary of changes from AI analysis."""
|
|
192
|
+
summary_lines = []
|
|
193
|
+
|
|
194
|
+
# Count impacts
|
|
195
|
+
high_count = ai_analysis.count("Impact: HIGH")
|
|
196
|
+
medium_count = ai_analysis.count("Impact: MEDIUM")
|
|
197
|
+
low_count = ai_analysis.count("Impact: LOW")
|
|
198
|
+
|
|
199
|
+
if high_count > 0:
|
|
200
|
+
summary_lines.append(f"🔴 {high_count} HIGH impact change(s)")
|
|
201
|
+
if medium_count > 0:
|
|
202
|
+
summary_lines.append(f"🟡 {medium_count} MEDIUM impact change(s)")
|
|
203
|
+
if low_count > 0:
|
|
204
|
+
summary_lines.append(f"🟢 {low_count} LOW impact change(s)")
|
|
205
|
+
|
|
206
|
+
return summary_lines
|
|
207
|
+
|
|
208
|
+
def extract_change_summary(ai_analysis, file_stats, symbols):
|
|
209
|
+
"""Extract a user-facing summary by translating technical changes into business requirements."""
|
|
210
|
+
summary_lines = []
|
|
211
|
+
|
|
212
|
+
# Parse AI analysis to extract business-level impacts
|
|
213
|
+
lines = ai_analysis.split('\n')
|
|
214
|
+
business_needs = []
|
|
215
|
+
|
|
216
|
+
i = 0
|
|
217
|
+
while i < len(lines):
|
|
218
|
+
line = lines[i]
|
|
219
|
+
if "Impact: HIGH" in line:
|
|
220
|
+
# Extract the summary for this HIGH impact change
|
|
221
|
+
for j in range(i, min(i+10, len(lines))):
|
|
222
|
+
if "Summary:" in lines[j]:
|
|
223
|
+
summary_text = lines[j].replace("Summary:", "").strip()
|
|
224
|
+
# Combine with next lines if they're part of the summary
|
|
225
|
+
k = j + 1
|
|
226
|
+
while k < len(lines) and lines[k].strip() and not "Impact:" in lines[k] and not "File:" in lines[k]:
|
|
227
|
+
summary_text += " " + lines[k].strip()
|
|
228
|
+
k += 1
|
|
229
|
+
if summary_text:
|
|
230
|
+
business_needs.append(("critical", summary_text[:120]))
|
|
231
|
+
break
|
|
232
|
+
i += 1
|
|
233
|
+
|
|
234
|
+
# Count impact levels
|
|
235
|
+
high_count = ai_analysis.count("Impact: HIGH")
|
|
236
|
+
medium_count = ai_analysis.count("Impact: MEDIUM")
|
|
237
|
+
low_count = ai_analysis.count("Impact: LOW")
|
|
238
|
+
|
|
239
|
+
# Extract file changes
|
|
240
|
+
total_files = len(file_stats)
|
|
241
|
+
total_added = sum(stats['added'] for stats in file_stats.values())
|
|
242
|
+
total_deleted = sum(stats['deleted'] for stats in file_stats.values())
|
|
243
|
+
|
|
244
|
+
# Generate business/user-facing summary
|
|
245
|
+
if high_count > 0:
|
|
246
|
+
if business_needs:
|
|
247
|
+
requirement = business_needs[0][1]
|
|
248
|
+
summary_lines.append(f"🔴 Critical: {requirement}")
|
|
249
|
+
else:
|
|
250
|
+
summary_lines.append(f"🔴 Critical: {high_count} {'change' if high_count == 1 else 'changes'} requiring careful validation")
|
|
251
|
+
|
|
252
|
+
if medium_count > 0:
|
|
253
|
+
summary_lines.append(f"🟡 Important: {medium_count} {'change' if medium_count == 1 else 'changes'} needing thorough testing and QA")
|
|
254
|
+
|
|
255
|
+
if high_count == 0 and medium_count == 0 and low_count > 0:
|
|
256
|
+
summary_lines.append(f"🟢 Low Risk: {low_count} minor {'update' if low_count == 1 else 'updates'} with minimal system impact")
|
|
257
|
+
|
|
258
|
+
# Add scope summary
|
|
259
|
+
if total_files > 0:
|
|
260
|
+
scope = f"Scope: {total_files} file{'s' if total_files != 1 else ''} affected in this change"
|
|
261
|
+
summary_lines.append(scope)
|
|
262
|
+
|
|
263
|
+
return summary_lines
|
|
264
|
+
|
|
265
|
+
def run_agent_with_ai():
|
|
266
|
+
"""Run the ExecDiff Git AI assessment with AI analysis."""
|
|
267
|
+
print("\n" + "="*30)
|
|
268
|
+
print("📊 File Change Assessment")
|
|
269
|
+
print("="*30)
|
|
270
|
+
|
|
271
|
+
diff = get_git_diff()
|
|
272
|
+
|
|
273
|
+
if not diff or diff == "No git repository found or no changes detected.":
|
|
274
|
+
print("(No changes detected)")
|
|
275
|
+
print("\n✅ Assessment complete!\n")
|
|
276
|
+
return
|
|
277
|
+
|
|
278
|
+
file_stats = parse_diff_stats(diff)
|
|
279
|
+
|
|
280
|
+
print(format_table_row("File", "+Lines", "-Lines"))
|
|
281
|
+
print("-" * 48)
|
|
282
|
+
for filename, stats in file_stats.items():
|
|
283
|
+
print(format_table_row(filename, str(stats['added']), str(stats['deleted'])))
|
|
284
|
+
|
|
285
|
+
print("\n" + "-" * 32)
|
|
286
|
+
print()
|
|
287
|
+
|
|
288
|
+
symbols = detect_changed_symbols(diff)
|
|
289
|
+
|
|
290
|
+
print("="*80)
|
|
291
|
+
print("📋 Impact Summary")
|
|
292
|
+
print("="*80)
|
|
293
|
+
print(format_table_row("Symbol", "Change Type", "Impact"))
|
|
294
|
+
print("-" * 56)
|
|
295
|
+
|
|
296
|
+
if symbols:
|
|
297
|
+
for symbol in symbols:
|
|
298
|
+
change_desc = f"{symbol['type']} {symbol['change']}"
|
|
299
|
+
print(format_table_row(symbol['name'], change_desc, symbol['risk']))
|
|
300
|
+
|
|
301
|
+
print()
|
|
302
|
+
|
|
303
|
+
# AI Impact Assessment Section
|
|
304
|
+
if symbols:
|
|
305
|
+
print("="*80)
|
|
306
|
+
print("🤖 AI Impact Assessment")
|
|
307
|
+
print("="*80)
|
|
308
|
+
|
|
309
|
+
ai_analysis = analyze_with_ollama(diff, symbols)
|
|
310
|
+
|
|
311
|
+
# Extract and display business-facing summary
|
|
312
|
+
summary = extract_change_summary(ai_analysis, file_stats, symbols)
|
|
313
|
+
if summary:
|
|
314
|
+
print("\n📋 What Changed:")
|
|
315
|
+
for line in summary:
|
|
316
|
+
print(f" {line}")
|
|
317
|
+
print()
|
|
318
|
+
|
|
319
|
+
print("Detailed Analysis:\n")
|
|
320
|
+
print(ai_analysis)
|
|
321
|
+
|
|
322
|
+
# Check for HIGH impact symbols and add warning
|
|
323
|
+
high_impact_count = ai_analysis.count("Impact: HIGH")
|
|
324
|
+
if high_impact_count > 0:
|
|
325
|
+
print("\n⚠️ ALERT: " + str(high_impact_count) + " critical " + ("change" if high_impact_count == 1 else "changes") + " detected!")
|
|
326
|
+
print("Please review carefully before deploying to production.\n")
|
|
327
|
+
|
|
328
|
+
print("✅ Assessment complete!\n")
|
execdiff_git_ai/cli.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from execdiff_git_ai.agent import run_agent, run_agent_with_ai
|
|
3
|
+
|
|
4
|
+
def scan():
|
|
5
|
+
"""Run the ExecDiff Git AI assessment agent (non-AI mode)."""
|
|
6
|
+
print("🔍 ExecDiff Git AI: Starting impact assessment (non-AI mode)...\n")
|
|
7
|
+
run_agent()
|
|
8
|
+
|
|
9
|
+
def scan_ai():
|
|
10
|
+
"""Run the ExecDiff Git AI assessment agent with AI analysis (Ollama)."""
|
|
11
|
+
print("🤖 ExecDiff Git AI: Starting AI-powered impact assessment...\n")
|
|
12
|
+
run_agent_with_ai()
|
|
13
|
+
|
|
14
|
+
def main():
|
|
15
|
+
parser = argparse.ArgumentParser(
|
|
16
|
+
prog="execdiff-git",
|
|
17
|
+
description="ExecDiff Git AI - Analyze AI-driven code changes"
|
|
18
|
+
)
|
|
19
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
20
|
+
|
|
21
|
+
scan_parser = subparsers.add_parser(
|
|
22
|
+
"scan",
|
|
23
|
+
help="Scan workspace and assess changes (non-AI mode)"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
scan_ai_parser = subparsers.add_parser(
|
|
27
|
+
"scan-ai",
|
|
28
|
+
help="Scan workspace with AI-powered analysis (requires Ollama)"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
args = parser.parse_args()
|
|
32
|
+
|
|
33
|
+
if args.command == "scan":
|
|
34
|
+
scan()
|
|
35
|
+
elif args.command == "scan-ai":
|
|
36
|
+
scan_ai()
|
|
37
|
+
|
|
38
|
+
if __name__ == "__main__":
|
|
39
|
+
main()
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: execdiff-git-ai
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Local-first tool for analyzing AI-driven code changes. Analyzes Git diffs and assesses impact of changes made by AI coding assistants.
|
|
5
|
+
Author-email: Anup Moncy <n93181165@gmail.com>
|
|
6
|
+
License: Apache License
|
|
7
|
+
Version 2.0, January 2004
|
|
8
|
+
http://www.apache.org/licenses/
|
|
9
|
+
|
|
10
|
+
Copyright 2025 Anup Moncy
|
|
11
|
+
|
|
12
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
13
|
+
you may not use this file except in compliance with the License.
|
|
14
|
+
You may obtain a copy of the License at
|
|
15
|
+
|
|
16
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
+
|
|
18
|
+
Unless required by applicable law or agreed to in writing, software
|
|
19
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
20
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
21
|
+
See the License for the specific language governing permissions and
|
|
22
|
+
limitations under the License.
|
|
23
|
+
|
|
24
|
+
Project-URL: Homepage, https://github.com/yourusername/execdiff-git-ai
|
|
25
|
+
Project-URL: Bug Tracker, https://github.com/yourusername/execdiff-git-ai/issues
|
|
26
|
+
Project-URL: Documentation, https://github.com/yourusername/execdiff-git-ai#readme
|
|
27
|
+
Keywords: git,ai,copilot,code-analysis,diff,impact-assessment,execdiff
|
|
28
|
+
Classifier: Development Status :: 4 - Beta
|
|
29
|
+
Classifier: Intended Audience :: Developers
|
|
30
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
31
|
+
Classifier: Programming Language :: Python :: 3
|
|
32
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
37
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
38
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
39
|
+
Requires-Python: >=3.8
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
License-File: LICENSE
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
# ExecDiff Git AI
|
|
45
|
+
|
|
46
|
+
AI Impact Assessment for git changes - understand what your AI copilot changed before you commit it.
|
|
47
|
+
|
|
48
|
+
## Overview
|
|
49
|
+
|
|
50
|
+
ExecDiff Git AI is a Python CLI tool that helps developers understand the scope and implications of code changes made by AI coding assistants (like GitHub Copilot, Cursor, or Replit AI) by analyzing git diffs and extracting modified symbols (functions, classes, variables). It can optionally use a local LLM (Ollama) to assess the risk of each change.
|
|
51
|
+
|
|
52
|
+
## Privacy
|
|
53
|
+
|
|
54
|
+
ExecDiff Git AI runs **entirely locally**.
|
|
55
|
+
|
|
56
|
+
- ✅ No code is uploaded
|
|
57
|
+
- ✅ No cloud calls required
|
|
58
|
+
- ✅ No telemetry
|
|
59
|
+
- ✅ Works offline with local LLM (Ollama)
|
|
60
|
+
- ✅ All analysis happens on your machine
|
|
61
|
+
|
|
62
|
+
## Features
|
|
63
|
+
|
|
64
|
+
- **Local-first**: Runs entirely on your machine with no cloud calls or telemetry
|
|
65
|
+
- **Impact Assessment**: Detects specific changes to functions, classes, and variables and provides human-readable summaries
|
|
66
|
+
- **AI-powered risk assessment**: Utilizes local Ollama for intelligent impact analysis and scoring (optional)
|
|
67
|
+
- **CLI-first**: `execdiff-git scan` and `execdiff-git scan-ai`
|
|
68
|
+
- **Works offline**, no telemetry
|
|
69
|
+
|
|
70
|
+
## Installation
|
|
71
|
+
|
|
72
|
+
### Prerequisites
|
|
73
|
+
|
|
74
|
+
- Python 3.8+
|
|
75
|
+
- Git
|
|
76
|
+
- Ollama (optional, for AI risk assessment)
|
|
77
|
+
|
|
78
|
+
### Initial Setup
|
|
79
|
+
|
|
80
|
+
Install from PyPI:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install execdiff-git-ai
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## How to Use
|
|
87
|
+
|
|
88
|
+
1. **Make your code change** (or let your AI copilot make changes)
|
|
89
|
+
|
|
90
|
+
2. **Stage your changes with git**
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
git add .
|
|
94
|
+
# For new files, you may need:
|
|
95
|
+
git add -N .
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
3. **Run the assessment (no AI)**
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
execdiff-git scan
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Or, to use AI-powered risk assessment (requires Ollama):
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
execdiff-git scan-ai
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Note**: For newly created files, you must run `git add -N .` (intent-to-add) so that `execdiff-git scan` or `execdiff-git scan-ai` can detect them. This is a git limitation for diff tools.
|
|
111
|
+
|
|
112
|
+
## Usage
|
|
113
|
+
|
|
114
|
+
### Basic Commands
|
|
115
|
+
|
|
116
|
+
Analyze changes in the current repository:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
execdiff-git scan
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Analyze with AI-powered risk assessment:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
execdiff-git scan-ai
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Example Output
|
|
129
|
+
|
|
130
|
+
**Non-AI Mode:**
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
==============================
|
|
134
|
+
📊 File Change Assessment
|
|
135
|
+
==============================
|
|
136
|
+
File +Lines -Lines
|
|
137
|
+
------------------------------------------------
|
|
138
|
+
shopping_cart.py 10 2
|
|
139
|
+
checkout.py 7 1
|
|
140
|
+
email/notifications.py 5 0
|
|
141
|
+
|
|
142
|
+
--------------------------------
|
|
143
|
+
|
|
144
|
+
================================================================================
|
|
145
|
+
📋 Impact Summary
|
|
146
|
+
================================================================================
|
|
147
|
+
Symbol Change Type Impact
|
|
148
|
+
--------------------------------------------------------
|
|
149
|
+
add_to_cart function modified MEDIUM
|
|
150
|
+
remove_from_cart function modified LOW
|
|
151
|
+
checkout function modified HIGH
|
|
152
|
+
send_order_email function added LOW
|
|
153
|
+
|
|
154
|
+
✅ Assessment complete!
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Optional: Install Ollama for AI Risk Assessment
|
|
158
|
+
|
|
159
|
+
Ollama enables intelligent risk scoring. Install and configure:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# macOS / Linux
|
|
163
|
+
curl -fsSL https://ollama.ai/install.sh | sh
|
|
164
|
+
|
|
165
|
+
# Or use Homebrew (macOS)
|
|
166
|
+
brew install ollama
|
|
167
|
+
|
|
168
|
+
# Pull the model
|
|
169
|
+
ollama pull llama2
|
|
170
|
+
|
|
171
|
+
# Start the server (runs on localhost:11434)
|
|
172
|
+
ollama serve
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
With Ollama running, you'll also get AI-powered impact assessment:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
==============================
|
|
179
|
+
📊 File Change Assessment
|
|
180
|
+
==============================
|
|
181
|
+
File +Lines -Lines
|
|
182
|
+
------------------------------------------------
|
|
183
|
+
shopping_cart.py 10 2
|
|
184
|
+
checkout.py 7 1
|
|
185
|
+
email/notifications.py 5 0
|
|
186
|
+
|
|
187
|
+
--------------------------------
|
|
188
|
+
|
|
189
|
+
================================================================================
|
|
190
|
+
📋 Impact Summary
|
|
191
|
+
================================================================================
|
|
192
|
+
Symbol Change Type Impact
|
|
193
|
+
--------------------------------------------------------
|
|
194
|
+
add_to_cart function modified MEDIUM
|
|
195
|
+
remove_from_cart function modified LOW
|
|
196
|
+
checkout function modified HIGH
|
|
197
|
+
send_order_email function added LOW
|
|
198
|
+
|
|
199
|
+
================================================================================
|
|
200
|
+
🤖 AI Impact Assessment
|
|
201
|
+
================================================================================
|
|
202
|
+
|
|
203
|
+
📋 What Changed:
|
|
204
|
+
🔴 Critical: Checkout now supports Apple Pay, Google Pay, and PayPal in addition to credit cards, and changes the order completion flow. Payment processing reliability and customer purchase experience are directly affected.
|
|
205
|
+
🟡 Important: Cart logic now merges duplicate items and updates product quantities in one step. This changes how users see totals and manage products in their cart.
|
|
206
|
+
🟢 Low Risk: Order confirmation emails improved. Cart item removal is more reliable.
|
|
207
|
+
|
|
208
|
+
Scope: 3 files modified (22 additions, 3 removals)
|
|
209
|
+
|
|
210
|
+
Detailed Analysis:
|
|
211
|
+
|
|
212
|
+
File: shopping_cart.py - Symbol: add_to_cart
|
|
213
|
+
Impact: MEDIUM
|
|
214
|
+
Summary: Cart logic updated to better handle product quantities and merging duplicate items.
|
|
215
|
+
|
|
216
|
+
File: shopping_cart.py - Symbol: remove_from_cart
|
|
217
|
+
Impact: LOW
|
|
218
|
+
Summary: Improved item removal to prevent accidental deletion of unrelated products.
|
|
219
|
+
|
|
220
|
+
File: checkout.py - Symbol: checkout
|
|
221
|
+
Impact: HIGH
|
|
222
|
+
Summary: Checkout flow changed to support Apple Pay, Google Pay, PayPal, and credit cards, and to update order completion steps.
|
|
223
|
+
|
|
224
|
+
File: email/notifications.py - Symbol: send_order_email
|
|
225
|
+
Impact: LOW
|
|
226
|
+
Summary: Confirmation emails are now sent after every successful order.
|
|
227
|
+
|
|
228
|
+
⚠️ ALERT: 1 critical change detected!
|
|
229
|
+
Please review carefully before deploying to production.
|
|
230
|
+
|
|
231
|
+
✅ Assessment complete!
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## How It Works
|
|
235
|
+
|
|
236
|
+
1. **Reads git diff** - Gets all staged and unstaged changes
|
|
237
|
+
2. **Extracts symbols** - Finds functions, classes, and variables
|
|
238
|
+
3. **Detects change type** - Identifies what kind of change was made
|
|
239
|
+
4. **Assesses impact** - Uses local AI (Ollama) or heuristics
|
|
240
|
+
5. **Generates recommendations** - Suggests testing and review actions (AI mode only)
|
|
241
|
+
6. **Advisory warnings** - Critical impact changes trigger warnings (AI mode only)
|
|
242
|
+
|
|
243
|
+
## Development
|
|
244
|
+
|
|
245
|
+
Install in editable mode:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
git clone https://github.com/yourusername/execdiff-git-ai.git
|
|
249
|
+
cd execdiff-git-ai
|
|
250
|
+
pip install -e .
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Run the CLI:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
execdiff-git scan
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Programmatic Usage
|
|
260
|
+
|
|
261
|
+
You can also use ExecDiff Git AI as a library:
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
from execdiff_git_ai.agent import run_agent, run_agent_with_ai
|
|
265
|
+
|
|
266
|
+
# Non-AI mode (default)
|
|
267
|
+
run_agent()
|
|
268
|
+
|
|
269
|
+
# AI-powered mode (optional, requires Ollama)
|
|
270
|
+
run_agent_with_ai()
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## License
|
|
274
|
+
|
|
275
|
+
Apache-2.0
|
|
276
|
+
|
|
277
|
+
## Author
|
|
278
|
+
|
|
279
|
+
Anup Moncy (n93181165@gmail.com)
|
|
280
|
+
|
|
281
|
+
## Contributing
|
|
282
|
+
|
|
283
|
+
Contributions welcome! Please open an issue or submit a pull request.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
**Note**: This is an early-stage project. The API and behavior are subject to change.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
execdiff_git_ai/__init__.py,sha256=62BXbkuoc676h4xcROTEjOX_1UrZVT9Gs-z0KzKTcnI,353
|
|
2
|
+
execdiff_git_ai/agent.py,sha256=iXp_9cwSYd8gaAxZCLXsrLH0wKV-8RzeBZPMoAQCte0,11432
|
|
3
|
+
execdiff_git_ai/cli.py,sha256=SWcGF1VoBoS6nqiqjh1mKsqeX3vV6M56P85GhDzRUFs,1136
|
|
4
|
+
execdiff_git_ai-1.0.0.dist-info/licenses/LICENSE,sha256=nWxRL_wvG4MC9-xRzs8pGP4eg1pD2b9xn8qe5XQHUbg,625
|
|
5
|
+
execdiff_git_ai-1.0.0.dist-info/METADATA,sha256=g6jQFFQCgiWpN2Kf1ajCYqhuUU0J_CJytSJlXMuROgM,9002
|
|
6
|
+
execdiff_git_ai-1.0.0.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
|
|
7
|
+
execdiff_git_ai-1.0.0.dist-info/entry_points.txt,sha256=lZY90eUNO6epjpDD5BveMjzs9_EmhCXn_7hQDDbw9v4,58
|
|
8
|
+
execdiff_git_ai-1.0.0.dist-info/top_level.txt,sha256=rHUr4lfk-wUH7HHBXBtCMGDdH8QHCoG-5Hqmbe0kkqg,16
|
|
9
|
+
execdiff_git_ai-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright 2025 Anup Moncy
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
execdiff_git_ai
|