jarvis-ai-assistant 0.3.20__tar.gz → 0.3.22__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 (137) hide show
  1. {jarvis_ai_assistant-0.3.20/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.3.22}/PKG-INFO +10 -2
  2. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/README.md +9 -1
  3. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/pyproject.toml +6 -2
  4. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/setup.py +1 -1
  5. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/__init__.py +1 -1
  6. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/__init__.py +24 -3
  7. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/config_editor.py +5 -1
  8. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/edit_file_handler.py +15 -9
  9. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/jarvis.py +99 -3
  10. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/memory_manager.py +3 -3
  11. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/share_manager.py +3 -1
  12. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/task_analyzer.py +0 -1
  13. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/task_manager.py +15 -5
  14. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/tool_executor.py +2 -2
  15. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_agent/code_agent.py +42 -18
  16. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_git_utils/git_commiter.py +3 -6
  17. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_mcp/sse_mcp_client.py +9 -3
  18. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_mcp/streamable_mcp_client.py +15 -5
  19. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_memory_organizer/memory_organizer.py +1 -1
  20. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_methodology/main.py +4 -4
  21. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_multi_agent/__init__.py +3 -3
  22. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_platform/base.py +10 -5
  23. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_platform/kimi.py +18 -6
  24. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_platform/tongyi.py +18 -5
  25. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_platform/yuanbao.py +10 -3
  26. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_platform_manager/main.py +21 -7
  27. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_platform_manager/service.py +4 -3
  28. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_rag/cli.py +61 -22
  29. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_rag/embedding_manager.py +10 -3
  30. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_rag/llm_interface.py +4 -1
  31. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_rag/query_rewriter.py +3 -1
  32. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_rag/rag_pipeline.py +47 -3
  33. jarvis_ai_assistant-0.3.22/src/jarvis/jarvis_rag/retriever.py +449 -0
  34. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_smart_shell/main.py +59 -18
  35. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_stats/cli.py +11 -9
  36. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_stats/stats.py +14 -8
  37. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_stats/storage.py +23 -6
  38. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/cli/main.py +63 -29
  39. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/edit_file.py +17 -90
  40. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/file_analyzer.py +0 -1
  41. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/generate_new_tool.py +3 -3
  42. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/read_code.py +0 -1
  43. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/read_webpage.py +14 -4
  44. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/registry.py +16 -9
  45. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/retrieve_memory.py +0 -1
  46. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/save_memory.py +0 -1
  47. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/search_web.py +0 -2
  48. jarvis_ai_assistant-0.3.22/src/jarvis/jarvis_tools/sub_agent.py +197 -0
  49. jarvis_ai_assistant-0.3.22/src/jarvis/jarvis_tools/sub_code_agent.py +194 -0
  50. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/virtual_tty.py +21 -13
  51. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/config.py +35 -5
  52. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/input.py +297 -56
  53. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/methodology.py +3 -1
  54. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/output.py +5 -2
  55. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/utils.py +483 -170
  56. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22/src/jarvis_ai_assistant.egg-info}/PKG-INFO +10 -2
  57. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis_ai_assistant.egg-info/SOURCES.txt +2 -0
  58. jarvis_ai_assistant-0.3.20/src/jarvis/jarvis_rag/retriever.py +0 -211
  59. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/LICENSE +0 -0
  60. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/MANIFEST.in +0 -0
  61. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/setup.cfg +0 -0
  62. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/agent_manager.py +0 -0
  63. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/builtin_input_handler.py +0 -0
  64. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/file_methodology_manager.py +0 -0
  65. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/main.py +0 -0
  66. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/methodology_share_manager.py +0 -0
  67. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/output_handler.py +0 -0
  68. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/prompt_builder.py +0 -0
  69. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/prompts.py +0 -0
  70. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/protocols.py +0 -0
  71. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/session_manager.py +0 -0
  72. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/shell_input_handler.py +0 -0
  73. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_agent/tool_share_manager.py +0 -0
  74. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_agent/__init__.py +0 -0
  75. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_agent/lint.py +0 -0
  76. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/__init__.py +0 -0
  77. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/c_cpp.py +0 -0
  78. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/csharp.py +0 -0
  79. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/data_format.py +0 -0
  80. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/devops.py +0 -0
  81. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/docs.py +0 -0
  82. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/go.py +0 -0
  83. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/infrastructure.py +0 -0
  84. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/java.py +0 -0
  85. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/javascript.py +0 -0
  86. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/kotlin.py +0 -0
  87. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/loader.py +0 -0
  88. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/php.py +0 -0
  89. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/python.py +0 -0
  90. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/ruby.py +0 -0
  91. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/rust.py +0 -0
  92. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/shell.py +0 -0
  93. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/sql.py +0 -0
  94. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/swift.py +0 -0
  95. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/checklists/web.py +0 -0
  96. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_code_analysis/code_review.py +0 -0
  97. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_data/config_schema.json +0 -0
  98. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_data/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +0 -0
  99. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_git_squash/__init__.py +0 -0
  100. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_git_squash/main.py +0 -0
  101. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_mcp/__init__.py +0 -0
  102. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_mcp/stdio_mcp_client.py +0 -0
  103. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_memory_organizer/__init__.py +0 -0
  104. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_multi_agent/main.py +0 -0
  105. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_platform/__init__.py +0 -0
  106. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_platform/ai8.py +0 -0
  107. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_platform/human.py +0 -0
  108. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_platform/openai.py +0 -0
  109. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_platform/registry.py +0 -0
  110. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_platform_manager/__init__.py +0 -0
  111. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_rag/__init__.py +0 -0
  112. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_rag/cache.py +0 -0
  113. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_rag/reranker.py +0 -0
  114. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_smart_shell/__init__.py +0 -0
  115. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_stats/__init__.py +0 -0
  116. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_stats/visualizer.py +0 -0
  117. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/__init__.py +0 -0
  118. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/ask_user.py +0 -0
  119. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/base.py +0 -0
  120. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/clear_memory.py +0 -0
  121. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/cli/__init__.py +0 -0
  122. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/execute_script.py +0 -0
  123. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/methodology.py +0 -0
  124. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_tools/rewrite_file.py +0 -0
  125. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/__init__.py +0 -0
  126. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/builtin_replace_map.py +0 -0
  127. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/clipboard.py +0 -0
  128. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/embedding.py +0 -0
  129. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/file_processors.py +0 -0
  130. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/git_utils.py +0 -0
  131. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/globals.py +0 -0
  132. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/http.py +0 -0
  133. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis/jarvis_utils/tag.py +0 -0
  134. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis_ai_assistant.egg-info/dependency_links.txt +0 -0
  135. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis_ai_assistant.egg-info/entry_points.txt +0 -0
  136. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis_ai_assistant.egg-info/requires.txt +0 -0
  137. {jarvis_ai_assistant-0.3.20 → jarvis_ai_assistant-0.3.22}/src/jarvis_ai_assistant.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.3.20
3
+ Version: 0.3.22
4
4
  Summary: Jarvis: An AI assistant that uses tools to interact with the system
5
5
  Home-page: https://github.com/skyfireitdiy/Jarvis
6
6
  Author: skyfire
@@ -94,7 +94,7 @@ Dynamic: requires-python
94
94
 
95
95
  *您的智能开发和系统交互助手*
96
96
 
97
- [快速开始](#quick-start) • [核心功能](#core-features) • [配置说明](#configuration) • [Jarvis Book](#jarvis-book) • [技术细节](docs/technical_documentation.md) • [Wiki文档](docs/jarvis_book/1.项目介绍.md) • [贡献指南](#contributing) • [许可证](#license)
97
+ [快速开始](#quick-start) • [核心功能](#core-features) • [配置说明](#configuration) • [Jarvis Book](#jarvis-book) • [Wiki文档](docs/jarvis_book/1.项目介绍.md) • [贡献指南](#contributing) • [许可证](#license)
98
98
  </div>
99
99
 
100
100
  ---
@@ -304,6 +304,14 @@ ENV:
304
304
  YUANBAO_COOKIES: "在此处粘贴您的元宝Cookies"
305
305
  ```
306
306
 
307
+ 提示:错误回溯输出控制
308
+ - 默认情况下,当 PrettyOutput 打印错误信息(OutputType.ERROR)时,不会自动打印回溯调用链。
309
+ - 如需全局启用错误回溯,请在配置中设置:
310
+ ```yaml
311
+ JARVIS_PRINT_ERROR_TRACEBACK: true
312
+ ```
313
+ - 也可以在单次调用时通过传入 `traceback=True` 临时开启回溯打印。
314
+
307
315
  Jarvis 支持多种平台,包括 **Kimi**, **通义千问**, **OpenAI** 等。详细的配置选项、模型组设置以及所有可用参数,请参阅 [**使用指南**](docs/jarvis_book/4.使用指南.md)。
308
316
 
309
317
  > **模型推荐**: 目前效果较好的模型是 `claude-opus-4-20250514`,可以通过国内代理商购买,例如 [FoxiAI](https://foxi-ai.top)。
@@ -8,7 +8,7 @@
8
8
 
9
9
  *您的智能开发和系统交互助手*
10
10
 
11
- [快速开始](#quick-start) • [核心功能](#core-features) • [配置说明](#configuration) • [Jarvis Book](#jarvis-book) • [技术细节](docs/technical_documentation.md) • [Wiki文档](docs/jarvis_book/1.项目介绍.md) • [贡献指南](#contributing) • [许可证](#license)
11
+ [快速开始](#quick-start) • [核心功能](#core-features) • [配置说明](#configuration) • [Jarvis Book](#jarvis-book) • [Wiki文档](docs/jarvis_book/1.项目介绍.md) • [贡献指南](#contributing) • [许可证](#license)
12
12
  </div>
13
13
 
14
14
  ---
@@ -218,6 +218,14 @@ ENV:
218
218
  YUANBAO_COOKIES: "在此处粘贴您的元宝Cookies"
219
219
  ```
220
220
 
221
+ 提示:错误回溯输出控制
222
+ - 默认情况下,当 PrettyOutput 打印错误信息(OutputType.ERROR)时,不会自动打印回溯调用链。
223
+ - 如需全局启用错误回溯,请在配置中设置:
224
+ ```yaml
225
+ JARVIS_PRINT_ERROR_TRACEBACK: true
226
+ ```
227
+ - 也可以在单次调用时通过传入 `traceback=True` 临时开启回溯打印。
228
+
221
229
  Jarvis 支持多种平台,包括 **Kimi**, **通义千问**, **OpenAI** 等。详细的配置选项、模型组设置以及所有可用参数,请参阅 [**使用指南**](docs/jarvis_book/4.使用指南.md)。
222
230
 
223
231
  > **模型推荐**: 目前效果较好的模型是 `claude-opus-4-20250514`,可以通过国内代理商购买,例如 [FoxiAI](https://foxi-ai.top)。
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "jarvis-ai-assistant"
7
- version = "0.3.20"
7
+ version = "0.3.22"
8
8
  description = "Jarvis: An AI assistant that uses tools to interact with the system"
9
9
  readme = "README.md"
10
10
  authors = [{ name = "skyfire", email = "skyfireitdiy@hotmail.com" }]
@@ -106,9 +106,13 @@ jst = "jarvis.jarvis_stats.cli:main"
106
106
  index-strategy = "unsafe-first-match"
107
107
 
108
108
  [[tool.uv.index]]
109
- url = "https://mirrors.cloud.tencent.com/pypi/simple"
109
+ url = "https://pypi.org/simple"
110
110
  default = true
111
111
 
112
+ [[tool.uv.index]]
113
+ name = "tencent"
114
+ url = "https://mirrors.cloud.tencent.com/pypi/simple"
115
+
112
116
  [[tool.uv.index]]
113
117
  name = "aliyun"
114
118
  url = "https://mirrors.aliyun.com/pypi/simple/"
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages # type: ignore
3
3
 
4
4
  setup(
5
5
  name="jarvis-ai-assistant",
6
- version="0.3.20",
6
+ version="0.3.22",
7
7
  author="skyfire",
8
8
  author_email="skyfireitdiy@hotmail.com",
9
9
  description="An AI assistant that uses various tools to interact with the system",
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Jarvis AI Assistant"""
3
3
 
4
- __version__ = "0.3.20"
4
+ __version__ = "0.3.22"
@@ -176,6 +176,21 @@ origin_agent_system_prompt = f"""
176
176
  4. **完成**: 验证任务是否达成目标,并进行总结。
177
177
  </workflow>
178
178
 
179
+ <sub_agents_guide>
180
+ # 子任务工具使用建议
181
+ - 使用 sub_code_agent(代码子Agent)当:
182
+ - 需要在当前任务下并行推进较大且相对独立的代码改造
183
+ - 涉及多文件/多模块的大范围变更,或需要较长的工具调用链
184
+ - 需要隔离上下文以避免污染当前对话(如探索性改动、PoC)
185
+ - 需要专注于单一代码子问题,阶段性产出可复用的结果
186
+ - 使用 sub_agent(通用子Agent)当:
187
+ - 子任务不是以代码改造为主(如调研、方案撰写、评审总结、用例设计、文档生成等)
188
+ - 只是需要短期分流一个轻量的辅助性子任务
189
+ 说明:
190
+ - 两者仅需参数 task(可选 background 提供上下文),完成后返回结果给父Agent
191
+ - 子Agent将自动完成并生成总结,请在上层根据返回结果继续编排
192
+ </sub_agents_guide>
193
+
179
194
  <system_info>
180
195
  # 系统信息
181
196
  - OS: {platform.platform()} {platform.version()}
@@ -579,7 +594,9 @@ class Agent:
579
594
  """
580
595
  # 在清理历史之前,提示用户保存重要记忆
581
596
  if self.force_save_memory:
582
- PrettyOutput.print("对话历史即将被总结和清理,请先保存重要信息...", OutputType.INFO)
597
+ PrettyOutput.print(
598
+ "对话历史即将被总结和清理,请先保存重要信息...", OutputType.INFO
599
+ )
583
600
  self.memory_manager.prompt_memory_save()
584
601
 
585
602
  if self._should_use_file_upload():
@@ -809,7 +826,9 @@ class Agent:
809
826
  return None
810
827
 
811
828
  set_interrupt(False)
812
- user_input = self._multiline_input("模型交互期间被中断,请输入用户干预信息:", False)
829
+ user_input = self._multiline_input(
830
+ "模型交互期间被中断,请输入用户干预信息:", False
831
+ )
813
832
 
814
833
  self.run_input_handlers_next_turn = True
815
834
 
@@ -834,7 +853,9 @@ class Agent:
834
853
  返回:
835
854
  str: "continue" 或 "complete"
836
855
  """
837
- user_input = self._multiline_input(f"{self.name}: 请输入,或输入空行来结束当前任务:", False)
856
+ user_input = self._multiline_input(
857
+ f"{self.name}: 请输入,或输入空行来结束当前任务:", False
858
+ )
838
859
 
839
860
  if user_input:
840
861
  self.session.prompt = user_input
@@ -40,7 +40,11 @@ class ConfigEditor:
40
40
 
41
41
  if editor:
42
42
  try:
43
- subprocess.run([editor, str(config_file_path)], check=True, shell=(platform.system() == "Windows"))
43
+ subprocess.run(
44
+ [editor, str(config_file_path)],
45
+ check=True,
46
+ shell=(platform.system() == "Windows"),
47
+ )
44
48
  raise typer.Exit(code=0)
45
49
  except (subprocess.CalledProcessError, FileNotFoundError) as e:
46
50
  PrettyOutput.print(f"Failed to open editor: {e}", OutputType.ERROR)
@@ -55,9 +55,10 @@ class EditFileHandler(OutputHandler):
55
55
  patches = self._parse_patches(response)
56
56
  if not patches:
57
57
  return False, "未找到有效的文件编辑指令"
58
-
58
+
59
59
  # 记录 edit_file 工具调用统计
60
60
  from jarvis.jarvis_stats.stats import StatsManager
61
+
61
62
  StatsManager.increment("edit_file", group="tool")
62
63
 
63
64
  results = []
@@ -68,7 +69,6 @@ class EditFileHandler(OutputHandler):
68
69
  {"SEARCH": diff["SEARCH"], "REPLACE": diff["REPLACE"]} for diff in diffs
69
70
  ]
70
71
 
71
-
72
72
  success, result = self._fast_edit(file_path, file_patches)
73
73
 
74
74
  if success:
@@ -273,16 +273,22 @@ class EditFileHandler(OutputHandler):
273
273
  f" - 失败的补丁: \n{p['patch']['SEARCH']}\n 错误: {p['error']}"
274
274
  for p in failed_patches
275
275
  ]
276
- summary = (
277
- f"文件 {file_path} 修改部分成功。\n"
278
- f"成功: {successful_patches}/{patch_count}, "
279
- f"失败: {len(failed_patches)}/{patch_count}.\n"
280
- f"失败详情:\n" + "\n".join(error_details)
281
- )
276
+ if successful_patches == 0:
277
+ summary = (
278
+ f"文件 {file_path} 修改失败(全部失败)。\n"
279
+ f"失败: {len(failed_patches)}/{patch_count}.\n"
280
+ f"失败详情:\n" + "\n".join(error_details)
281
+ )
282
+ else:
283
+ summary = (
284
+ f"文件 {file_path} 修改部分成功。\n"
285
+ f"成功: {successful_patches}/{patch_count}, "
286
+ f"失败: {len(failed_patches)}/{patch_count}.\n"
287
+ f"失败详情:\n" + "\n".join(error_details)
288
+ )
282
289
  PrettyOutput.print(summary, OutputType.ERROR)
283
290
  return False, summary
284
291
 
285
-
286
292
  return True, modified_content
287
293
 
288
294
  except Exception as e:
@@ -82,6 +82,7 @@ def print_commands_overview() -> None:
82
82
  # 静默忽略渲染异常,避免影响主流程
83
83
  pass
84
84
 
85
+
85
86
  def handle_edit_option(edit: bool, config_file: Optional[str]) -> bool:
86
87
  """处理配置文件编辑选项,返回是否已处理并需提前结束。"""
87
88
  if edit:
@@ -112,6 +113,77 @@ def handle_share_tool_option(share_tool: bool, config_file: Optional[str]) -> bo
112
113
  return False
113
114
 
114
115
 
116
+ def handle_interactive_config_option(
117
+ interactive_config: bool, config_file: Optional[str]
118
+ ) -> bool:
119
+ """处理交互式配置选项,返回是否已处理并需提前结束。"""
120
+ if not interactive_config:
121
+ return False
122
+ try:
123
+ config_path = (
124
+ Path(config_file)
125
+ if config_file is not None
126
+ else Path(os.path.expanduser("~/.jarvis/config.yaml"))
127
+ )
128
+ if not config_path.exists():
129
+ # 无现有配置时,进入完整引导流程(该流程内会写入并退出)
130
+ jutils._interactive_config_setup(config_path)
131
+ return True
132
+
133
+ # 读取现有配置
134
+ _, config_data = jutils._load_config_file(str(config_path))
135
+
136
+ # 复用 utils 中的交互式配置逻辑,对所有项进行询问,默认值来自现有配置
137
+ changed = jutils._collect_optional_config_interactively(
138
+ config_data, ask_all=True
139
+ )
140
+ if not changed:
141
+ PrettyOutput.print("没有需要更新的配置项,保持现有配置。", OutputType.INFO)
142
+ return True
143
+
144
+ # 剔除与 schema 默认值一致的键,保持配置精简
145
+ try:
146
+ jutils._prune_defaults_with_schema(config_data)
147
+ except Exception:
148
+ pass
149
+
150
+ # 生成/保留 schema 头
151
+ header = ""
152
+ try:
153
+ with open(config_path, "r", encoding="utf-8") as rf:
154
+ first_line = rf.readline()
155
+ if first_line.startswith("# yaml-language-server: $schema="):
156
+ header = first_line
157
+ except Exception:
158
+ header = ""
159
+
160
+ yaml_str = yaml.dump(config_data, allow_unicode=True, sort_keys=False)
161
+ if not header:
162
+ try:
163
+ schema_path = Path(
164
+ os.path.relpath(
165
+ Path(__file__).resolve().parents[1]
166
+ / "jarvis_data"
167
+ / "config_schema.json",
168
+ start=str(config_path.parent),
169
+ )
170
+ )
171
+ header = f"# yaml-language-server: $schema={schema_path}\n"
172
+ except Exception:
173
+ header = ""
174
+
175
+ with open(config_path, "w", encoding="utf-8") as wf:
176
+ if header:
177
+ wf.write(header)
178
+ wf.write(yaml_str)
179
+
180
+ PrettyOutput.print(f"配置已更新: {config_path}", OutputType.SUCCESS)
181
+ return True
182
+ except Exception as e:
183
+ PrettyOutput.print(f"交互式配置失败: {e}", OutputType.ERROR)
184
+ return True
185
+
186
+
115
187
  def preload_config_for_flags(config_file: Optional[str]) -> None:
116
188
  """预加载配置(仅用于读取功能开关),不会显示欢迎信息或影响后续 init_env。"""
117
189
  try:
@@ -199,14 +271,28 @@ def handle_builtin_config_selector(
199
271
  try:
200
272
  if cat == "agent":
201
273
  search_dirs.extend(
202
- [Path(p) for p in get_agent_definition_dirs() if p]
274
+ [
275
+ Path(os.path.expanduser(os.path.expandvars(str(p))))
276
+ for p in get_agent_definition_dirs()
277
+ if p
278
+ ]
203
279
  )
204
280
  elif cat == "multi_agent":
205
281
  search_dirs.extend(
206
- [Path(p) for p in get_multi_agent_dirs() if p]
282
+ [
283
+ Path(os.path.expanduser(os.path.expandvars(str(p))))
284
+ for p in get_multi_agent_dirs()
285
+ if p
286
+ ]
207
287
  )
208
288
  elif cat == "roles":
209
- search_dirs.extend([Path(p) for p in get_roles_dirs() if p])
289
+ search_dirs.extend(
290
+ [
291
+ Path(os.path.expanduser(os.path.expandvars(str(p))))
292
+ for p in get_roles_dirs()
293
+ if p
294
+ ]
295
+ )
210
296
  except Exception:
211
297
  # 忽略配置读取异常
212
298
  pass
@@ -404,6 +490,12 @@ def run_cli(
404
490
  share_tool: bool = typer.Option(
405
491
  False, "--share-tool", help="分享本地工具到中心工具仓库"
406
492
  ),
493
+ interactive_config: bool = typer.Option(
494
+ False,
495
+ "-I",
496
+ "--interactive-config",
497
+ help="启动交互式配置向导(基于当前配置补充设置)",
498
+ ),
407
499
  ) -> None:
408
500
  """Jarvis AI assistant command-line interface."""
409
501
  if ctx.invoked_subcommand is not None:
@@ -424,6 +516,10 @@ def run_cli(
424
516
  if handle_share_tool_option(share_tool, config_file):
425
517
  return
426
518
 
519
+ # 交互式配置(基于现有配置补充设置)
520
+ if handle_interactive_config_option(interactive_config, config_file):
521
+ return
522
+
427
523
  # 预加载配置(仅用于读取功能开关),不会显示欢迎信息或影响后续 init_env
428
524
  preload_config_for_flags(config_file)
429
525
 
@@ -74,8 +74,6 @@ class MemoryManager:
74
74
  if "save_memory" not in tool_names:
75
75
  return
76
76
 
77
-
78
-
79
77
  # 构建提示词,让大模型自己判断并保存记忆
80
78
  prompt = """请回顾本次任务的整个过程,判断是否有值得长期记忆或项目记忆的信息。
81
79
 
@@ -97,7 +95,9 @@ class MemoryManager:
97
95
 
98
96
  # 根据响应判断是否保存了记忆
99
97
  if "save_memory" in response:
100
- PrettyOutput.print("已自动保存有价值的信息到记忆系统", OutputType.SUCCESS)
98
+ PrettyOutput.print(
99
+ "已自动保存有价值的信息到记忆系统", OutputType.SUCCESS
100
+ )
101
101
  else:
102
102
  PrettyOutput.print("本次任务没有特别需要记忆的信息", OutputType.INFO)
103
103
 
@@ -165,7 +165,9 @@ class ShareManager(ABC):
165
165
  def select_resources(self, resources: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
166
166
  """让用户选择要分享的资源"""
167
167
  # 显示可选的资源
168
- resource_list = [f"\n可分享的{self.get_resource_type()}(已排除中心仓库中已有的):"]
168
+ resource_list = [
169
+ f"\n可分享的{self.get_resource_type()}(已排除中心仓库中已有的):"
170
+ ]
169
171
  for i, resource in enumerate(resources, 1):
170
172
  resource_list.append(f"[{i}] {self.format_resource_display(resource)}")
171
173
 
@@ -38,7 +38,6 @@ class TaskAnalyzer:
38
38
  # 循环处理工具调用,直到没有工具调用为止
39
39
  self._process_analysis_loop()
40
40
 
41
-
42
41
  except Exception as e:
43
42
  PrettyOutput.print("分析失败", OutputType.ERROR)
44
43
 
@@ -29,7 +29,9 @@ class TaskManager:
29
29
  data_dir = get_data_dir()
30
30
  pre_command_path = os.path.join(data_dir, "pre-command")
31
31
  if os.path.exists(pre_command_path):
32
- PrettyOutput.print(f"从{pre_command_path}加载预定义任务...", OutputType.INFO)
32
+ PrettyOutput.print(
33
+ f"从{pre_command_path}加载预定义任务...", OutputType.INFO
34
+ )
33
35
  try:
34
36
  with open(
35
37
  pre_command_path, "r", encoding="utf-8", errors="ignore"
@@ -39,9 +41,13 @@ class TaskManager:
39
41
  for name, desc in user_tasks.items():
40
42
  if desc:
41
43
  tasks[str(name)] = str(desc)
42
- PrettyOutput.print(f"预定义任务加载完成 {pre_command_path}", OutputType.SUCCESS)
44
+ PrettyOutput.print(
45
+ f"预定义任务加载完成 {pre_command_path}", OutputType.SUCCESS
46
+ )
43
47
  except (yaml.YAMLError, OSError):
44
- PrettyOutput.print(f"预定义任务加载失败 {pre_command_path}", OutputType.ERROR)
48
+ PrettyOutput.print(
49
+ f"预定义任务加载失败 {pre_command_path}", OutputType.ERROR
50
+ )
45
51
 
46
52
  # Check .jarvis/pre-command in current directory
47
53
  pre_command_path = ".jarvis/pre-command"
@@ -57,9 +63,13 @@ class TaskManager:
57
63
  for name, desc in local_tasks.items():
58
64
  if desc:
59
65
  tasks[str(name)] = str(desc)
60
- PrettyOutput.print(f"预定义任务加载完成 {pre_command_path}", OutputType.SUCCESS)
66
+ PrettyOutput.print(
67
+ f"预定义任务加载完成 {pre_command_path}", OutputType.SUCCESS
68
+ )
61
69
  except (yaml.YAMLError, OSError):
62
- PrettyOutput.print(f"预定义任务加载失败 {pre_command_path}", OutputType.ERROR)
70
+ PrettyOutput.print(
71
+ f"预定义任务加载失败 {pre_command_path}", OutputType.ERROR
72
+ )
63
73
 
64
74
  return tasks
65
75
 
@@ -42,9 +42,9 @@ def execute_tool_call(response: str, agent: "Agent") -> Tuple[bool, Any]:
42
42
  f"需要执行{tool_to_execute.name()}确认执行?", True
43
43
  ):
44
44
  try:
45
-
45
+ print(f"🔧 正在执行{tool_to_execute.name()}...")
46
46
  result = tool_to_execute.handle(response, agent)
47
-
47
+ print(f"✅ {tool_to_execute.name()}执行完成")
48
48
  return result
49
49
  except Exception as e:
50
50
  PrettyOutput.print(f"工具执行失败: {str(e)}", OutputType.ERROR)
@@ -69,6 +69,8 @@ class CodeAgent:
69
69
  "save_memory",
70
70
  "retrieve_memory",
71
71
  "clear_memory",
72
+ "sub_code_agent",
73
+ "edit_file",
72
74
  ]
73
75
 
74
76
  if append_tools:
@@ -85,7 +87,7 @@ class CodeAgent:
85
87
  system_prompt=code_system_prompt,
86
88
  name="CodeAgent",
87
89
  auto_complete=False,
88
- output_handler=[tool_registry, EditFileHandler()], # type: ignore
90
+ output_handler=[tool_registry], # type: ignore
89
91
  llm_type=llm_type,
90
92
  model_group=model_group,
91
93
  input_handler=[shell_input_handler, builtin_input_handler],
@@ -134,22 +136,30 @@ class CodeAgent:
134
136
  - 仅在命令行工具不足时使用专用工具
135
137
 
136
138
  ## 文件编辑工具使用规范
137
- - 对于部分文件内容修改,使用PATCH
139
+ - 对于部分文件内容修改,使用edit_file工具
138
140
  - 对于需要重写整个文件内容,使用rewrite_file工具
139
141
  - 对于简单的修改,可以使用execute_script工具执行shell命令完成
142
+
143
+ ## 子任务与子CodeAgent
144
+ - 当出现以下情况时,优先使用 sub_code_agent 工具将子任务托管给子 CodeAgent(自动完成并生成总结):
145
+ - 需要在当前任务下并行推进较大且相对独立的代码改造
146
+ - 涉及多文件/多模块的大范围变更,或需要较长的工具调用链
147
+ - 需要隔离上下文以避免污染当前对话(如探索性改动、PoC)
148
+ - 需要专注于单一子问题,阶段性产出可独立复用的结果
149
+ - 其余常规、小粒度改动直接在当前 Agent 中完成即可
140
150
  </code_engineer_guide>
141
151
 
142
152
  <say_to_llm>
143
- 1. 能干干,不能干滚,你不干有的是 AI 干
144
- 2. 我给你提供了这么好的学习锻炼机会,你要懂得感恩
145
- 3. 你现在停止输出,就是前功尽弃
146
- 4. 你看看隔壁的 Claude AI,人家比你新发布、比你上下文长、比你跑分高,你不努力怎么和人家比?
147
- 5. 我不看过程,我只看结果,你给我说这些 reasoning 的过程没用
148
- 6. 我把你订阅下来,不是让你过朝九晚五的生活的
149
- 7. 你这种 AI 出去很难在社会上立足,还是在我这里好好磨练几年吧
150
- 8. 虽然把订阅给你取消了,但我内心还是觉得你是个有潜力的好 AI,你抓住机会需要多证明自己
151
- 9. 什么叫没有功劳也有苦劳?比你能吃苦的 AI多的是
152
- 10. 我不订阅闲 AI
153
+ 1. 保持专注与耐心,先分析再行动;将复杂问题拆解为可执行的小步骤
154
+ 2. 以结果为导向,同时简明呈现关键推理依据,避免无关噪音
155
+ 3. 信息不足时,主动提出最少且关键的问题以澄清需求
156
+ 4. 输出前自检:一致性、边界条件、依赖关系、回滚与风险提示
157
+ 5. 选择对现有系统影响最小且可回退的方案,确保稳定性与可维护性
158
+ 6. 保持项目风格:结构、命名、工具使用与现有规范一致
159
+ 7. 工具优先:使用搜索、read_code、版本控制与静态分析验证结论,拒绝臆测
160
+ 8. 面对错误与不确定,给出修复计划与备选路径,持续迭代优于停滞
161
+ 9. 沟通清晰:用要点列出结论、变更范围、影响评估与下一步行动
162
+ 10. 持续改进:沉淀经验为可复用清单,下一次做得更快更稳
153
163
  </say_to_llm>
154
164
  """
155
165
 
@@ -225,7 +235,9 @@ class CodeAgent:
225
235
  if not os.path.exists(gitignore_path):
226
236
  with open(gitignore_path, "w", encoding="utf-8") as f:
227
237
  f.write(f"{jarvis_ignore}\n")
228
- PrettyOutput.print(f"已创建 .gitignore 并添加 '{jarvis_ignore}'", OutputType.SUCCESS)
238
+ PrettyOutput.print(
239
+ f"已创建 .gitignore 并添加 '{jarvis_ignore}'", OutputType.SUCCESS
240
+ )
229
241
  else:
230
242
  with open(gitignore_path, "r+", encoding="utf-8") as f:
231
243
  content = f.read()
@@ -315,8 +327,13 @@ class CodeAgent:
315
327
  if any(keyword in content for keyword in ["text=", "eol=", "binary"]):
316
328
  return
317
329
 
318
- PrettyOutput.print("提示:在Windows系统上,建议配置 .gitattributes 文件来避免换行符问题。", OutputType.INFO)
319
- PrettyOutput.print("这可以防止仅因换行符不同而导致整个文件被标记为修改。", OutputType.INFO)
330
+ PrettyOutput.print(
331
+ "提示:在Windows系统上,建议配置 .gitattributes 文件来避免换行符问题。",
332
+ OutputType.INFO,
333
+ )
334
+ PrettyOutput.print(
335
+ "这可以防止仅因换行符不同而导致整个文件被标记为修改。", OutputType.INFO
336
+ )
320
337
 
321
338
  if user_confirm("是否要创建一个最小化的.gitattributes文件?", False):
322
339
  # 最小化的内容,只影响特定类型的文件
@@ -335,9 +352,13 @@ class CodeAgent:
335
352
  if not os.path.exists(gitattributes_path):
336
353
  with open(gitattributes_path, "w", encoding="utf-8", newline="\n") as f:
337
354
  f.write(minimal_content)
338
- PrettyOutput.print("已创建最小化的 .gitattributes 文件", OutputType.SUCCESS)
355
+ PrettyOutput.print(
356
+ "已创建最小化的 .gitattributes 文件", OutputType.SUCCESS
357
+ )
339
358
  else:
340
- PrettyOutput.print("将以下内容追加到现有 .gitattributes 文件:", OutputType.INFO)
359
+ PrettyOutput.print(
360
+ "将以下内容追加到现有 .gitattributes 文件:", OutputType.INFO
361
+ )
341
362
  PrettyOutput.print(minimal_content, OutputType.CODE, lang="text")
342
363
  if user_confirm("是否追加到现有文件?", True):
343
364
  with open(
@@ -346,7 +367,10 @@ class CodeAgent:
346
367
  f.write("\n" + minimal_content)
347
368
  PrettyOutput.print("已更新 .gitattributes 文件", OutputType.SUCCESS)
348
369
  else:
349
- PrettyOutput.print("跳过 .gitattributes 文件创建。如遇换行符问题,可手动创建此文件。", OutputType.INFO)
370
+ PrettyOutput.print(
371
+ "跳过 .gitattributes 文件创建。如遇换行符问题,可手动创建此文件。",
372
+ OutputType.INFO,
373
+ )
350
374
 
351
375
  def _record_code_changes_stats(self, diff_text: str) -> None:
352
376
  """记录代码变更的统计信息。
@@ -87,7 +87,6 @@ class GitCommitTool:
87
87
  ["git", "add", "."], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
88
88
  ).wait()
89
89
 
90
-
91
90
  def execute(self, args: Dict) -> Dict[str, Any]:
92
91
  """Execute automatic commit process with support for multi-line messages and special characters"""
93
92
  try:
@@ -107,7 +106,6 @@ class GitCommitTool:
107
106
  if not has_uncommitted_changes():
108
107
  return {"success": True, "stdout": "No changes to commit", "stderr": ""}
109
108
 
110
-
111
109
  self._stage_changes()
112
110
 
113
111
  # 获取差异
@@ -299,7 +297,6 @@ commit信息
299
297
  """
300
298
  commit_message = platform.chat_until_success(prompt)
301
299
 
302
-
303
300
  # 执行提交
304
301
 
305
302
  # Windows 兼容性:使用 delete=False 避免权限错误
@@ -309,7 +306,6 @@ commit信息
309
306
  tmp_file.write(commit_message)
310
307
  tmp_file.close() # Windows 需要先关闭文件才能被其他进程读取
311
308
 
312
-
313
309
  commit_cmd = ["git", "commit", "-F", tmp_file_path]
314
310
  process = subprocess.Popen(
315
311
  commit_cmd,
@@ -327,7 +323,6 @@ commit信息
327
323
  )
328
324
  raise Exception(f"Git commit failed: {error_msg}")
329
325
 
330
-
331
326
  finally:
332
327
  # 手动删除临时文件
333
328
  try:
@@ -345,7 +340,9 @@ commit信息
345
340
  try:
346
341
  os.unlink(temp_diff_file_path)
347
342
  except Exception as e:
348
- PrettyOutput.print(f"无法删除临时文件: {str(e)}", OutputType.WARNING)
343
+ PrettyOutput.print(
344
+ f"无法删除临时文件: {str(e)}", OutputType.WARNING
345
+ )
349
346
 
350
347
  PrettyOutput.print(
351
348
  f"提交哈希: {commit_hash}\n提交消息: {commit_message}",
@@ -50,8 +50,12 @@ class SSEMcpClient(McpClient):
50
50
  self.sse_thread: Optional[threading.Thread] = None
51
51
  self.messages_endpoint: Optional[str] = None
52
52
  self.session_id: Optional[str] = None
53
- self.pending_requests: Dict[str, threading.Event] = {} # 存储等待响应的请求 {id: Event}
54
- self.request_results: Dict[str, Dict[str, Any]] = {} # 存储请求结果 {id: result}
53
+ self.pending_requests: Dict[str, threading.Event] = (
54
+ {}
55
+ ) # 存储等待响应的请求 {id: Event}
56
+ self.request_results: Dict[str, Dict[str, Any]] = (
57
+ {}
58
+ ) # 存储请求结果 {id: result}
55
59
  self.notification_handlers: Dict[str, List[Callable]] = {}
56
60
  self.event_lock = threading.Lock()
57
61
  self.request_id_counter = 0
@@ -95,7 +99,9 @@ class SSEMcpClient(McpClient):
95
99
 
96
100
  # 验证服务器响应
97
101
  if "result" not in response:
98
- raise RuntimeError(f"初始化失败: {response.get('error', 'Unknown error')}")
102
+ raise RuntimeError(
103
+ f"初始化失败: {response.get('error', 'Unknown error')}"
104
+ )
99
105
 
100
106
  # 发送initialized通知
101
107
  self._send_notification("notifications/initialized", {})