ace-git-copilot 0.3.8__tar.gz → 0.4.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 (133) hide show
  1. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/PKG-INFO +9 -66
  2. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/README.md +8 -65
  3. ace_git_copilot-0.4.0/ace/__init__.py +1 -0
  4. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/history_analyzer.py +59 -0
  5. ace_git_copilot-0.4.0/ace/ai/prompts/blame.py +34 -0
  6. ace_git_copilot-0.4.0/ace/ai/prompts/standup.py +19 -0
  7. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/cli.py +144 -0
  8. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/pyproject.toml +1 -1
  9. ace_git_copilot-0.4.0/tests/test_blame.py +31 -0
  10. ace_git_copilot-0.4.0/tests/test_standup.py +28 -0
  11. ace_git_copilot-0.3.8/ace/__init__.py +0 -1
  12. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/AGENTS.md +0 -0
  13. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/BRIEFING.md +0 -0
  14. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/ORIGINAL_REQUEST.md +0 -0
  15. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/e2e_testing_track/BRIEFING.md +0 -0
  16. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/e2e_testing_track/ORIGINAL_REQUEST.md +0 -0
  17. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/e2e_testing_track/SCOPE.md +0 -0
  18. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/e2e_testing_track/progress.md +0 -0
  19. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/BRIEFING.md +0 -0
  20. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/ORIGINAL_REQUEST.md +0 -0
  21. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/emojis_list.txt +0 -0
  22. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/find_unused_modules.py +0 -0
  23. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/handoff.md +0 -0
  24. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/measure_lazy_startup.py +0 -0
  25. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/measure_startup.py +0 -0
  26. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/profile_imports.py +0 -0
  27. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/progress.md +0 -0
  28. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/run_importtime.py +0 -0
  29. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/search_banner.py +0 -0
  30. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/search_emojis.py +0 -0
  31. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/search_git_usages.py +0 -0
  32. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/search_usages.py +0 -0
  33. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/test_import_profiler.py +0 -0
  34. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/test_mocked_sys.py +0 -0
  35. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/handoff.md +0 -0
  36. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/implementation_track/BRIEFING.md +0 -0
  37. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/implementation_track/ORIGINAL_REQUEST.md +0 -0
  38. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/implementation_track/explorer_initial_report.md +0 -0
  39. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/implementation_track/progress.md +0 -0
  40. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/orchestrator/.gitkeep +0 -0
  41. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/orchestrator/BRIEFING.md +0 -0
  42. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/orchestrator/ORIGINAL_REQUEST.md +0 -0
  43. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/orchestrator/PROJECT.md +0 -0
  44. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/orchestrator/progress.md +0 -0
  45. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/teamwork_preview_explorer_e2e_explore/BRIEFING.md +0 -0
  46. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/teamwork_preview_explorer_e2e_explore/ORIGINAL_REQUEST.md +0 -0
  47. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/teamwork_preview_explorer_e2e_explore/handoff.md +0 -0
  48. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/teamwork_preview_explorer_e2e_explore/progress.md +0 -0
  49. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_e2e_testing/BRIEFING.md +0 -0
  50. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_e2e_testing/ORIGINAL_REQUEST.md +0 -0
  51. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_e2e_testing/progress.md +0 -0
  52. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_m1_startup/BRIEFING.md +0 -0
  53. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_m1_startup/ORIGINAL_REQUEST.md +0 -0
  54. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_m1_startup/progress.md +0 -0
  55. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.env.example +0 -0
  56. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.github/workflows/tests.yml +0 -0
  57. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.gitignore +0 -0
  58. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/CODE_OF_CONDUCT.md +0 -0
  59. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/CONTRIBUTING.md +0 -0
  60. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/LICENSE +0 -0
  61. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/PROJECT.md +0 -0
  62. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/SECURITY.md +0 -0
  63. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/SUPPORT.md +0 -0
  64. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/TEST_INFRA.md +0 -0
  65. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/TEST_READY.md +0 -0
  66. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/__main__.py +0 -0
  67. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/changelog_generator.py +0 -0
  68. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/code_reviewer.py +0 -0
  69. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/commit_generator.py +0 -0
  70. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/conflict_resolver.py +0 -0
  71. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/gitignore_generator.py +0 -0
  72. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/intent_parser.py +0 -0
  73. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/llm_factory.py +0 -0
  74. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/pr_drafter.py +0 -0
  75. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/changelog.py +0 -0
  76. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/commit.py +0 -0
  77. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/conflict.py +0 -0
  78. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/doctor.py +0 -0
  79. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/explain.py +0 -0
  80. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/ignore.py +0 -0
  81. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/intent.py +0 -0
  82. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/pr.py +0 -0
  83. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/rebase.py +0 -0
  84. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/review.py +0 -0
  85. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/search.py +0 -0
  86. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/undo.py +0 -0
  87. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/rebase_helper.py +0 -0
  88. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/core/config.py +0 -0
  89. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/core/context.py +0 -0
  90. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/core/diagnostics.py +0 -0
  91. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/core/git_ops.py +0 -0
  92. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/core/hooks.py +0 -0
  93. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/core/safety.py +0 -0
  94. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ui/banner.py +0 -0
  95. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ui/dashboard.py +0 -0
  96. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ui/display.py +0 -0
  97. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ui/prompts.py +0 -0
  98. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ui/themes.py +0 -0
  99. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/utils/conflict_parser.py +0 -0
  100. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/utils/diff_parser.py +0 -0
  101. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/utils/json_utils.py +0 -0
  102. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/utils/string_utils.py +0 -0
  103. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/conftest.py +0 -0
  104. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/e2e/conftest.py +0 -0
  105. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/e2e/test_tier1_features.py +0 -0
  106. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/e2e/test_tier2_boundaries.py +0 -0
  107. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/e2e/test_tier3_combinations.py +0 -0
  108. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/e2e/test_tier4_workloads.py +0 -0
  109. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_changelog_generator.py +0 -0
  110. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_code_reviewer.py +0 -0
  111. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_config_atomic_write.py +0 -0
  112. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_conflict_resolver.py +0 -0
  113. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_conflict_resolver_backup.py +0 -0
  114. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_context_gitdir_detection.py +0 -0
  115. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_diagnostics.py +0 -0
  116. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_diff_trimmer.py +0 -0
  117. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_git_ops.py +0 -0
  118. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_git_ops_execute.py +0 -0
  119. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_help.py +0 -0
  120. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_history_analyzer.py +0 -0
  121. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_hooks.py +0 -0
  122. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_ignore.py +0 -0
  123. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_intent_parser.py +0 -0
  124. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_llm_factory.py +0 -0
  125. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_llm_factory_ollama.py +0 -0
  126. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_merge_state.py +0 -0
  127. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_pr_drafter.py +0 -0
  128. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_rebase_helper.py +0 -0
  129. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_safety.py +0 -0
  130. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_search.py +0 -0
  131. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_string_utils.py +0 -0
  132. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_undo.py +0 -0
  133. {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/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.8
3
+ Version: 0.4.0
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
@@ -143,12 +143,14 @@ Allows using any custom endpoint that supports the OpenAI API schema (e.g. Groq,
143
143
  ## Usage
144
144
 
145
145
  ### Natural Language Mode
146
- Run natural language requests directly in quotes:
146
+
147
+ You can speak to Git in plain English. There is no need to use double quotes — simply write your request directly:
147
148
  ```bash
148
- ace "stage everything and commit with a message about authentication"
149
- ace "undo my last commit but keep the files"
150
- ace "switch to a new branch called design-updates"
149
+ ace stage everything and commit with a message about authentication
150
+ ace undo my last commit but keep the files
151
+ ace switch to a new branch called design-updates
151
152
  ```
153
+ *(Double quotes are optional, e.g. `ace "stage everything and commit"`).*
152
154
 
153
155
  ### Command-Line Toolchain
154
156
  Ace has dedicated subcommands for specific tasks. Here is the complete command list:
@@ -165,6 +167,8 @@ Ace has dedicated subcommands for specific tasks. Here is the complete command l
165
167
  | `ace hook <action>` | — | Install or uninstall pre-commit and prepare-commit-msg Git hooks. |
166
168
  | `ace stats` | — | Rich visualization of repo statistics, extension breakdowns, and history. |
167
169
  | `ace changelog` | — | Compile release changelogs since the last tag. |
170
+ | `ace standup` | — | Generate a professional daily standup update based on your recent commits. |
171
+ | `ace blame <file> <line>` | — | AI-powered Git blame: analyze who wrote a line and explain WHY they wrote it. |
168
172
  | `ace pr` | — | Draft a Markdown pull request title and description. |
169
173
  | `ace search <query>` | — | Semantically search commit history with interactive checkout options. |
170
174
  | `ace squash` | — | Automatically analyze commit history and run AI-guided interactive rebases. |
@@ -194,64 +198,3 @@ The dashboard features:
194
198
  ## License
195
199
 
196
200
  Distributed under the MIT License. See [LICENSE](LICENSE) for more details.
197
-
198
- ---
199
-
200
- ## Changelog
201
-
202
- ### v0.3.8 — Emoji Stripping from Git History (2026-07-14)
203
- * Implemented automatic Unicode emoji stripping for all Git commit messages retrieved via `GitOps.get_log`.
204
- * Ensured history query summaries, rebase lists, and dashboard commit tables are completely clean and emoji-free.
205
-
206
- ### v0.3.7 — UI Status Icons Modernization (2026-07-14)
207
- * Replaced clunky double-character ASCII status indicators (`>>`, `**`, `!!`, `EE`) with clean, modern Unicode status icons (`›`, `✔`, `⚠`, `✘`).
208
- * Updated confirm prompts, severity warnings, and code review listings to use the new icons for a clean, consistent terminal interface.
209
-
210
- ### v0.3.6 — Merge/Rebase Conflict Planning Fix (2026-07-12)
211
- * Enhanced repository context builder to check for active unmerged files in the index, distinguishing between resolved and unresolved conflict states.
212
- * Updated AI intent guidelines to prevent the planner from incorrectly suggesting `git merge --abort` when conflicts are already resolved and ready to be finalized.
213
-
214
- ### v0.3.5 — Empty Diff Handling (2026-07-11)
215
- * Improved warning panel message and title when committing empty files or mode changes to prevent confusing users when files are already staged.
216
-
217
- ### v0.3.4 — Workspace Management (2026-07-11)
218
- * Added new `workspace` command (alias `ws`) to scan, monitor, and navigate multiple repositories.
219
- * Shows active branch, staged/unstaged/untracked file counts, and local upstream sync offsets in a Rich Table.
220
- * Supports interactive actions to open the TUI dashboard, spawn a nested shell, or run copy-paste commands inside any chosen repository.
221
-
222
- ### v0.3.3 — Stability & Resilience (2026-07-04)
223
- * Implemented streaming progress and download percentages for Ollama model pulls to prevent thread hangs.
224
- * Added atomic file saves and rollback backups for merge conflict resolutions and config modifications to prevent data corruption.
225
- * Fixed merge/rebase detection in git worktrees and submodules by resolving the authoritative `git_dir` dynamically.
226
- * Added `shlex` command splitting to safely parse and execute quoted arguments in Git commands.
227
- * Created python module entry point (`python -m ace`) for nested execution support.
228
-
229
- ### v0.3.2 — Windows Compatibility & E2E Fixes (2026-07-01)
230
- * Resolved Windows-specific UTF-8 encoding issues in E2E tests and log parsers.
231
- * Fixed subprocess natural language command execution paths to execute nested ace commands through Python interpreter contexts.
232
- * Refactored CLI error panel formatting to match expected exception names.
233
-
234
- ### v0.3.1 — Patch (2026-06-30)
235
- * Fixed invisible key labels (`[c]`, `[r]`, etc.) in the dashboard and search menus caused by Rich markup tag conflicts.
236
- * Fixed `[Y/n]` confirmation prompt rendering invisibly.
237
-
238
- ### v0.3.0 — UI Polish (2026-06-30)
239
- * Rewrote all UI output modules (`display.py`, `prompts.py`, `dashboard.py`, `themes.py`) for a polished, professional look.
240
- * Removed all unprofessional emojis; replaced with clean ASCII status symbols (`>>`, `**`, `!!`, `EE`).
241
- * Dashboard panels now use consistent `ROUNDED` borders, colour-coded file lists (`+` staged, `~` unstaged, `?` untracked), and a styled commit history table.
242
- * Execution plan table uses `SIMPLE_HEAD` style with colour-highlighted `git` and `ace` command prefixes.
243
- * Commit message panel shows character count badge coloured green/amber/red relative to the 72-char limit.
244
- * AI code review score rendered as a styled badge based on score range.
245
- * Added `[tool.ruff]` configuration to exclude `.agents/` scratch folder from lint checks.
246
-
247
- ### v0.2.9 — Metadata & Build Fix (2026-06-30)
248
- * Fixed broken `pyproject.toml` TOML syntax (invalid inline `urls` table).
249
- * Added full `authors` and `[project.urls]` metadata visible on PyPI.
250
-
251
- ### v0.2.6 — Startup Optimisation (2026-06-21)
252
- * Implemented lazy-loading for all heavy LangChain imports — CLI startup under 200 ms.
253
- * Added `ace switch` command for switching between sibling repositories from the dashboard.
254
-
255
- ### v0.2.3 — Feature Expansion (2026-06-09)
256
- * Added `ace doctor`, `ace hook`, and `ace squash` commands.
257
- * Comprehensive E2E test suite added under `tests/e2e/`.
@@ -110,12 +110,14 @@ Allows using any custom endpoint that supports the OpenAI API schema (e.g. Groq,
110
110
  ## Usage
111
111
 
112
112
  ### Natural Language Mode
113
- Run natural language requests directly in quotes:
113
+
114
+ You can speak to Git in plain English. There is no need to use double quotes — simply write your request directly:
114
115
  ```bash
115
- ace "stage everything and commit with a message about authentication"
116
- ace "undo my last commit but keep the files"
117
- ace "switch to a new branch called design-updates"
116
+ ace stage everything and commit with a message about authentication
117
+ ace undo my last commit but keep the files
118
+ ace switch to a new branch called design-updates
118
119
  ```
120
+ *(Double quotes are optional, e.g. `ace "stage everything and commit"`).*
119
121
 
120
122
  ### Command-Line Toolchain
121
123
  Ace has dedicated subcommands for specific tasks. Here is the complete command list:
@@ -132,6 +134,8 @@ Ace has dedicated subcommands for specific tasks. Here is the complete command l
132
134
  | `ace hook <action>` | — | Install or uninstall pre-commit and prepare-commit-msg Git hooks. |
133
135
  | `ace stats` | — | Rich visualization of repo statistics, extension breakdowns, and history. |
134
136
  | `ace changelog` | — | Compile release changelogs since the last tag. |
137
+ | `ace standup` | — | Generate a professional daily standup update based on your recent commits. |
138
+ | `ace blame <file> <line>` | — | AI-powered Git blame: analyze who wrote a line and explain WHY they wrote it. |
135
139
  | `ace pr` | — | Draft a Markdown pull request title and description. |
136
140
  | `ace search <query>` | — | Semantically search commit history with interactive checkout options. |
137
141
  | `ace squash` | — | Automatically analyze commit history and run AI-guided interactive rebases. |
@@ -161,64 +165,3 @@ The dashboard features:
161
165
  ## License
162
166
 
163
167
  Distributed under the MIT License. See [LICENSE](LICENSE) for more details.
164
-
165
- ---
166
-
167
- ## Changelog
168
-
169
- ### v0.3.8 — Emoji Stripping from Git History (2026-07-14)
170
- * Implemented automatic Unicode emoji stripping for all Git commit messages retrieved via `GitOps.get_log`.
171
- * Ensured history query summaries, rebase lists, and dashboard commit tables are completely clean and emoji-free.
172
-
173
- ### v0.3.7 — UI Status Icons Modernization (2026-07-14)
174
- * Replaced clunky double-character ASCII status indicators (`>>`, `**`, `!!`, `EE`) with clean, modern Unicode status icons (`›`, `✔`, `⚠`, `✘`).
175
- * Updated confirm prompts, severity warnings, and code review listings to use the new icons for a clean, consistent terminal interface.
176
-
177
- ### v0.3.6 — Merge/Rebase Conflict Planning Fix (2026-07-12)
178
- * Enhanced repository context builder to check for active unmerged files in the index, distinguishing between resolved and unresolved conflict states.
179
- * Updated AI intent guidelines to prevent the planner from incorrectly suggesting `git merge --abort` when conflicts are already resolved and ready to be finalized.
180
-
181
- ### v0.3.5 — Empty Diff Handling (2026-07-11)
182
- * Improved warning panel message and title when committing empty files or mode changes to prevent confusing users when files are already staged.
183
-
184
- ### v0.3.4 — Workspace Management (2026-07-11)
185
- * Added new `workspace` command (alias `ws`) to scan, monitor, and navigate multiple repositories.
186
- * Shows active branch, staged/unstaged/untracked file counts, and local upstream sync offsets in a Rich Table.
187
- * Supports interactive actions to open the TUI dashboard, spawn a nested shell, or run copy-paste commands inside any chosen repository.
188
-
189
- ### v0.3.3 — Stability & Resilience (2026-07-04)
190
- * Implemented streaming progress and download percentages for Ollama model pulls to prevent thread hangs.
191
- * Added atomic file saves and rollback backups for merge conflict resolutions and config modifications to prevent data corruption.
192
- * Fixed merge/rebase detection in git worktrees and submodules by resolving the authoritative `git_dir` dynamically.
193
- * Added `shlex` command splitting to safely parse and execute quoted arguments in Git commands.
194
- * Created python module entry point (`python -m ace`) for nested execution support.
195
-
196
- ### v0.3.2 — Windows Compatibility & E2E Fixes (2026-07-01)
197
- * Resolved Windows-specific UTF-8 encoding issues in E2E tests and log parsers.
198
- * Fixed subprocess natural language command execution paths to execute nested ace commands through Python interpreter contexts.
199
- * Refactored CLI error panel formatting to match expected exception names.
200
-
201
- ### v0.3.1 — Patch (2026-06-30)
202
- * Fixed invisible key labels (`[c]`, `[r]`, etc.) in the dashboard and search menus caused by Rich markup tag conflicts.
203
- * Fixed `[Y/n]` confirmation prompt rendering invisibly.
204
-
205
- ### v0.3.0 — UI Polish (2026-06-30)
206
- * Rewrote all UI output modules (`display.py`, `prompts.py`, `dashboard.py`, `themes.py`) for a polished, professional look.
207
- * Removed all unprofessional emojis; replaced with clean ASCII status symbols (`>>`, `**`, `!!`, `EE`).
208
- * Dashboard panels now use consistent `ROUNDED` borders, colour-coded file lists (`+` staged, `~` unstaged, `?` untracked), and a styled commit history table.
209
- * Execution plan table uses `SIMPLE_HEAD` style with colour-highlighted `git` and `ace` command prefixes.
210
- * Commit message panel shows character count badge coloured green/amber/red relative to the 72-char limit.
211
- * AI code review score rendered as a styled badge based on score range.
212
- * Added `[tool.ruff]` configuration to exclude `.agents/` scratch folder from lint checks.
213
-
214
- ### v0.2.9 — Metadata & Build Fix (2026-06-30)
215
- * Fixed broken `pyproject.toml` TOML syntax (invalid inline `urls` table).
216
- * Added full `authors` and `[project.urls]` metadata visible on PyPI.
217
-
218
- ### v0.2.6 — Startup Optimisation (2026-06-21)
219
- * Implemented lazy-loading for all heavy LangChain imports — CLI startup under 200 ms.
220
- * Added `ace switch` command for switching between sibling repositories from the dashboard.
221
-
222
- ### v0.2.3 — Feature Expansion (2026-06-09)
223
- * Added `ace doctor`, `ace hook`, and `ace squash` commands.
224
- * Comprehensive E2E test suite added under `tests/e2e/`.
@@ -0,0 +1 @@
1
+ __version__ = "0.4.0"
@@ -187,3 +187,62 @@ class HistoryAnalyzer:
187
187
  response = llm.invoke(messages)
188
188
  return extract_json(response.content)
189
189
 
190
+ def generate_standup(self, commits: list, offline: bool = False) -> str:
191
+ """
192
+ Analyze recent commits and generate a daily standup markdown report.
193
+ """
194
+ if not commits:
195
+ return "No recent commits found to generate a standup from."
196
+
197
+ commit_lines = []
198
+ for c in commits:
199
+ commit_lines.append(f"- {c['hexsha'][:7]} - {c['summary']} (by {c['author']})")
200
+ commit_list_text = "\n".join(commit_lines)
201
+
202
+ from ace.ai.prompts.standup import STANDUP_SYSTEM_PROMPT, USER_PROMPT_TEMPLATE
203
+ llm = get_llm(offline_override=offline)
204
+
205
+ usr_prompt = USER_PROMPT_TEMPLATE.format(commit_list_text=commit_list_text)
206
+ messages = [
207
+ SystemMessage(content=STANDUP_SYSTEM_PROMPT),
208
+ HumanMessage(content=usr_prompt)
209
+ ]
210
+
211
+ response = llm.invoke(messages)
212
+ return response.content.strip()
213
+
214
+ def analyze_blame(
215
+ self,
216
+ file: str,
217
+ line: int,
218
+ commit_info: dict,
219
+ commit_show_output: str,
220
+ line_content: str,
221
+ offline: bool = False
222
+ ) -> str:
223
+ """
224
+ Analyze why a specific line was written using LLM and commit patch info.
225
+ """
226
+ from ace.ai.prompts.blame import BLAME_SYSTEM_PROMPT, USER_PROMPT_TEMPLATE
227
+ llm = get_llm(offline_override=offline)
228
+
229
+ usr_prompt = USER_PROMPT_TEMPLATE.format(
230
+ file=file,
231
+ line=line,
232
+ line_content=line_content,
233
+ commit_hash=commit_info.get("hexsha", ""),
234
+ author=commit_info.get("author", ""),
235
+ date=commit_info.get("date", ""),
236
+ summary=commit_info.get("summary", ""),
237
+ message=commit_info.get("message", ""),
238
+ patch=commit_show_output[:15000]
239
+ )
240
+
241
+ messages = [
242
+ SystemMessage(content=BLAME_SYSTEM_PROMPT),
243
+ HumanMessage(content=usr_prompt)
244
+ ]
245
+
246
+ response = llm.invoke(messages)
247
+ return response.content.strip()
248
+
@@ -0,0 +1,34 @@
1
+ BLAME_SYSTEM_PROMPT = """You are "Ace", the AI Git Copilot.
2
+ Your task is to analyze why a specific line of code was introduced by looking at the line content, file path, commit summary, message, and the commit's diff patch.
3
+
4
+ Provide a concise, professional explanation formatted in Markdown. Do NOT use emojis.
5
+ Structure the response as follows:
6
+
7
+ ### Summary
8
+ - **Author**: [Author Name]
9
+ - **Date**: [Commit Date]
10
+ - **Commit**: [Commit Hash - Commit Summary]
11
+
12
+ ### Why this line was written
13
+ [Analyze the patch/diff and commit message. Explain in plain English the intent and logic behind adding or modifying this line. Highlight what problem it solved.]
14
+
15
+ ### Potential Risks / Side Effects
16
+ [Briefly assess if modifying this line has potential risks, or if it is a standard/safe utility.]
17
+ """.strip()
18
+
19
+ USER_PROMPT_TEMPLATE = """File Path: {file}
20
+ Line Number: {line}
21
+ Line Content: "{line_content}"
22
+
23
+ Commit Details:
24
+ - Commit Hash: {commit_hash}
25
+ - Author: {author}
26
+ - Date: {date}
27
+ - Summary: {summary}
28
+ - Message: {message}
29
+
30
+ Commit Diff Patch (around the target line):
31
+ \"\"\"
32
+ {patch}
33
+ \"\"\"
34
+ """.strip()
@@ -0,0 +1,19 @@
1
+ STANDUP_SYSTEM_PROMPT = """You are "Ace", the AI Git Copilot.
2
+ Your task is to analyze the provided list of Git commits from the user's recent work period and generate a professional, clear daily standup update.
3
+
4
+ Format your output exactly as follows (using clean markdown bullet points, and do NOT use emojis):
5
+
6
+ **Yesterday / Recent Work:**
7
+ - [Summarize the key achievements from the commits in a clear, professional way]
8
+ - [Group related commits together under a single point if applicable]
9
+
10
+ **Today / Planned Work:**
11
+ - [Suggest logical next steps based on the commits, or add a placeholder: "Continue development based on recent work"]
12
+
13
+ **Blockers:**
14
+ - None
15
+ """.strip()
16
+
17
+ USER_PROMPT_TEMPLATE = """Commits in this work period:
18
+ {commit_list_text}
19
+ """.strip()
@@ -1887,6 +1887,150 @@ def ws_cmd(
1887
1887
  ):
1888
1888
  workspace_cmd(path)
1889
1889
 
1890
+ @app.command(name="standup", help="Generate a professional daily standup update based on your recent commits.")
1891
+ def standup_cmd(
1892
+ days: int = typer.Option(1, "--days", "-d", help="Number of days of history to scan"),
1893
+ all_authors: bool = typer.Option(False, "--all", "-a", help="Include commits from all authors (defaults to current user only)"),
1894
+ offline: bool = typer.Option(False, "--offline", help="Force Ollama offline mode"),
1895
+ ):
1896
+ from ace.core.git_ops import GitOps, NotAGitRepositoryError
1897
+ from ace.ai.llm_factory import get_llm
1898
+ from ace.ai.history_analyzer import HistoryAnalyzer
1899
+ from rich.markdown import Markdown
1900
+ from rich.panel import Panel
1901
+
1902
+ try:
1903
+ git_ops = GitOps()
1904
+ except NotAGitRepositoryError as e:
1905
+ show_error_panel(str(e), "Git Error")
1906
+ raise typer.Exit(code=1)
1907
+
1908
+ # 1. Resolve author filter
1909
+ author_name = None
1910
+ if not all_authors:
1911
+ try:
1912
+ author_name = git_ops.repo.git.config("user.name")
1913
+ except Exception:
1914
+ pass
1915
+
1916
+ # 2. Get recent commits
1917
+ since_arg = f"{days} days ago"
1918
+ commits = git_ops.get_log(since=since_arg, author=author_name)
1919
+
1920
+ if not commits:
1921
+ author_msg = "your" if not all_authors else "any"
1922
+ print_warning(f"No recent commits found from {author_msg} author in the last {days} day(s).")
1923
+ raise typer.Exit(code=0)
1924
+
1925
+ analyzer = HistoryAnalyzer(git_ops)
1926
+
1927
+ try:
1928
+ get_llm(offline_override=offline)
1929
+ with spinner(f"Analyzing {len(commits)} commits and generating standup..."):
1930
+ standup_report = analyzer.generate_standup(commits, offline=offline)
1931
+ except Exception as e:
1932
+ show_error_panel(f"Failed to generate standup: {e}", "AI Error")
1933
+ raise typer.Exit(code=1)
1934
+
1935
+ console.print()
1936
+ console.print(Panel(
1937
+ Markdown(standup_report),
1938
+ title="[bold green]AI Daily Standup Report[/bold green]",
1939
+ border_style="#00E676",
1940
+ padding=(1, 2)
1941
+ ))
1942
+ console.print()
1943
+
1944
+ @app.command(name="blame", help="AI-powered Git blame: analyze who wrote a line, when, and explain WHY they wrote it.")
1945
+ def blame_cmd(
1946
+ file: str = typer.Argument(..., help="Path to the file to inspect"),
1947
+ line: int = typer.Argument(..., help="Line number to inspect"),
1948
+ offline: bool = typer.Option(False, "--offline", help="Force Ollama offline mode"),
1949
+ ):
1950
+ from ace.core.git_ops import GitOps, NotAGitRepositoryError
1951
+ from ace.ai.llm_factory import get_llm
1952
+ from ace.ai.history_analyzer import HistoryAnalyzer
1953
+ from rich.markdown import Markdown
1954
+ from rich.panel import Panel
1955
+ import pathlib
1956
+
1957
+ try:
1958
+ git_ops = GitOps()
1959
+ except NotAGitRepositoryError as e:
1960
+ show_error_panel(str(e), "Git Error")
1961
+ raise typer.Exit(code=1)
1962
+
1963
+ # 1. Resolve path and verify it exists
1964
+ filepath = pathlib.Path(file)
1965
+ if not filepath.exists() or not filepath.is_file():
1966
+ show_error_panel(f"File '{file}' does not exist or is not a regular file.", "Input Error")
1967
+ raise typer.Exit(code=1)
1968
+
1969
+ # 2. Retrieve the line content
1970
+ try:
1971
+ file_lines = filepath.read_text(encoding="utf-8", errors="replace").splitlines()
1972
+ if line < 1 or line > len(file_lines):
1973
+ show_error_panel(f"Line number {line} is out of bounds for '{file}' (total lines: {len(file_lines)}).", "Input Error")
1974
+ raise typer.Exit(code=1)
1975
+ line_content = file_lines[line - 1].strip()
1976
+ except Exception as e:
1977
+ show_error_panel(f"Failed to read file: {e}", "Read Error")
1978
+ raise typer.Exit(code=1)
1979
+
1980
+ # 3. Run git blame for this line
1981
+ try:
1982
+ blame_output = git_ops.execute(f"blame -L {line},{line} -- {file}")
1983
+ parts = blame_output.strip().split()
1984
+ if not parts:
1985
+ raise ValueError("Blame output is empty.")
1986
+ commit_hash = parts[0]
1987
+ commit_hash = commit_hash.lstrip("^")
1988
+ except Exception as e:
1989
+ show_error_panel(f"Failed to execute git blame: {e}", "Git Error")
1990
+ raise typer.Exit(code=1)
1991
+
1992
+ # 4. Get commit details and full diff patch
1993
+ try:
1994
+ commit = git_ops.repo.commit(commit_hash)
1995
+ commit_info = {
1996
+ "hexsha": commit.hexsha,
1997
+ "author": commit.author.name,
1998
+ "date": commit.committed_datetime.isoformat(),
1999
+ "summary": commit.summary,
2000
+ "message": commit.message,
2001
+ }
2002
+ commit_show_output = git_ops.execute(f"show -p {commit_hash} -- {file}")
2003
+ except Exception as e:
2004
+ show_error_panel(f"Failed to fetch commit details for '{commit_hash}': {e}", "Git Error")
2005
+ raise typer.Exit(code=1)
2006
+
2007
+ # 5. Run LLM blame analysis
2008
+ analyzer = HistoryAnalyzer(git_ops)
2009
+
2010
+ try:
2011
+ get_llm(offline_override=offline)
2012
+ with spinner(f"Analyzing commit history for line {line}..."):
2013
+ blame_analysis = analyzer.analyze_blame(
2014
+ file=file,
2015
+ line=line,
2016
+ commit_info=commit_info,
2017
+ commit_show_output=commit_show_output,
2018
+ line_content=line_content,
2019
+ offline=offline
2020
+ )
2021
+ except Exception as e:
2022
+ show_error_panel(f"Failed to analyze blame: {e}", "AI Error")
2023
+ raise typer.Exit(code=1)
2024
+
2025
+ console.print()
2026
+ console.print(Panel(
2027
+ Markdown(blame_analysis),
2028
+ title=f"[bold cyan]AI Blame Analysis: {file}:{line}[/bold cyan]",
2029
+ border_style="#00D5FF",
2030
+ padding=(1, 2)
2031
+ ))
2032
+ console.print()
2033
+
1890
2034
  if __name__ == "__main__":
1891
2035
  app()
1892
2036
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ace-git-copilot"
3
- version = "0.3.8"
3
+ version = "0.4.0"
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,31 @@
1
+ from unittest.mock import MagicMock, patch
2
+ from ace.ai.history_analyzer import HistoryAnalyzer
3
+
4
+ def test_analyze_blame():
5
+ mock_git_ops = MagicMock()
6
+ analyzer = HistoryAnalyzer(mock_git_ops)
7
+
8
+ commit_info = {
9
+ "hexsha": "12345678",
10
+ "author": "Jachin Samuel",
11
+ "date": "2026-07-14",
12
+ "summary": "Fix login bug",
13
+ "message": "Detailed description of login fix",
14
+ }
15
+
16
+ with patch("ace.ai.history_analyzer.get_llm") as mock_get_llm:
17
+ mock_llm = MagicMock()
18
+ mock_response = MagicMock()
19
+ mock_response.content = "### Why this line was written\nTo fix the login check."
20
+ mock_llm.invoke.return_value = mock_response
21
+ mock_get_llm.return_value = mock_llm
22
+
23
+ res = analyzer.analyze_blame(
24
+ file="src/auth.py",
25
+ line=45,
26
+ commit_info=commit_info,
27
+ commit_show_output="git show diff output",
28
+ line_content="if not user.is_authenticated:",
29
+ )
30
+ assert "To fix the login check" in res
31
+ assert mock_llm.invoke.call_count == 1
@@ -0,0 +1,28 @@
1
+ from unittest.mock import MagicMock, patch
2
+ from ace.ai.history_analyzer import HistoryAnalyzer
3
+
4
+ def test_generate_standup():
5
+ mock_git_ops = MagicMock()
6
+ analyzer = HistoryAnalyzer(mock_git_ops)
7
+
8
+ commits = [
9
+ {"hexsha": "1234567890", "summary": "Initial Commit", "author": "Jachin Samuel"},
10
+ {"hexsha": "abcdef0123", "summary": "Fix login bug", "author": "Jachin Samuel"}
11
+ ]
12
+
13
+ with patch("ace.ai.history_analyzer.get_llm") as mock_get_llm:
14
+ mock_llm = MagicMock()
15
+ mock_response = MagicMock()
16
+ mock_response.content = "Yesterday:\n- Fixed bug\n- Initial commit\n\nToday:\n- Add features"
17
+ mock_llm.invoke.return_value = mock_response
18
+ mock_get_llm.return_value = mock_llm
19
+
20
+ res = analyzer.generate_standup(commits)
21
+ assert "Fixed bug" in res
22
+ assert mock_llm.invoke.call_count == 1
23
+
24
+ def test_generate_standup_empty():
25
+ mock_git_ops = MagicMock()
26
+ analyzer = HistoryAnalyzer(mock_git_ops)
27
+ res = analyzer.generate_standup([])
28
+ assert "No recent commits found" in res
@@ -1 +0,0 @@
1
- __version__ = "0.3.8"
File without changes