jarvis-ai-assistant 0.3.19__tar.gz → 0.3.20__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 (134) hide show
  1. {jarvis_ai_assistant-0.3.19/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.3.20}/PKG-INFO +1 -1
  2. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/pyproject.toml +1 -1
  3. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/setup.py +1 -1
  4. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/__init__.py +1 -1
  5. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/__init__.py +9 -2
  6. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/config_editor.py +1 -1
  7. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/shell_input_handler.py +17 -2
  8. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_platform/ai8.py +0 -4
  9. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_platform_manager/service.py +2 -2
  10. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_smart_shell/main.py +1 -1
  11. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_stats/cli.py +2 -1
  12. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_stats/stats.py +5 -5
  13. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/clipboard.py +1 -1
  14. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/input.py +253 -7
  15. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/output.py +215 -129
  16. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20/src/jarvis_ai_assistant.egg-info}/PKG-INFO +1 -1
  17. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/LICENSE +0 -0
  18. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/MANIFEST.in +0 -0
  19. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/README.md +0 -0
  20. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/setup.cfg +0 -0
  21. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/agent_manager.py +0 -0
  22. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/builtin_input_handler.py +0 -0
  23. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/edit_file_handler.py +0 -0
  24. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/file_methodology_manager.py +0 -0
  25. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/jarvis.py +0 -0
  26. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/main.py +0 -0
  27. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/memory_manager.py +0 -0
  28. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/methodology_share_manager.py +0 -0
  29. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/output_handler.py +0 -0
  30. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/prompt_builder.py +0 -0
  31. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/prompts.py +0 -0
  32. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/protocols.py +0 -0
  33. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/session_manager.py +0 -0
  34. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/share_manager.py +0 -0
  35. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/task_analyzer.py +0 -0
  36. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/task_manager.py +0 -0
  37. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/tool_executor.py +0 -0
  38. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_agent/tool_share_manager.py +0 -0
  39. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_agent/__init__.py +0 -0
  40. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_agent/code_agent.py +0 -0
  41. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_agent/lint.py +0 -0
  42. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/__init__.py +0 -0
  43. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/c_cpp.py +0 -0
  44. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/csharp.py +0 -0
  45. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/data_format.py +0 -0
  46. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/devops.py +0 -0
  47. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/docs.py +0 -0
  48. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/go.py +0 -0
  49. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/infrastructure.py +0 -0
  50. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/java.py +0 -0
  51. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/javascript.py +0 -0
  52. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/kotlin.py +0 -0
  53. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/loader.py +0 -0
  54. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/php.py +0 -0
  55. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/python.py +0 -0
  56. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/ruby.py +0 -0
  57. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/rust.py +0 -0
  58. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/shell.py +0 -0
  59. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/sql.py +0 -0
  60. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/swift.py +0 -0
  61. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/checklists/web.py +0 -0
  62. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_code_analysis/code_review.py +0 -0
  63. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_data/config_schema.json +0 -0
  64. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_data/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +0 -0
  65. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_git_squash/__init__.py +0 -0
  66. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_git_squash/main.py +0 -0
  67. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_git_utils/git_commiter.py +0 -0
  68. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_mcp/__init__.py +0 -0
  69. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_mcp/sse_mcp_client.py +0 -0
  70. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_mcp/stdio_mcp_client.py +0 -0
  71. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_mcp/streamable_mcp_client.py +0 -0
  72. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_memory_organizer/__init__.py +0 -0
  73. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_memory_organizer/memory_organizer.py +0 -0
  74. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_methodology/main.py +0 -0
  75. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_multi_agent/__init__.py +0 -0
  76. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_multi_agent/main.py +0 -0
  77. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_platform/__init__.py +0 -0
  78. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_platform/base.py +2 -2
  79. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_platform/human.py +0 -0
  80. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_platform/kimi.py +0 -0
  81. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_platform/openai.py +0 -0
  82. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_platform/registry.py +0 -0
  83. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_platform/tongyi.py +0 -0
  84. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_platform/yuanbao.py +0 -0
  85. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_platform_manager/__init__.py +0 -0
  86. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_platform_manager/main.py +0 -0
  87. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_rag/__init__.py +0 -0
  88. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_rag/cache.py +0 -0
  89. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_rag/cli.py +0 -0
  90. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_rag/embedding_manager.py +0 -0
  91. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_rag/llm_interface.py +0 -0
  92. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_rag/query_rewriter.py +0 -0
  93. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_rag/rag_pipeline.py +0 -0
  94. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_rag/reranker.py +0 -0
  95. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_rag/retriever.py +0 -0
  96. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_smart_shell/__init__.py +0 -0
  97. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_stats/__init__.py +0 -0
  98. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_stats/storage.py +0 -0
  99. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_stats/visualizer.py +0 -0
  100. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/__init__.py +0 -0
  101. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/ask_user.py +0 -0
  102. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/base.py +0 -0
  103. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/clear_memory.py +0 -0
  104. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/cli/__init__.py +0 -0
  105. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/cli/main.py +0 -0
  106. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/edit_file.py +0 -0
  107. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/execute_script.py +0 -0
  108. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/file_analyzer.py +0 -0
  109. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/generate_new_tool.py +0 -0
  110. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/methodology.py +0 -0
  111. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/read_code.py +0 -0
  112. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/read_webpage.py +0 -0
  113. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/registry.py +0 -0
  114. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/retrieve_memory.py +0 -0
  115. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/rewrite_file.py +0 -0
  116. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/save_memory.py +0 -0
  117. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/search_web.py +0 -0
  118. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_tools/virtual_tty.py +0 -0
  119. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/__init__.py +0 -0
  120. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/builtin_replace_map.py +0 -0
  121. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/config.py +0 -0
  122. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/embedding.py +0 -0
  123. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/file_processors.py +0 -0
  124. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/git_utils.py +0 -0
  125. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/globals.py +0 -0
  126. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/http.py +0 -0
  127. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/methodology.py +0 -0
  128. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/tag.py +0 -0
  129. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis/jarvis_utils/utils.py +0 -0
  130. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis_ai_assistant.egg-info/SOURCES.txt +0 -0
  131. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis_ai_assistant.egg-info/dependency_links.txt +0 -0
  132. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis_ai_assistant.egg-info/entry_points.txt +0 -0
  133. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/src/jarvis_ai_assistant.egg-info/requires.txt +0 -0
  134. {jarvis_ai_assistant-0.3.19 → jarvis_ai_assistant-0.3.20}/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.19
3
+ Version: 0.3.20
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "jarvis-ai-assistant"
7
- version = "0.3.19"
7
+ version = "0.3.20"
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" }]
@@ -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.19",
6
+ version="0.3.20",
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.19"
4
+ __version__ = "0.3.20"
@@ -223,6 +223,7 @@ class Agent:
223
223
  use_analysis: Optional[bool] = None,
224
224
  force_save_memory: Optional[bool] = None,
225
225
  files: Optional[List[str]] = None,
226
+ confirm_callback: Optional[Callable[[str, bool], bool]] = None,
226
227
  ):
227
228
  """初始化Jarvis Agent实例
228
229
 
@@ -241,6 +242,7 @@ class Agent:
241
242
  use_methodology: 是否使用方法论
242
243
  use_analysis: 是否使用任务分析
243
244
  force_save_memory: 是否强制保存记忆
245
+ confirm_callback: 用户确认回调函数,签名为 (tip: str, default: bool) -> bool;默认使用CLI的user_confirm
244
246
  """
245
247
  # 基础属性初始化
246
248
  self.files = files or []
@@ -254,6 +256,11 @@ class Agent:
254
256
  self.user_data: Dict[str, Any] = {}
255
257
  self.after_tool_call_cb: Optional[Callable[[Agent], None]] = None
256
258
 
259
+ # 用户确认回调:默认使用 CLI 的 user_confirm,可由外部注入以支持 TUI/GUI
260
+ self.user_confirm: Callable[[str, bool], bool] = (
261
+ confirm_callback or user_confirm # type: ignore[assignment]
262
+ )
263
+
257
264
  # 初始化模型和会话
258
265
  self._init_model(llm_type, model_group)
259
266
  self._init_session()
@@ -811,7 +818,7 @@ class Agent:
811
818
  return self._complete_task(auto_completed=False)
812
819
 
813
820
  if any(handler.can_handle(current_response) for handler in self.output_handler):
814
- if user_confirm("检测到有工具调用,是否继续处理工具调用?", True):
821
+ if self.user_confirm("检测到有工具调用,是否继续处理工具调用?", True):
815
822
  self.session.prompt = f"被用户中断,用户补充信息为:{user_input}\n\n用户同意继续工具调用。"
816
823
  return None # 继续执行工具调用
817
824
  else:
@@ -905,7 +912,7 @@ class Agent:
905
912
  f"并且存在3个以上标签重叠的记忆。\n"
906
913
  f"是否立即整理记忆库以优化性能和相关性?"
907
914
  )
908
- if user_confirm(prompt, default=True):
915
+ if self.user_confirm(prompt, True):
909
916
  PrettyOutput.print(
910
917
  f"正在开始整理 '{scope_name}' ({memory_type}) 记忆库...",
911
918
  OutputType.INFO,
@@ -40,7 +40,7 @@ class ConfigEditor:
40
40
 
41
41
  if editor:
42
42
  try:
43
- subprocess.run([editor, str(config_file_path)], check=True)
43
+ subprocess.run([editor, str(config_file_path)], check=True, shell=(platform.system() == "Windows"))
44
44
  raise typer.Exit(code=0)
45
45
  except (subprocess.CalledProcessError, FileNotFoundError) as e:
46
46
  PrettyOutput.print(f"Failed to open editor: {e}", OutputType.ERROR)
@@ -11,9 +11,24 @@ def shell_input_handler(user_input: str, agent: Any) -> Tuple[str, bool]:
11
11
  if len(cmdline) == 0:
12
12
  return user_input, False
13
13
  else:
14
- script = "\n".join([c[1:] for c in cmdline])
14
+ marker = "# JARVIS-NOCONFIRM"
15
+
16
+ def _clean(line: str) -> str:
17
+ s = line[1:] # remove leading '!'
18
+ # strip no-confirm marker if present
19
+ idx = s.find(marker)
20
+ if idx != -1:
21
+ s = s[:idx]
22
+ return s.rstrip()
23
+
24
+ # Build script while stripping the no-confirm marker from each line
25
+ script = "\n".join([_clean(c) for c in cmdline])
15
26
  PrettyOutput.print(script, OutputType.CODE, lang="bash")
16
- if user_confirm(f"是否要执行以上shell脚本?", default=True):
27
+
28
+ # If any line contains the no-confirm marker, skip the pre-execution confirmation
29
+ no_confirm = any(marker in c for c in cmdline)
30
+
31
+ if no_confirm or user_confirm(f"是否要执行以上shell脚本?", default=True):
17
32
  from jarvis.jarvis_tools.registry import ToolRegistry
18
33
 
19
34
  output = ToolRegistry().handle_tool_calls(
@@ -50,10 +50,6 @@ class AI8Model(BasePlatform):
50
50
  }
51
51
 
52
52
  self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
53
- if self.model_name not in self.get_available_models():
54
- PrettyOutput.print(
55
- f"警告: 选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING
56
- )
57
53
 
58
54
  def set_model_name(self, model_name: str):
59
55
  """Set model name"""
@@ -108,7 +108,7 @@ def start_service(
108
108
  OutputType.INFO,
109
109
  )
110
110
 
111
- PrettyOutput.print("Available platforms:", OutputType.INFO)
111
+
112
112
 
113
113
  # Platform and model cache
114
114
  platform_instances: Dict[str, Any] = {}
@@ -178,7 +178,7 @@ def start_service(
178
178
  }
179
179
  )
180
180
  except Exception as exc:
181
- print(f"Error getting models for {default_platform}: {str(exc)}")
181
+ PrettyOutput.print(f"Error getting models for {default_platform}: {str(exc)}", OutputType.ERROR)
182
182
 
183
183
  # Return model list
184
184
  return {"object": "list", "data": model_list}
@@ -24,7 +24,7 @@ Example:
24
24
 
25
25
  def execute_command(command: str, should_run: bool) -> None:
26
26
  """Print command without execution"""
27
- print(command)
27
+ PrettyOutput.print(command, OutputType.CODE, lang="bash")
28
28
  if should_run:
29
29
  os.system(command)
30
30
 
@@ -16,6 +16,7 @@ from pathlib import Path
16
16
  from .stats import StatsManager
17
17
  from jarvis.jarvis_utils.utils import init_env
18
18
  from jarvis.jarvis_utils.config import get_data_dir
19
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
19
20
 
20
21
  app = typer.Typer(help="Jarvis 统计模块命令行工具")
21
22
  console = Console()
@@ -291,7 +292,7 @@ def export(
291
292
 
292
293
  if output == "json":
293
294
  # JSON格式输出
294
- print(json.dumps(data, indent=2, ensure_ascii=False))
295
+ PrettyOutput.print(json.dumps(data, indent=2, ensure_ascii=False), OutputType.CODE, lang="json")
295
296
  else:
296
297
  # CSV格式输出
297
298
  records = data.get("records", [])
@@ -9,6 +9,7 @@ from typing import Dict, List, Optional, Union, Any
9
9
 
10
10
  from jarvis.jarvis_stats.storage import StatsStorage
11
11
  from jarvis.jarvis_stats.visualizer import StatsVisualizer
12
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
12
13
 
13
14
 
14
15
  class StatsManager:
@@ -307,7 +308,6 @@ class StatsManager:
307
308
  """
308
309
  storage = StatsManager._get_storage()
309
310
  storage.delete_old_data(days_to_keep)
310
- print(f"已清理 {days_to_keep} 天前的数据")
311
311
 
312
312
  @staticmethod
313
313
  def remove_metric(metric_name: str) -> bool:
@@ -440,7 +440,7 @@ class StatsManager:
440
440
  )
441
441
 
442
442
  if not aggregated:
443
- print(f"没有找到指标 '{metric_name}' 的数据")
443
+ PrettyOutput.print(f"没有找到指标 '{metric_name}' 的数据", OutputType.WARNING)
444
444
  return
445
445
 
446
446
  # 获取指标信息
@@ -474,7 +474,7 @@ class StatsManager:
474
474
  show_values=True,
475
475
  )
476
476
 
477
- print(chart)
477
+ PrettyOutput.print(chart, OutputType.CODE, lang="text")
478
478
 
479
479
  # 显示时间范围
480
480
  from rich.panel import Panel
@@ -550,7 +550,7 @@ class StatsManager:
550
550
  )
551
551
 
552
552
  if not aggregated:
553
- print(f"没有找到指标 '{metric_name}' 的数据")
553
+ PrettyOutput.print(f"没有找到指标 '{metric_name}' 的数据", OutputType.WARNING)
554
554
  return
555
555
 
556
556
  # 获取指标信息
@@ -560,7 +560,7 @@ class StatsManager:
560
560
  # 显示汇总
561
561
  summary = visualizer.show_summary(aggregated, metric_name, unit, tags)
562
562
  if summary: # 如果返回了内容才打印(兼容性)
563
- print(summary)
563
+ PrettyOutput.print(summary, OutputType.INFO)
564
564
 
565
565
  # 显示时间范围
566
566
  from rich.panel import Panel
@@ -12,7 +12,7 @@ def copy_to_clipboard(text: str) -> None:
12
12
  text: 要复制的文本
13
13
  """
14
14
  PrettyOutput.print("--- 剪贴板内容开始 ---", OutputType.INFO)
15
- PrettyOutput.print(text, OutputType.CODE, lang="text")
15
+ print(text)
16
16
  PrettyOutput.print("--- 剪贴板内容结束 ---", OutputType.INFO)
17
17
 
18
18
  system = platform.system()
@@ -9,7 +9,10 @@
9
9
  - 用于输入控制的自定义键绑定
10
10
  """
11
11
  import os
12
+ import sys
13
+ import base64
12
14
  from typing import Iterable, List
15
+ import wcwidth
13
16
 
14
17
  from colorama import Fore
15
18
  from colorama import Style as ColoramaStyle
@@ -41,10 +44,63 @@ from jarvis.jarvis_utils.tag import ot
41
44
 
42
45
  # Sentinel value to indicate that Ctrl+O was pressed
43
46
  CTRL_O_SENTINEL = "__CTRL_O_PRESSED__"
47
+ # Sentinel prefix to indicate that Ctrl+F (fzf) inserted content should prefill next prompt
48
+ FZF_INSERT_SENTINEL_PREFIX = "__FZF_INSERT__::"
49
+ # Sentinel to request running fzf outside the prompt and then prefill next prompt
50
+ FZF_REQUEST_SENTINEL_PREFIX = "__FZF_REQUEST__::"
44
51
 
45
52
  # Persistent hint marker for multiline input (shown only once across runs)
46
53
  _MULTILINE_HINT_MARK_FILE = os.path.join(get_data_dir(), "multiline_enter_hint_shown")
47
54
 
55
+ def _display_width(s: str) -> int:
56
+ """Calculate printable width of a string in terminal columns (handles wide chars)."""
57
+ try:
58
+ w = 0
59
+ for ch in s:
60
+ cw = wcwidth.wcwidth(ch)
61
+ if cw is None or cw < 0:
62
+ # Fallback for unknown width chars (e.g. emoji on some terminals)
63
+ cw = 1
64
+ w += cw
65
+ return w
66
+ except Exception:
67
+ return len(s)
68
+
69
+ def _calc_prompt_rows(prev_text: str) -> int:
70
+ """
71
+ Estimate how many terminal rows the previous prompt occupied.
72
+ Considers prompt prefix and soft-wrapping across terminal columns.
73
+ """
74
+ try:
75
+ cols = os.get_terminal_size().columns
76
+ except Exception:
77
+ cols = 80
78
+ prefix = "👤 > "
79
+ prefix_w = _display_width(prefix)
80
+
81
+ if prev_text is None:
82
+ return 1
83
+
84
+ lines = prev_text.splitlines()
85
+ if not lines:
86
+ lines = [""]
87
+ # If the text ends with a newline, there is a visible empty line at the end.
88
+ if prev_text.endswith("\n"):
89
+ lines.append("")
90
+ total_rows = 0
91
+ for i, line in enumerate(lines):
92
+ lw = _display_width(line)
93
+ if i == 0:
94
+ width = prefix_w + lw
95
+ else:
96
+ width = lw
97
+ rows = max(1, (width + cols - 1) // cols)
98
+ total_rows += rows
99
+ return max(1, total_rows)
100
+
101
+
102
+
103
+
48
104
 
49
105
  def _multiline_hint_already_shown() -> bool:
50
106
  """Check if the multiline Enter hint has been shown before (persisted)."""
@@ -71,7 +127,7 @@ def get_single_line_input(tip: str, default: str = "") -> str:
71
127
  """
72
128
  session: PromptSession = PromptSession(history=None)
73
129
  style = PromptStyle.from_dict({"prompt": "ansicyan", "bottom-toolbar": "fg:#888888"})
74
- prompt = FormattedText([("class:prompt", f"👤 {tip}")])
130
+ prompt = FormattedText([("class:prompt", f"👤 > {tip}")])
75
131
  return session.prompt(prompt, default=default, style=style)
76
132
 
77
133
 
@@ -333,7 +389,7 @@ def _show_history_and_copy():
333
389
  break
334
390
 
335
391
 
336
- def _get_multiline_input_internal(tip: str) -> str:
392
+ def _get_multiline_input_internal(tip: str, preset: str | None = None, preset_cursor: int | None = None) -> str:
337
393
  """
338
394
  Internal function to get multiline input using prompt_toolkit.
339
395
  Returns a sentinel value if Ctrl+O is pressed.
@@ -385,6 +441,64 @@ def _get_multiline_input_internal(tip: str) -> str:
385
441
  """Handle Ctrl+O by exiting the prompt and returning the sentinel value."""
386
442
  event.app.exit(result=CTRL_O_SENTINEL)
387
443
 
444
+ @bindings.add("c-t", filter=has_focus(DEFAULT_BUFFER))
445
+ def _(event):
446
+ """Return a shell command like '!bash' for upper input_handler to execute."""
447
+ def _gen_shell_cmd() -> str: # type: ignore
448
+ try:
449
+ import os
450
+ import shutil
451
+
452
+ if os.name == "nt":
453
+ # Prefer PowerShell if available, otherwise fallback to cmd
454
+ for name in ("pwsh", "powershell", "cmd"):
455
+ if name == "cmd" or shutil.which(name):
456
+ return f"!{name}"
457
+ else:
458
+ shell_path = os.environ.get("SHELL", "")
459
+ if shell_path:
460
+ base = os.path.basename(shell_path)
461
+ if base:
462
+ return f"!{base}"
463
+ for name in ("fish", "zsh", "bash", "sh"):
464
+ if shutil.which(name):
465
+ return f"!{name}"
466
+ return "!bash"
467
+ except Exception:
468
+ return "!bash"
469
+
470
+ # Append a special marker to indicate no-confirm execution in shell_input_handler
471
+ event.app.exit(result=_gen_shell_cmd() + " # JARVIS-NOCONFIRM")
472
+
473
+
474
+ @bindings.add("@", filter=has_focus(DEFAULT_BUFFER), eager=True)
475
+ def _(event):
476
+ """
477
+ 使用 @ 触发 fzf(当 fzf 存在);否则仅插入 @ 以启用内置补全
478
+ 逻辑:
479
+ - 若检测到系统存在 fzf,则先插入 '@',随后请求外层运行 fzf 并在返回后进行替换/插入
480
+ - 若不存在 fzf 或发生异常,则直接插入 '@'
481
+ """
482
+ try:
483
+ import shutil
484
+ buf = event.current_buffer
485
+ if shutil.which("fzf") is None:
486
+ buf.insert_text("@")
487
+ return
488
+ # 先插入 '@',以便外层根据最后一个 '@' 进行片段替换
489
+ buf.insert_text("@")
490
+ doc = buf.document
491
+ text = doc.text
492
+ cursor = doc.cursor_position
493
+ payload = f"{cursor}:{base64.b64encode(text.encode('utf-8')).decode('ascii')}"
494
+ event.app.exit(result=FZF_REQUEST_SENTINEL_PREFIX + payload)
495
+ return
496
+ except Exception:
497
+ try:
498
+ event.current_buffer.insert_text("@")
499
+ except Exception:
500
+ pass
501
+
388
502
  style = PromptStyle.from_dict(
389
503
  {
390
504
  "prompt": "ansibrightmagenta bold",
@@ -414,11 +528,17 @@ def _get_multiline_input_internal(tip: str) -> str:
414
528
  ("class:bt.key", "Ctrl+O"),
415
529
  ("class:bt.label", " 历史复制 "),
416
530
  ("class:bt.sep", " • "),
531
+ ("class:bt.key", "@"),
532
+ ("class:bt.label", " FZF文件 "),
533
+ ("class:bt.sep", " • "),
534
+ ("class:bt.key", "Ctrl+T"),
535
+ ("class:bt.label", " 终端(!SHELL) "),
536
+ ("class:bt.sep", " • "),
417
537
  ("class:bt.key", "Ctrl+C/D"),
418
538
  ("class:bt.label", " 取消 "),
419
539
  ]
420
540
  )
421
-
541
+
422
542
  history_dir = get_data_dir()
423
543
  session: PromptSession = PromptSession(
424
544
  history=FileHistory(os.path.join(history_dir, "multiline_input_history")),
@@ -431,14 +551,26 @@ def _get_multiline_input_internal(tip: str) -> str:
431
551
  )
432
552
 
433
553
  # Tip is shown in bottom toolbar; avoid extra print
434
- prompt = FormattedText([("class:prompt", "👤 ")])
554
+ prompt = FormattedText([("class:prompt", "👤 > ")])
555
+
556
+ def _pre_run():
557
+ try:
558
+ from prompt_toolkit.application.current import get_app as _ga
559
+ app = _ga()
560
+ buf = app.current_buffer
561
+ if preset is not None and preset_cursor is not None:
562
+ cp = max(0, min(len(buf.text), preset_cursor))
563
+ buf.cursor_position = cp
564
+ except Exception:
565
+ pass
435
566
 
436
567
  try:
437
568
  return session.prompt(
438
569
  prompt,
439
570
  style=style,
440
- pre_run=lambda: None,
571
+ pre_run=_pre_run,
441
572
  bottom_toolbar=_bottom_toolbar,
573
+ default=(preset or ""),
442
574
  ).strip()
443
575
  except (KeyboardInterrupt, EOFError):
444
576
  return ""
@@ -453,14 +585,128 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
453
585
  tip: 提示文本,将显示在底部工具栏中
454
586
  print_on_empty: 当输入为空字符串时,是否打印“输入已取消”提示。默认打印。
455
587
  """
588
+ preset: str | None = None
589
+ preset_cursor: int | None = None
456
590
  while True:
457
- user_input = _get_multiline_input_internal(tip)
591
+ user_input = _get_multiline_input_internal(tip, preset=preset, preset_cursor=preset_cursor)
458
592
 
459
593
  if user_input == CTRL_O_SENTINEL:
460
594
  _show_history_and_copy()
461
595
  tip = "请继续输入(或按Ctrl+J确认):"
462
596
  continue
597
+ elif isinstance(user_input, str) and user_input.startswith(FZF_REQUEST_SENTINEL_PREFIX):
598
+ # Handle fzf request outside the prompt, then prefill new text.
599
+ try:
600
+ payload = user_input[len(FZF_REQUEST_SENTINEL_PREFIX) :]
601
+ sep_index = payload.find(":")
602
+ cursor = int(payload[:sep_index])
603
+ text = base64.b64decode(payload[sep_index + 1 :].encode("ascii")).decode("utf-8")
604
+ except Exception:
605
+ # Malformed payload; just continue without change.
606
+ preset = None
607
+ tip = "FZF 预填失败,继续输入:"
608
+ continue
609
+
610
+ # Run fzf to get a file selection synchronously (outside prompt)
611
+ selected_path = ""
612
+ try:
613
+ import shutil
614
+ import subprocess
615
+
616
+ if shutil.which("fzf") is None:
617
+ PrettyOutput.print("未检测到 fzf,无法打开文件选择器。", OutputType.WARNING)
618
+ else:
619
+ files: list[str] = []
620
+ try:
621
+ r = subprocess.run(
622
+ ["git", "ls-files"],
623
+ stdout=subprocess.PIPE,
624
+ stderr=subprocess.PIPE,
625
+ text=True,
626
+ )
627
+ if r.returncode == 0:
628
+ files = [line for line in r.stdout.splitlines() if line.strip()]
629
+ except Exception:
630
+ files = []
631
+
632
+ if not files:
633
+ import os as _os
634
+ for root, _, fnames in _os.walk(".", followlinks=False):
635
+ for name in fnames:
636
+ files.append(_os.path.relpath(_os.path.join(root, name), "."))
637
+ if len(files) > 10000:
638
+ break
639
+
640
+ if not files:
641
+ PrettyOutput.print("未找到可选择的文件。", OutputType.INFO)
642
+ else:
643
+ try:
644
+ specials = [ot("Summary"), ot("Clear"), ot("ToolUsage"), ot("ReloadConfig"), ot("SaveSession")]
645
+ except Exception:
646
+ specials = []
647
+ items = [s for s in specials if isinstance(s, str) and s.strip()] + files
648
+ proc = subprocess.run(
649
+ ["fzf", "--prompt", "Files> ", "--height", "40%", "--border"],
650
+ input="\n".join(items),
651
+ stdout=subprocess.PIPE,
652
+ stderr=subprocess.PIPE,
653
+ text=True,
654
+ )
655
+ sel = proc.stdout.strip()
656
+ if sel:
657
+ selected_path = sel
658
+ except Exception as e:
659
+ PrettyOutput.print(f"FZF 执行失败: {e}", OutputType.ERROR)
660
+
661
+ # Compute new text based on selection (or keep original if none)
662
+ if selected_path:
663
+ text_before = text[:cursor]
664
+ last_at = text_before.rfind("@")
665
+ if last_at != -1 and " " not in text_before[last_at + 1 :]:
666
+ # Replace @... segment
667
+ inserted = f"'{selected_path}'"
668
+ new_text = text[:last_at] + inserted + text[cursor:]
669
+ new_cursor = last_at + len(inserted)
670
+ else:
671
+ # Plain insert
672
+ inserted = f"'{selected_path}'"
673
+ new_text = text[:cursor] + inserted + text[cursor:]
674
+ new_cursor = cursor + len(inserted)
675
+ preset = new_text
676
+ preset_cursor = new_cursor
677
+ tip = "已插入文件,继续编辑或按Ctrl+J确认:"
678
+ else:
679
+ # No selection; keep original text and cursor
680
+ preset = text
681
+ preset_cursor = cursor
682
+ tip = "未选择文件或已取消,继续编辑:"
683
+ # 清除上一条输入行(多行安全),避免多清,保守仅按提示行估算
684
+ try:
685
+ rows_total = _calc_prompt_rows(text)
686
+ for _ in range(rows_total):
687
+ sys.stdout.write("\x1b[1A") # 光标上移一行
688
+ sys.stdout.write("\x1b[2K\r") # 清除整行
689
+ sys.stdout.flush()
690
+ except Exception:
691
+ pass
692
+ continue
693
+ elif isinstance(user_input, str) and user_input.startswith(FZF_INSERT_SENTINEL_PREFIX):
694
+ # 从哨兵载荷中提取新文本,作为下次进入提示的预填内容
695
+ preset = user_input[len(FZF_INSERT_SENTINEL_PREFIX) :]
696
+ preset_cursor = len(preset)
697
+
698
+ # 清除上一条输入行(多行安全),避免多清,保守仅按提示行估算
699
+ try:
700
+ rows_total = _calc_prompt_rows(preset)
701
+ for _ in range(rows_total):
702
+ sys.stdout.write("\x1b[1A")
703
+ sys.stdout.write("\x1b[2K\r")
704
+ sys.stdout.flush()
705
+ except Exception:
706
+ pass
707
+ tip = "已插入文件,继续编辑或按Ctrl+J确认:"
708
+ continue
463
709
  else:
464
710
  if not user_input and print_on_empty:
465
- PrettyOutput.print("\n输入已取消", OutputType.INFO)
711
+ PrettyOutput.print("输入已取消", OutputType.INFO)
466
712
  return user_input