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.
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/PKG-INFO +9 -66
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/README.md +8 -65
- ace_git_copilot-0.4.0/ace/__init__.py +1 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/history_analyzer.py +59 -0
- ace_git_copilot-0.4.0/ace/ai/prompts/blame.py +34 -0
- ace_git_copilot-0.4.0/ace/ai/prompts/standup.py +19 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/cli.py +144 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/pyproject.toml +1 -1
- ace_git_copilot-0.4.0/tests/test_blame.py +31 -0
- ace_git_copilot-0.4.0/tests/test_standup.py +28 -0
- ace_git_copilot-0.3.8/ace/__init__.py +0 -1
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/AGENTS.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/BRIEFING.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/ORIGINAL_REQUEST.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/e2e_testing_track/BRIEFING.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/e2e_testing_track/ORIGINAL_REQUEST.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/e2e_testing_track/SCOPE.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/e2e_testing_track/progress.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/BRIEFING.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/ORIGINAL_REQUEST.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/emojis_list.txt +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/find_unused_modules.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/handoff.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/measure_lazy_startup.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/measure_startup.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/profile_imports.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/progress.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/run_importtime.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/search_banner.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/search_emojis.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/search_git_usages.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/search_usages.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/test_import_profiler.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/test_mocked_sys.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/handoff.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/implementation_track/BRIEFING.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/implementation_track/ORIGINAL_REQUEST.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/implementation_track/explorer_initial_report.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/implementation_track/progress.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/orchestrator/.gitkeep +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/orchestrator/BRIEFING.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/orchestrator/ORIGINAL_REQUEST.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/orchestrator/PROJECT.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/orchestrator/progress.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/teamwork_preview_explorer_e2e_explore/BRIEFING.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/teamwork_preview_explorer_e2e_explore/ORIGINAL_REQUEST.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/teamwork_preview_explorer_e2e_explore/handoff.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/teamwork_preview_explorer_e2e_explore/progress.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_e2e_testing/BRIEFING.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_e2e_testing/ORIGINAL_REQUEST.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_e2e_testing/progress.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_m1_startup/BRIEFING.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_m1_startup/ORIGINAL_REQUEST.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_m1_startup/progress.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.env.example +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.github/workflows/tests.yml +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.gitignore +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/CODE_OF_CONDUCT.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/CONTRIBUTING.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/LICENSE +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/PROJECT.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/SECURITY.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/SUPPORT.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/TEST_INFRA.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/TEST_READY.md +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/__main__.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/changelog_generator.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/code_reviewer.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/commit_generator.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/conflict_resolver.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/gitignore_generator.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/intent_parser.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/llm_factory.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/pr_drafter.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/changelog.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/commit.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/conflict.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/doctor.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/explain.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/ignore.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/intent.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/pr.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/rebase.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/review.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/search.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/prompts/undo.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ai/rebase_helper.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/core/config.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/core/context.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/core/diagnostics.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/core/git_ops.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/core/hooks.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/core/safety.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ui/banner.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ui/dashboard.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ui/display.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ui/prompts.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/ui/themes.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/utils/conflict_parser.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/utils/diff_parser.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/utils/json_utils.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/ace/utils/string_utils.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/conftest.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/e2e/conftest.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/e2e/test_tier1_features.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/e2e/test_tier2_boundaries.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/e2e/test_tier3_combinations.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/e2e/test_tier4_workloads.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_changelog_generator.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_code_reviewer.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_config_atomic_write.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_conflict_resolver.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_conflict_resolver_backup.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_context_gitdir_detection.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_diagnostics.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_diff_trimmer.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_git_ops.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_git_ops_execute.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_help.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_history_analyzer.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_hooks.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_ignore.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_intent_parser.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_llm_factory.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_llm_factory_ollama.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_merge_state.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_pr_drafter.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_rebase_helper.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_safety.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_search.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_string_utils.py +0 -0
- {ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/tests/test_undo.py +0 -0
- {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
|
+
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
|
-
|
|
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
|
|
149
|
-
ace
|
|
150
|
-
ace
|
|
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
|
-
|
|
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
|
|
116
|
-
ace
|
|
117
|
-
ace
|
|
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
|
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/e2e_testing_track/ORIGINAL_REQUEST.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/find_unused_modules.py
RENAMED
|
File without changes
|
|
File without changes
|
{ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/measure_lazy_startup.py
RENAMED
|
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
|
{ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/explorer_init/test_import_profiler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/implementation_track/ORIGINAL_REQUEST.md
RENAMED
|
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
|
{ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_e2e_testing/ORIGINAL_REQUEST.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ace_git_copilot-0.3.8 → ace_git_copilot-0.4.0}/.agents/worker_m1_startup/ORIGINAL_REQUEST.md
RENAMED
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|