jarvis-ai-assistant 0.7.0__py3-none-any.whl → 0.7.6__py3-none-any.whl

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 (159) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +243 -139
  3. jarvis/jarvis_agent/agent_manager.py +5 -10
  4. jarvis/jarvis_agent/builtin_input_handler.py +2 -6
  5. jarvis/jarvis_agent/config_editor.py +2 -7
  6. jarvis/jarvis_agent/event_bus.py +82 -12
  7. jarvis/jarvis_agent/file_context_handler.py +265 -15
  8. jarvis/jarvis_agent/file_methodology_manager.py +3 -4
  9. jarvis/jarvis_agent/jarvis.py +113 -98
  10. jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
  11. jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
  12. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
  13. jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
  14. jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
  15. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
  16. jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
  17. jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
  18. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
  19. jarvis/jarvis_agent/language_support_info.py +486 -0
  20. jarvis/jarvis_agent/main.py +6 -12
  21. jarvis/jarvis_agent/memory_manager.py +7 -16
  22. jarvis/jarvis_agent/methodology_share_manager.py +10 -16
  23. jarvis/jarvis_agent/prompt_manager.py +1 -1
  24. jarvis/jarvis_agent/prompts.py +193 -171
  25. jarvis/jarvis_agent/protocols.py +8 -12
  26. jarvis/jarvis_agent/run_loop.py +77 -14
  27. jarvis/jarvis_agent/session_manager.py +2 -3
  28. jarvis/jarvis_agent/share_manager.py +12 -21
  29. jarvis/jarvis_agent/shell_input_handler.py +1 -2
  30. jarvis/jarvis_agent/task_analyzer.py +26 -4
  31. jarvis/jarvis_agent/task_manager.py +11 -27
  32. jarvis/jarvis_agent/tool_executor.py +2 -3
  33. jarvis/jarvis_agent/tool_share_manager.py +12 -24
  34. jarvis/jarvis_agent/web_server.py +55 -20
  35. jarvis/jarvis_c2rust/__init__.py +5 -5
  36. jarvis/jarvis_c2rust/cli.py +461 -499
  37. jarvis/jarvis_c2rust/collector.py +45 -53
  38. jarvis/jarvis_c2rust/constants.py +26 -0
  39. jarvis/jarvis_c2rust/library_replacer.py +264 -132
  40. jarvis/jarvis_c2rust/llm_module_agent.py +162 -190
  41. jarvis/jarvis_c2rust/loaders.py +207 -0
  42. jarvis/jarvis_c2rust/models.py +28 -0
  43. jarvis/jarvis_c2rust/optimizer.py +1592 -395
  44. jarvis/jarvis_c2rust/transpiler.py +1722 -1064
  45. jarvis/jarvis_c2rust/utils.py +385 -0
  46. jarvis/jarvis_code_agent/build_validation_config.py +2 -3
  47. jarvis/jarvis_code_agent/code_agent.py +394 -320
  48. jarvis/jarvis_code_agent/code_analyzer/__init__.py +3 -0
  49. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +4 -0
  50. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +17 -2
  51. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +3 -0
  52. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +36 -4
  53. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +9 -0
  54. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +9 -0
  55. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +12 -1
  56. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +22 -5
  57. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +57 -32
  58. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +62 -6
  59. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +8 -9
  60. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +290 -5
  61. jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -0
  62. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +21 -3
  63. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +72 -4
  64. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +35 -3
  65. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
  66. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
  67. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +52 -2
  68. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +73 -1
  69. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
  70. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +306 -152
  71. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
  72. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +193 -18
  73. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +18 -8
  74. jarvis/jarvis_code_agent/lint.py +258 -27
  75. jarvis/jarvis_code_agent/utils.py +0 -1
  76. jarvis/jarvis_code_analysis/code_review.py +19 -24
  77. jarvis/jarvis_data/config_schema.json +53 -26
  78. jarvis/jarvis_git_squash/main.py +4 -5
  79. jarvis/jarvis_git_utils/git_commiter.py +44 -49
  80. jarvis/jarvis_mcp/sse_mcp_client.py +20 -27
  81. jarvis/jarvis_mcp/stdio_mcp_client.py +11 -12
  82. jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
  83. jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
  84. jarvis/jarvis_methodology/main.py +32 -48
  85. jarvis/jarvis_multi_agent/__init__.py +79 -61
  86. jarvis/jarvis_multi_agent/main.py +3 -7
  87. jarvis/jarvis_platform/base.py +469 -199
  88. jarvis/jarvis_platform/human.py +7 -8
  89. jarvis/jarvis_platform/kimi.py +30 -36
  90. jarvis/jarvis_platform/openai.py +65 -27
  91. jarvis/jarvis_platform/registry.py +26 -10
  92. jarvis/jarvis_platform/tongyi.py +24 -25
  93. jarvis/jarvis_platform/yuanbao.py +31 -42
  94. jarvis/jarvis_platform_manager/main.py +66 -77
  95. jarvis/jarvis_platform_manager/service.py +8 -13
  96. jarvis/jarvis_rag/cli.py +49 -51
  97. jarvis/jarvis_rag/embedding_manager.py +13 -18
  98. jarvis/jarvis_rag/llm_interface.py +8 -9
  99. jarvis/jarvis_rag/query_rewriter.py +10 -21
  100. jarvis/jarvis_rag/rag_pipeline.py +24 -27
  101. jarvis/jarvis_rag/reranker.py +4 -5
  102. jarvis/jarvis_rag/retriever.py +28 -30
  103. jarvis/jarvis_sec/__init__.py +220 -3520
  104. jarvis/jarvis_sec/agents.py +143 -0
  105. jarvis/jarvis_sec/analysis.py +276 -0
  106. jarvis/jarvis_sec/cli.py +29 -6
  107. jarvis/jarvis_sec/clustering.py +1439 -0
  108. jarvis/jarvis_sec/file_manager.py +427 -0
  109. jarvis/jarvis_sec/parsers.py +73 -0
  110. jarvis/jarvis_sec/prompts.py +268 -0
  111. jarvis/jarvis_sec/report.py +83 -4
  112. jarvis/jarvis_sec/review.py +453 -0
  113. jarvis/jarvis_sec/utils.py +499 -0
  114. jarvis/jarvis_sec/verification.py +848 -0
  115. jarvis/jarvis_sec/workflow.py +7 -0
  116. jarvis/jarvis_smart_shell/main.py +38 -87
  117. jarvis/jarvis_stats/cli.py +1 -1
  118. jarvis/jarvis_stats/stats.py +7 -7
  119. jarvis/jarvis_stats/storage.py +15 -21
  120. jarvis/jarvis_tools/clear_memory.py +3 -20
  121. jarvis/jarvis_tools/cli/main.py +20 -23
  122. jarvis/jarvis_tools/edit_file.py +1066 -0
  123. jarvis/jarvis_tools/execute_script.py +42 -21
  124. jarvis/jarvis_tools/file_analyzer.py +6 -9
  125. jarvis/jarvis_tools/generate_new_tool.py +11 -20
  126. jarvis/jarvis_tools/lsp_client.py +1552 -0
  127. jarvis/jarvis_tools/methodology.py +2 -3
  128. jarvis/jarvis_tools/read_code.py +1525 -87
  129. jarvis/jarvis_tools/read_symbols.py +2 -3
  130. jarvis/jarvis_tools/read_webpage.py +7 -10
  131. jarvis/jarvis_tools/registry.py +370 -181
  132. jarvis/jarvis_tools/retrieve_memory.py +20 -19
  133. jarvis/jarvis_tools/rewrite_file.py +105 -0
  134. jarvis/jarvis_tools/save_memory.py +3 -15
  135. jarvis/jarvis_tools/search_web.py +3 -7
  136. jarvis/jarvis_tools/sub_agent.py +17 -6
  137. jarvis/jarvis_tools/sub_code_agent.py +14 -16
  138. jarvis/jarvis_tools/virtual_tty.py +54 -32
  139. jarvis/jarvis_utils/clipboard.py +7 -10
  140. jarvis/jarvis_utils/config.py +98 -63
  141. jarvis/jarvis_utils/embedding.py +5 -5
  142. jarvis/jarvis_utils/fzf.py +8 -8
  143. jarvis/jarvis_utils/git_utils.py +81 -67
  144. jarvis/jarvis_utils/input.py +24 -49
  145. jarvis/jarvis_utils/jsonnet_compat.py +465 -0
  146. jarvis/jarvis_utils/methodology.py +33 -35
  147. jarvis/jarvis_utils/utils.py +245 -202
  148. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/METADATA +205 -70
  149. jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
  150. jarvis/jarvis_agent/edit_file_handler.py +0 -584
  151. jarvis/jarvis_agent/rewrite_file_handler.py +0 -141
  152. jarvis/jarvis_agent/task_planner.py +0 -496
  153. jarvis/jarvis_platform/ai8.py +0 -332
  154. jarvis/jarvis_tools/ask_user.py +0 -54
  155. jarvis_ai_assistant-0.7.0.dist-info/RECORD +0 -192
  156. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
  157. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +0 -0
  158. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
  159. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
@@ -7,7 +7,7 @@ from abc import ABC, abstractmethod
7
7
 
8
8
  from prompt_toolkit import prompt
9
9
 
10
- from jarvis.jarvis_agent import OutputType, PrettyOutput, user_confirm
10
+ from jarvis.jarvis_agent import user_confirm
11
11
  from jarvis.jarvis_utils.config import get_data_dir
12
12
 
13
13
 
@@ -61,9 +61,7 @@ class ShareManager(ABC):
61
61
  def update_central_repo(self) -> None:
62
62
  """克隆或更新中心仓库"""
63
63
  if not os.path.exists(self.repo_path):
64
- PrettyOutput.print(
65
- f"正在克隆中心{self.get_resource_type()}仓库...", OutputType.INFO
66
- )
64
+ print(f"ℹ️ 正在克隆中心{self.get_resource_type()}仓库...")
67
65
  subprocess.run(
68
66
  ["git", "clone", self.central_repo_url, self.repo_path], check=True
69
67
  )
@@ -92,9 +90,7 @@ class ShareManager(ABC):
92
90
  )
93
91
  subprocess.run(["git", "push"], cwd=self.repo_path, check=True)
94
92
  else:
95
- PrettyOutput.print(
96
- f"正在更新中心{self.get_resource_type()}仓库...", OutputType.INFO
97
- )
93
+ print(f"ℹ️ 正在更新中心{self.get_resource_type()}仓库...")
98
94
  # 检查是否是空仓库
99
95
  try:
100
96
  # 先尝试获取远程分支信息
@@ -123,24 +119,18 @@ class ShareManager(ABC):
123
119
  ["git", "checkout", "."], cwd=self.repo_path, check=True
124
120
  )
125
121
  else:
126
- PrettyOutput.print(
127
- f"跳过更新 '{self.repo_name}' 以保留未提交的更改。",
128
- OutputType.INFO,
129
- )
122
+ print(f"ℹ️ 跳过更新 '{self.repo_name}' 以保留未提交的更改。")
130
123
  return
131
124
  subprocess.run(["git", "pull"], cwd=self.repo_path, check=True)
132
125
  else:
133
- PrettyOutput.print(
134
- f"中心{self.get_resource_type()}仓库是空的,将初始化为新仓库",
135
- OutputType.INFO,
136
- )
126
+ print(f"ℹ️ 中心{self.get_resource_type()}仓库是空的,将初始化为新仓库")
137
127
  except subprocess.CalledProcessError:
138
128
  # 如果命令失败,可能是网络问题或其他错误
139
- PrettyOutput.print("无法连接到远程仓库,将跳过更新", OutputType.WARNING)
129
+ print("⚠️ 无法连接到远程仓库,将跳过更新")
140
130
 
141
131
  def commit_and_push(self, count: int) -> None:
142
132
  """提交并推送更改"""
143
- PrettyOutput.print("\n正在提交更改...", OutputType.INFO)
133
+ print("ℹ️ 正在提交更改...")
144
134
  subprocess.run(["git", "add", "."], cwd=self.repo_path, check=True)
145
135
 
146
136
  commit_msg = f"Add {count} {self.get_resource_type()}(s) from local collection"
@@ -148,7 +138,7 @@ class ShareManager(ABC):
148
138
  ["git", "commit", "-m", commit_msg], cwd=self.repo_path, check=True
149
139
  )
150
140
 
151
- PrettyOutput.print("正在推送到远程仓库...", OutputType.INFO)
141
+ print("ℹ️ 正在推送到远程仓库...")
152
142
  # 检查是否需要设置上游分支(空仓库的情况)
153
143
  try:
154
144
  # 先尝试普通推送
@@ -179,7 +169,8 @@ class ShareManager(ABC):
179
169
  resource_list.append(f"[{i}] {self.format_resource_display(resource)}")
180
170
 
181
171
  # 一次性打印所有资源
182
- PrettyOutput.print("\n".join(resource_list), OutputType.INFO)
172
+ joined_resources = '\n'.join(resource_list)
173
+ print(f"ℹ️ {joined_resources}")
183
174
 
184
175
  # 让用户选择
185
176
  while True:
@@ -195,12 +186,12 @@ class ShareManager(ABC):
195
186
  else:
196
187
  selected_indices = parse_selection(choice_str, len(resources))
197
188
  if not selected_indices:
198
- PrettyOutput.print("无效的选择", OutputType.WARNING)
189
+ print("⚠️ 无效的选择")
199
190
  continue
200
191
  return [resources[i - 1] for i in selected_indices]
201
192
 
202
193
  except ValueError:
203
- PrettyOutput.print("请输入有效的数字", OutputType.WARNING)
194
+ print("⚠️ 请输入有效的数字")
204
195
 
205
196
  @abstractmethod
206
197
  def get_resource_type(self) -> str:
@@ -1,7 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  from typing import Any, Tuple
3
3
 
4
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
5
4
  from jarvis.jarvis_utils.input import user_confirm
6
5
  from jarvis.jarvis_agent.utils import join_prompts
7
6
 
@@ -24,7 +23,7 @@ def shell_input_handler(user_input: str, agent: Any) -> Tuple[str, bool]:
24
23
 
25
24
  # Build script while stripping the no-confirm marker from each line
26
25
  script = "\n".join([_clean(c) for c in cmdline])
27
- PrettyOutput.print(script, OutputType.CODE, lang="bash")
26
+ print(script)
28
27
 
29
28
  # If any line contains the no-confirm marker, skip the pre-execution confirmation
30
29
  no_confirm = any(marker in c for c in cmdline)
@@ -6,8 +6,7 @@
6
6
 
7
7
  from jarvis.jarvis_utils.globals import get_interrupt, set_interrupt
8
8
 
9
- from jarvis.jarvis_agent.prompts import TASK_ANALYSIS_PROMPT
10
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
9
+ from jarvis.jarvis_agent.prompts import get_task_analysis_prompt
11
10
  from jarvis.jarvis_agent.utils import join_prompts
12
11
  from jarvis.jarvis_agent.events import BEFORE_TOOL_CALL, AFTER_TOOL_CALL, BEFORE_SUMMARY, TASK_COMPLETED
13
12
 
@@ -46,7 +45,7 @@ class TaskAnalyzer:
46
45
  self._process_analysis_loop()
47
46
 
48
47
  except Exception:
49
- PrettyOutput.print("分析失败", OutputType.ERROR)
48
+ print("分析失败")
50
49
  finally:
51
50
  # 标记已完成一次分析,避免事件回调重复执行
52
51
  self._analysis_done = True
@@ -57,7 +56,30 @@ class TaskAnalyzer:
57
56
 
58
57
  def _prepare_analysis_prompt(self, satisfaction_feedback: str) -> str:
59
58
  """准备分析提示"""
60
- return join_prompts([TASK_ANALYSIS_PROMPT, satisfaction_feedback])
59
+ # 检查是否有 save_memory 工具(工具可用性)
60
+ has_save_memory = False
61
+ # 检查是否有 generate_new_tool 工具
62
+ has_generate_new_tool = False
63
+ try:
64
+ tool_registry = self.agent.get_tool_registry()
65
+ if tool_registry:
66
+ # 检查 save_memory 工具
67
+ save_memory_tool = tool_registry.get_tool("save_memory")
68
+ has_save_memory = save_memory_tool is not None
69
+
70
+ # 检查 generate_new_tool 工具
71
+ generate_tool = tool_registry.get_tool("generate_new_tool")
72
+ has_generate_new_tool = generate_tool is not None
73
+ except Exception:
74
+ pass
75
+
76
+ # 根据配置获取相应的提示词
77
+ analysis_prompt = get_task_analysis_prompt(
78
+ has_save_memory=has_save_memory,
79
+ has_generate_new_tool=has_generate_new_tool
80
+ )
81
+
82
+ return join_prompts([analysis_prompt, satisfaction_feedback])
61
83
 
62
84
  def _process_analysis_loop(self):
63
85
  """处理分析循环"""
@@ -9,8 +9,6 @@ from rich.table import Table
9
9
  from rich.console import Console
10
10
 
11
11
  from jarvis.jarvis_agent import (
12
- OutputType,
13
- PrettyOutput,
14
12
  get_multiline_input,
15
13
  user_confirm,
16
14
  )
@@ -31,9 +29,7 @@ class TaskManager:
31
29
  data_dir = get_data_dir()
32
30
  pre_command_path = os.path.join(data_dir, "pre-command")
33
31
  if os.path.exists(pre_command_path):
34
- PrettyOutput.print(
35
- f"从{pre_command_path}加载预定义任务...", OutputType.INFO
36
- )
32
+ print(f"ℹ️ 从{pre_command_path}加载预定义任务...")
37
33
  try:
38
34
  with open(
39
35
  pre_command_path, "r", encoding="utf-8", errors="ignore"
@@ -43,19 +39,15 @@ class TaskManager:
43
39
  for name, desc in user_tasks.items():
44
40
  if desc:
45
41
  tasks[str(name)] = str(desc)
46
- PrettyOutput.print(
47
- f"预定义任务加载完成 {pre_command_path}", OutputType.SUCCESS
48
- )
42
+ print(f"✅ 预定义任务加载完成 {pre_command_path}")
49
43
  except (yaml.YAMLError, OSError):
50
- PrettyOutput.print(
51
- f"预定义任务加载失败 {pre_command_path}", OutputType.ERROR
52
- )
44
+ print(f"❌ 预定义任务加载失败 {pre_command_path}")
53
45
 
54
46
  # Check .jarvis/pre-command in current directory
55
47
  pre_command_path = ".jarvis/pre-command"
56
48
  if os.path.exists(pre_command_path):
57
49
  abs_path = os.path.abspath(pre_command_path)
58
- PrettyOutput.print(f"从{abs_path}加载预定义任务...", OutputType.INFO)
50
+ print(f"ℹ️ 从{abs_path}加载预定义任务...")
59
51
  try:
60
52
  with open(
61
53
  pre_command_path, "r", encoding="utf-8", errors="ignore"
@@ -65,13 +57,9 @@ class TaskManager:
65
57
  for name, desc in local_tasks.items():
66
58
  if desc:
67
59
  tasks[str(name)] = str(desc)
68
- PrettyOutput.print(
69
- f"预定义任务加载完成 {pre_command_path}", OutputType.SUCCESS
70
- )
60
+ print(f"✅ 预定义任务加载完成 {pre_command_path}")
71
61
  except (yaml.YAMLError, OSError):
72
- PrettyOutput.print(
73
- f"预定义任务加载失败 {pre_command_path}", OutputType.ERROR
74
- )
62
+ print(f"❌ 预定义任务加载失败 {pre_command_path}")
75
63
 
76
64
  return tasks
77
65
 
@@ -89,7 +77,7 @@ class TaskManager:
89
77
  for i, name in enumerate(task_names, 1):
90
78
  table.add_row(str(i), name)
91
79
  Console().print(table)
92
- PrettyOutput.print("[0] 跳过预定义任务", OutputType.INFO)
80
+ print("ℹ️ [0] 跳过预定义任务")
93
81
 
94
82
  # Try fzf selection first (with numbered options and a skip option)
95
83
  fzf_list = [f"{0:>3} | 跳过预定义任务"] + [
@@ -104,7 +92,7 @@ class TaskManager:
104
92
  return ""
105
93
  if 1 <= idx <= len(task_names):
106
94
  selected_task = tasks[task_names[idx - 1]]
107
- PrettyOutput.print(f"将要执行任务:\n {selected_task}", OutputType.INFO)
95
+ print(f"ℹ️ 将要执行任务:\n {selected_task}")
108
96
  # 询问是否需要补充信息
109
97
  need_additional = user_confirm("需要为此任务添加补充信息吗?", default=False)
110
98
  if need_additional:
@@ -129,9 +117,7 @@ class TaskManager:
129
117
  return ""
130
118
  if 1 <= choice <= len(task_names):
131
119
  selected_task = tasks[task_names[choice - 1]]
132
- PrettyOutput.print(
133
- f"将要执行任务:\n {selected_task}", OutputType.INFO
134
- )
120
+ print(f"ℹ️ 将要执行任务:\n {selected_task}")
135
121
  # 询问是否需要补充信息
136
122
  need_additional = user_confirm(
137
123
  "需要为此任务添加补充信息吗?", default=False
@@ -144,11 +130,9 @@ class TaskManager:
144
130
  f"补充信息:\n{additional_input}"
145
131
  ])
146
132
  return selected_task
147
- PrettyOutput.print(
148
- "无效的选择。请选择列表中的一个号码。", OutputType.WARNING
149
- )
133
+ print("⚠️ 无效的选择。请选择列表中的一个号码。")
150
134
 
151
135
  except (KeyboardInterrupt, EOFError):
152
136
  return ""
153
137
  except ValueError as val_err:
154
- PrettyOutput.print(f"选择任务失败: {str(val_err)}", OutputType.ERROR)
138
+ print(f"选择任务失败: {str(val_err)}")
@@ -2,7 +2,6 @@
2
2
  from typing import Any, Tuple, TYPE_CHECKING
3
3
 
4
4
  from jarvis.jarvis_utils.input import user_confirm
5
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
6
5
 
7
6
  if TYPE_CHECKING:
8
7
  from jarvis.jarvis_agent import Agent
@@ -31,7 +30,7 @@ def execute_tool_call(response: str, agent: "Agent") -> Tuple[bool, Any]:
31
30
  f"操作失败:检测到多个操作。一次只能执行一个操作。"
32
31
  f"尝试执行的操作:{', '.join([handler.name() for handler in tool_list])}"
33
32
  )
34
- PrettyOutput.print(error_message, OutputType.WARNING)
33
+ print(f"⚠️ {error_message}")
35
34
  return False, error_message
36
35
 
37
36
  if not tool_list:
@@ -47,7 +46,7 @@ def execute_tool_call(response: str, agent: "Agent") -> Tuple[bool, Any]:
47
46
  print(f"✅ {tool_to_execute.name()}执行完成")
48
47
  return result
49
48
  except Exception as e:
50
- PrettyOutput.print(f"工具执行失败: {str(e)}", OutputType.ERROR)
49
+ print(f"工具执行失败: {str(e)}")
51
50
  return False, str(e)
52
51
 
53
52
  return False, ""
@@ -7,7 +7,7 @@ from typing import List, Dict, Any, Set
7
7
 
8
8
  import typer
9
9
 
10
- from jarvis.jarvis_agent import OutputType, PrettyOutput, user_confirm
10
+ from jarvis.jarvis_agent import user_confirm
11
11
  from jarvis.jarvis_agent.share_manager import ShareManager
12
12
  from jarvis.jarvis_utils.config import get_central_tool_repo, get_data_dir
13
13
 
@@ -18,13 +18,8 @@ class ToolShareManager(ShareManager):
18
18
  def __init__(self):
19
19
  central_repo = get_central_tool_repo()
20
20
  if not central_repo:
21
- PrettyOutput.print(
22
- "错误:未配置中心工具仓库(JARVIS_CENTRAL_TOOL_REPO)",
23
- OutputType.ERROR,
24
- )
25
- PrettyOutput.print(
26
- "请在配置文件中设置中心工具仓库的Git地址", OutputType.INFO
27
- )
21
+ print("❌ 错误:未配置中心工具仓库(JARVIS_CENTRAL_TOOL_REPO)")
22
+ print("ℹ️ 请在配置文件中设置中心工具仓库的Git地址")
28
23
  raise typer.Exit(code=1)
29
24
 
30
25
  super().__init__(central_repo, "central_tool_repo")
@@ -52,10 +47,7 @@ class ToolShareManager(ShareManager):
52
47
  # 只从数据目录的tools目录获取工具
53
48
  local_tools_dir = os.path.join(get_data_dir(), "tools")
54
49
  if not os.path.exists(local_tools_dir):
55
- PrettyOutput.print(
56
- f"本地工具目录不存在: {local_tools_dir}",
57
- OutputType.WARNING,
58
- )
50
+ print(f"⚠️ 本地工具目录不存在: {local_tools_dir}")
59
51
  return []
60
52
 
61
53
  # 收集本地工具文件(排除已存在的)
@@ -84,7 +76,8 @@ class ToolShareManager(ShareManager):
84
76
  share_list = ["\n将要分享以下工具到中心仓库(注意:文件将被移动而非复制):"]
85
77
  for tool in resources:
86
78
  share_list.append(f"- {tool['tool_name']} ({tool['filename']})")
87
- PrettyOutput.print("\n".join(share_list), OutputType.WARNING)
79
+ joined_list = '\n'.join(share_list)
80
+ print(f"⚠️ {joined_list}")
88
81
 
89
82
  if not user_confirm("确认移动这些工具到中心仓库吗?(原文件将被删除)"):
90
83
  return []
@@ -108,10 +101,7 @@ class ToolShareManager(ShareManager):
108
101
  # 获取本地资源
109
102
  local_resources = self.get_local_resources()
110
103
  if not local_resources:
111
- PrettyOutput.print(
112
- "没有找到新的工具文件(所有工具可能已存在于中心仓库)",
113
- OutputType.WARNING,
114
- )
104
+ print("⚠️ 没有找到新的工具文件(所有工具可能已存在于中心仓库)")
115
105
  return
116
106
 
117
107
  # 选择要分享的资源
@@ -123,17 +113,15 @@ class ToolShareManager(ShareManager):
123
113
  moved_list = self.share_resources(selected_resources)
124
114
  if moved_list:
125
115
  # 一次性显示所有移动结果
126
- PrettyOutput.print("\n".join(moved_list), OutputType.SUCCESS)
116
+ joined_moved = '\n'.join(moved_list)
117
+ print(f"✅ {joined_moved}")
127
118
 
128
119
  # 提交并推送
129
120
  self.commit_and_push(len(selected_resources))
130
121
 
131
- PrettyOutput.print("\n工具已成功分享到中心仓库!", OutputType.SUCCESS)
132
- PrettyOutput.print(
133
- f"原文件已从 {os.path.join(get_data_dir(), 'tools')} 移动到中心仓库",
134
- OutputType.INFO,
135
- )
122
+ print("工具已成功分享到中心仓库!")
123
+ print(f"ℹ️ 原文件已从 {os.path.join(get_data_dir(), 'tools')} 移动到中心仓库")
136
124
 
137
125
  except Exception as e:
138
- PrettyOutput.print(f"分享工具时出错: {str(e)}", OutputType.ERROR)
126
+ print(f"分享工具时出错: {str(e)}")
139
127
  raise typer.Exit(code=1)
@@ -18,7 +18,7 @@ import os
18
18
  import signal
19
19
  import atexit
20
20
  from pathlib import Path
21
- from typing import Any, Dict, Callable, Optional
21
+ from typing import Any, Dict, Callable, Optional, List
22
22
 
23
23
  import uvicorn
24
24
  from fastapi import FastAPI, WebSocket, WebSocketDisconnect
@@ -27,7 +27,6 @@ from fastapi.middleware.cors import CORSMiddleware
27
27
 
28
28
  from jarvis.jarvis_agent.web_bridge import WebBridge
29
29
  from jarvis.jarvis_utils.globals import set_interrupt, console
30
- from jarvis.jarvis_utils.output import PrettyOutput, OutputType
31
30
 
32
31
  # ---------------------------
33
32
  # 应用与页面
@@ -290,10 +289,14 @@ def _run_and_notify(agent: Any, text: str) -> None:
290
289
  except Exception:
291
290
  pass
292
291
 
293
- def start_web_server(agent: Any, host: str = "127.0.0.1", port: int = 8765) -> None:
292
+ def start_web_server(agent: Any, host: str = "127.0.0.1", port: int = 8765, launch_command: Optional[List[str]] = None) -> None:
294
293
  """
295
294
  启动Web服务,并将Agent绑定到应用上下文。
296
295
  - agent: 现有的 Agent 实例(已完成初始化)
296
+ - host: Web 服务主机地址
297
+ - port: Web 服务端口
298
+ - launch_command: 交互式终端启动命令(列表格式,如 ["jvs", "--task", "xxx"]),
299
+ 如果为 None,则从环境变量 JARVIS_WEB_LAUNCH_JSON 读取
297
300
  """
298
301
  app = _build_app()
299
302
  app.state.agent = agent # 供 WS 端点调用
@@ -304,6 +307,8 @@ def start_web_server(agent: Any, host: str = "127.0.0.1", port: int = 8765) -> N
304
307
  app.state.agent_manager = agent if hasattr(agent, "initialize") else None
305
308
  except Exception:
306
309
  app.state.agent_manager = None
310
+ # 存储启动命令到应用状态
311
+ app.state.launch_command = launch_command
307
312
 
308
313
  @app.websocket("/stdio")
309
314
  async def websocket_stdio(ws: WebSocket) -> None:
@@ -451,26 +456,48 @@ def start_web_server(agent: Any, host: str = "127.0.0.1", port: int = 8765) -> N
451
456
  # 会话结束后等待用户按回车再重启
452
457
  waiting_for_ack = False
453
458
  ack_event = asyncio.Event()
454
-
459
+
460
+ # 在 fork 前获取启动命令(避免在子进程中访问 app.state)
461
+ _launch_cmd = None
462
+ try:
463
+ if hasattr(app.state, "launch_command") and app.state.launch_command:
464
+ _launch_cmd = app.state.launch_command
465
+ # 调试输出
466
+ if _os.environ.get("JARVIS_DEBUG_WEB_LAUNCH_CMD") == "1":
467
+ print(f"🔍 Web服务器: 使用传入的启动命令: {_launch_cmd}")
468
+ else:
469
+ # 回退到环境变量
470
+ import json as _json
471
+ _cmd_json = _os.environ.get("JARVIS_WEB_LAUNCH_JSON", "")
472
+ if _cmd_json:
473
+ try:
474
+ _launch_cmd = _json.loads(_cmd_json)
475
+ if _os.environ.get("JARVIS_DEBUG_WEB_LAUNCH_CMD") == "1":
476
+ print(f"🔍 Web服务器: 从环境变量读取启动命令: {_launch_cmd}")
477
+ except Exception:
478
+ _launch_cmd = None
479
+ except Exception:
480
+ _launch_cmd = None
455
481
 
456
482
  def _spawn_jvs_session() -> bool:
457
- nonlocal session
483
+ nonlocal session, _launch_cmd
458
484
  try:
459
485
  pid, master_fd = _pty.fork()
460
486
  if pid == 0:
461
- # 子进程:执行 jvs 启动命令(移除 web 相关参数),失败时回退到系统 shell
462
- try:
463
- import json as _json
464
- _cmd_json = _os.environ.get("JARVIS_WEB_LAUNCH_JSON", "")
465
- if _cmd_json:
466
- try:
467
- _argv = _json.loads(_cmd_json)
468
- except Exception:
469
- _argv = []
470
- if isinstance(_argv, list) and len(_argv) > 0 and isinstance(_argv[0], str):
471
- _os.execvp(_argv[0], _argv)
472
- except Exception:
473
- pass
487
+ # 子进程:执行启动命令,失败时回退到系统 shell
488
+ # 使用在 fork 前获取的命令
489
+ _argv = _launch_cmd
490
+
491
+ # 如果获取到有效命令,执行它
492
+ if _argv and isinstance(_argv, list) and len(_argv) > 0 and isinstance(_argv[0], str):
493
+ try:
494
+ if _os.environ.get("JARVIS_DEBUG_WEB_LAUNCH_CMD") == "1":
495
+ print(f"🔍 子进程: 执行命令: {_argv}")
496
+ _os.execvp(_argv[0], _argv)
497
+ except Exception as e:
498
+ if _os.environ.get("JARVIS_DEBUG_WEB_LAUNCH_CMD") == "1":
499
+ print(f"⚠️ 子进程: 执行命令失败: {e}")
500
+ pass
474
501
  # 若未配置或执行失败,回退到 /bin/bash 或 /bin/sh
475
502
  try:
476
503
  _os.execvp("/bin/bash", ["/bin/bash"])
@@ -707,7 +734,7 @@ def start_web_server(agent: Any, host: str = "127.0.0.1", port: int = 8765) -> N
707
734
  except Exception:
708
735
  pass
709
736
 
710
- PrettyOutput.print(f"启动 Jarvis Web 服务: http://{host}:{port}", OutputType.SUCCESS)
737
+ print(f"启动 Jarvis Web 服务: http://{host}:{port}")
711
738
  # 在服务端进程内也写入并维护 PID 文件,增强可检测性与可清理性
712
739
  try:
713
740
  pidfile = Path(os.path.expanduser("~/.jarvis")) / f"jarvis_web_{port}.pid"
@@ -748,4 +775,12 @@ def start_web_server(agent: Any, host: str = "127.0.0.1", port: int = 8765) -> N
748
775
  pass
749
776
  except Exception:
750
777
  pass
751
- uvicorn.run(app, host=host, port=port)
778
+ # 配置 uvicorn 日志级别,隐藏连接信息和访问日志
779
+ import logging
780
+ # 禁用 uvicorn 的访问日志
781
+ logging.getLogger("uvicorn.access").setLevel(logging.WARNING)
782
+ # 禁用 uvicorn 的常规日志(连接信息等)
783
+ logging.getLogger("uvicorn").setLevel(logging.WARNING)
784
+ # 禁用 uvicorn.error 的 INFO 级别日志
785
+ logging.getLogger("uvicorn.error").setLevel(logging.WARNING)
786
+ uvicorn.run(app, host=host, port=port, log_level="warning", access_log=False)
@@ -5,16 +5,16 @@ Jarvis C2Rust 工具集。
5
5
  核心数据:
6
6
  - 统一符号表(JSONL):<project_root>/.jarvis/c2rust/symbols.jsonl(后续流程的主输入)
7
7
  - 原始符号表(JSONL):<project_root>/.jarvis/c2rust/symbols_raw.jsonl
8
- - 其他产物:translation_order.jsonl、library_replacements.jsonl、progress.json、symbol_map.jsonl 等
8
+ - 其他产物:translation_order.jsonl、library_replacements.jsonl、progress.json、config.json、symbol_map.jsonl 等
9
9
 
10
10
  推荐用法(CLI):
11
+ - 配置管理: jarvis-c2rust config --files <hdrs...> [--root-list-syms ...] [--disabled-libs ...]
11
12
  - 扫描: jarvis-c2rust scan
12
- - 库替代评估: jarvis-c2rust lib-replace --root-list-file roots.txt [--disabled-libs ...]
13
+ - 库替代评估: jarvis-c2rust lib-replace [-g <llm-group>]
13
14
  - 规划/落盘: jarvis-c2rust prepare [-g <llm-group>]
14
- - 转译: jarvis-c2rust transpile [-g <llm-group>] [--only ...] [--max-retries N] [--resume/--no-resume]
15
+ - 转译: jarvis-c2rust transpile [-g <llm-group>] [-m <max-retries>](断点续跑默认始终启用)
15
16
  - 代码优化: jarvis-c2rust optimize [--crate-dir ...] [--unsafe/--no-unsafe] [--structure/--no-structure] [--visibility/--no-visibility] [--doc/--no-doc] [-m N] [--dry-run]
16
- - 头文件收集: jarvis-c2rust collect <hdrs...> -o roots.txt
17
- - 一键流水线: jarvis-c2rust run [--files <hdrs...> -o roots.txt | --root-list-syms ...] [-g <llm-group>] [--disabled-libs ...]
17
+ - 一键流水线: jarvis-c2rust run [-g <llm-group>] [-m <max-retries>]
18
18
 
19
19
  或(模块方式):
20
20
  python -m jarvis.jarvis_c2rust.cli <subcommand>