fancygit 1.0.24__tar.gz → 1.0.26__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 (71) hide show
  1. {fancygit-1.0.24 → fancygit-1.0.26}/PKG-INFO +1 -1
  2. fancygit-1.0.26/VERSION +1 -0
  3. {fancygit-1.0.24 → fancygit-1.0.26}/fancygit.egg-info/PKG-INFO +1 -1
  4. {fancygit-1.0.24 → fancygit-1.0.26}/fancygit.py +13 -0
  5. {fancygit-1.0.24 → fancygit-1.0.26}/src/ai_engine.py +37 -11
  6. {fancygit-1.0.24 → fancygit-1.0.26}/src/mermaid_export.py +11 -1
  7. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_ai_engine.py +2 -3
  8. fancygit-1.0.24/VERSION +0 -1
  9. {fancygit-1.0.24 → fancygit-1.0.26}/CD_GUIDE.md +0 -0
  10. {fancygit-1.0.24 → fancygit-1.0.26}/COLOR_SYSTEM_GUIDE.md +0 -0
  11. {fancygit-1.0.24 → fancygit-1.0.26}/EMAIL_SETUP_GUIDE.md +0 -0
  12. {fancygit-1.0.24 → fancygit-1.0.26}/LICENSE +0 -0
  13. {fancygit-1.0.24 → fancygit-1.0.26}/MANIFEST.in +0 -0
  14. {fancygit-1.0.24 → fancygit-1.0.26}/PYPI_DESCRIPTION.md +0 -0
  15. {fancygit-1.0.24 → fancygit-1.0.26}/README.md +0 -0
  16. {fancygit-1.0.24 → fancygit-1.0.26}/TESTING_GUIDE.md +0 -0
  17. {fancygit-1.0.24 → fancygit-1.0.26}/TESTING_SUMMARY.md +0 -0
  18. {fancygit-1.0.24 → fancygit-1.0.26}/command-list.txt +0 -0
  19. {fancygit-1.0.24 → fancygit-1.0.26}/fancygit.egg-info/SOURCES.txt +0 -0
  20. {fancygit-1.0.24 → fancygit-1.0.26}/fancygit.egg-info/dependency_links.txt +0 -0
  21. {fancygit-1.0.24 → fancygit-1.0.26}/fancygit.egg-info/entry_points.txt +0 -0
  22. {fancygit-1.0.24 → fancygit-1.0.26}/fancygit.egg-info/requires.txt +0 -0
  23. {fancygit-1.0.24 → fancygit-1.0.26}/fancygit.egg-info/top_level.txt +0 -0
  24. {fancygit-1.0.24 → fancygit-1.0.26}/game_questions.json +0 -0
  25. {fancygit-1.0.24 → fancygit-1.0.26}/images/Logo.png +0 -0
  26. {fancygit-1.0.24 → fancygit-1.0.26}/images/Logo_with_name.png +0 -0
  27. {fancygit-1.0.24 → fancygit-1.0.26}/images/dark_background_logo.png +0 -0
  28. {fancygit-1.0.24 → fancygit-1.0.26}/images/light_background_logo.png +0 -0
  29. {fancygit-1.0.24 → fancygit-1.0.26}/images/overview.png +0 -0
  30. {fancygit-1.0.24 → fancygit-1.0.26}/quiz_server.py +0 -0
  31. {fancygit-1.0.24 → fancygit-1.0.26}/setup.cfg +0 -0
  32. {fancygit-1.0.24 → fancygit-1.0.26}/setup.py +0 -0
  33. {fancygit-1.0.24 → fancygit-1.0.26}/src/__init__.py +0 -0
  34. {fancygit-1.0.24 → fancygit-1.0.26}/src/colors.py +0 -0
  35. {fancygit-1.0.24 → fancygit-1.0.26}/src/config_manager.py +0 -0
  36. {fancygit-1.0.24 → fancygit-1.0.26}/src/fancygit_config_dc.py +0 -0
  37. {fancygit-1.0.24 → fancygit-1.0.26}/src/git_error.py +0 -0
  38. {fancygit-1.0.24 → fancygit-1.0.26}/src/git_error_parser.py +0 -0
  39. {fancygit-1.0.24 → fancygit-1.0.26}/src/git_insights.py +0 -0
  40. {fancygit-1.0.24 → fancygit-1.0.26}/src/git_runner.py +0 -0
  41. {fancygit-1.0.24 → fancygit-1.0.26}/src/loading_animation.py +0 -0
  42. {fancygit-1.0.24 → fancygit-1.0.26}/src/merge_conflict.py +0 -0
  43. {fancygit-1.0.24 → fancygit-1.0.26}/src/model_provider.py +0 -0
  44. {fancygit-1.0.24 → fancygit-1.0.26}/src/output_colorizer.py +0 -0
  45. {fancygit-1.0.24 → fancygit-1.0.26}/src/providers/__init__.py +0 -0
  46. {fancygit-1.0.24 → fancygit-1.0.26}/src/providers/anthropic_model.py +0 -0
  47. {fancygit-1.0.24 → fancygit-1.0.26}/src/providers/base_model.py +0 -0
  48. {fancygit-1.0.24 → fancygit-1.0.26}/src/providers/ollama_model.py +0 -0
  49. {fancygit-1.0.24 → fancygit-1.0.26}/src/providers/openai_model.py +0 -0
  50. {fancygit-1.0.24 → fancygit-1.0.26}/src/quiz_html_generator.py +0 -0
  51. {fancygit-1.0.24 → fancygit-1.0.26}/src/quiz_manager.py +0 -0
  52. {fancygit-1.0.24 → fancygit-1.0.26}/src/repo_inspector.py +0 -0
  53. {fancygit-1.0.24 → fancygit-1.0.26}/src/repo_state.py +0 -0
  54. {fancygit-1.0.24 → fancygit-1.0.26}/src/utils.py +0 -0
  55. {fancygit-1.0.24 → fancygit-1.0.26}/tests/__init__.py +0 -0
  56. {fancygit-1.0.24 → fancygit-1.0.26}/tests/conftest.py +0 -0
  57. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_ai_integration.py +0 -0
  58. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_config_manager.py +0 -0
  59. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_conflict_parser_integration.py +0 -0
  60. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_fancygit_advanced.py +0 -0
  61. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_fancygit_commands.py +0 -0
  62. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_fancygit_integration.py +0 -0
  63. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_fancygit_workflows.py +0 -0
  64. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_git_error.py +0 -0
  65. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_git_error_parser.py +0 -0
  66. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_git_runner.py +0 -0
  67. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_model_provider.py +0 -0
  68. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_ollama_model.py +0 -0
  69. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_providers.py +0 -0
  70. {fancygit-1.0.24 → fancygit-1.0.26}/tests/test_undo_redo.py +0 -0
  71. {fancygit-1.0.24 → fancygit-1.0.26}/welcome.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fancygit
3
- Version: 1.0.24
3
+ Version: 1.0.26
4
4
  Summary: A smart CLI tool that provides intelligent recommendations and helps solve merge conflicts
5
5
  Author: Youssif Ashmawy
6
6
  Author-email: ashmawyyoussif@gmail.com
@@ -0,0 +1 @@
1
+ 1.0.26
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fancygit
3
- Version: 1.0.24
3
+ Version: 1.0.26
4
4
  Summary: A smart CLI tool that provides intelligent recommendations and helps solve merge conflicts
5
5
  Author: Youssif Ashmawy
6
6
  Author-email: ashmawyyoussif@gmail.com
@@ -560,6 +560,19 @@ class FancyGit:
560
560
  print(f" Deps : {color_file(paths['deps_mmd'])}")
561
561
  print(f" HTML : {color_file(paths['html'])}")
562
562
 
563
+ # Add output directory to .gitignore if not already present
564
+ gitignore_path = os.path.join(os.getcwd(), '.gitignore')
565
+ output_dir_name = os.path.basename(os.path.abspath(output_dir))
566
+ gitignore_entry = f'{output_dir_name}/'
567
+ existing_lines = []
568
+ if os.path.exists(gitignore_path):
569
+ with open(gitignore_path, 'r', encoding='utf-8') as f:
570
+ existing_lines = f.read().splitlines()
571
+ if gitignore_entry not in existing_lines and output_dir_name not in existing_lines:
572
+ with open(gitignore_path, 'a', encoding='utf-8') as f:
573
+ f.write(f'\n{gitignore_entry}\n')
574
+ print(color_info(f"Added {gitignore_entry} to .gitignore"))
575
+
563
576
  if open_browser:
564
577
  # Convert to absolute path for browser
565
578
  html_path = os.path.abspath(paths['html'])
@@ -3,6 +3,7 @@ from src.model_provider import ModelProvider
3
3
  from src.providers.ollama_model import OllamaModel
4
4
  from src.config_manager import ConfigManager
5
5
  from typing import List, Dict, Optional
6
+ import re
6
7
  import time
7
8
 
8
9
  class AIEngine:
@@ -38,10 +39,25 @@ class AIEngine:
38
39
 
39
40
  try:
40
41
  response = self.analysis_provider._call_model(prompt)
41
- return response if response else "Unable to get AI analysis."
42
+ return self._strip_markdown(response) if response else "Unable to get AI analysis."
42
43
  except Exception as e:
43
44
  return f"Failed to get AI analysis: {str(e)}"
44
45
 
46
+ def _strip_markdown(self, text: str) -> str:
47
+ """Remove markdown formatting so output renders cleanly in a terminal."""
48
+ # Remove bold/italic: **text**, *text*, __text__, _text_
49
+ text = re.sub(r'\*{1,3}(.*?)\*{1,3}', r'\1', text)
50
+ text = re.sub(r'_{1,3}(.*?)_{1,3}', r'\1', text)
51
+ # Remove ATX headings: ## Heading → Heading
52
+ text = re.sub(r'^\s{0,3}#{1,6}\s+', '', text, flags=re.MULTILINE)
53
+ # Remove inline code: `code` → code
54
+ text = re.sub(r'`([^`]+)`', r'\1', text)
55
+ # Remove code fences
56
+ text = re.sub(r'```.*?```', '', text, flags=re.DOTALL)
57
+ # Collapse 3+ blank lines down to 2
58
+ text = re.sub(r'\n{3,}', '\n\n', text)
59
+ return text.strip()
60
+
45
61
  def explain_command(self, command: str) -> Optional[str]:
46
62
  """
47
63
  Explain a git command using the configured explanation provider.
@@ -76,24 +92,34 @@ class AIEngine:
76
92
 
77
93
  def _build_analysis_prompt(self, messages: List[Dict]) -> str:
78
94
  """Build the analysis prompt for the AI model"""
79
- prompt = """You are a Git expert assistant. Analyze the following Git error/warning messages and provide:
80
- 1. A clear summary of what went wrong
81
- 2. Step-by-step instructions on how to resolve the issue
82
- 3. Any preventive measures to avoid this in the future
95
+ prompt = """You are a Git expert assistant. Analyze the following Git error/warning messages.
83
96
 
84
- Keep your response concise, practical, and focused on solutions.
97
+ IMPORTANT FORMATTING RULES you MUST follow these exactly:
98
+ - Plain text only. No markdown. No asterisks, no hashes, no backticks, no bold, no headers.
99
+ - Use this exact structure with these exact labels on their own lines:
100
+
101
+ WHAT WENT WRONG:
102
+ [1-2 sentences explaining the root cause]
103
+
104
+ HOW TO FIX IT:
105
+ 1. [first step]
106
+ 2. [second step]
107
+ (add more steps only if truly needed)
108
+
109
+ TIP:
110
+ [one short preventive tip, or omit this section entirely if not useful]
111
+
112
+ Messages to analyze:
113
+ """
85
114
 
86
- Messages to analyze:
87
- """
88
-
89
115
  for i, msg in enumerate(messages, 1):
90
116
  severity = msg.get('severity', 'unknown').upper()
91
117
  message_text = msg.get('message', str(msg))
92
118
  error_type = msg.get('type', 'Unknown')
93
119
  file_info = f" (file: {msg.get('file', 'N/A')})" if msg.get('file') else ""
94
-
120
+
95
121
  prompt += f"\n{i}. [{severity}] {error_type}{file_info}\n {message_text}\n"
96
-
122
+
97
123
  prompt += "\n\nAnalysis:"
98
124
  return prompt
99
125
 
@@ -1063,6 +1063,14 @@ class MermaidExporter:
1063
1063
  """
1064
1064
  )
1065
1065
 
1066
+ def _diagram_has_content(self, mmd: str) -> bool:
1067
+ """Return True if the diagram has actual node/edge content (not just header and styling)."""
1068
+ for line in mmd.splitlines():
1069
+ stripped = line.strip()
1070
+ if stripped and not stripped.startswith('flowchart') and not stripped.startswith('classDef'):
1071
+ return True
1072
+ return False
1073
+
1066
1074
  def export_all(self, output_dir: str, repo_state: dict, max_commits: int = 15) -> dict:
1067
1075
  os.makedirs(output_dir, exist_ok=True)
1068
1076
 
@@ -1073,13 +1081,15 @@ class MermaidExporter:
1073
1081
  deps_mmd = self.python_import_dependency_flowchart(repo_root)
1074
1082
  tree_mmd = self.repo_file_structure_flowchart(repo_root)
1075
1083
 
1076
- diagrams = {
1084
+ all_diagrams = {
1077
1085
  'Repo Status': status_mmd,
1078
1086
  'Commit Graph': graph_mmd,
1079
1087
  'Python Import Dependencies': deps_mmd,
1080
1088
  'Repo File Structure': tree_mmd,
1081
1089
  }
1082
1090
 
1091
+ diagrams = {name: mmd for name, mmd in all_diagrams.items() if self._diagram_has_content(mmd)}
1092
+
1083
1093
  html = self.build_html(diagrams)
1084
1094
 
1085
1095
  status_path = os.path.join(output_dir, 'repo_status.mmd')
@@ -139,9 +139,8 @@ class TestAIEngine:
139
139
 
140
140
  # Check prompt structure
141
141
  assert "You are a Git expert assistant" in call_args
142
- assert "1. A clear summary of what went wrong" in call_args
143
- assert "2. Step-by-step instructions" in call_args
144
- assert "3. Any preventive measures" in call_args
142
+ assert "WHAT WENT WRONG:" in call_args
143
+ assert "HOW TO FIX IT:" in call_args
145
144
  assert "Messages to analyze:" in call_args
146
145
  assert "Analysis:" in call_args
147
146
 
fancygit-1.0.24/VERSION DELETED
@@ -1 +0,0 @@
1
- 1.0.24
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes