ace-git-copilot 0.3.5__tar.gz → 0.3.7__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 (127) hide show
  1. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/PKG-INFO +9 -1
  2. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/README.md +8 -0
  3. ace_git_copilot-0.3.7/ace/__init__.py +1 -0
  4. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/prompts/intent.py +3 -0
  5. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/core/context.py +25 -4
  6. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ui/display.py +7 -7
  7. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ui/prompts.py +1 -1
  8. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/pyproject.toml +1 -1
  9. ace_git_copilot-0.3.7/tests/test_merge_state.py +84 -0
  10. ace_git_copilot-0.3.5/ace/__init__.py +0 -1
  11. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/AGENTS.md +0 -0
  12. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/BRIEFING.md +0 -0
  13. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/ORIGINAL_REQUEST.md +0 -0
  14. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/e2e_testing_track/BRIEFING.md +0 -0
  15. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/e2e_testing_track/ORIGINAL_REQUEST.md +0 -0
  16. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/e2e_testing_track/SCOPE.md +0 -0
  17. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/e2e_testing_track/progress.md +0 -0
  18. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/BRIEFING.md +0 -0
  19. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/ORIGINAL_REQUEST.md +0 -0
  20. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/emojis_list.txt +0 -0
  21. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/find_unused_modules.py +0 -0
  22. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/handoff.md +0 -0
  23. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/measure_lazy_startup.py +0 -0
  24. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/measure_startup.py +0 -0
  25. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/profile_imports.py +0 -0
  26. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/progress.md +0 -0
  27. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/run_importtime.py +0 -0
  28. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/search_banner.py +0 -0
  29. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/search_emojis.py +0 -0
  30. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/search_git_usages.py +0 -0
  31. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/search_usages.py +0 -0
  32. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/test_import_profiler.py +0 -0
  33. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/explorer_init/test_mocked_sys.py +0 -0
  34. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/handoff.md +0 -0
  35. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/implementation_track/BRIEFING.md +0 -0
  36. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/implementation_track/ORIGINAL_REQUEST.md +0 -0
  37. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/implementation_track/explorer_initial_report.md +0 -0
  38. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/implementation_track/progress.md +0 -0
  39. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/orchestrator/.gitkeep +0 -0
  40. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/orchestrator/BRIEFING.md +0 -0
  41. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/orchestrator/ORIGINAL_REQUEST.md +0 -0
  42. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/orchestrator/PROJECT.md +0 -0
  43. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/orchestrator/progress.md +0 -0
  44. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/teamwork_preview_explorer_e2e_explore/BRIEFING.md +0 -0
  45. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/teamwork_preview_explorer_e2e_explore/ORIGINAL_REQUEST.md +0 -0
  46. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/teamwork_preview_explorer_e2e_explore/handoff.md +0 -0
  47. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/teamwork_preview_explorer_e2e_explore/progress.md +0 -0
  48. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/worker_e2e_testing/BRIEFING.md +0 -0
  49. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/worker_e2e_testing/ORIGINAL_REQUEST.md +0 -0
  50. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/worker_e2e_testing/progress.md +0 -0
  51. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/worker_m1_startup/BRIEFING.md +0 -0
  52. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/worker_m1_startup/ORIGINAL_REQUEST.md +0 -0
  53. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.agents/worker_m1_startup/progress.md +0 -0
  54. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.env.example +0 -0
  55. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.github/workflows/tests.yml +0 -0
  56. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/.gitignore +0 -0
  57. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/CODE_OF_CONDUCT.md +0 -0
  58. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/CONTRIBUTING.md +0 -0
  59. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/LICENSE +0 -0
  60. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/PROJECT.md +0 -0
  61. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/SECURITY.md +0 -0
  62. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/SUPPORT.md +0 -0
  63. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/TEST_INFRA.md +0 -0
  64. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/TEST_READY.md +0 -0
  65. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/__main__.py +0 -0
  66. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/changelog_generator.py +0 -0
  67. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/code_reviewer.py +0 -0
  68. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/commit_generator.py +0 -0
  69. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/conflict_resolver.py +0 -0
  70. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/gitignore_generator.py +0 -0
  71. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/history_analyzer.py +0 -0
  72. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/intent_parser.py +0 -0
  73. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/llm_factory.py +0 -0
  74. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/pr_drafter.py +0 -0
  75. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/prompts/changelog.py +0 -0
  76. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/prompts/commit.py +0 -0
  77. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/prompts/conflict.py +0 -0
  78. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/prompts/doctor.py +0 -0
  79. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/prompts/explain.py +0 -0
  80. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/prompts/ignore.py +0 -0
  81. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/prompts/pr.py +0 -0
  82. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/prompts/rebase.py +0 -0
  83. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/prompts/review.py +0 -0
  84. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/prompts/search.py +0 -0
  85. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/prompts/undo.py +0 -0
  86. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ai/rebase_helper.py +0 -0
  87. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/cli.py +0 -0
  88. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/core/config.py +0 -0
  89. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/core/diagnostics.py +0 -0
  90. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/core/git_ops.py +0 -0
  91. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/core/hooks.py +0 -0
  92. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/core/safety.py +0 -0
  93. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ui/banner.py +0 -0
  94. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ui/dashboard.py +0 -0
  95. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/ui/themes.py +0 -0
  96. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/utils/conflict_parser.py +0 -0
  97. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/utils/diff_parser.py +0 -0
  98. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/ace/utils/json_utils.py +0 -0
  99. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/conftest.py +0 -0
  100. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/e2e/conftest.py +0 -0
  101. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/e2e/test_tier1_features.py +0 -0
  102. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/e2e/test_tier2_boundaries.py +0 -0
  103. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/e2e/test_tier3_combinations.py +0 -0
  104. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/e2e/test_tier4_workloads.py +0 -0
  105. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_changelog_generator.py +0 -0
  106. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_code_reviewer.py +0 -0
  107. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_config_atomic_write.py +0 -0
  108. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_conflict_resolver.py +0 -0
  109. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_conflict_resolver_backup.py +0 -0
  110. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_context_gitdir_detection.py +0 -0
  111. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_diagnostics.py +0 -0
  112. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_diff_trimmer.py +0 -0
  113. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_git_ops.py +0 -0
  114. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_git_ops_execute.py +0 -0
  115. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_help.py +0 -0
  116. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_history_analyzer.py +0 -0
  117. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_hooks.py +0 -0
  118. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_ignore.py +0 -0
  119. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_intent_parser.py +0 -0
  120. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_llm_factory.py +0 -0
  121. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_llm_factory_ollama.py +0 -0
  122. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_pr_drafter.py +0 -0
  123. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_rebase_helper.py +0 -0
  124. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_safety.py +0 -0
  125. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_search.py +0 -0
  126. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_undo.py +0 -0
  127. {ace_git_copilot-0.3.5 → ace_git_copilot-0.3.7}/tests/test_workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ace-git-copilot
3
- Version: 0.3.5
3
+ Version: 0.3.7
4
4
  Summary: AI-powered Git copilot — talk to Git in plain English
5
5
  Project-URL: Homepage, https://github.com/jachinsamuel/Ace
6
6
  Project-URL: Documentation, https://github.com/jachinsamuel/Ace#readme
@@ -199,6 +199,14 @@ Distributed under the MIT License. See [LICENSE](LICENSE) for more details.
199
199
 
200
200
  ## Changelog
201
201
 
202
+ ### v0.3.7 — UI Status Icons Modernization (2026-07-14)
203
+ * Replaced clunky double-character ASCII status indicators (`>>`, `**`, `!!`, `EE`) with clean, modern Unicode status icons (`›`, `✔`, `⚠`, `✘`).
204
+ * Updated confirm prompts, severity warnings, and code review listings to use the new icons for a clean, consistent terminal interface.
205
+
206
+ ### v0.3.6 — Merge/Rebase Conflict Planning Fix (2026-07-12)
207
+ * Enhanced repository context builder to check for active unmerged files in the index, distinguishing between resolved and unresolved conflict states.
208
+ * Updated AI intent guidelines to prevent the planner from incorrectly suggesting `git merge --abort` when conflicts are already resolved and ready to be finalized.
209
+
202
210
  ### v0.3.5 — Empty Diff Handling (2026-07-11)
203
211
  * Improved warning panel message and title when committing empty files or mode changes to prevent confusing users when files are already staged.
204
212
 
@@ -166,6 +166,14 @@ Distributed under the MIT License. See [LICENSE](LICENSE) for more details.
166
166
 
167
167
  ## Changelog
168
168
 
169
+ ### v0.3.7 — UI Status Icons Modernization (2026-07-14)
170
+ * Replaced clunky double-character ASCII status indicators (`>>`, `**`, `!!`, `EE`) with clean, modern Unicode status icons (`›`, `✔`, `⚠`, `✘`).
171
+ * Updated confirm prompts, severity warnings, and code review listings to use the new icons for a clean, consistent terminal interface.
172
+
173
+ ### v0.3.6 — Merge/Rebase Conflict Planning Fix (2026-07-12)
174
+ * Enhanced repository context builder to check for active unmerged files in the index, distinguishing between resolved and unresolved conflict states.
175
+ * Updated AI intent guidelines to prevent the planner from incorrectly suggesting `git merge --abort` when conflicts are already resolved and ready to be finalized.
176
+
169
177
  ### v0.3.5 — Empty Diff Handling (2026-07-11)
170
178
  * Improved warning panel message and title when committing empty files or mode changes to prevent confusing users when files are already staged.
171
179
 
@@ -0,0 +1 @@
1
+ __version__ = "0.3.7"
@@ -26,6 +26,9 @@ You MUST return a JSON response containing exactly the following keys, and nothi
26
26
  - **moderate**: Standard modifications (commit, standard push, branch creation, switching branches, merge, rebase, stashing, soft/mixed reset).
27
27
  - **destructive**: Irreversible changes (hard reset, force push, git clean, force branch deletion).
28
28
  6. Always provide a safer alternative in `alternatives` if `risk_level` is moderate or destructive.
29
+ 7. If a merge, rebase, cherry-pick, or revert is in progress and the context indicates that conflicts are resolved (e.g., "Merge conflicts resolved. Ready to finalize merge."), do NOT abort the operation unless the user explicitly requests to abort. Instead, finalize/continue the operation:
30
+ - For a resolved merge, cherry-pick, or revert, use `git commit` or `ace commit` to finalize.
31
+ - For a resolved rebase, use `git rebase --continue` to continue.
29
32
 
30
33
  ### Examples:
31
34
 
@@ -75,22 +75,43 @@ class RepoContext:
75
75
  if not git_dir.exists():
76
76
  return state
77
77
 
78
+ # Check if index has unmerged (conflicted) files
79
+ has_conflicts = False
80
+ try:
81
+ unmerged = self.git_ops.repo.index.unmerged_files()
82
+ if unmerged:
83
+ has_conflicts = True
84
+ except Exception:
85
+ pass
86
+
78
87
  if (git_dir / "MERGE_HEAD").exists():
79
88
  state["in_progress"] = True
80
89
  state["type"] = "merge"
81
- state["detail"] = "Merge conflict/resolution in progress."
90
+ if has_conflicts:
91
+ state["detail"] = "Merge conflicts exist. Need resolution."
92
+ else:
93
+ state["detail"] = "Merge conflicts resolved. Ready to finalize merge."
82
94
  elif (git_dir / "rebase-merge").exists() or (git_dir / "rebase-apply").exists():
83
95
  state["in_progress"] = True
84
96
  state["type"] = "rebase"
85
- state["detail"] = "Rebase operation in progress."
97
+ if has_conflicts:
98
+ state["detail"] = "Rebase conflicts exist. Need resolution."
99
+ else:
100
+ state["detail"] = "Rebase conflicts resolved. Ready to continue rebase."
86
101
  elif (git_dir / "CHERRY_PICK_HEAD").exists():
87
102
  state["in_progress"] = True
88
103
  state["type"] = "cherry-pick"
89
- state["detail"] = "Cherry-pick operation in progress."
104
+ if has_conflicts:
105
+ state["detail"] = "Cherry-pick conflicts exist. Need resolution."
106
+ else:
107
+ state["detail"] = "Cherry-pick conflicts resolved. Ready to finalize cherry-pick."
90
108
  elif (git_dir / "REVERT_HEAD").exists():
91
109
  state["in_progress"] = True
92
110
  state["type"] = "revert"
93
- state["detail"] = "Revert operation in progress."
111
+ if has_conflicts:
112
+ state["detail"] = "Revert conflicts exist. Need resolution."
113
+ else:
114
+ state["detail"] = "Revert conflicts resolved. Ready to finalize revert."
94
115
 
95
116
  return state
96
117
 
@@ -10,10 +10,10 @@ console = Console(theme=get_rich_theme(), force_terminal=True)
10
10
  err_console = Console(theme=get_rich_theme(), force_terminal=True, stderr=True)
11
11
 
12
12
  # Status symbols — safe subset that renders in all modern Windows terminals
13
- _SYM_INFO = ">>" # informational
14
- _SYM_SUCCESS = "**" # success
15
- _SYM_WARNING = "!!" # warning
16
- _SYM_ERROR = "EE" # error
13
+ _SYM_INFO = "›" # informational
14
+ _SYM_SUCCESS = "✔" # success
15
+ _SYM_WARNING = "⚠" # warning
16
+ _SYM_ERROR = "✘" # error
17
17
 
18
18
 
19
19
  # ─── Inline status printers ──────────────────────────────────────────────────
@@ -277,9 +277,9 @@ def show_review(findings: List[Dict[str, Any]], score: float) -> None:
277
277
  return
278
278
 
279
279
  sev_sym = {
280
- "critical": ("EE", "bold #FF1744"),
281
- "warning": ("!!", "bold #FFD600"),
282
- "info": (">>", "bold #00D5FF"),
280
+ "critical": ("✘", "bold #FF1744"),
281
+ "warning": ("⚠", "bold #FFD600"),
282
+ "info": ("›", "bold #00D5FF"),
283
283
  }
284
284
 
285
285
  for item in findings:
@@ -13,7 +13,7 @@ def confirm(question: str, default: bool = True) -> bool:
13
13
  hint = "[Y/n]" if default else "[y/N]"
14
14
  console.print(
15
15
  Text.assemble(
16
- (" >> ", "bold #00D5FF"),
16
+ (" › ", "bold #00D5FF"),
17
17
  (question + " ", "bold white"),
18
18
  (hint, "bold #666666"),
19
19
  (" ", ""),
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ace-git-copilot"
3
- version = "0.3.5"
3
+ version = "0.3.7"
4
4
  description = "AI-powered Git copilot — talk to Git in plain English"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -0,0 +1,84 @@
1
+ import pytest
2
+ from unittest.mock import patch, MagicMock
3
+ from pathlib import Path
4
+ from ace.core.context import RepoContext
5
+ from ace.core.git_ops import GitOps
6
+
7
+ @pytest.fixture
8
+ def mock_git_ops():
9
+ git_ops = MagicMock(spec=GitOps)
10
+ git_ops.working_dir = "/mock/repo"
11
+ mock_repo = MagicMock()
12
+ mock_repo.git_dir = "/mock/repo/.git"
13
+ git_ops.repo = mock_repo
14
+ return git_ops
15
+
16
+ @patch("pathlib.Path.exists", autospec=True)
17
+ def test_no_active_operation(mock_exists, mock_git_ops):
18
+ mock_exists.return_value = False
19
+ context = RepoContext(mock_git_ops)
20
+ state = context.check_merge_rebase_state()
21
+
22
+ assert state["in_progress"] is False
23
+ assert state["type"] is None
24
+ assert state["detail"] == ""
25
+
26
+ @patch("pathlib.Path.exists", autospec=True)
27
+ def test_merge_active_unresolved(mock_exists, mock_git_ops):
28
+ mock_exists.return_value = True
29
+ mock_git_ops.repo.index.unmerged_files.return_value = {"file1.txt": [None]}
30
+
31
+ context = RepoContext(mock_git_ops)
32
+ state = context.check_merge_rebase_state()
33
+
34
+ assert state["in_progress"] is True
35
+ assert state["type"] == "merge"
36
+ assert "Need resolution" in state["detail"]
37
+
38
+ @patch("pathlib.Path.exists", autospec=True)
39
+ def test_merge_active_resolved(mock_exists, mock_git_ops):
40
+ mock_exists.return_value = True
41
+ mock_git_ops.repo.index.unmerged_files.return_value = {}
42
+
43
+ context = RepoContext(mock_git_ops)
44
+ state = context.check_merge_rebase_state()
45
+
46
+ assert state["in_progress"] is True
47
+ assert state["type"] == "merge"
48
+ assert "resolved" in state["detail"]
49
+ assert "finalize merge" in state["detail"]
50
+
51
+ @patch("pathlib.Path.exists", autospec=True)
52
+ def test_rebase_active_unresolved(mock_exists, mock_git_ops):
53
+ def exists_check(path_obj):
54
+ if path_obj.name == "MERGE_HEAD":
55
+ return False
56
+ return True
57
+
58
+ mock_exists.side_effect = exists_check
59
+ mock_git_ops.repo.index.unmerged_files.return_value = {"file2.txt": [None]}
60
+
61
+ context = RepoContext(mock_git_ops)
62
+ state = context.check_merge_rebase_state()
63
+
64
+ assert state["in_progress"] is True
65
+ assert state["type"] == "rebase"
66
+ assert "Need resolution" in state["detail"]
67
+
68
+ @patch("pathlib.Path.exists", autospec=True)
69
+ def test_rebase_active_resolved(mock_exists, mock_git_ops):
70
+ def exists_check(path_obj):
71
+ if path_obj.name == "MERGE_HEAD":
72
+ return False
73
+ return True
74
+
75
+ mock_exists.side_effect = exists_check
76
+ mock_git_ops.repo.index.unmerged_files.return_value = {}
77
+
78
+ context = RepoContext(mock_git_ops)
79
+ state = context.check_merge_rebase_state()
80
+
81
+ assert state["in_progress"] is True
82
+ assert state["type"] == "rebase"
83
+ assert "resolved" in state["detail"]
84
+ assert "continue rebase" in state["detail"]
@@ -1 +0,0 @@
1
- __version__ = "0.3.5"
File without changes